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

+99 -52
View File
@@ -1,73 +1,120 @@
"use server";
import { eq } from "drizzle-orm";
import { revalidatePath } from "next/cache";
import { redirect } from "next/navigation";
import {
contentMutationService,
createContentMutationInvocation,
} from "@/features/housekeeping/domains/content/services/mutations";
import { createCorrelationId } from "@/features/housekeeping/foundation/contracts";
import { requirePermission } from "@/lib/admin/guard";
import {
db,
WebsiteArticleComments,
WebsiteArticleReactions,
WebsiteArticles,
} from "@/lib/db";
import { slugify } from "@/lib/format";
import { PERMS } from "@/lib/permissions";
function articleInput(formData: FormData) {
return {
title: String(formData.get("title") ?? "")
.normalize("NFC")
.trim(),
shortStory: String(formData.get("shortStory") ?? "")
.normalize("NFC")
.trim(),
fullStory: String(formData.get("fullStory") ?? "")
.normalize("NFC")
.trim(),
image: String(formData.get("image") ?? "")
.normalize("NFC")
.trim(),
slug: String(formData.get("slug") ?? "").trim(),
};
async function uniqueSlug(title: string): Promise<string> {
const base = slugify(title);
let slug = base;
let n = 2;
for (;;) {
const [existing] = await db
.select({ id: WebsiteArticles.id })
.from(WebsiteArticles)
.where(eq(WebsiteArticles.slug, slug))
.limit(1);
if (!existing) return slug;
slug = `${base}-${n++}`;
}
}
export async function createArticle(formData: FormData): Promise<void> {
const staff = await requirePermission(PERMS.NEWS_EDIT);
const input = articleInput(formData);
if (!input.title) return;
const result = await contentMutationService.execute(
createContentMutationInvocation(staff, createCorrelationId()),
"article.change",
{ action: "create", ...input },
);
if (!result.ok) {
const title = String(formData.get("title") ?? "")
.normalize("NFC")
.trim();
const shortStory = String(formData.get("shortStory") ?? "")
.normalize("NFC")
.trim();
const fullStory = String(formData.get("fullStory") ?? "")
.normalize("NFC")
.trim();
const image = String(formData.get("image") ?? "")
.normalize("NFC")
.trim();
const rawSlug = String(formData.get("slug") ?? "").trim();
if (!title) return;
try {
const now = new Date();
await db.insert(WebsiteArticles).values({
slug: rawSlug ? await uniqueSlug(rawSlug) : await uniqueSlug(title),
title: title.slice(0, 255),
shortStory: shortStory.slice(0, 255),
fullStory,
image: image.slice(0, 255),
userId: staff.id,
createdAt: now,
updatedAt: now,
});
} catch {
// Database error — re-render unchanged with error.
redirect(
"/ase/content/editorial/articles/new?error=Database error while creating article. Please try again.",
"/admin/articles/new?error=Database error while creating article. Please try again.",
);
}
redirect("/ase/content/editorial/articles");
redirect("/admin/articles");
}
export async function updateArticle(formData: FormData): Promise<void> {
const staff = await requirePermission(PERMS.NEWS_EDIT);
const id = String(formData.get("id") ?? "");
const result = await contentMutationService.execute(
createContentMutationInvocation(staff, createCorrelationId()),
"article.change",
{ action: "update", id, ...articleInput(formData) },
);
if (!result.ok)
redirect("/ase/content/editorial/articles?error=Update failed");
revalidatePath(`/ase/content/editorial/articles/${id}`);
redirect("/ase/content/editorial/articles");
await requirePermission(PERMS.NEWS_EDIT);
const id = BigInt(String(formData.get("id")));
const rawSlug = String(formData.get("slug") ?? "").trim();
try {
await db
.update(WebsiteArticles)
.set({
title: String(formData.get("title") ?? "")
.normalize("NFC")
.trim()
.slice(0, 255),
...(rawSlug ? { slug: await uniqueSlug(rawSlug) } : {}),
shortStory: String(formData.get("shortStory") ?? "")
.normalize("NFC")
.trim()
.slice(0, 255),
fullStory: String(formData.get("fullStory") ?? "")
.normalize("NFC")
.trim(),
image: String(formData.get("image") ?? "")
.normalize("NFC")
.trim()
.slice(0, 255),
updatedAt: new Date(),
})
.where(eq(WebsiteArticles.id, id));
} catch {
redirect("/admin/articles?error=Update failed");
}
revalidatePath(`/admin/articles/${id}`);
redirect("/admin/articles");
}
export async function deleteArticle(formData: FormData): Promise<void> {
const staff = await requirePermission(PERMS.NEWS_EDIT);
const id = String(formData.get("id") ?? "");
const result = await contentMutationService.execute(
createContentMutationInvocation(staff, createCorrelationId()),
"article.change",
{ action: "delete", id },
);
if (!result.ok)
redirect("/ase/content/editorial/articles?error=Delete failed");
redirect("/ase/content/editorial/articles");
await requirePermission(PERMS.NEWS_EDIT);
const id = BigInt(String(formData.get("id")));
try {
await db.transaction(async (tx) => {
await tx
.delete(WebsiteArticleReactions)
.where(eq(WebsiteArticleReactions.articleId, id));
await tx
.delete(WebsiteArticleComments)
.where(eq(WebsiteArticleComments.articleId, id));
await tx.delete(WebsiteArticles).where(eq(WebsiteArticles.id, id));
});
} catch {
redirect("/admin/articles?error=Delete failed");
}
redirect("/admin/articles");
}