This commit is contained in:
Benjamin Toby
2025-07-09 20:42:01 +01:00
parent c37d105dee
commit 382da38bb0
25 changed files with 752 additions and 21 deletions
@@ -6,7 +6,7 @@ import updateUsersTableSchema from "../../backend/updateUsersTableSchema";
import dbHandler from "../../backend/dbHandler";
import hashPassword from "../../dsql/hashPassword";
import validateEmail from "../../email/fns/validate-email";
import { DSQL_DATASQUIREL_USERS } from "@/package-shared/types/dsql";
import { DSQL_DATASQUIREL_USERS } from "../../../types/dsql";
/**
* # API Create User
@@ -0,0 +1,78 @@
import _ from "lodash";
import path from "path";
import writeBacupFiles from "./write-backup-files";
import { APIResponseObject } from "../../../../../types";
import grabDirNames from "../../../../../utils/backend/names/grab-dir-names";
import {
DSQL_DATASQUIREL_BACKUPS,
DsqlTables,
} from "../../../../../types/dsql";
import addDbEntry from "../../../db/addDbEntry";
import numberfy from "../../../../../utils/numberfy";
import dbGrabUserResource from "../../../../web-app/db/grab-user-resource";
type Params = {
targetUserId?: string | number;
};
export default async function suAddBackup({
targetUserId,
}: Params): Promise<APIResponseObject> {
try {
const { mainBackupDir, userBackupDir } = grabDirNames({
userId: targetUserId,
});
if (targetUserId && !userBackupDir) {
return {
success: false,
msg: `Error grabbing user backup directory`,
};
}
const newBackup: DSQL_DATASQUIREL_BACKUPS = {
user_id: targetUserId ? numberfy(targetUserId) : undefined,
};
const newBackupEntry = await addDbEntry<
DSQL_DATASQUIREL_BACKUPS,
(typeof DsqlTables)[number]
>({
tableName: "backups",
data: newBackup,
});
if (!newBackupEntry?.payload?.insertId) {
return {
success: false,
msg: `Couldn't create new backup entry`,
};
}
const { single: newlyAddedBackup } =
await dbGrabUserResource<DSQL_DATASQUIREL_BACKUPS>({
tableName: "backups",
targetID: newBackupEntry.payload?.insertId,
isSuperUser: true,
});
if (!newlyAddedBackup?.id) {
return {
success: false,
msg: `Couldn't fetch newly added backup`,
};
}
const writeBackup = await writeBacupFiles({
backup: newlyAddedBackup,
});
return writeBackup;
} catch (error: any) {
return {
success: false,
msg: `Backup add failed`,
error: error.message,
};
}
}
@@ -0,0 +1,114 @@
import fs from "fs";
import path from "path";
import grabDirNames from "../../../../../utils/backend/names/grab-dir-names";
import { APIResponseObject, UserType } from "../../../../../types";
import { DSQL_DATASQUIREL_BACKUPS } from "../../../../../types/dsql";
import importMariadbDatabase from "../../../../../utils/backend/import-mariadb-database";
type Params = {
user: UserType;
backup: DSQL_DATASQUIREL_BACKUPS;
};
export default async function suRestoreBackup({
user,
backup,
}: Params): Promise<APIResponseObject> {
try {
const {
mainBackupDir,
userBackupDir,
sqlBackupDirName,
schemasBackupDirName,
targetUserPrivateDir,
oldSchemasDir,
} = grabDirNames({
userId: backup.user_id,
});
if (backup.user_id && !userBackupDir) {
return {
success: false,
msg: `Error grabbing user backup directory`,
};
}
if (!backup.uuid) {
return {
success: false,
msg: `No UUID found for backup`,
};
}
const existingBackupDir = path.join(
backup.user_id && userBackupDir ? userBackupDir : mainBackupDir,
backup.uuid
);
const userDatabases = fs.readdirSync(
path.join(existingBackupDir, sqlBackupDirName)
);
const databasesToRestore = userDatabases?.map(
(db) => db.split(".")[0]
) || [process.env.DSQL_DB_NAME || "datasquirel"];
for (let i = 0; i < databasesToRestore.length; i++) {
const dbToBackup = databasesToRestore[i];
if (!dbToBackup) continue;
const dbFileName = `${dbToBackup}.sql`;
const dbFilePath = path.join(
existingBackupDir,
sqlBackupDirName,
dbFileName
);
importMariadbDatabase({
dbFullName: dbToBackup,
targetFilePath: dbFilePath,
});
}
const userSchemaDirFiles = targetUserPrivateDir
? fs
.readdirSync(targetUserPrivateDir)
.filter((dirName) => dirName.match(/^\d+\.json$/))
: undefined;
const appSchemaDirFiles = fs
.readdirSync(oldSchemasDir)
.filter((dirName) => dirName.match(/^\d+\.json$/));
const schemaFilesToWrite =
backup.user_id && userSchemaDirFiles
? userSchemaDirFiles
: appSchemaDirFiles;
for (let i = 0; i < schemaFilesToWrite.length; i++) {
const schemaFileName = schemaFilesToWrite[i];
const originSchemaFilePath = path.join(
existingBackupDir,
schemasBackupDirName,
schemaFileName
);
const destinationSchemaFilePath = path.join(
backup.user_id && targetUserPrivateDir
? targetUserPrivateDir
: oldSchemasDir,
schemaFileName
);
fs.copyFileSync(originSchemaFilePath, destinationSchemaFilePath);
}
return { success: true };
} catch (error: any) {
return {
success: false,
msg: `Failed to write backup files`,
error: error.message,
};
}
}
@@ -0,0 +1,124 @@
import fs from "fs";
import path from "path";
import { DSQL_DATASQUIREL_BACKUPS } from "../../../../../types/dsql";
import { APIResponseObject } from "../../../../../types";
import grabDirNames from "../../../../../utils/backend/names/grab-dir-names";
import { AppNames } from "../../../../../dict/app-names";
import dbHandler from "../../../dbHandler";
import exportMariadbDatabase from "../../../../../utils/backend/export-mariadb-database";
type Params = {
backup: DSQL_DATASQUIREL_BACKUPS;
};
export default async function writeBackupFiles({
backup,
}: Params): Promise<APIResponseObject> {
try {
const {
mainBackupDir,
userBackupDir,
sqlBackupDirName,
schemasBackupDirName,
targetUserPrivateDir,
oldSchemasDir,
} = grabDirNames({
userId: backup.user_id,
});
if (backup.user_id && !userBackupDir) {
return {
success: false,
msg: `Error grabbing user backup directory`,
};
}
if (!backup.uuid) {
return {
success: false,
msg: `No UUID found for backup`,
};
}
const newBackupDir = path.join(
backup.user_id && userBackupDir ? userBackupDir : mainBackupDir,
backup.uuid
);
fs.mkdirSync(newBackupDir, { recursive: true });
fs.mkdirSync(path.join(newBackupDir, sqlBackupDirName), {
recursive: true,
});
fs.mkdirSync(path.join(newBackupDir, schemasBackupDirName), {
recursive: true,
});
const userDatabases = backup.user_id
? ((await dbHandler({
query: `SHOW DATABASES LIKE '${AppNames["DsqlDbPrefix"]}${backup.user_id}_%'`,
})) as { [k: string]: string }[])
: undefined;
const databasesToBackup = userDatabases?.map(
(db) => Object.values(db)[0]
) || [process.env.DSQL_DB_NAME || "datasquirel"];
for (let i = 0; i < databasesToBackup.length; i++) {
const dbToBackup = databasesToBackup[i];
if (!dbToBackup) continue;
const dbFileName = `${dbToBackup}.sql`;
const dbFilePath = path.join(
newBackupDir,
sqlBackupDirName,
dbFileName
);
exportMariadbDatabase({
dbFullName: dbToBackup,
targetFilePath: dbFilePath,
});
}
const userSchemaDirFiles = targetUserPrivateDir
? fs
.readdirSync(targetUserPrivateDir)
.filter((dirName) => dirName.match(/^\d+\.json$/))
: undefined;
const appSchemaDirFiles = fs
.readdirSync(oldSchemasDir)
.filter((dirName) => dirName.match(/^\d+\.json$/));
const schemaFilesToWrite =
backup.user_id && userSchemaDirFiles
? userSchemaDirFiles
: appSchemaDirFiles;
for (let i = 0; i < schemaFilesToWrite.length; i++) {
const schemaFileName = schemaFilesToWrite[i];
const originSchemaFilePath = path.join(
backup.user_id && targetUserPrivateDir
? targetUserPrivateDir
: oldSchemasDir,
schemaFileName
);
const destinationSchemaFilePath = path.join(
newBackupDir,
schemasBackupDirName,
schemaFileName
);
fs.copyFileSync(originSchemaFilePath, destinationSchemaFilePath);
}
return { success: true };
} catch (error: any) {
return {
success: false,
msg: `Failed to write backup files`,
error: error.message,
};
}
}
@@ -0,0 +1,60 @@
import fs from "fs";
import path from "path";
import _ from "lodash";
import { DSQL_DATASQUIREL_BACKUPS, DsqlTables } from "../../../../types/dsql";
import { APIResponseObject } from "../../../../types";
import grabDirNames from "../../../../utils/backend/names/grab-dir-names";
import deleteDbEntry from "../../db/deleteDbEntry";
import numberfy from "../../../../utils/numberfy";
type Params = {
backup: DSQL_DATASQUIREL_BACKUPS;
};
export default async function deleteBackup({
backup,
}: Params): Promise<APIResponseObject> {
try {
const { mainBackupDir, userBackupDir } = grabDirNames({
userId: backup.user_id,
});
if (backup.user_id && !userBackupDir) {
return {
success: false,
msg: `Error grabbing user backup directory`,
};
}
if (!backup.uuid) {
return {
success: false,
msg: `No UUID found for backup`,
};
}
const newBackupDir = path.join(
backup.user_id && userBackupDir ? userBackupDir : mainBackupDir,
backup.uuid
);
fs.rmSync(newBackupDir, { recursive: true, force: true });
await deleteDbEntry<
DSQL_DATASQUIREL_BACKUPS,
(typeof DsqlTables)[number]
>({
identifierColumnName: "id",
identifierValue: numberfy(backup.id),
tableName: "backups",
});
return { success: true };
} catch (error: any) {
return {
success: false,
msg: `Failed to write backup files`,
error: error.message,
};
}
}
@@ -1,8 +1,8 @@
import dbGrabUserResource from "@/src/functions/db/grab-user-resource";
import { DSQL_DATASQUIREL_BACKUPS } from "@/package-shared/types/dsql";
import suAddBackup from "@/src/functions/api/su/add-backup";
import grabConfig from "@/package-shared/utils/backend/config/grab-config";
import deleteBackup from "@/src/functions/api/su/add-backup/delete-backup";
import { DSQL_DATASQUIREL_BACKUPS } from "../../types/dsql";
import grabConfig from "../../utils/backend/config/grab-config";
import dbGrabUserResource from "../web-app/db/grab-user-resource";
import suAddBackup from "./backups/su/add-backup";
import deleteBackup from "./backups/su/delete-backup";
type HandleBackupParams = {
appBackup?: boolean;