Make application and logo configurable (#336)

* Adds settings for server name and logo

* Implements ApplicationLogo and replaces site name based on settings

* Refactors component for changing the company logo

* Removes unused variable

* Uses message instead of statusMessage

* Replaces favicon with logo if set
This commit is contained in:
Paco
2026-02-06 00:43:21 +00:00
committed by GitHub
parent d80c1e5b91
commit 965cbff8ff
27 changed files with 452 additions and 102 deletions
@@ -42,7 +42,7 @@ export default defineEventHandler(async (h3) => {
},
});
if (count == 0) {
await dump();
dump();
throw createError({ statusCode: 404, message: "Company not found" });
}
+34 -6
View File
@@ -3,21 +3,49 @@ import { applicationSettings } from "~/server/internal/config/application-config
import { readDropValidatedBody } from "~/server/arktype";
import { defineEventHandler, createError } from "h3";
import aclManager from "~/server/internal/acls";
import objectHandler from "~/server/internal/objects";
import type { Settings } from "~/server/internal/utils/types";
const UpdateSettings = type({
showGamePanelTextDecoration: "boolean",
"store?": {
showGamePanelTextDecoration: "boolean",
},
"generalSettings?": {
serverName: "string",
mLogoObjectId: "string | null",
},
});
export default defineEventHandler<{ body: typeof UpdateSettings.infer }>(
async (h3) => {
async (h3): Promise<Settings> => {
const allowed = await aclManager.allowSystemACL(h3, ["settings:update"]);
if (!allowed) throw createError({ statusCode: 403 });
const body = await readDropValidatedBody(h3, UpdateSettings);
await applicationSettings.set(
"showGamePanelTextDecoration",
body.showGamePanelTextDecoration,
);
if (body.store) {
await applicationSettings.set(
"showGamePanelTextDecoration",
body.store.showGamePanelTextDecoration,
);
}
if (body.generalSettings) {
const previousMLogoObjectId =
await applicationSettings.get("mLogoObjectId");
await applicationSettings.set(
"serverName",
body.generalSettings.serverName,
);
if (body.generalSettings.mLogoObjectId !== previousMLogoObjectId) {
if (previousMLogoObjectId) {
await objectHandler.deleteAsSystem(previousMLogoObjectId);
}
applicationSettings.set(
"mLogoObjectId",
body.generalSettings.mLogoObjectId || null,
);
}
}
return await applicationSettings.getSettings();
},
);
+26
View File
@@ -0,0 +1,26 @@
import aclManager from "~/server/internal/acls";
import { handleFileUpload } from "~/server/internal/utils/handlefileupload";
export default defineEventHandler(async (h3) => {
const allowed = await aclManager.allowSystemACL(h3, ["settings:update"]);
if (!allowed) throw createError({ statusCode: 403 });
const result = await handleFileUpload(h3, {}, ["anonymous:read"], 1);
if (!result)
throw createError({
statusCode: 400,
message: "File upload required (multipart form)",
});
const [ids, , pull] = result;
const id = ids.at(0);
if (!id)
throw createError({
statusCode: 400,
statusMessage: "Upload at least one file.",
});
await pull();
return { id: id };
});
+4 -1
View File
@@ -1,10 +1,13 @@
import { applicationSettings } from "~/server/internal/config/application-configuration";
import { systemConfig } from "~/server/internal/config/sys-conf";
export default defineEventHandler((_h3) => {
export default defineEventHandler(async (_h3) => {
return {
appName: "Drop",
version: systemConfig.getDropVersion(),
gitRef: `#${systemConfig.getGitRef()}`,
external: systemConfig.getExternalUrl(),
serverName: await applicationSettings.get("serverName"),
mLogoObjectId: await applicationSettings.get("mLogoObjectId"),
};
});
+3 -6
View File
@@ -1,13 +1,10 @@
import aclManager from "~/server/internal/acls";
import { applicationSettings } from "~/server/internal/config/application-configuration";
import type { Settings } from "~/server/internal/utils/types";
export default defineEventHandler(async (h3) => {
export default defineEventHandler(async (h3): Promise<Settings> => {
const allowed = await aclManager.getUserACL(h3, ["settings:read"]);
if (!allowed) throw createError({ statusCode: 403 });
const showGamePanelTextDecoration = await applicationSettings.get(
"showGamePanelTextDecoration",
);
return { showGamePanelTextDecoration };
return applicationSettings.getSettings();
});
@@ -1,5 +1,6 @@
import type { ApplicationSettingsModel } from "~/prisma/client/models";
import prisma from "../db/database";
import type { Settings } from "../utils/types";
class ApplicationConfiguration {
// Reference to the currently selected application configuration
@@ -80,6 +81,20 @@ class ApplicationConfiguration {
return this.currentApplicationSettings[key];
}
async getSettings(): Promise<Settings> {
return {
store: {
showGamePanelTextDecoration: await applicationSettings.get(
"showGamePanelTextDecoration",
),
},
generalSettings: {
serverName: await applicationSettings.get("serverName"),
mLogoObjectId: await applicationSettings.get("mLogoObjectId"),
},
};
}
}
export const applicationSettings = new ApplicationConfiguration();
+10
View File
@@ -11,3 +11,13 @@ export type KeyOfType<T, V> = keyof {
type EnumDictionary<T extends string | symbol | number, U> = {
[K in T]: U;
};
export type Settings = {
store: {
showGamePanelTextDecoration: boolean;
};
generalSettings: {
serverName: string;
mLogoObjectId: string | null;
};
};