mirror of
https://github.com/crocofied/CoreControl.git
synced 2025-12-29 16:14:43 +00:00
35
app/api/applications/add/route.ts
Normal file
35
app/api/applications/add/route.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { NextResponse, NextRequest } from "next/server";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
interface AddRequest {
|
||||
serverId: number;
|
||||
name: string;
|
||||
description: string;
|
||||
icon: string;
|
||||
publicURL: string;
|
||||
localURL: string;
|
||||
uptimecheckUrl: string;
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body: AddRequest = await request.json();
|
||||
const { serverId, name, description, icon, publicURL, localURL, uptimecheckUrl } = body;
|
||||
|
||||
const application = await prisma.application.create({
|
||||
data: {
|
||||
serverId,
|
||||
name,
|
||||
description,
|
||||
icon,
|
||||
publicURL,
|
||||
localURL,
|
||||
uptimecheckUrl
|
||||
}
|
||||
});
|
||||
|
||||
return NextResponse.json({ message: "Success", application });
|
||||
} catch (error: any) {
|
||||
return NextResponse.json({ error: error.message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
25
app/api/applications/delete/route.ts
Normal file
25
app/api/applications/delete/route.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { NextResponse, NextRequest } from "next/server";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const id = Number(body.id);
|
||||
|
||||
if (!id) {
|
||||
return NextResponse.json({ error: "Missing ID" }, { status: 400 });
|
||||
}
|
||||
|
||||
await prisma.application.delete({
|
||||
where: { id: id }
|
||||
});
|
||||
|
||||
await prisma.uptime_history.deleteMany({
|
||||
where: { applicationId: id }
|
||||
});
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
} catch (error: any) {
|
||||
return NextResponse.json({ error: error.message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
42
app/api/applications/edit/route.ts
Normal file
42
app/api/applications/edit/route.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { NextResponse, NextRequest } from "next/server";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
interface EditRequest {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
serverId: number;
|
||||
icon: string;
|
||||
publicURL: string;
|
||||
localURL: string;
|
||||
uptimecheckUrl: string;
|
||||
}
|
||||
|
||||
export async function PUT(request: NextRequest) {
|
||||
try {
|
||||
const body: EditRequest = await request.json();
|
||||
const { id, name, description, serverId, icon, publicURL, localURL, uptimecheckUrl } = body;
|
||||
|
||||
const existingApp = await prisma.application.findUnique({ where: { id } });
|
||||
if (!existingApp) {
|
||||
return NextResponse.json({ error: "Server not found" }, { status: 404 });
|
||||
}
|
||||
|
||||
const updatedApplication = await prisma.application.update({
|
||||
where: { id },
|
||||
data: {
|
||||
serverId,
|
||||
name,
|
||||
description,
|
||||
icon,
|
||||
publicURL,
|
||||
localURL,
|
||||
uptimecheckUrl
|
||||
}
|
||||
});
|
||||
|
||||
return NextResponse.json({ message: "Application updated", application: updatedApplication });
|
||||
} catch (error: any) {
|
||||
return NextResponse.json({ error: error.message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
50
app/api/applications/get/route.ts
Normal file
50
app/api/applications/get/route.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { NextResponse, NextRequest } from "next/server";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
interface PostRequest {
|
||||
page?: number;
|
||||
ITEMS_PER_PAGE?: number;
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body: PostRequest = await request.json();
|
||||
const page = Math.max(1, body.page || 1);
|
||||
const ITEMS_PER_PAGE = body.ITEMS_PER_PAGE || 10;
|
||||
|
||||
const [applications, totalCount, servers_all] = await Promise.all([
|
||||
prisma.application.findMany({
|
||||
skip: (page - 1) * ITEMS_PER_PAGE,
|
||||
take: ITEMS_PER_PAGE,
|
||||
orderBy: { name: "asc" }
|
||||
}),
|
||||
prisma.application.count(),
|
||||
prisma.server.findMany()
|
||||
]);
|
||||
|
||||
const serverIds = applications
|
||||
.map((app: { serverId: number | null }) => app.serverId)
|
||||
.filter((id:any): id is number => id !== null);
|
||||
|
||||
const servers = await prisma.server.findMany({
|
||||
where: { id: { in: serverIds } }
|
||||
});
|
||||
|
||||
const applicationsWithServers = applications.map((app: any) => ({
|
||||
...app,
|
||||
server: servers.find((s: any) => s.id === app.serverId)?.name || "No server"
|
||||
}));
|
||||
|
||||
const maxPage = Math.ceil(totalCount / ITEMS_PER_PAGE);
|
||||
|
||||
return NextResponse.json({
|
||||
applications: applicationsWithServers,
|
||||
servers: servers_all,
|
||||
maxPage,
|
||||
totalItems: totalCount
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const message = error instanceof Error ? error.message : "Unknown error";
|
||||
return NextResponse.json({ error: message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
48
app/api/applications/search/route.ts
Normal file
48
app/api/applications/search/route.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
import { NextResponse, NextRequest } from "next/server";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import Fuse from "fuse.js";
|
||||
|
||||
interface SearchRequest {
|
||||
searchterm: string;
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const body: SearchRequest = await request.json();
|
||||
const { searchterm } = body;
|
||||
|
||||
const applications = await prisma.application.findMany({});
|
||||
|
||||
const fuseOptions = {
|
||||
keys: ['name', 'description'],
|
||||
threshold: 0.3,
|
||||
includeScore: true,
|
||||
};
|
||||
|
||||
const fuse = new Fuse(applications, fuseOptions);
|
||||
|
||||
const searchResults = fuse.search(searchterm);
|
||||
|
||||
const searchedApps = searchResults.map(({ item }) => item);
|
||||
|
||||
// Get server IDs from the search results
|
||||
const serverIds = searchedApps
|
||||
.map(app => app.serverId)
|
||||
.filter((id): id is number => id !== null);
|
||||
|
||||
// Fetch server data for these applications
|
||||
const servers = await prisma.server.findMany({
|
||||
where: { id: { in: serverIds } }
|
||||
});
|
||||
|
||||
// Add server name to each application
|
||||
const results = searchedApps.map(app => ({
|
||||
...app,
|
||||
server: servers.find(s => s.id === app.serverId)?.name || "No server"
|
||||
}));
|
||||
|
||||
return NextResponse.json({ results });
|
||||
} catch (error: any) {
|
||||
return NextResponse.json({ error: error.message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
175
app/api/applications/uptime/route.ts
Normal file
175
app/api/applications/uptime/route.ts
Normal file
@@ -0,0 +1,175 @@
|
||||
import { NextResponse, NextRequest } from "next/server";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
interface RequestBody {
|
||||
timespan?: number;
|
||||
page?: number;
|
||||
itemsPerPage?: number;
|
||||
}
|
||||
|
||||
|
||||
const getTimeRange = (timespan: number) => {
|
||||
const now = new Date();
|
||||
switch (timespan) {
|
||||
case 1:
|
||||
return {
|
||||
start: new Date(now.getTime() - 60 * 60 * 1000),
|
||||
interval: 'minute'
|
||||
};
|
||||
case 2:
|
||||
return {
|
||||
start: new Date(now.getTime() - 24 * 60 * 60 * 1000),
|
||||
interval: 'hour'
|
||||
};
|
||||
case 3:
|
||||
return {
|
||||
start: new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000),
|
||||
interval: 'day'
|
||||
};
|
||||
case 4:
|
||||
return {
|
||||
start: new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000),
|
||||
interval: 'day'
|
||||
};
|
||||
default:
|
||||
return {
|
||||
start: new Date(now.getTime() - 60 * 60 * 1000),
|
||||
interval: 'minute'
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const generateIntervals = (timespan: number) => {
|
||||
const now = new Date();
|
||||
now.setSeconds(0, 0);
|
||||
|
||||
switch (timespan) {
|
||||
case 1: // 1 hour - 60 one-minute intervals
|
||||
return Array.from({ length: 60 }, (_, i) => {
|
||||
const d = new Date(now);
|
||||
d.setMinutes(d.getMinutes() - i);
|
||||
d.setSeconds(0, 0);
|
||||
return d;
|
||||
});
|
||||
|
||||
case 2: // 1 day - 24 one-hour intervals
|
||||
return Array.from({ length: 24 }, (_, i) => {
|
||||
const d = new Date(now);
|
||||
d.setHours(d.getHours() - i);
|
||||
d.setMinutes(0, 0, 0);
|
||||
return d;
|
||||
});
|
||||
|
||||
case 3: // 7 days
|
||||
return Array.from({ length: 7 }, (_, i) => {
|
||||
const d = new Date(now);
|
||||
d.setDate(d.getDate() - i);
|
||||
d.setHours(0, 0, 0, 0);
|
||||
return d;
|
||||
});
|
||||
|
||||
case 4: // 30 days
|
||||
return Array.from({ length: 30 }, (_, i) => {
|
||||
const d = new Date(now);
|
||||
d.setDate(d.getDate() - i);
|
||||
d.setHours(0, 0, 0, 0);
|
||||
return d;
|
||||
});
|
||||
|
||||
default:
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
const getIntervalKey = (date: Date, timespan: number) => {
|
||||
const d = new Date(date);
|
||||
switch (timespan) {
|
||||
case 1: // 1 hour - minute intervals
|
||||
d.setSeconds(0, 0);
|
||||
return d.toISOString();
|
||||
case 2: // 1 day - hour intervals
|
||||
d.setMinutes(0, 0, 0);
|
||||
return d.toISOString();
|
||||
case 3: // 7 days - day intervals
|
||||
case 4: // 30 days - day intervals
|
||||
d.setHours(0, 0, 0, 0);
|
||||
return d.toISOString();
|
||||
default:
|
||||
return d.toISOString();
|
||||
}
|
||||
};
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
const { timespan = 1, page = 1, itemsPerPage = 5 }: RequestBody = await request.json();
|
||||
const skip = (page - 1) * itemsPerPage;
|
||||
|
||||
// Get paginated and sorted applications
|
||||
const [applications, totalCount] = await Promise.all([
|
||||
prisma.application.findMany({
|
||||
skip,
|
||||
take: itemsPerPage,
|
||||
orderBy: { name: 'asc' }
|
||||
}),
|
||||
prisma.application.count()
|
||||
]);
|
||||
|
||||
const applicationIds = applications.map(app => app.id);
|
||||
|
||||
// Get time range and intervals
|
||||
const { start } = getTimeRange(timespan);
|
||||
const intervals = generateIntervals(timespan);
|
||||
|
||||
// Get uptime history for the filtered applications
|
||||
const uptimeHistory = await prisma.uptime_history.findMany({
|
||||
where: {
|
||||
applicationId: { in: applicationIds },
|
||||
createdAt: { gte: start }
|
||||
},
|
||||
orderBy: { createdAt: "desc" }
|
||||
});
|
||||
|
||||
// Process data for each application
|
||||
const result = applications.map(app => {
|
||||
const appChecks = uptimeHistory.filter(check => check.applicationId === app.id);
|
||||
const checksMap = new Map<string, { failed: number; total: number }>();
|
||||
|
||||
for (const check of appChecks) {
|
||||
const intervalKey = getIntervalKey(check.createdAt, timespan);
|
||||
const current = checksMap.get(intervalKey) || { failed: 0, total: 0 };
|
||||
current.total++;
|
||||
if (!check.online) current.failed++;
|
||||
checksMap.set(intervalKey, current);
|
||||
}
|
||||
|
||||
const uptimeSummary = intervals.map(interval => {
|
||||
const intervalKey = getIntervalKey(interval, timespan);
|
||||
const stats = checksMap.get(intervalKey);
|
||||
|
||||
return {
|
||||
timestamp: intervalKey,
|
||||
missing: !stats,
|
||||
online: stats ? (stats.failed / stats.total) <= 0.5 : null
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
appName: app.name,
|
||||
appId: app.id,
|
||||
uptimeSummary
|
||||
};
|
||||
});
|
||||
|
||||
return NextResponse.json({
|
||||
data: result,
|
||||
pagination: {
|
||||
currentPage: page,
|
||||
totalPages: Math.ceil(totalCount / itemsPerPage),
|
||||
totalItems: totalCount
|
||||
}
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const message = error instanceof Error ? error.message : "Unknown error";
|
||||
return NextResponse.json({ error: message }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user