partial: new documentation additions (company admin)

This commit is contained in:
DecDuck
2025-08-09 22:18:34 +10:00
parent 7af29ef0eb
commit ef7a62bf0b
15 changed files with 181 additions and 122 deletions

View File

@ -2,6 +2,9 @@ import { AuthMec } from "~/prisma/client/enums";
import aclManager from "~/server/internal/acls"; import aclManager from "~/server/internal/acls";
import authManager from "~/server/internal/auth"; import authManager from "~/server/internal/auth";
/**
* Fetches all the enabled authentication mechanisms on this instance, and their configuration, if enabled.
*/
export default defineEventHandler(async (h3) => { export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["auth:read", "setup"]); const allowed = await aclManager.allowSystemACL(h3, ["auth:read", "setup"]);
if (!allowed) throw createError({ statusCode: 403 }); if (!allowed) throw createError({ statusCode: 403 });

View File

@ -8,7 +8,8 @@ const DeleteInvite = type({
}).configure(throwingArktype); }).configure(throwingArktype);
/** /**
* Delete a simple auth invitation * Deletes a "Simple" invitation
* @returns nothing
*/ */
export default defineEventHandler<{ export default defineEventHandler<{
body: typeof DeleteInvite.infer; body: typeof DeleteInvite.infer;

View File

@ -3,6 +3,9 @@ import { systemConfig } from "~/server/internal/config/sys-conf";
import prisma from "~/server/internal/db/database"; import prisma from "~/server/internal/db/database";
import taskHandler from "~/server/internal/tasks"; import taskHandler from "~/server/internal/tasks";
/**
* Fetches a "Simple" invitation
*/
export default defineEventHandler(async (h3) => { export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, [ const allowed = await aclManager.allowSystemACL(h3, [
"auth:simple:invitation:read", "auth:simple:invitation:read",

View File

@ -11,6 +11,9 @@ const CreateInvite = SharedRegisterValidator.partial()
}) })
.configure(throwingArktype); .configure(throwingArktype);
/**
* Creates a "Simple" invitation
*/
export default defineEventHandler(async (h3) => { export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, [ const allowed = await aclManager.allowSystemACL(h3, [
"auth:simple:invitation:new", "auth:simple:invitation:new",

View File

@ -3,6 +3,11 @@ import prisma from "~/server/internal/db/database";
import objectHandler from "~/server/internal/objects"; import objectHandler from "~/server/internal/objects";
import { handleFileUpload } from "~/server/internal/utils/handlefileupload"; import { handleFileUpload } from "~/server/internal/utils/handlefileupload";
/**
* Multi-part form upload for the banner.
* @request `multipart/form-data` data. Only one file, can be named anything.
* @param id Company ID
*/
export default defineEventHandler(async (h3) => { export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["company:update"]); const allowed = await aclManager.allowSystemACL(h3, ["company:update"]);
if (!allowed) throw createError({ statusCode: 403 }); if (!allowed) throw createError({ statusCode: 403 });

View File

@ -7,31 +7,37 @@ const GameDelete = type({
id: "string", id: "string",
}).configure(throwingArktype); }).configure(throwingArktype);
export default defineEventHandler(async (h3) => { /**
const allowed = await aclManager.allowSystemACL(h3, ["company:update"]); * Delete a game's association with a company
if (!allowed) throw createError({ statusCode: 403 }); * @param id Company ID
*/
export default defineEventHandler<{ body: typeof GameDelete.infer }>(
async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["company:update"]);
if (!allowed) throw createError({ statusCode: 403 });
const companyId = getRouterParam(h3, "id")!; const companyId = getRouterParam(h3, "id")!;
const body = await readDropValidatedBody(h3, GameDelete); const body = await readDropValidatedBody(h3, GameDelete);
await prisma.game.update({ await prisma.game.update({
where: { where: {
id: body.id, id: body.id,
}, },
data: { data: {
publishers: { publishers: {
disconnect: { disconnect: {
id: companyId, id: companyId,
},
},
developers: {
disconnect: {
id: companyId,
},
}, },
}, },
developers: { });
disconnect: {
id: companyId,
},
},
},
});
return; return;
}); },
);

View File

@ -9,29 +9,35 @@ const GamePatch = type({
id: "string", id: "string",
}).configure(throwingArktype); }).configure(throwingArktype);
export default defineEventHandler(async (h3) => { /**
const allowed = await aclManager.allowSystemACL(h3, ["company:update"]); * Update a company's association with a game.
if (!allowed) throw createError({ statusCode: 403 }); * @param id Company ID
*/
export default defineEventHandler<{ body: typeof GamePatch.infer }>(
async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["company:update"]);
if (!allowed) throw createError({ statusCode: 403 });
const companyId = getRouterParam(h3, "id")!; const companyId = getRouterParam(h3, "id")!;
const body = await readDropValidatedBody(h3, GamePatch); const body = await readDropValidatedBody(h3, GamePatch);
const action = body.action === "developed" ? "developers" : "publishers"; const action = body.action === "developed" ? "developers" : "publishers";
const actionType = body.enabled ? "connect" : "disconnect"; const actionType = body.enabled ? "connect" : "disconnect";
await prisma.game.update({ await prisma.game.update({
where: { where: {
id: body.id, id: body.id,
}, },
data: { data: {
[action]: { [action]: {
[actionType]: { [actionType]: {
id: companyId, id: companyId,
},
}, },
}, },
}, });
});
return; return;
}); },
);

View File

@ -9,61 +9,67 @@ const GamePost = type({
id: "string", id: "string",
}).configure(throwingArktype); }).configure(throwingArktype);
export default defineEventHandler(async (h3) => { /**
const allowed = await aclManager.allowSystemACL(h3, ["company:update"]); * Add a new game association to this company
if (!allowed) throw createError({ statusCode: 403 }); * @param id Company ID
*/
export default defineEventHandler<{ body: typeof GamePost.infer }>(
async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["company:update"]);
if (!allowed) throw createError({ statusCode: 403 });
const companyId = getRouterParam(h3, "id")!; const companyId = getRouterParam(h3, "id")!;
const body = await readDropValidatedBody(h3, GamePost); const body = await readDropValidatedBody(h3, GamePost);
if (!body.published && !body.developed) if (!body.published && !body.developed)
throw createError({ throw createError({
statusCode: 400, statusCode: 400,
statusMessage: "Must be related (either developed or published).", statusMessage: "Must be related (either developed or published).",
});
const publisherConnect = body.published
? {
publishers: {
connect: {
id: companyId,
},
},
}
: undefined;
const developerConnect = body.developed
? {
developers: {
connect: {
id: companyId,
},
},
}
: undefined;
const game = await prisma.game.update({
where: {
id: body.id,
},
data: {
...publisherConnect,
...developerConnect,
},
include: {
publishers: {
select: {
id: true,
},
},
developers: {
select: {
id: true,
},
},
},
}); });
const publisherConnect = body.published return game;
? { },
publishers: { );
connect: {
id: companyId,
},
},
}
: undefined;
const developerConnect = body.developed
? {
developers: {
connect: {
id: companyId,
},
},
}
: undefined;
const game = await prisma.game.update({
where: {
id: body.id,
},
data: {
...publisherConnect,
...developerConnect,
},
include: {
publishers: {
select: {
id: true,
},
},
developers: {
select: {
id: true,
},
},
},
});
return game;
});

