feat(media): add admin media CRUD preview and storage cleanup
This commit is contained in:
@@ -29,6 +29,23 @@ export const createMediaAssetInputSchema = z.object({
|
||||
isPublished: z.boolean().optional(),
|
||||
})
|
||||
|
||||
export const updateMediaAssetInputSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
type: mediaAssetTypeSchema.optional(),
|
||||
title: z.string().min(1).max(180).optional(),
|
||||
description: z.string().max(5000).nullable().optional(),
|
||||
altText: z.string().max(1000).nullable().optional(),
|
||||
source: z.string().max(500).nullable().optional(),
|
||||
copyright: z.string().max(500).nullable().optional(),
|
||||
author: z.string().max(180).nullable().optional(),
|
||||
tags: z.array(z.string().min(1).max(100)).optional(),
|
||||
mimeType: z.string().max(180).nullable().optional(),
|
||||
width: z.number().int().positive().nullable().optional(),
|
||||
height: z.number().int().positive().nullable().optional(),
|
||||
sizeBytes: z.number().int().min(0).nullable().optional(),
|
||||
isPublished: z.boolean().optional(),
|
||||
})
|
||||
|
||||
export const createArtworkInputSchema = z.object({
|
||||
title: z.string().min(1).max(180),
|
||||
slug: z.string().min(1).max(180),
|
||||
@@ -66,6 +83,7 @@ export const attachArtworkRenditionInputSchema = z.object({
|
||||
export type MediaAssetType = z.infer<typeof mediaAssetTypeSchema>
|
||||
export type ArtworkRenditionSlot = z.infer<typeof artworkRenditionSlotSchema>
|
||||
export type CreateMediaAssetInput = z.infer<typeof createMediaAssetInputSchema>
|
||||
export type UpdateMediaAssetInput = z.infer<typeof updateMediaAssetInputSchema>
|
||||
export type CreateArtworkInput = z.infer<typeof createArtworkInputSchema>
|
||||
export type CreateGroupingInput = z.infer<typeof createGroupingInputSchema>
|
||||
export type LinkArtworkGroupingInput = z.infer<typeof linkArtworkGroupingInputSchema>
|
||||
|
||||
@@ -7,11 +7,14 @@ export {
|
||||
createGallery,
|
||||
createMediaAsset,
|
||||
createTag,
|
||||
deleteMediaAsset,
|
||||
getMediaAssetById,
|
||||
getMediaFoundationSummary,
|
||||
linkArtworkToGrouping,
|
||||
listArtworks,
|
||||
listMediaAssets,
|
||||
listMediaFoundationGroups,
|
||||
updateMediaAsset,
|
||||
} from "./media-foundation"
|
||||
export {
|
||||
createPost,
|
||||
|
||||
@@ -7,7 +7,7 @@ const { mockDb } = vi.hoisted(() => ({
|
||||
artworkCategory: { upsert: vi.fn() },
|
||||
artworkTag: { upsert: vi.fn() },
|
||||
artworkRendition: { upsert: vi.fn() },
|
||||
mediaAsset: { create: vi.fn() },
|
||||
mediaAsset: { create: vi.fn(), findUnique: vi.fn(), update: vi.fn(), delete: vi.fn() },
|
||||
artwork: { create: vi.fn() },
|
||||
gallery: { create: vi.fn() },
|
||||
album: { create: vi.fn() },
|
||||
@@ -24,7 +24,10 @@ import {
|
||||
attachArtworkRendition,
|
||||
createArtwork,
|
||||
createMediaAsset,
|
||||
deleteMediaAsset,
|
||||
getMediaAssetById,
|
||||
linkArtworkToGrouping,
|
||||
updateMediaAsset,
|
||||
} from "./media-foundation"
|
||||
|
||||
describe("media foundation service", () => {
|
||||
@@ -36,6 +39,15 @@ describe("media foundation service", () => {
|
||||
if ("create" in value) {
|
||||
value.create.mockReset()
|
||||
}
|
||||
if ("findUnique" in value) {
|
||||
value.findUnique.mockReset()
|
||||
}
|
||||
if ("update" in value) {
|
||||
value.update.mockReset()
|
||||
}
|
||||
if ("delete" in value) {
|
||||
value.delete.mockReset()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -90,4 +102,22 @@ describe("media foundation service", () => {
|
||||
expect(mockDb.mediaAsset.create).toHaveBeenCalledTimes(1)
|
||||
expect(mockDb.artwork.create).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it("handles media asset read/update/delete operations", async () => {
|
||||
mockDb.mediaAsset.findUnique.mockResolvedValue({ id: "asset-1" })
|
||||
mockDb.mediaAsset.update.mockResolvedValue({ id: "asset-1", title: "Updated" })
|
||||
mockDb.mediaAsset.delete.mockResolvedValue({ id: "asset-1" })
|
||||
|
||||
await getMediaAssetById("asset-1")
|
||||
await updateMediaAsset({
|
||||
id: "c58f3aca-f958-4079-b2df-c9edf3a5fb0a",
|
||||
title: "Updated",
|
||||
tags: ["a", "b"],
|
||||
})
|
||||
await deleteMediaAsset("asset-1")
|
||||
|
||||
expect(mockDb.mediaAsset.findUnique).toHaveBeenCalledTimes(1)
|
||||
expect(mockDb.mediaAsset.update).toHaveBeenCalledTimes(1)
|
||||
expect(mockDb.mediaAsset.delete).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
createGroupingInputSchema,
|
||||
createMediaAssetInputSchema,
|
||||
linkArtworkGroupingInputSchema,
|
||||
updateMediaAssetInputSchema,
|
||||
} from "@cms/content"
|
||||
|
||||
import { db } from "./client"
|
||||
@@ -107,6 +108,28 @@ export async function createMediaAsset(input: unknown) {
|
||||
})
|
||||
}
|
||||
|
||||
export async function getMediaAssetById(id: string) {
|
||||
return db.mediaAsset.findUnique({
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
|
||||
export async function updateMediaAsset(input: unknown) {
|
||||
const payload = updateMediaAssetInputSchema.parse(input)
|
||||
const { id, ...data } = payload
|
||||
|
||||
return db.mediaAsset.update({
|
||||
where: { id },
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
export async function deleteMediaAsset(id: string) {
|
||||
return db.mediaAsset.delete({
|
||||
where: { id },
|
||||
})
|
||||
}
|
||||
|
||||
export async function createArtwork(input: unknown) {
|
||||
const payload = createArtworkInputSchema.parse(input)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user