Rearchitecture for v0.4.0 (#197)

* feat: database redist support

* feat: rearchitecture of database schemas, migration reset, and #180

* feat: import redists

* fix: giantbomb logging bug

* feat: partial user platform support + statusMessage -> message

* feat: add user platform filters to store view

* fix: sanitize svg uploads

... copilot suggested this

I feel dirty.

* feat: beginnings of platform & redist management

* feat: add server side redist patching

* fix: update drop-base commit

* feat: import of custom platforms & file extensions

* fix: redelete platform

* fix: remove platform

* feat: uninstall commands, new R UI

* checkpoint: before migrating to nuxt v4

* update to nuxt 4

* fix: fixes for Nuxt v4 update

* fix: remaining type issues

* feat: initial feedback to import other kinds of versions

* working commit

* fix: lint

* feat: redist import
This commit is contained in:
DecDuck
2025-11-10 10:36:13 +11:00
committed by GitHub
parent dfa30c8a65
commit 251ddb8ff8
465 changed files with 8029 additions and 7509 deletions

View File

@ -1,6 +1,6 @@
import { AuthMec } from "~/prisma/client/enums";
import aclManager from "~/server/internal/acls";
import authManager from "~/server/internal/auth";
import { AuthMec } from "~~/prisma/client/enums";
import aclManager from "~~/server/internal/acls";
import authManager from "~~/server/internal/auth";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["auth:read", "setup"]);

View File