View File

@ -3,6 +3,11 @@ import prisma from "~/server/internal/db/database";
import objectHandler from "~/server/internal/objects"; import objectHandler from "~/server/internal/objects";
import { handleFileUpload } from "~/server/internal/utils/handlefileupload"; import { handleFileUpload } from "~/server/internal/utils/handlefileupload";
/**
* Multi-part form upload for the icon of this company
* @request `multipart/form-data` data. Only one file, can be named anything.
* @param id Company ID
*/
export default defineEventHandler(async (h3) => { export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["company:update"]); const allowed = await aclManager.allowSystemACL(h3, ["company:update"]);
if (!allowed) throw createError({ statusCode: 403 }); if (!allowed) throw createError({ statusCode: 403 });

View File

@ -1,6 +1,10 @@
import aclManager from "~/server/internal/acls"; import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database"; import prisma from "~/server/internal/db/database";
/**
* Delete this company
* @param id Company ID
*/
export default defineEventHandler(async (h3) => { export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["company:delete"]); const allowed = await aclManager.allowSystemACL(h3, ["company:delete"]);
if (!allowed) throw createError({ statusCode: 403 }); if (!allowed) throw createError({ statusCode: 403 });

View File

@ -1,6 +1,10 @@
import aclManager from "~/server/internal/acls"; import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database"; import prisma from "~/server/internal/db/database";
/**
* Fetch a company and its associations
* @param id Company ID
*/
export default defineEventHandler(async (h3) => { export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["company:read"]); const allowed = await aclManager.allowSystemACL(h3, ["company:read"]);
if (!allowed) throw createError({ statusCode: 403 }); if (!allowed) throw createError({ statusCode: 403 });

View File

@ -1,6 +1,11 @@
import aclManager from "~/server/internal/acls"; import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database"; import prisma from "~/server/internal/db/database";
/**
* Update a company. Pass any fields into the body to be updated on the model
* @request Partial of the data returned by GET, minus the `developed` and `published` fields.
* @param id Company ID
*/
export default defineEventHandler(async (h3) => { export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["company:update"]); const allowed = await aclManager.allowSystemACL(h3, ["company:update"]);
if (!allowed) throw createError({ statusCode: 403 }); if (!allowed) throw createError({ statusCode: 403 });

View File

@ -1,6 +1,9 @@
import aclManager from "~/server/internal/acls"; import aclManager from "~/server/internal/acls";
import prisma from "~/server/internal/db/database"; import prisma from "~/server/internal/db/database";
/**
* Fetch all companies on this instance
*/
export default defineEventHandler(async (h3) => { export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["company:read"]); const allowed = await aclManager.allowSystemACL(h3, ["company:read"]);
if (!allowed) throw createError({ statusCode: 403 }); if (!allowed) throw createError({ statusCode: 403 });

View File

@ -12,36 +12,41 @@ const CompanyCreate = type({
website: "string", website: "string",
}).configure(throwingArktype); }).configure(throwingArktype);
export default defineEventHandler(async (h3) => { /**
const allowed = await aclManager.allowSystemACL(h3, ["company:create"]); * Create a new company on this instance
if (!allowed) throw createError({ statusCode: 403 }); */
export default defineEventHandler<{ body: typeof CompanyCreate.infer }>(
async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["company:create"]);
if (!allowed) throw createError({ statusCode: 403 });
const body = await readDropValidatedBody(h3, CompanyCreate); const body = await readDropValidatedBody(h3, CompanyCreate);
const obj = new ObjectTransactionalHandler(); const obj = new ObjectTransactionalHandler();
const [register, pull, _] = obj.new({}, ["internal:read"]); const [register, pull, _] = obj.new({}, ["internal:read"]);
const icon = jdenticon.toPng(body.name, 512); const icon = jdenticon.toPng(body.name, 512);
const logoId = register(icon); const logoId = register(icon);
const banner = jdenticon.toPng(body.description, 1024); const banner = jdenticon.toPng(body.description, 1024);
const bannerId = register(banner); const bannerId = register(banner);
const company = await prisma.company.create({ const company = await prisma.company.create({
data: { data: {
metadataSource: MetadataSource.Manual, metadataSource: MetadataSource.Manual,
metadataId: crypto.randomUUID(), metadataId: crypto.randomUUID(),
metadataOriginalQuery: "", metadataOriginalQuery: "",
mName: body.name, mName: body.name,
mShortDescription: body.description, mShortDescription: body.description,
mDescription: "", mDescription: "",
mLogoObjectId: logoId, mLogoObjectId: logoId,
mBannerObjectId: bannerId, mBannerObjectId: bannerId,
mWebsite: body.website, mWebsite: body.website,
}, },
}); });
await pull(); await pull();
return company; return company;
}); },
);

View File

@ -1,6 +1,6 @@
import { systemConfig } from "~/server/internal/config/sys-conf"; import { systemConfig } from "~/server/internal/config/sys-conf";
export default defineEventHandler((_h3) => { export default defineEventHandler(async (_h3) => {
return { return {
appName: "Drop", appName: "Drop",
version: systemConfig.getDropVersion(), version: systemConfig.getDropVersion(),