Files
portabase/app/api/agent/[agentId]/status/helpers.ts
T

167 lines
6.2 KiB
TypeScript
Raw Normal View History

2024-11-29 12:54:34 +01:00
import {NextResponse} from "next/server";
import {Body} from "./route";
import {isUuidv4} from "@/utils/verify-uuid";
import {getFileUrlPresignedLocal, getFileUrlPreSignedS3Action} from "@/features/upload/private/upload.action";
import {Agent} from "@/db/schema/08_agent";
import {Database} from "@/db/schema/07_database";
2025-07-16 18:15:28 +02:00
import * as drizzleDb from "@/db";
import {db as dbClient} from "@/db";
import {and, eq} from "drizzle-orm";
2025-07-16 20:16:18 +02:00
import {dbmsEnumSchema, EDbmsSchema} from "@/db/schema/types";
import {ServerActionResult} from "@/types/action-type";
import {SafeActionResult} from "next-safe-action";
import {ZodString} from "zod";
import {withUpdatedAt} from "@/db/utils";
2024-11-29 12:54:34 +01:00
export async function handleDatabases(body: Body, agent: Agent, lastContact: Date) {
const databasesResponse = [];
2024-12-11 20:46:26 +01:00
const formatDatabase = (database: Database, backupAction: boolean, restoreAction: boolean, UrlBackup: string) => ({
2025-07-16 18:15:28 +02:00
generatedId: database.agentDatabaseId,
2024-11-29 12:54:34 +01:00
dbms: database.dbms,
data: {
backup: {
action: backupAction,
2024-12-13 14:05:40 +01:00
cron: database.backupPolicy,
2024-11-29 12:54:34 +01:00
},
restore: {
2024-12-11 20:46:26 +01:00
action: restoreAction,
file: UrlBackup,
2024-11-29 12:54:34 +01:00
},
},
});
for (const db of body.databases) {
2025-07-16 18:15:28 +02:00
const existingDatabase = await dbClient.query.database.findFirst({
where: eq(drizzleDb.schemas.database.agentDatabaseId, db.generatedId)
2024-11-29 12:54:34 +01:00
});
let backupAction: boolean = false
2024-12-11 20:46:26 +01:00
let restoreAction: boolean = false
let urlBackup: string = ""
2024-11-29 12:54:34 +01:00
if (!existingDatabase) {
if (!isUuidv4(db.generatedId)) {
return NextResponse.json(
{error: "generatedId is not a valid uuid"},
{status: 500}
2024-11-29 12:54:34 +01:00
);
}
2025-07-16 18:15:28 +02:00
const [databaseCreated] = await dbClient
.insert(drizzleDb.schemas.database)
.values({
2024-11-29 12:54:34 +01:00
agentId: agent.id,
name: db.name,
2025-07-16 20:16:18 +02:00
dbms: db.dbms as EDbmsSchema,
2025-07-16 18:15:28 +02:00
agentDatabaseId: db.generatedId,
2024-11-29 12:54:34 +01:00
lastContact: lastContact,
2025-07-16 18:15:28 +02:00
})
.returning();
2024-11-29 12:54:34 +01:00
if (databaseCreated) {
databasesResponse.push(formatDatabase(databaseCreated, backupAction, restoreAction, urlBackup));
2024-11-29 12:54:34 +01:00
}
} else {
2025-07-16 18:15:28 +02:00
const [databaseUpdated] = await dbClient
.update(drizzleDb.schemas.database)
.set({lastContact: lastContact})
2025-07-16 18:15:28 +02:00
.where(eq(drizzleDb.schemas.database.id, existingDatabase.id))
.returning();
const backup = await dbClient.query.backup.findFirst({
where: and(eq(drizzleDb.schemas.backup.databaseId, databaseUpdated.id), eq(drizzleDb.schemas.backup.status, "waiting"))
})
2025-07-16 18:15:28 +02:00
const restoration = await dbClient.query.restoration.findFirst({
where: and(eq(drizzleDb.schemas.restoration.databaseId, databaseUpdated.id), eq(drizzleDb.schemas.restoration.status, "waiting"))
2024-12-11 20:46:26 +01:00
})
if (backup) {
backupAction = true
2025-07-16 18:15:28 +02:00
await dbClient
.update(drizzleDb.schemas.backup)
.set(withUpdatedAt({status: "ongoing"}))
2025-07-16 18:15:28 +02:00
.where(eq(drizzleDb.schemas.backup.id, backup.id));
}
if (restoration) {
2024-12-11 20:46:26 +01:00
restoreAction = true
2025-07-16 18:15:28 +02:00
const backupToRestore = await dbClient.query.backup.findFirst({
where: eq(drizzleDb.schemas.backup.id, restoration.backupId),
with: {
database: {
with: {
project: true
}
}
}
2024-12-11 20:46:26 +01:00
})
2025-07-16 18:15:28 +02:00
const [settings] = await dbClient.select().from(drizzleDb.schemas.setting).where(eq(drizzleDb.schemas.setting.name, "system")).limit(1);
if (!settings) {
return NextResponse.json(
{error: "Unable to find settings"},
{status: 500}
);
}
2025-07-16 18:15:28 +02:00
const fileName = backupToRestore?.file
let data: SafeActionResult<string, ZodString, readonly [], {
_errors?: string[] | undefined;
}, readonly [], ServerActionResult<string>, object> | undefined
try {
if (settings.storage == "local") {
data = await getFileUrlPresignedLocal({fileName: fileName!})
} else if (settings.storage == "s3") {
data = await getFileUrlPreSignedS3Action(`backups/${backupToRestore?.database.project?.slug}/${fileName}`);
}
if (data?.data?.success) {
urlBackup = data.data.value ?? "";
} else {
await dbClient
.update(drizzleDb.schemas.restoration)
.set({status: "failed"})
.where(eq(drizzleDb.schemas.restoration.id, restoration.id));
// @ts-ignore
const errorMessage = data?.data?.actionError?.message || "Failed to get presigned URL";
console.error("Restoration failed: ", errorMessage);
continue;
}
} catch (err) {
console.error("Restoration crashed unexpectedly:", err);
await dbClient
.update(drizzleDb.schemas.restoration)
.set({status: "failed"})
.where(eq(drizzleDb.schemas.restoration.id, restoration.id));
continue;
}
2025-07-16 18:15:28 +02:00
await dbClient
.update(drizzleDb.schemas.restoration)
.set({status: "ongoing"})
2025-07-16 18:15:28 +02:00
.where(eq(drizzleDb.schemas.restoration.id, restoration.id));
2024-12-11 20:46:26 +01:00
}
databasesResponse.push(formatDatabase(databaseUpdated, backupAction, restoreAction, urlBackup));
2024-11-29 12:54:34 +01:00
}
}
return databasesResponse;
}