@ -1,7 +1,7 @@
import { type } from "arktype";
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
const DeleteInvite = type({
id: "string",

View File

@ -1,7 +1,7 @@
import aclManager from "~/server/internal/acls";
import { systemConfig } from "~/server/internal/config/sys-conf";
import prisma from "~/server/internal/db/database";
import taskHandler from "~/server/internal/tasks";
import aclManager from "~~/server/internal/acls";
import { systemConfig } from "~~/server/internal/config/sys-conf";
import prisma from "~~/server/internal/db/database";
import taskHandler from "~~/server/internal/tasks";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, [

View File

@ -1,8 +1,8 @@
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
import { SharedRegisterValidator } from "../../../auth/signup/simple.post";
import { systemConfig } from "~/server/internal/config/sys-conf";
import { systemConfig } from "~~/server/internal/config/sys-conf";
const CreateInvite = SharedRegisterValidator.partial()
.and({

View File

@ -1,7 +1,7 @@
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import objectHandler from "~/server/internal/objects";
import { handleFileUpload } from "~/server/internal/utils/handlefileupload";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
import objectHandler from "~~/server/internal/objects";
import { handleFileUpload } from "~~/server/internal/utils/handlefileupload";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["company:update"]);
@ -15,13 +15,13 @@ export default defineEventHandler(async (h3) => {
});
if (!company)
throw createError({ statusCode: 400, statusMessage: "Invalid company id" });
throw createError({ statusCode: 400, message: "Invalid company id" });
const result = await handleFileUpload(h3, {}, ["internal:read"], 1);
if (!result)
throw createError({
statusCode: 400,
statusMessage: "File upload required (multipart form)",
message: "File upload required (multipart form)",
});
const [ids, , pull, dump] = result;
@ -29,7 +29,7 @@ export default defineEventHandler(async (h3) => {
if (!id)
throw createError({
statusCode: 400,
statusMessage: "Upload at least one file.",
message: "Upload at least one file.",
});
try {

View File

@ -1,7 +1,7 @@
import { type } from "arktype";
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
const GameDelete = type({
id: "string",

View File

@ -1,7 +1,7 @@
import { type } from "arktype";
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
const GamePatch = type({
action: "'developed' | 'published'",

View File

@ -1,7 +1,7 @@
import { type } from "arktype";
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
const GamePost = type({
published: "boolean",
@ -20,7 +20,7 @@ export default defineEventHandler(async (h3) => {
if (!body.published && !body.developed)
throw createError({
statusCode: 400,
statusMessage: "Must be related (either developed or published).",
message: "Must be related (either developed or published).",
});
const publisherConnect = body.published

View File

@ -1,7 +1,7 @@
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import objectHandler from "~/server/internal/objects";
import { handleFileUpload } from "~/server/internal/utils/handlefileupload";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
import objectHandler from "~~/server/internal/objects";
import { handleFileUpload } from "~~/server/internal/utils/handlefileupload";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["company:update"]);
@ -15,13 +15,13 @@ export default defineEventHandler(async (h3) => {
});
if (!company)
throw createError({ statusCode: 400, statusMessage: "Invalid company id" });
throw createError({ statusCode: 400, message: "Invalid company id" });
const result = await handleFileUpload(h3, {}, ["internal:read"], 1);
if (!result)
throw createError({
statusCode: 400,
statusMessage: "File upload required (multipart form)",
message: "File upload required (multipart form)",
});
const [ids, , pull, dump] = result;
@ -29,7 +29,7 @@ export default defineEventHandler(async (h3) => {
if (!id)
throw createError({
statusCode: 400,
statusMessage: "Upload at least one file.",
message: "Upload at least one file.",
});
try {

View File

@ -1,5 +1,5 @@
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["company:delete"]);
@ -9,6 +9,6 @@ export default defineEventHandler(async (h3) => {
const company = await prisma.company.deleteMany({ where: { id } });
if (company.count == 0)
throw createError({ statusCode: 404, statusMessage: "Company not found" });
throw createError({ statusCode: 404, message: "Company not found" });
return;
});

View File

@ -1,5 +1,5 @@
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["company:read"]);
@ -23,7 +23,7 @@ export default defineEventHandler(async (h3) => {
},
});
if (!company)
throw createError({ statusCode: 404, statusMessage: "Company not found" });
throw createError({ statusCode: 404, message: "Company not found" });
const games = await prisma.game.findMany({
where: {
OR: [

View File

@ -1,5 +1,5 @@
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["company:update"]);

View File

@ -1,5 +1,5 @@
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["company:read"]);

View File

@ -1,10 +1,10 @@
import { type } from "arktype";
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import aclManager from "~/server/internal/acls";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
import aclManager from "~~/server/internal/acls";
import * as jdenticon from "jdenticon";
import { ObjectTransactionalHandler } from "~/server/internal/objects/transactional";
import prisma from "~/server/internal/db/database";
import { MetadataSource } from "~/prisma/client/enums";
import { ObjectTransactionalHandler } from "~~/server/internal/objects/transactional";
import prisma from "~~/server/internal/db/database";
import { MetadataSource } from "~~/prisma/client/enums";
const CompanyCreate = type({
name: "string",

View File

@ -1,5 +1,5 @@
import aclManager from "~/server/internal/acls";
import libraryManager from "~/server/internal/library";
import aclManager from "~~/server/internal/acls";
import libraryManager from "~~/server/internal/library";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["game:delete"]);
@ -7,7 +7,7 @@ export default defineEventHandler(async (h3) => {
const gameId = getRouterParam(h3, "id")!;
libraryManager.deleteGame(gameId);
await libraryManager.deleteGame(gameId);
return {};
});

View File

@ -1,7 +1,6 @@
import type { GameVersion } from "~/prisma/client/client";
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import libraryManager from "~/server/internal/library";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
import libraryManager from "~~/server/internal/library";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["game:read"]);
@ -15,24 +14,32 @@ export default defineEventHandler(async (h3) => {
},
include: {
versions: {
orderBy: {
versionIndex: "asc",
},
omit: {
dropletManifest: true,
},
include: {
gameVersions: {
include: {
install: true,
uninstall: true,
launches: true,
},
},
},
},
tags: true,
},
});
if (!game || !game.libraryId)
throw createError({ statusCode: 404, statusMessage: "Game ID not found" });
throw createError({ statusCode: 404, message: "Game ID not found" });
const getGameVersionSize = async (version: GameVersion) => {
const getGameVersionSize = async (
version: Omit<(typeof game)["versions"][number], "dropletManifest">,
) => {
const size = await libraryManager.getGameVersionSize(
gameId,
version.versionName,
version.versionId,
);
return { ...version, size };
};

View File

@ -1,5 +1,5 @@
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["game:update"]);

View File

@ -1,7 +1,13 @@
import type { Prisma } from "~/prisma/client/client";
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import { handleFileUpload } from "~/server/internal/utils/handlefileupload";
import { ArkErrors, type } from "arktype";
import type { Prisma } from "~~/prisma/client/client";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
import { handleFileUpload } from "~~/server/internal/utils/handlefileupload";
const UpdateMetadata = type({
name: "string?",
description: "string?",
});
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["game:update"]);
@ -11,7 +17,7 @@ export default defineEventHandler(async (h3) => {
if (!form)
throw createError({
statusCode: 400,
statusMessage: "This endpoint requires multipart form data.",
message: "This endpoint requires multipart form data.",
});
const gameId = getRouterParam(h3, "id")!;
@ -20,20 +26,20 @@ export default defineEventHandler(async (h3) => {
if (!uploadResult)
throw createError({
statusCode: 400,
statusMessage: "Failed to upload file",
message: "Failed to upload file",
});
const [ids, options, pull, dump] = uploadResult;
const id = ids.at(0);
// handleFileUpload reads the rest of the options for us.
const name = options.name;
const description = options.description;
const body = UpdateMetadata(options);
if (body instanceof ArkErrors)
throw createError({ statusCode: 400, message: body.summary });
const updateModel: Prisma.GameUpdateInput = {
mName: name,
mShortDescription: description,
...(body.name ? { mName: body.name } : undefined),
...(body.description ? { mShortDescription: body.description } : undefined),
};
// handle if user uploaded new icon

View File

@ -1,7 +1,7 @@
import { type } from "arktype";
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
const PatchTags = type({
tags: "string[]",

View File

@ -1,8 +1,8 @@
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import objectHandler from "~/server/internal/objects";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
import objectHandler from "~~/server/internal/objects";
import { type } from "arktype";
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
const DeleteGameImage = type({
gameId: "string",
@ -32,20 +32,20 @@ export default defineEventHandler<{
});
if (!game)
throw createError({ statusCode: 400, statusMessage: "Invalid game ID" });
throw createError({ statusCode: 400, message: "Invalid game ID" });
const imageIndex = game.mImageLibraryObjectIds.findIndex((e) => e == imageId);
if (imageIndex == -1)
throw createError({ statusCode: 400, statusMessage: "Image not found" });
throw createError({ statusCode: 400, message: "Image not found" });
game.mImageLibraryObjectIds.splice(imageIndex, 1);
await objectHandler.deleteAsSystem(imageId);
if (game.mBannerObjectId === imageId) {
game.mBannerObjectId = game.mImageLibraryObjectIds[0];
game.mBannerObjectId = game.mImageLibraryObjectIds[0] ?? "";
}
if (game.mCoverObjectId === imageId) {
game.mCoverObjectId = game.mImageLibraryObjectIds[0];
game.mCoverObjectId = game.mImageLibraryObjectIds[0] ?? "";
}
const result = await prisma.game.update({

View File

@ -1,6 +1,6 @@
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import { handleFileUpload } from "~/server/internal/utils/handlefileupload";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
import { handleFileUpload } from "~~/server/internal/utils/handlefileupload";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["game:image:new"]);
@ -10,14 +10,14 @@ export default defineEventHandler(async (h3) => {
if (!form)
throw createError({
statusCode: 400,
statusMessage: "This endpoint requires multipart form data.",
message: "This endpoint requires multipart form data.",
});
const uploadResult = await handleFileUpload(h3, {}, ["internal:read"]);
if (!uploadResult)
throw createError({
statusCode: 400,
statusMessage: "Failed to upload file",
message: "Failed to upload file",
});
const [ids, options, pull, dump] = uploadResult;
@ -25,21 +25,21 @@ export default defineEventHandler(async (h3) => {
dump();
throw createError({
statusCode: 400,
statusMessage: "Did not upload a file",
message: "Did not upload a file",
});
}
const gameId = options.id;
const gameId = options.id as string;
if (!gameId)
throw createError({
statusCode: 400,
statusMessage: "No game ID attached",
message: "No game ID attached",
});
const hasGame = (await prisma.game.count({ where: { id: gameId } })) != 0;
if (!hasGame) {
dump();
throw createError({ statusCode: 400, statusMessage: "Invalid game ID" });
throw createError({ statusCode: 400, message: "Invalid game ID" });
}
const result = await prisma.game.update({

View File

@ -1,5 +1,5 @@
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["game:read"]);

View File

@ -1,11 +1,10 @@
import { type } from "arktype";
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import aclManager from "~/server/internal/acls";
import libraryManager from "~/server/internal/library";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
import aclManager from "~~/server/internal/acls";
import libraryManager from "~~/server/internal/library";
const DeleteVersion = type({
id: "string",
versionName: "string",
}).configure(throwingArktype);
export default defineEventHandler<{ body: typeof DeleteVersion }>(
@ -17,10 +16,8 @@ export default defineEventHandler<{ body: typeof DeleteVersion }>(
const body = await readDropValidatedBody(h3, DeleteVersion);
const gameId = body.id.toString();
const version = body.versionName.toString();
await libraryManager.deleteGameVersion(body.id);
await libraryManager.deleteGameVersion(gameId, version);
return {};
},
);

View File

@ -1,7 +1,7 @@
import { type } from "arktype";
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
const UpdateVersionOrder = type({
id: "string",
@ -16,57 +16,24 @@ export default defineEventHandler<{ body: typeof UpdateVersionOrder }>(
if (!allowed) throw createError({ statusCode: 403 });
const body = await readDropValidatedBody(h3, UpdateVersionOrder);
const gameId = body.id;
// We expect an array of the version names for this game
const unsortedVersions = await prisma.gameVersion.findMany({
where: {
versionName: { in: body.versions },
},
select: {
versionName: true,
versionIndex: true,
delta: true,
platform: true,
},
});
const versions = body.versions
.map((e) => unsortedVersions.find((v) => v.versionName === e))
.filter((e) => e !== undefined);
if (versions.length !== unsortedVersions.length)
throw createError({
statusCode: 500,
statusMessage: "Sorting versions yielded less results, somehow.",
});
// Validate the new order
const has: { [key: string]: boolean } = {};
for (const version of versions) {
if (version.delta && !has[version.platform])
throw createError({
statusCode: 400,
statusMessage: `"${version.versionName}" requires a base version to apply the delta to.`,
});
has[version.platform] = true;
}
const versions = body.versions;
await prisma.$transaction(
versions.map((version, versionIndex) =>
prisma.gameVersion.update({
versions.map((versionId, versionIndex) =>
prisma.version.update({
where: {
gameId_versionName: {
gameId: gameId,
versionName: version.versionName,
},
versionId,
},
data: {
versionIndex: versionIndex,
},
select: {},
}),
),
);
return versions;
setResponseStatus(h3, 201);
return;
},
);

View File

@ -1,8 +1,8 @@
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import { systemConfig } from "~/server/internal/config/sys-conf";
import libraryManager from "~/server/internal/library";
import userStatsManager from "~/server/internal/userstats";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
import { systemConfig } from "~~/server/internal/config/sys-conf";
import libraryManager from "~~/server/internal/library";
import userStatsManager from "~~/server/internal/userstats";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["game:read"]);

View File

@ -1,8 +1,8 @@
import aclManager from "~/server/internal/acls";
import libraryManager from "~/server/internal/library";
import aclManager from "~~/server/internal/acls";
import libraryManager from "~~/server/internal/library";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["import:game:read"]);
const allowed = await aclManager.allowSystemACL(h3, ["import:game:read", "import:redist:read"]);
if (!allowed) throw createError({ statusCode: 403 });
const unimportedGames = await libraryManager.fetchUnimportedGames();

View File

@ -1,8 +1,8 @@
import { type } from "arktype";
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import aclManager from "~/server/internal/acls";
import libraryManager from "~/server/internal/library";
import metadataHandler from "~/server/internal/metadata";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
import aclManager from "~~/server/internal/acls";
import libraryManager from "~~/server/internal/library";
import metadataHandler from "~~/server/internal/metadata";
const ImportGameBody = type({
library: "string",
@ -27,14 +27,14 @@ export default defineEventHandler<{ body: typeof ImportGameBody.infer }>(
if (!path)
throw createError({
statusCode: 400,
statusMessage: "Path missing from body",
message: "Path missing from body",
});
const valid = await libraryManager.checkUnimportedGamePath(library, path);
if (!valid)
throw createError({
statusCode: 400,
statusMessage: "Invalid library or game.",
message: "Invalid library or game.",
});
const taskId = metadata
@ -44,7 +44,7 @@ export default defineEventHandler<{ body: typeof ImportGameBody.infer }>(
if (!taskId)
throw createError({
statusCode: 400,
statusMessage:
message:
"Duplicate metadata import. Please chose a different game or metadata provider.",
});

View File

@ -1,5 +1,5 @@
import aclManager from "~/server/internal/acls";
import metadataHandler from "~/server/internal/metadata";
import aclManager from "~~/server/internal/acls";
import metadataHandler from "~~/server/internal/metadata";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["import:game:read"]);
@ -8,14 +8,14 @@ export default defineEventHandler(async (h3) => {
const query = getQuery(h3);
const search = query.q?.toString();
if (!search)
throw createError({ statusCode: 400, statusMessage: "Invalid search" });
throw createError({ statusCode: 400, message: "Invalid search" });
const results = await metadataHandler.search(search);
if (results.length == 0)
throw createError({
statusCode: 404,
statusMessage: "No metadata provider returned search results.",
message: "No metadata provider returned search results.",
});
return results;

View File

@ -0,0 +1,3 @@
import handler from "../game/index.get";
export default handler;

View File

@ -0,0 +1,92 @@
import { ArkErrors, type } from "arktype";
import aclManager from "~~/server/internal/acls";
import { handleFileUpload } from "~~/server/internal/utils/handlefileupload";
import * as jdenticon from "jdenticon";
import prisma from "~~/server/internal/db/database";
import libraryManager from "~~/server/internal/library";
import jsdom from "jsdom";
export const ImportRedist = type({
library: "string",
path: "string",
name: "string",
description: "string",
"platform?": type({
name: "string",
icon: "string",
fileExts: type("string").pipe.try((s) => JSON.parse(s), type("string.alphanumeric").array()),
}),
});
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["import:redist:new"]);
if (!allowed) throw createError({ statusCode: 403 });
const body = await handleFileUpload(h3, {}, ["internal:read"], 1);
if (!body) throw createError({ statusCode: 400, message: "Body required." });
const [ids, rawOptions, pull, , add] = body;
const id = ids.at(0);
const options = ImportRedist(rawOptions);
if (options instanceof ArkErrors)
throw createError({ statusCode: 400, message: options.summary });
const valid = await libraryManager.checkUnimportedGamePath(
options.library,
options.path,
);
if (!valid)
throw createError({
statusCode: 400,
message: "Invalid library or game.",
});
const icon = id ?? add(jdenticon.toPng(options.name, 512));
let svgContent = "";
if (options.platform) {
// This logic is duplicated on the client to make viewing there possible.
// TODO?: refactor into a single function. Not totally sure if this is a good idea though,
// because they do different things
const dom = new jsdom.JSDOM(options.platform.icon);
const svg = dom.window.document.getElementsByTagName("svg").item(0);
if (!svg)
throw createError({
statusCode: 400,
statusMessage: "No SVG in uploaded image.",
});
svg.removeAttribute("width");
svg.removeAttribute("height");
svgContent = svg.outerHTML;
}
const redist = await prisma.redist.create({
data: {
libraryId: options.library,
libraryPath: options.path,
mName: options.name,
mShortDescription: options.description,
mIconObjectId: icon,
platform: {
...(options.platform
? {
create: {
platformName: options.platform.name,
iconSvg: svgContent,
fileExtensions: options.platform.fileExts.map((v) => `.${v}`),
},
}
: undefined),
},
},
});
await pull();
return redist;
});

View File

@ -1,32 +1,36 @@
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import libraryManager from "~/server/internal/library";
import { ArkErrors, type } from "arktype";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
import libraryManager, { VersionImportModes } from "~~/server/internal/library";
export const PreloadQuery = type({
id: "string",
mode: type.enumerated(...VersionImportModes),
});
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["import:version:read"]);
if (!allowed) throw createError({ statusCode: 403 });
const query = await getQuery(h3);
const gameId = query.id?.toString();
if (!gameId)
throw createError({
statusCode: 400,
statusMessage: "Missing id in request params",
});
const rawQuery = await getQuery(h3);
const query = PreloadQuery(rawQuery);
if (query instanceof ArkErrors)
throw createError({ statusCode: 400, message: query.summary });
const game = await prisma.game.findUnique({
where: { id: gameId },
select: { libraryId: true, libraryPath: true },
});
if (!game || !game.libraryId)
throw createError({ statusCode: 404, statusMessage: "Game not found" });
const value: { libraryId: string; libraryPath: string } | undefined =
await // eslint-disable-next-line @typescript-eslint/no-explicit-any
(prisma[query.mode] as any).findUnique({
where: { id: query.id },
select: { libraryId: true, libraryPath: true },
});
if (!value) throw createError({ statusCode: 404, message: "Not found" });
const unimportedVersions = await libraryManager.fetchUnimportedGameVersions(
game.libraryId,
game.libraryPath,
value.libraryId,
value.libraryPath,
);
if (!unimportedVersions)
throw createError({ statusCode: 400, statusMessage: "Invalid game ID" });
throw createError({ statusCode: 400, message: "Invalid game ID" });
return unimportedVersions;
});

View File

@ -1,88 +1,71 @@
import { type } from "arktype";
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import libraryManager from "~/server/internal/library";
import { parsePlatform } from "~/server/internal/utils/parseplatform";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
import aclManager from "~~/server/internal/acls";
import libraryManager from "~~/server/internal/library";
const ImportVersion = type({
export const LaunchCommands = type({
name: "string > 0",
description: "string = ''",
launchCommand: "string > 0",
launchArgs: "string = ''",
}).array();
const ImportVersionBase = type({
id: "string",
version: "string",
name: "string?",
platform: "string",
launch: "string = ''",
launchArgs: "string = ''",
setup: "string = ''",
setupArgs: "string = ''",
onlySetup: "boolean = false",
delta: "boolean = false",
});
const ImportGameVersion = type({
mode: "'game'",
onlySetup: "boolean = false",
umuId: "string = ''",
}).configure(throwingArktype);
install: "string?",
installArgs: "string?",
launches: LaunchCommands,
uninstall: "string?",
uninstallArgs: "string?",
});
const ImportRedistVersion = type({
mode: "'redist'",
install: "string?",
installArgs: "string?",
launches: LaunchCommands,
uninstall: "string?",
uninstallArgs: "string?",
});
export const ImportVersion = ImportVersionBase.and(
ImportGameVersion.or(ImportRedistVersion),
).configure(throwingArktype);
export type ImportGameVersion = typeof ImportVersionBase.infer &
typeof ImportGameVersion.infer;
export type ImportRedistVersion = typeof ImportVersionBase.infer &
typeof ImportRedistVersion.infer;
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["import:version:new"]);
if (!allowed) throw createError({ statusCode: 403 });
const {
id,
version,
platform,
launch,
launchArgs,
setup,
setupArgs,
onlySetup,
delta,
umuId,
} = await readDropValidatedBody(h3, ImportVersion);
const platformParsed = parsePlatform(platform);
if (!platformParsed)
throw createError({ statusCode: 400, statusMessage: "Invalid platform." });
if (delta) {
const validOverlayVersions = await prisma.gameVersion.count({
where: { gameId: id, platform: platformParsed, delta: false },
});
if (validOverlayVersions == 0)
throw createError({
statusCode: 400,
statusMessage:
"Update mode requires a pre-existing version for this platform.",
});
}
if (onlySetup) {
if (!setup)
throw createError({
statusCode: 400,
statusMessage: 'Setup required in "setup mode".',
});
} else {
if (!delta && !launch)
throw createError({
statusCode: 400,
statusMessage: "Launch executable is required for non-update versions",
});
}
const body = await readDropValidatedBody(h3, ImportVersion);
// startup & delta require more complex checking logic
const taskId = await libraryManager.importVersion(id, version, {
platform,
onlySetup,
launch,
launchArgs,
setup,
setupArgs,
umuId,
delta,
});
const taskId = await libraryManager.importVersion(
body.id,
body.version,
body,
);
if (!taskId)
throw createError({
statusCode: 400,
statusMessage: "Invalid options for import",
message: "Invalid options for import",
});
return { taskId: taskId };

View File

@ -1,27 +1,31 @@
import aclManager from "~/server/internal/acls";
import libraryManager from "~/server/internal/library";
import { ArkErrors, type } from "arktype";
import aclManager from "~~/server/internal/acls";
import libraryManager, { VersionImportModes } from "~~/server/internal/library";
export const PreloadQuery = type({
id: "string",
version: "string",
mode: type.enumerated(...VersionImportModes),
});
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["import:version:read"]);
if (!allowed) throw createError({ statusCode: 403 });
const query = await getQuery(h3);
const gameId = query.id?.toString();
const versionName = query.version?.toString();
if (!gameId || !versionName)
throw createError({
statusCode: 400,
statusMessage: "Missing id or version in request params",
});
const rawQuery = await getQuery(h3);
const query = PreloadQuery(rawQuery);
if (query instanceof ArkErrors)
throw createError({ statusCode: 400, message: query.summary });
const preload = await libraryManager.fetchUnimportedVersionInformation(
gameId,
versionName,
query.id,
query.mode,
query.version,
);
if (!preload)
throw createError({
statusCode: 400,
statusMessage: "Invalid game or version id/name",
message: "Invalid game or version id/name",
});
return preload;

View File

@ -1,4 +1,4 @@
import aclManager from "~/server/internal/acls";
import aclManager from "~~/server/internal/acls";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, []);

View File

@ -1,5 +1,5 @@
import aclManager from "~/server/internal/acls";
import libraryManager from "~/server/internal/library";
import aclManager from "~~/server/internal/acls";
import libraryManager from "~~/server/internal/library";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["library:read"]);
@ -7,9 +7,15 @@ export default defineEventHandler(async (h3) => {
const unimportedGames = await libraryManager.fetchUnimportedGames();
const games = await libraryManager.fetchGamesWithStatus();
const redists = await libraryManager.fetchRedistsWithStatus();
const libraries = await libraryManager.fetchLibraries();
// Fetch other library data here
return { unimportedGames, games, hasLibraries: libraries.length > 0 };
return {
unimportedGames,
games,
redists,
hasLibraries: libraries.length > 0,
};
});

View File

@ -1,8 +1,8 @@
import { type } from "arktype";
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import libraryManager from "~/server/internal/library";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
import libraryManager from "~~/server/internal/library";
const DeleteLibrarySource = type({
id: "string",

View File

@ -1,6 +1,6 @@
import type { LibraryModel } from "~/prisma/client/models";
import aclManager from "~/server/internal/acls";
import libraryManager from "~/server/internal/library";
import type { LibraryModel } from "~~/prisma/client/models";
import aclManager from "~~/server/internal/acls";
import libraryManager from "~~/server/internal/library";
export type WorkingLibrarySource = LibraryModel & {
working: boolean;

View File

@ -1,10 +1,10 @@
import { type } from "arktype";
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import libraryManager from "~/server/internal/library";
import type { WorkingLibrarySource } from "~/server/api/v1/admin/library/sources/index.get";
import { libraryConstructors } from "~/server/plugins/05.library-init";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
import libraryManager from "~~/server/internal/library";
import type { WorkingLibrarySource } from "~~/server/api/v1/admin/library/sources/index.get";
import { libraryConstructors } from "~~/server/plugins/05.library-init";
const UpdateLibrarySource = type({
id: "string",
@ -26,7 +26,7 @@ export default defineEventHandler<{ body: typeof UpdateLibrarySource.infer }>(
if (!source)
throw createError({
statusCode: 400,
statusMessage: "Library source not found",
message: "Library source not found",
});
const constructor = libraryConstructors[source.backend];
@ -61,7 +61,7 @@ export default defineEventHandler<{ body: typeof UpdateLibrarySource.infer }>(
} catch (e) {
throw createError({
statusCode: 400,
statusMessage: `Failed to create source: ${e}`,
message: `Failed to create source: ${e}`,
});
}
},

View File

@ -1,12 +1,12 @@
import { type } from "arktype";
import { randomUUID } from "crypto";
import { LibraryBackend } from "~/prisma/client/enums";
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import libraryManager from "~/server/internal/library";
import { libraryConstructors } from "~/server/plugins/05.library-init";
import type { WorkingLibrarySource } from "~/server/api/v1/admin/library/sources/index.get";
import { LibraryBackend } from "~~/prisma/client/enums";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
import libraryManager from "~~/server/internal/library";
import { libraryConstructors } from "~~/server/plugins/05.library-init";
import type { WorkingLibrarySource } from "~~/server/api/v1/admin/library/sources/index.get";
const CreateLibrarySource = type({
name: "string",
@ -29,7 +29,7 @@ export default defineEventHandler<{ body: typeof CreateLibrarySource.infer }>(
if (!backend)
throw createError({
statusCode: 400,
statusMessage: "Invalid source backend.",
message: "Invalid source backend.",
});
const constructor = libraryConstructors[backend];
@ -64,7 +64,7 @@ export default defineEventHandler<{ body: typeof CreateLibrarySource.infer }>(
} catch (e) {
throw createError({
statusCode: 400,
statusMessage: `Failed to create source: ${e}`,
message: `Failed to create source: ${e}`,
});
}
},

View File

@ -1,6 +1,6 @@
import { defineEventHandler, createError } from "h3";
import aclManager from "~/server/internal/acls";
import newsManager from "~/server/internal/news";
import aclManager from "~~/server/internal/acls";
import newsManager from "~~/server/internal/news";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["news:delete"]);

View File

@ -1,6 +1,6 @@
import { defineEventHandler, createError } from "h3";
import aclManager from "~/server/internal/acls";
import newsManager from "~/server/internal/news";
import aclManager from "~~/server/internal/acls";
import newsManager from "~~/server/internal/news";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["news:read"]);

View File

@ -1,6 +1,6 @@
import { defineEventHandler, getQuery } from "h3";
import aclManager from "~/server/internal/acls";
import newsManager from "~/server/internal/news";
import aclManager from "~~/server/internal/acls";
import newsManager from "~~/server/internal/news";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["news:read"]);
@ -14,13 +14,13 @@ export default defineEventHandler(async (h3) => {
const orderBy = query.order as "asc" | "desc";
if (orderBy) {
if (typeof orderBy !== "string" || !["asc", "desc"].includes(orderBy))
throw createError({ statusCode: 400, statusMessage: "Invalid order" });
throw createError({ statusCode: 400, message: "Invalid order" });
}
const tags = query.tags as string[] | undefined;
if (tags) {
if (typeof tags !== "object" || !Array.isArray(tags))
throw createError({ statusCode: 400, statusMessage: "Invalid tags" });
throw createError({ statusCode: 400, message: "Invalid tags" });
}
const options = {

View File

@ -1,8 +1,8 @@
import { ArkErrors, type } from "arktype";
import { defineEventHandler, createError } from "h3";
import aclManager from "~/server/internal/acls";
import newsManager from "~/server/internal/news";
import { handleFileUpload } from "~/server/internal/utils/handlefileupload";
import aclManager from "~~/server/internal/acls";
import newsManager from "~~/server/internal/news";
import { handleFileUpload } from "~~/server/internal/utils/handlefileupload";
const CreateNews = type({
title: "string",
@ -19,27 +19,27 @@ export default defineEventHandler(async (h3) => {
if (!form)
throw createError({
statusCode: 400,
statusMessage: "This endpoint requires multipart form data.",
message: "This endpoint requires multipart form data.",
});
const uploadResult = await handleFileUpload(h3, {}, ["internal:read"], 1);
if (!uploadResult)
throw createError({
statusCode: 400,
statusMessage: "Failed to upload file",
message: "Failed to upload file",
});
const [imageIds, options, pull, _dump] = uploadResult;
const body = await CreateNews(options);
if (body instanceof ArkErrors)
throw createError({ statusCode: 400, statusMessage: body.summary });
throw createError({ statusCode: 400, message: body.summary });
const parsedTags = JSON.parse(body.tags);
if (typeof parsedTags !== "object" || !Array.isArray(parsedTags))
throw createError({
statusCode: 400,
statusMessage: "Tags must be an array",
message: "Tags must be an array",
});
const imageId = imageIds.at(0);

View File

@ -0,0 +1,11 @@
import aclManager from "~~/server/internal/acls"
import prisma from "~~/server/internal/db/database";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["import:version:read"]);
if(!allowed) throw createError({statusCode: 403});
const userPlatforms = await prisma.userPlatform.findMany({});
return userPlatforms;
})

View File

@ -0,0 +1,19 @@
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["redist:delete"]);
if (!allowed) throw createError({ statusCode: 403 });
const id = getRouterParam(h3, "id")!;
const { count } = await prisma.redist.deleteMany({
where: {
id,
},
});
if (count == 0) throw createError({ statusCode: 404 });
return;
});

View File

@ -0,0 +1,38 @@
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
import libraryManager from "~~/server/internal/library";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["redist:read"]);
if (!allowed) throw createError({ statusCode: 403 });
const id = getRouterParam(h3, "id")!;
const redist = await prisma.redist.findUnique({
where: {
id,
},
include: {
platform: true,
versions: true,
},
});
if (!redist)
throw createError({
statusCode: 404,
message: "Redistributable not found.",
});
const unimportedVersions = await libraryManager.fetchUnimportedGameVersions(
redist.libraryId,
redist.libraryPath,
);
if (!unimportedVersions)
throw createError({
statusCode: 500,
message: "Failed to fetch unimported versions for redistributable.",
});
return { redist, unimportedVersions };
});

View File

@ -0,0 +1,27 @@
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["redist:update"]);
if (!allowed) throw createError({ statusCode: 403 });
const body = await readBody(h3);
const id = body.id;
if (!id || typeof id !== "string")
throw createError({ statusCode: 400, message: "ID required in body." });
const updateParams = body;
delete updateParams["id"];
try {
return await prisma.redist.update({
where: {
id,
},
data: updateParams,
});
} catch (e) {
throw createError({ statusCode: 400, message: (e as string)?.toString() });
}
});

View File

@ -0,0 +1,16 @@
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["redist:read"]);
if (!allowed) throw createError({ statusCode: 403 });
return await prisma.redist.findMany({
select: {
id: true,
mName: true,
mShortDescription: true,
mIconObjectId: true,
},
});
});

View File

@ -1,5 +1,5 @@
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.getUserACL(h3, ["settings:read"]);

View File

@ -1,8 +1,8 @@
import { type } from "arktype";
import { applicationSettings } from "~/server/internal/config/application-configuration";
import { readDropValidatedBody } from "~/server/arktype";
import { applicationSettings } from "~~/server/internal/config/application-configuration";
import { readDropValidatedBody } from "~~/server/arktype";
import { defineEventHandler, createError } from "h3";
import aclManager from "~/server/internal/acls";
import aclManager from "~~/server/internal/acls";
const UpdateSettings = type({
showGamePanelTextDecoration: "boolean",

View File

@ -1,5 +1,5 @@
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["tags:delete"]);
@ -9,6 +9,6 @@ export default defineEventHandler(async (h3) => {
const tag = await prisma.gameTag.deleteMany({ where: { id } });
if (tag.count == 0)
throw createError({ statusCode: 404, statusMessage: "Tag not found" });
throw createError({ statusCode: 404, message: "Tag not found" });
return;
});

View File

@ -1,5 +1,5 @@
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["tags:read"]);

View File

@ -1,7 +1,7 @@
import { type } from "arktype";
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
const CreateTag = type({
name: "string",

View File

@ -1,7 +1,7 @@
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import type { TaskMessage } from "~/server/internal/tasks";
import taskHandler from "~/server/internal/tasks";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
import type { TaskMessage } from "~~/server/internal/tasks";
import taskHandler from "~~/server/internal/tasks";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["task:read"]);
@ -10,7 +10,7 @@ export default defineEventHandler(async (h3) => {
if (!allAcls)
throw createError({
statusCode: 403,
statusMessage: "Somehow no ACLs on authenticated request.",
message: "Somehow no ACLs on authenticated request.",
});
const runningTasks = (await taskHandler.runningTasks()).map((e) => e.id);

View File

@ -1,12 +1,11 @@
import { type } from "arktype";
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import aclManager from "~/server/internal/acls";
import taskHandler from "~/server/internal/tasks";
import type { TaskGroup } from "~/server/internal/tasks/group";
import { taskGroups } from "~/server/internal/tasks/group";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
import aclManager from "~~/server/internal/acls";
import taskHandler from "~~/server/internal/tasks";
import { TASK_GROUPS } from "~~/server/internal/tasks/group";
const StartTask = type({
taskGroup: type("string"),
taskGroup: type.enumerated(...TASK_GROUPS),
}).configure(throwingArktype);
export default defineEventHandler(async (h3) => {
@ -14,18 +13,12 @@ export default defineEventHandler(async (h3) => {
if (!allowed) throw createError({ statusCode: 403 });
const body = await readDropValidatedBody(h3, StartTask);
const taskGroup = body.taskGroup as TaskGroup;
if (!taskGroups[taskGroup])
throw createError({
statusCode: 400,
statusMessage: "Invalid task group.",
});
const task = await taskHandler.runTaskGroupByName(taskGroup);
const task = await taskHandler.runTaskGroupByName(body.taskGroup);
if (!task)
throw createError({
statusCode: 500,
statusMessage: "Could not start task.",
message: "Could not start task.",
});
return { id: task };
});

View File

@ -1,6 +1,6 @@
import { APITokenMode } from "~/prisma/client/enums";
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import { APITokenMode } from "~~/prisma/client/enums";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, []); // No ACLs only allows session authentication
@ -10,14 +10,14 @@ export default defineEventHandler(async (h3) => {
if (!id)
throw createError({
statusCode: 400,
statusMessage: "No id in router params",
message: "No id in router params",
});
const deleted = await prisma.aPIToken.delete({
where: { id: id, mode: APITokenMode.System },
})!;
if (!deleted)
throw createError({ statusCode: 404, statusMessage: "Token not found" });
throw createError({ statusCode: 404, message: "Token not found" });
return;
});

View File

@ -1,5 +1,5 @@
import aclManager from "~/server/internal/acls";
import { systemACLDescriptions } from "~/server/internal/acls/descriptions";
import aclManager from "~~/server/internal/acls";
import { systemACLDescriptions } from "~~/server/internal/acls/descriptions";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, []); // No ACLs only allows session authentication

View File

@ -1,6 +1,6 @@
import { APITokenMode } from "~/prisma/client/enums";
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import { APITokenMode } from "~~/prisma/client/enums";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, []); // No ACLs only allows session authentication

View File

@ -1,8 +1,8 @@
import { type } from "arktype";
import { APITokenMode } from "~/prisma/client/enums";
import { readDropValidatedBody, throwingArktype } from "~/server/arktype";
import aclManager, { systemACLs } from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import { APITokenMode } from "~~/prisma/client/enums";
import { readDropValidatedBody, throwingArktype } from "~~/server/arktype";
import aclManager, { systemACLs } from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
const CreateToken = type({
name: "string",
@ -22,7 +22,7 @@ export default defineEventHandler(async (h3) => {
if (invalidACLs.length > 0)
throw createError({
statusCode: 400,
statusMessage: `Invalid ACLs: ${invalidACLs.join(", ")}`,
message: `Invalid ACLs: ${invalidACLs.join(", ")}`,
});
const token = await prisma.aPIToken.create({

View File

@ -1,7 +1,7 @@
import { defineEventHandler, createError } from "h3";
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import userStatsManager from "~/server/internal/userstats";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
import userStatsManager from "~~/server/internal/userstats";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["user:delete"]);
@ -20,12 +20,12 @@ export default defineEventHandler(async (h3) => {
if (userId === "system")
throw createError({
statusCode: 400,
statusMessage: "Cannot interact with system user.",
message: "Cannot interact with system user.",
});
const user = await prisma.user.findUnique({ where: { id: userId } });
if (!user)
throw createError({ statusCode: 404, statusMessage: "User not found." });
throw createError({ statusCode: 404, message: "User not found." });
await prisma.user.delete({ where: { id: userId } });
await userStatsManager.deleteUser();

View File

@ -1,5 +1,5 @@
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["user:read"]);
@ -9,18 +9,18 @@ export default defineEventHandler(async (h3) => {
if (!userId)
throw createError({
statusCode: 400,
statusMessage: "No userId in route.",
message: "No userId in route.",
});
if (userId == "system")
throw createError({
statusCode: 400,
statusMessage: "Cannot delete system user.",
message: "Cannot fetch system user.",
});
const user = await prisma.user.findUnique({ where: { id: userId } });
if (!user)
throw createError({ statusCode: 404, statusMessage: "User not found." });
throw createError({ statusCode: 404, message: "User not found." });
return user;
});

View File

@ -1,5 +1,5 @@
import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database";
import aclManager from "~~/server/internal/acls";
import prisma from "~~/server/internal/db/database";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["user:read"]);