feat: comprehensive CMS improvements
CI / runtime-diagnostics (push) Skipped
CI / release (push) Skipped
CI / check (push) Failing after 0s
CI / deploy (push) Skipped

- Fix DOMPurify SSR crash (use isomorphic-dompurify)
- Fix SanitizedHtml to sanitize by default
- Add auth guards to studio/catalog maintenance pages
- Add update/edit to vouchers CRUD
- Add update/edit to rare-values CRUD
- Add approve workflow to applications page
- Add edit form to guilds detail page
- Add SEO metadata to all public pages (21 pages)
- Fix mobile nav accessibility (focus trap, aria attributes)
- Fix missing labels and table accessibility
- Add dynamic imports for heavy client components (6 components)
- Fix silent error swallowing (40+ locations)
- Add content scheduling for articles (publishAt, status)
- Wire up 12 missing webhook notification triggers
- Add global search to admin panel
- Add bulk actions to admin users table
- Fix JSON formatting and a11y issues
This commit is contained in:
openhands committed 2026-09-03 16:00:32 +02:00
1 parent b810b16672
commit 30c95b1a5c
78 files changed
+2252 -134

No files matched your search

+11 -2
View File
@@ -1,4 +1,4 @@
import { eq } from "drizzle-orm";
import { and, eq, or, sql } from "drizzle-orm";
import { apiJson } from "@/lib/api";
import { db, WebsiteArticles } from "@/lib/db";
import { apiCacheKey, cacheSafe, redisCache } from "@/lib/redis-cache";
@@ -30,7 +30,16 @@ export async function GET(
updatedAt: WebsiteArticles.updatedAt,
})
.from(WebsiteArticles)
.where(eq(WebsiteArticles.slug, slug))
.where(
and(
eq(WebsiteArticles.slug, slug),
eq(WebsiteArticles.status, "published"),
or(
sql`${WebsiteArticles.publishAt} IS NULL`,
sql`${WebsiteArticles.publishAt} <= NOW()`,
),
),
)
.limit(1);
if (!article) {
+13 -2
View File
@@ -1,4 +1,4 @@
import { count, desc } from "drizzle-orm";
import { and, count, desc, eq, or, sql } from "drizzle-orm";
import { apiJson, pagination } from "@/lib/api";
import { db, WebsiteArticles } from "@/lib/db";
import { apiCacheKey, cacheSafe, redisCache } from "@/lib/redis-cache";
@@ -17,8 +17,18 @@ export async function GET(req: Request) {
apiCacheKey(`articles:${page}:${perPage}`),
60,
async () => {
const publishedFilter = and(
eq(WebsiteArticles.status, "published"),
or(
sql`${WebsiteArticles.publishAt} IS NULL`,
sql`${WebsiteArticles.publishAt} <= NOW()`,
),
);
const [totalRows, articles] = await Promise.all([
db.select({ total: count() }).from(WebsiteArticles),
db
.select({ total: count() })
.from(WebsiteArticles)
.where(publishedFilter),
db
.select({
id: WebsiteArticles.id,
@@ -29,6 +39,7 @@ export async function GET(req: Request) {
createdAt: WebsiteArticles.createdAt,
})
.from(WebsiteArticles)
.where(publishedFilter)
.orderBy(desc(WebsiteArticles.createdAt))
.limit(take)
.offset(skip),