191 lines
4.2 KiB
TypeScript
191 lines
4.2 KiB
TypeScript
import {
|
|
type CreatePostInput,
|
|
createPostInputSchema,
|
|
type UpdatePostInput,
|
|
updatePostInputSchema,
|
|
} from "@cms/content"
|
|
import { type CrudAuditHook, type CrudMutationContext, createCrudService } from "@cms/crud"
|
|
import { z } from "zod"
|
|
import type { Post } from "../prisma/generated/client/client"
|
|
|
|
import { db } from "./client"
|
|
|
|
const postRepository = {
|
|
list: () =>
|
|
db.post.findMany({
|
|
orderBy: {
|
|
updatedAt: "desc",
|
|
},
|
|
}),
|
|
findById: (id: string) =>
|
|
db.post.findUnique({
|
|
where: { id },
|
|
}),
|
|
create: (input: CreatePostInput) =>
|
|
db.post.create({
|
|
data: input,
|
|
}),
|
|
update: (id: string, input: UpdatePostInput) =>
|
|
db.post.update({
|
|
where: { id },
|
|
data: input,
|
|
}),
|
|
delete: (id: string) =>
|
|
db.post.delete({
|
|
where: { id },
|
|
}),
|
|
}
|
|
|
|
const supportedLocaleSchema = z.enum(["de", "en", "es", "fr"])
|
|
const upsertPostTranslationInputSchema = z.object({
|
|
postId: z.string().uuid(),
|
|
locale: supportedLocaleSchema,
|
|
title: z.string().min(3).max(180),
|
|
excerpt: z.string().max(320).nullable().optional(),
|
|
body: z.string().min(1),
|
|
})
|
|
|
|
const postAuditHooks: Array<CrudAuditHook<Post>> = []
|
|
|
|
const postCrudService = createCrudService({
|
|
resource: "post",
|
|
repository: postRepository,
|
|
schemas: {
|
|
create: createPostInputSchema,
|
|
update: updatePostInputSchema,
|
|
},
|
|
auditHooks: postAuditHooks,
|
|
})
|
|
|
|
export function registerPostCrudAuditHook(hook: CrudAuditHook<Post>): () => void {
|
|
postAuditHooks.push(hook)
|
|
|
|
return () => {
|
|
const index = postAuditHooks.indexOf(hook)
|
|
|
|
if (index >= 0) {
|
|
postAuditHooks.splice(index, 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
export async function listPosts() {
|
|
return postCrudService.list()
|
|
}
|
|
|
|
export async function getPostById(id: string) {
|
|
return postCrudService.getById(id)
|
|
}
|
|
|
|
export async function getPostBySlug(slug: string) {
|
|
return db.post.findUnique({
|
|
where: { slug },
|
|
})
|
|
}
|
|
|
|
export async function getPostBySlugForLocale(slug: string, locale: string) {
|
|
const normalizedLocale = supportedLocaleSchema.safeParse(locale).data
|
|
const post = await db.post.findUnique({
|
|
where: { slug },
|
|
include: {
|
|
translations: normalizedLocale
|
|
? {
|
|
where: {
|
|
locale: normalizedLocale,
|
|
},
|
|
take: 1,
|
|
}
|
|
: false,
|
|
},
|
|
})
|
|
|
|
if (!post) {
|
|
return null
|
|
}
|
|
|
|
const translation = post.translations?.[0]
|
|
|
|
return {
|
|
...post,
|
|
title: translation?.title ?? post.title,
|
|
excerpt: translation?.excerpt ?? post.excerpt,
|
|
body: translation?.body ?? post.body,
|
|
}
|
|
}
|
|
|
|
export async function listPostsForLocale(locale: string) {
|
|
const normalizedLocale = supportedLocaleSchema.safeParse(locale).data
|
|
const posts = await db.post.findMany({
|
|
where: {
|
|
status: "published",
|
|
},
|
|
orderBy: {
|
|
updatedAt: "desc",
|
|
},
|
|
include: {
|
|
translations: normalizedLocale
|
|
? {
|
|
where: { locale: normalizedLocale },
|
|
take: 1,
|
|
}
|
|
: false,
|
|
},
|
|
})
|
|
|
|
return posts.map((post) => {
|
|
const translation = post.translations?.[0]
|
|
|
|
return {
|
|
...post,
|
|
title: translation?.title ?? post.title,
|
|
excerpt: translation?.excerpt ?? post.excerpt,
|
|
body: translation?.body ?? post.body,
|
|
}
|
|
})
|
|
}
|
|
|
|
export async function listPostsWithTranslations() {
|
|
return db.post.findMany({
|
|
orderBy: {
|
|
updatedAt: "desc",
|
|
},
|
|
include: {
|
|
translations: {
|
|
orderBy: [{ locale: "asc" }],
|
|
},
|
|
},
|
|
})
|
|
}
|
|
|
|
export async function upsertPostTranslation(input: unknown) {
|
|
const payload = upsertPostTranslationInputSchema.parse(input)
|
|
const { postId, locale, ...data } = payload
|
|
|
|
return db.postTranslation.upsert({
|
|
where: {
|
|
postId_locale: {
|
|
postId,
|
|
locale,
|
|
},
|
|
},
|
|
create: {
|
|
postId,
|
|
locale,
|
|
...data,
|
|
},
|
|
update: data,
|
|
})
|
|
}
|
|
|
|
export async function createPost(input: unknown, context?: CrudMutationContext) {
|
|
return postCrudService.create(input, context)
|
|
}
|
|
|
|
export async function updatePost(id: string, input: unknown, context?: CrudMutationContext) {
|
|
return postCrudService.update(id, input, context)
|
|
}
|
|
|
|
export async function deletePost(id: string, context?: CrudMutationContext) {
|
|
return postCrudService.delete(id, context)
|
|
}
|