feat(cms): improve catalog, editorial recovery and operations
This commit is contained in:
1 parent
2fead134e6
commit
c389c3893d
122 files changed
+8137
-703
No files matched your search
@@ -0,0 +1,110 @@
|
||||
"use server";
|
||||
import { and, desc, eq } from "drizzle-orm";
|
||||
import { ArticleDrafts, ArticleRevisions } from "@/db/article-editor";
|
||||
import { requirePermission } from "@/lib/admin/guard";
|
||||
import {
|
||||
type ArticleDraft,
|
||||
articleKey,
|
||||
readArticleDraft,
|
||||
} from "@/lib/article-draft";
|
||||
import { db, WebsiteArticles } from "@/lib/db";
|
||||
import { PERMS } from "@/lib/permissions";
|
||||
|
||||
export async function loadArticleRecovery(key: string) {
|
||||
const staff = await requirePermission(PERMS.NEWS_EDIT);
|
||||
key = articleKey(key);
|
||||
const [draft] = await db
|
||||
.select()
|
||||
.from(ArticleDrafts)
|
||||
.where(
|
||||
and(
|
||||
eq(ArticleDrafts.userId, staff.id),
|
||||
eq(ArticleDrafts.articleKey, key),
|
||||
),
|
||||
)
|
||||
.limit(1);
|
||||
const revisions =
|
||||
key === "new"
|
||||
? []
|
||||
: await db
|
||||
.select()
|
||||
.from(ArticleRevisions)
|
||||
.where(eq(ArticleRevisions.articleId, BigInt(key)))
|
||||
.orderBy(desc(ArticleRevisions.id))
|
||||
.limit(20);
|
||||
return {
|
||||
version: draft?.version ?? 0,
|
||||
draft:
|
||||
draft && draft.payload !== "{}"
|
||||
? {
|
||||
version: draft.version,
|
||||
payload: JSON.parse(draft.payload) as ArticleDraft,
|
||||
}
|
||||
: null,
|
||||
revisions: revisions.map((r) => ({
|
||||
id: r.id,
|
||||
createdAt: r.createdAt.toISOString(),
|
||||
payload: JSON.parse(r.payload) as ArticleDraft,
|
||||
})),
|
||||
};
|
||||
}
|
||||
export async function autosaveArticle(
|
||||
key: string,
|
||||
expectedVersion: number,
|
||||
form: FormData,
|
||||
) {
|
||||
const staff = await requirePermission(PERMS.NEWS_EDIT);
|
||||
key = articleKey(key);
|
||||
const payload = JSON.stringify(readArticleDraft(form));
|
||||
if (!Number.isSafeInteger(expectedVersion) || expectedVersion < 0)
|
||||
throw new Error("draftInvalid");
|
||||
return db.transaction(async (tx) => {
|
||||
if (key !== "new") {
|
||||
const [article] = await tx
|
||||
.select({ id: WebsiteArticles.id })
|
||||
.from(WebsiteArticles)
|
||||
.where(eq(WebsiteArticles.id, BigInt(key)))
|
||||
.limit(1)
|
||||
.for("update");
|
||||
if (!article) return { ok: false as const };
|
||||
}
|
||||
await tx
|
||||
.insert(ArticleDrafts)
|
||||
.values({ userId: staff.id, articleKey: key, version: 0, payload: "{}" })
|
||||
.onDuplicateKeyUpdate({ set: { articleKey: key } });
|
||||
const where = and(
|
||||
eq(ArticleDrafts.userId, staff.id),
|
||||
eq(ArticleDrafts.articleKey, key),
|
||||
);
|
||||
const [draft] = await tx
|
||||
.select()
|
||||
.from(ArticleDrafts)
|
||||
.where(where)
|
||||
.for("update");
|
||||
if (!draft || draft.version !== expectedVersion)
|
||||
return { ok: false as const };
|
||||
await tx
|
||||
.update(ArticleDrafts)
|
||||
.set({ payload, version: expectedVersion + 1, updatedAt: new Date() })
|
||||
.where(where);
|
||||
return { ok: true as const, version: expectedVersion + 1 };
|
||||
});
|
||||
}
|
||||
|
||||
export async function clearArticleRecovery(
|
||||
key: string,
|
||||
expectedVersion: number,
|
||||
) {
|
||||
const staff = await requirePermission(PERMS.NEWS_EDIT);
|
||||
key = articleKey(key);
|
||||
await db
|
||||
.update(ArticleDrafts)
|
||||
.set({ payload: "{}", version: expectedVersion + 1, updatedAt: new Date() })
|
||||
.where(
|
||||
and(
|
||||
eq(ArticleDrafts.userId, staff.id),
|
||||
eq(ArticleDrafts.articleKey, key),
|
||||
eq(ArticleDrafts.version, expectedVersion),
|
||||
),
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user