feat(web): add public portfolio rendering and media streaming
This commit is contained in:
@@ -27,10 +27,13 @@ export {
|
||||
deleteMediaAsset,
|
||||
getMediaAssetById,
|
||||
getMediaFoundationSummary,
|
||||
getPublishedArtworkBySlug,
|
||||
linkArtworkToGrouping,
|
||||
listArtworks,
|
||||
listMediaAssets,
|
||||
listMediaFoundationGroups,
|
||||
listPublishedArtworks,
|
||||
listPublishedPortfolioGroups,
|
||||
updateMediaAsset,
|
||||
} from "./media-foundation"
|
||||
export type { PublicNavigationItem } from "./pages-navigation"
|
||||
|
||||
@@ -8,11 +8,11 @@ const { mockDb } = vi.hoisted(() => ({
|
||||
artworkTag: { upsert: vi.fn() },
|
||||
artworkRendition: { upsert: 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() },
|
||||
category: { create: vi.fn() },
|
||||
tag: { create: vi.fn() },
|
||||
artwork: { create: vi.fn(), findMany: vi.fn(), findFirst: vi.fn() },
|
||||
gallery: { create: vi.fn(), findMany: vi.fn() },
|
||||
album: { create: vi.fn(), findMany: vi.fn() },
|
||||
category: { create: vi.fn(), findMany: vi.fn() },
|
||||
tag: { create: vi.fn(), findMany: vi.fn() },
|
||||
},
|
||||
}))
|
||||
|
||||
@@ -26,7 +26,10 @@ import {
|
||||
createMediaAsset,
|
||||
deleteMediaAsset,
|
||||
getMediaAssetById,
|
||||
getPublishedArtworkBySlug,
|
||||
linkArtworkToGrouping,
|
||||
listPublishedArtworks,
|
||||
listPublishedPortfolioGroups,
|
||||
updateMediaAsset,
|
||||
} from "./media-foundation"
|
||||
|
||||
@@ -42,6 +45,12 @@ describe("media foundation service", () => {
|
||||
if ("findUnique" in value) {
|
||||
value.findUnique.mockReset()
|
||||
}
|
||||
if ("findMany" in value) {
|
||||
value.findMany.mockReset()
|
||||
}
|
||||
if ("findFirst" in value) {
|
||||
value.findFirst.mockReset()
|
||||
}
|
||||
if ("update" in value) {
|
||||
value.update.mockReset()
|
||||
}
|
||||
@@ -120,4 +129,58 @@ describe("media foundation service", () => {
|
||||
expect(mockDb.mediaAsset.update).toHaveBeenCalledTimes(1)
|
||||
expect(mockDb.mediaAsset.delete).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it("lists published artworks with group filters", async () => {
|
||||
mockDb.artwork.findMany.mockResolvedValue([])
|
||||
|
||||
await listPublishedArtworks({
|
||||
groupType: "gallery",
|
||||
groupSlug: "showcase",
|
||||
})
|
||||
|
||||
expect(mockDb.artwork.findMany).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
where: expect.objectContaining({
|
||||
isPublished: true,
|
||||
galleryLinks: {
|
||||
some: {
|
||||
gallery: {
|
||||
slug: "showcase",
|
||||
isVisible: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
}),
|
||||
)
|
||||
})
|
||||
|
||||
it("lists published portfolio groups", async () => {
|
||||
mockDb.gallery.findMany.mockResolvedValue([])
|
||||
mockDb.album.findMany.mockResolvedValue([])
|
||||
mockDb.category.findMany.mockResolvedValue([])
|
||||
mockDb.tag.findMany.mockResolvedValue([])
|
||||
|
||||
await listPublishedPortfolioGroups()
|
||||
|
||||
expect(mockDb.gallery.findMany).toHaveBeenCalledTimes(1)
|
||||
expect(mockDb.album.findMany).toHaveBeenCalledTimes(1)
|
||||
expect(mockDb.category.findMany).toHaveBeenCalledTimes(1)
|
||||
expect(mockDb.tag.findMany).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it("loads a published artwork by slug", async () => {
|
||||
mockDb.artwork.findFirst.mockResolvedValue(null)
|
||||
|
||||
await getPublishedArtworkBySlug("artwork-slug")
|
||||
|
||||
expect(mockDb.artwork.findFirst).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
where: {
|
||||
slug: "artwork-slug",
|
||||
isPublished: true,
|
||||
},
|
||||
}),
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -9,6 +9,14 @@ import {
|
||||
|
||||
import { db } from "./client"
|
||||
|
||||
type PublicArtworkGroupType = "gallery" | "album" | "category" | "tag"
|
||||
|
||||
type ListPublishedArtworksInput = {
|
||||
groupType?: PublicArtworkGroupType
|
||||
groupSlug?: string
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export async function listMediaAssets(limit = 24) {
|
||||
return db.mediaAsset.findMany({
|
||||
orderBy: { updatedAt: "desc" },
|
||||
@@ -280,3 +288,251 @@ export async function getMediaFoundationSummary() {
|
||||
tags,
|
||||
}
|
||||
}
|
||||
|
||||
export async function listPublishedPortfolioGroups() {
|
||||
const [galleries, albums, categories, tags] = await Promise.all([
|
||||
db.gallery.findMany({
|
||||
where: {
|
||||
isVisible: true,
|
||||
},
|
||||
orderBy: [{ sortOrder: "asc" }, { name: "asc" }],
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
},
|
||||
}),
|
||||
db.album.findMany({
|
||||
where: {
|
||||
isVisible: true,
|
||||
},
|
||||
orderBy: [{ sortOrder: "asc" }, { name: "asc" }],
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
},
|
||||
}),
|
||||
db.category.findMany({
|
||||
where: {
|
||||
isVisible: true,
|
||||
},
|
||||
orderBy: [{ sortOrder: "asc" }, { name: "asc" }],
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
},
|
||||
}),
|
||||
db.tag.findMany({
|
||||
orderBy: [{ name: "asc" }],
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
},
|
||||
}),
|
||||
])
|
||||
|
||||
return {
|
||||
galleries,
|
||||
albums,
|
||||
categories,
|
||||
tags,
|
||||
}
|
||||
}
|
||||
|
||||
export async function listPublishedArtworks(input: ListPublishedArtworksInput = {}) {
|
||||
const take = input.limit ?? 36
|
||||
const where: Record<string, unknown> = {
|
||||
isPublished: true,
|
||||
}
|
||||
|
||||
if (input.groupType && input.groupSlug) {
|
||||
if (input.groupType === "gallery") {
|
||||
where.galleryLinks = {
|
||||
some: {
|
||||
gallery: {
|
||||
slug: input.groupSlug,
|
||||
isVisible: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
} else if (input.groupType === "album") {
|
||||
where.albumLinks = {
|
||||
some: {
|
||||
album: {
|
||||
slug: input.groupSlug,
|
||||
isVisible: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
} else if (input.groupType === "category") {
|
||||
where.categoryLinks = {
|
||||
some: {
|
||||
category: {
|
||||
slug: input.groupSlug,
|
||||
isVisible: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
} else if (input.groupType === "tag") {
|
||||
where.tagLinks = {
|
||||
some: {
|
||||
tag: {
|
||||
slug: input.groupSlug,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return db.artwork.findMany({
|
||||
where,
|
||||
orderBy: [{ updatedAt: "desc" }],
|
||||
take,
|
||||
include: {
|
||||
renditions: {
|
||||
where: {
|
||||
mediaAsset: {
|
||||
isPublished: true,
|
||||
},
|
||||
},
|
||||
include: {
|
||||
mediaAsset: {
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
altText: true,
|
||||
mimeType: true,
|
||||
width: true,
|
||||
height: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
galleryLinks: {
|
||||
include: {
|
||||
gallery: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
albumLinks: {
|
||||
include: {
|
||||
album: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
categoryLinks: {
|
||||
include: {
|
||||
category: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tagLinks: {
|
||||
include: {
|
||||
tag: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export async function getPublishedArtworkBySlug(slug: string) {
|
||||
return db.artwork.findFirst({
|
||||
where: {
|
||||
slug,
|
||||
isPublished: true,
|
||||
},
|
||||
include: {
|
||||
renditions: {
|
||||
where: {
|
||||
mediaAsset: {
|
||||
isPublished: true,
|
||||
},
|
||||
},
|
||||
include: {
|
||||
mediaAsset: {
|
||||
select: {
|
||||
id: true,
|
||||
title: true,
|
||||
altText: true,
|
||||
mimeType: true,
|
||||
width: true,
|
||||
height: true,
|
||||
source: true,
|
||||
author: true,
|
||||
copyright: true,
|
||||
tags: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
galleryLinks: {
|
||||
include: {
|
||||
gallery: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
albumLinks: {
|
||||
include: {
|
||||
album: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
categoryLinks: {
|
||||
include: {
|
||||
category: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
tagLinks: {
|
||||
include: {
|
||||
tag: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
slug: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user