From 545ee688169217bac645c74ca9caaf5abe4d9d63 Mon Sep 17 00:00:00 2001 From: seeyebe Date: Sun, 7 Dec 2025 17:08:08 +0200 Subject: [PATCH 1/2] feat: use guild time/date settings in archives metadata --- backend/src/api/archives.ts | 57 +++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 3 deletions(-) diff --git a/backend/src/api/archives.ts b/backend/src/api/archives.ts index 77da999d9..80e1de738 100644 --- a/backend/src/api/archives.ts +++ b/backend/src/api/archives.ts @@ -1,10 +1,58 @@ import express, { Request, Response } from "express"; import moment from "moment-timezone"; +import { Configs } from "../data/Configs.js"; import { GuildArchives } from "../data/GuildArchives.js"; +import { defaultDateFormats } from "../plugins/TimeAndDate/defaultDateFormats.js"; +import { zTimeAndDateConfig } from "../plugins/TimeAndDate/types.js"; +import { zZeppelinGuildConfig } from "../types.js"; +import { loadYamlSafely } from "../utils/loadYamlSafely.js"; import { notFound } from "./responses.js"; +const defaultTimeAndDateConfig = zTimeAndDateConfig.parse({}); +function getDefaultTimeAndDateSettings() { + return { + timezone: defaultTimeAndDateConfig.timezone, + dateFormats: { ...defaultTimeAndDateConfig.date_formats }, + }; +} + +async function getTimeAndDateSettingsForGuild(guildId: string, configs: Configs) { + try { + const configEntry = await configs.getActiveByKey(`guild-${guildId}`); + if (!configEntry?.config) { + return getDefaultTimeAndDateSettings(); + } + + const parsedConfig = loadYamlSafely(configEntry.config); + const guildConfig = zZeppelinGuildConfig.safeParse(parsedConfig); + if (!guildConfig.success) { + return getDefaultTimeAndDateSettings(); + } + + const pluginOptions = guildConfig.data.plugins?.time_and_date; + if (!pluginOptions || typeof pluginOptions !== "object") { + return getDefaultTimeAndDateSettings(); + } + + const basePluginConfig = + typeof (pluginOptions as any).config === "object" ? (pluginOptions as any).config : pluginOptions; + const pluginConfig = zTimeAndDateConfig.safeParse(basePluginConfig ?? {}); + if (!pluginConfig.success) { + return getDefaultTimeAndDateSettings(); + } + + return { + timezone: pluginConfig.data.timezone, + dateFormats: pluginConfig.data.date_formats, + }; + } catch { + return getDefaultTimeAndDateSettings(); + } +} + export function initArchives(router: express.Router) { const archives = new GuildArchives(null); + const configs = new Configs(); // Legacy redirect router.get("/spam-logs/:id", (req: Request, res: Response) => { @@ -18,13 +66,16 @@ export function initArchives(router: express.Router) { let body = archive.body; // Add some metadata at the end of the log file (but only if it doesn't already have it directly in the body) - // TODO: Use server timezone / date formats if (archive.body.indexOf("Log file generated on") === -1) { - const createdAt = moment.utc(archive.created_at).format("YYYY-MM-DD [at] HH:mm:ss [(+00:00)]"); + const timeAndDate = await getTimeAndDateSettingsForGuild(archive.guild_id, configs); + const prettyDatetimeFormat = + timeAndDate.dateFormats.pretty_datetime ?? defaultDateFormats.pretty_datetime; + + const createdAt = moment.utc(archive.created_at).tz(timeAndDate.timezone).format(prettyDatetimeFormat); body += `\n\nLog file generated on ${createdAt}`; if (archive.expires_at !== null) { - const expiresAt = moment.utc(archive.expires_at).format("YYYY-MM-DD [at] HH:mm:ss [(+00:00)]"); + const expiresAt = moment.utc(archive.expires_at).tz(timeAndDate.timezone).format(prettyDatetimeFormat); body += `\nExpires at ${expiresAt}`; } } From b4e7a7b5729be9ff5c811acb5d4c43c5443dd2e5 Mon Sep 17 00:00:00 2001 From: seeyebe Date: Mon, 3 Aug 2026 17:23:06 +0300 Subject: [PATCH 2/2] fix: resolve archive time config through Vety --- backend/src/api/archives.ts | 51 +++++++++++++++---------------------- 1 file changed, 21 insertions(+), 30 deletions(-) diff --git a/backend/src/api/archives.ts b/backend/src/api/archives.ts index 80e1de738..940ac40c2 100644 --- a/backend/src/api/archives.ts +++ b/backend/src/api/archives.ts @@ -1,52 +1,44 @@ import express, { Request, Response } from "express"; import moment from "moment-timezone"; +import { GuildPluginData, PluginConfigManager } from "vety"; import { Configs } from "../data/Configs.js"; import { GuildArchives } from "../data/GuildArchives.js"; -import { defaultDateFormats } from "../plugins/TimeAndDate/defaultDateFormats.js"; -import { zTimeAndDateConfig } from "../plugins/TimeAndDate/types.js"; +import { TimeAndDatePluginType, zTimeAndDateConfig } from "../plugins/TimeAndDate/types.js"; import { zZeppelinGuildConfig } from "../types.js"; import { loadYamlSafely } from "../utils/loadYamlSafely.js"; import { notFound } from "./responses.js"; const defaultTimeAndDateConfig = zTimeAndDateConfig.parse({}); -function getDefaultTimeAndDateSettings() { - return { - timezone: defaultTimeAndDateConfig.timezone, - dateFormats: { ...defaultTimeAndDateConfig.date_formats }, - }; -} -async function getTimeAndDateSettingsForGuild(guildId: string, configs: Configs) { +async function getTimeAndDateConfigForGuild(guildId: string, configs: Configs) { try { const configEntry = await configs.getActiveByKey(`guild-${guildId}`); if (!configEntry?.config) { - return getDefaultTimeAndDateSettings(); + return defaultTimeAndDateConfig; } const parsedConfig = loadYamlSafely(configEntry.config); const guildConfig = zZeppelinGuildConfig.safeParse(parsedConfig); if (!guildConfig.success) { - return getDefaultTimeAndDateSettings(); + return defaultTimeAndDateConfig; } const pluginOptions = guildConfig.data.plugins?.time_and_date; - if (!pluginOptions || typeof pluginOptions !== "object") { - return getDefaultTimeAndDateSettings(); + if (!pluginOptions) { + return defaultTimeAndDateConfig; } - const basePluginConfig = - typeof (pluginOptions as any).config === "object" ? (pluginOptions as any).config : pluginOptions; - const pluginConfig = zTimeAndDateConfig.safeParse(basePluginConfig ?? {}); - if (!pluginConfig.success) { - return getDefaultTimeAndDateSettings(); - } + const configManager = new PluginConfigManager>(pluginOptions, { + configSchema: zTimeAndDateConfig, + defaultOverrides: [], + levels: guildConfig.data.levels ?? {}, + }); + await configManager.init(); - return { - timezone: pluginConfig.data.timezone, - dateFormats: pluginConfig.data.date_formats, - }; - } catch { - return getDefaultTimeAndDateSettings(); + return configManager.get(); + } catch (err) { + console.error(`Failed to load time and date config for guild ${guildId}`, err); + return defaultTimeAndDateConfig; } } @@ -67,15 +59,14 @@ export function initArchives(router: express.Router) { // Add some metadata at the end of the log file (but only if it doesn't already have it directly in the body) if (archive.body.indexOf("Log file generated on") === -1) { - const timeAndDate = await getTimeAndDateSettingsForGuild(archive.guild_id, configs); - const prettyDatetimeFormat = - timeAndDate.dateFormats.pretty_datetime ?? defaultDateFormats.pretty_datetime; + const timeAndDateConfig = await getTimeAndDateConfigForGuild(archive.guild_id, configs); + const prettyDatetimeFormat = timeAndDateConfig.date_formats.pretty_datetime; - const createdAt = moment.utc(archive.created_at).tz(timeAndDate.timezone).format(prettyDatetimeFormat); + const createdAt = moment.utc(archive.created_at).tz(timeAndDateConfig.timezone).format(prettyDatetimeFormat); body += `\n\nLog file generated on ${createdAt}`; if (archive.expires_at !== null) { - const expiresAt = moment.utc(archive.expires_at).tz(timeAndDate.timezone).format(prettyDatetimeFormat); + const expiresAt = moment.utc(archive.expires_at).tz(timeAndDateConfig.timezone).format(prettyDatetimeFormat); body += `\nExpires at ${expiresAt}`; } }