Revert "Merge pull request 'Complete Housekeeping migration and /ase cutover' (#52) from codex/housekeeping-complete into main"
CI / check (push) Successful in 27s
CI / release (push) Skipped
CI / deploy (push) Successful in 43s

This reverts commit 488b6e57c4, reversing
changes made to b506b4499a.
This commit is contained in:
Simo committed 2026-08-30 21:31:34 +02:00
1 parent 488b6e57c4
commit b1ddda66ff
802 files changed
+61370 -76659

No files matched your search

+91 -66
View File
@@ -1,12 +1,15 @@
"use server";
import { mkdir, unlink, writeFile } from "node:fs/promises";
import path from "node:path";
import { eq } from "drizzle-orm";
import { revalidatePath } from "next/cache";
import type { ContentMutationSnapshot } from "@/features/housekeeping/domains/content/services/mutations";
import { createCorrelationId } from "@/features/housekeeping/foundation/contracts";
import { requirePermission, type StaffUser } from "@/lib/admin/guard";
import { PERMS } from "@/lib/permissions";
import { db, WebsiteSetting } from "@/lib/db";
import { resolveMediaPath } from "@/lib/media-storage";
import { siteSettings } from "@/lib/services/site-settings";
const MAX_SIZE = 2 * 1024 * 1024;
const FAVICON_DIR = resolveMediaPath("favicon");
const MAX_SIZE = 2 * 1024 * 1024; // 2MB
const ALLOWED = [
"image/png",
"image/jpeg",
@@ -15,37 +18,10 @@ const ALLOWED = [
"image/x-icon",
"image/svg+xml",
];
const PARTIAL_ERROR =
"Favicon change completed partially; verify storage and audit state";
async function executeAuditedFaviconMutation(
staff: StaffUser,
operation: "favicon.save" | "favicon.delete",
input: unknown,
): Promise<ContentMutationSnapshot> {
const [
{ contentProductionMutationAdapter },
{ getHousekeepingCapabilityContext },
] = await Promise.all([
import(
"@/features/housekeeping/domains/content/services/mutations-production"
),
import("@/features/housekeeping/foundation/server-capability-context"),
]);
const capability = await getHousekeepingCapabilityContext();
if (capability.actor.id !== staff.id)
throw new Error("Authenticated staff changed during favicon mutation");
return contentProductionMutationAdapter.execute(operation, input, {
capability,
correlationId: createCorrelationId(),
legacy: true,
});
}
export async function saveFavicon(
formData: FormData,
): Promise<{ success: boolean; url?: string; error?: string }> {
const staff = await requirePermission(PERMS.SETTINGS_VIEW);
try {
const file = formData.get("file") as File | null;
if (!file || file.size === 0)
@@ -57,27 +33,62 @@ export async function saveFavicon(
success: false,
error: "Invalid file type. Allowed: PNG, JPEG, GIF, WebP, ICO, SVG",
};
const result = await executeAuditedFaviconMutation(staff, "favicon.save", {
file,
});
siteRevalidate();
const url =
typeof result.output?.url === "string" ? result.output.url : undefined;
if (result.completion?.status === "partial") {
return {
success: false,
...(url ? { url } : {}),
error: PARTIAL_ERROR,
};
}
return {
success: true,
...(url ? { url } : {}),
const mimeExt: Record<string, string> = {
"image/png": "png",
"image/jpeg": "jpg",
"image/gif": "gif",
"image/webp": "webp",
"image/x-icon": "ico",
"image/svg+xml": "svg",
};
} catch (error) {
const ext = mimeExt[file.type] ?? "png";
const filename = `favicon-${Date.now()}.${ext}`;
const baseDir = FAVICON_DIR;
const filePath = path.resolve(baseDir, filename);
if (!filePath.startsWith(baseDir + path.sep)) {
return { success: false, error: "Invalid path" };
}
const buffer = Buffer.from(await file.arrayBuffer());
// eslint-disable-next-line security/detect-non-literal-fs-filename
await mkdir(baseDir, { recursive: true });
// eslint-disable-next-line security/detect-non-literal-fs-filename
await writeFile(filePath, buffer);
const url = `/api/media/favicon/${filename}`;
// Remove old favicon file if it exists
const oldUrl = await siteSettings.get("cms_favicon");
if (oldUrl?.startsWith("/api/media/favicon/")) {
const oldName = oldUrl.replace("/api/media/favicon/", "");
if (!oldName.includes("..") && !oldName.includes("/")) {
const oldPath = path.resolve(baseDir, oldName);
if (oldPath.startsWith(baseDir + path.sep)) {
try {
// eslint-disable-next-line security/detect-non-literal-fs-filename
await unlink(oldPath);
} catch {
/* ignore if file doesn't exist */
}
}
}
}
await db
.insert(WebsiteSetting)
.values({ key: "cms_favicon", value: url, comment: "Favicon URL" })
.onDuplicateKeyUpdate({ set: { value: url } });
siteSettings.reload();
revalidatePath("/", "layout");
revalidatePath("/admin/favicon");
return { success: true, url };
} catch (e) {
return {
success: false,
error: error instanceof Error ? error.message : "Unknown error",
error: e instanceof Error ? e.message : "Unknown error",
};
}
}
@@ -86,26 +97,40 @@ export async function deleteFavicon(): Promise<{
success: boolean;
error?: string;
}> {
const staff = await requirePermission(PERMS.SETTINGS_VIEW);
try {
const result = await executeAuditedFaviconMutation(
staff,
"favicon.delete",
{},
);
siteRevalidate();
if (result.completion?.status === "partial")
return { success: false, error: PARTIAL_ERROR };
const oldUrl = await siteSettings.get("cms_favicon");
if (oldUrl?.startsWith("/api/media/favicon/")) {
const baseDir = FAVICON_DIR;
const oldName = oldUrl.replace("/api/media/favicon/", "");
if (!oldName.includes("..") && !oldName.includes("/")) {
const oldPath = path.resolve(baseDir, oldName);
if (oldPath.startsWith(baseDir + path.sep)) {
try {
// eslint-disable-next-line security/detect-non-literal-fs-filename
await unlink(oldPath);
} catch {
/* ignore */
}
}
}
}
try {
await db
.delete(WebsiteSetting)
.where(eq(WebsiteSetting.key, "cms_favicon"));
} catch {
/* ignore missing row */
}
siteSettings.reload();
revalidatePath("/", "layout");
revalidatePath("/admin/favicon");
return { success: true };
} catch (error) {
} catch (e) {
return {
success: false,
error: error instanceof Error ? error.message : "Unknown error",
error: e instanceof Error ? e.message : "Unknown error",
};
}
}
function siteRevalidate(): void {
revalidatePath("/", "layout");
revalidatePath("/ase/content/brand/favicon");
}