|
|
@ -2,8 +2,10 @@ import { dbGlobal } from "drizzle-pkg/lib/db"; |
|
|
import { postMediaRefs, posts } from "drizzle-pkg/lib/schema/content"; |
|
|
import { postMediaRefs, posts } from "drizzle-pkg/lib/schema/content"; |
|
|
import { reconcileAssetTimestampsAfterRefChange, syncPostMediaRefs } from "#server/service/media"; |
|
|
import { reconcileAssetTimestampsAfterRefChange, syncPostMediaRefs } from "#server/service/media"; |
|
|
import { users } from "drizzle-pkg/lib/schema/auth"; |
|
|
import { users } from "drizzle-pkg/lib/schema/auth"; |
|
|
import { and, desc, eq } from "drizzle-orm"; |
|
|
import { and, count, desc, eq } from "drizzle-orm"; |
|
|
|
|
|
import { PUBLIC_LIST_PAGE_SIZE, PUBLIC_PREVIEW_LIMIT } from "#server/constants/public-profile-lists"; |
|
|
import { visibilitySchema, type Visibility } from "#server/constants/visibility"; |
|
|
import { visibilitySchema, type Visibility } from "#server/constants/visibility"; |
|
|
|
|
|
import { normalizePublicListPage } from "#server/utils/public-pagination"; |
|
|
import { visibilityShareToken } from "#server/utils/share-token"; |
|
|
import { visibilityShareToken } from "#server/utils/share-token"; |
|
|
import { nextIntegerId } from "#server/utils/sqlite-id"; |
|
|
import { nextIntegerId } from "#server/utils/sqlite-id"; |
|
|
|
|
|
|
|
|
@ -128,25 +130,85 @@ export async function deletePost(userId: number, id: number) { |
|
|
return true; |
|
|
return true; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
export async function listPublicPostsBySlug(publicSlug: string) { |
|
|
const publicPostsListSelect = { |
|
|
return dbGlobal |
|
|
title: posts.title, |
|
|
.select({ |
|
|
excerpt: posts.excerpt, |
|
|
title: posts.title, |
|
|
slug: posts.slug, |
|
|
excerpt: posts.excerpt, |
|
|
coverUrl: posts.coverUrl, |
|
|
slug: posts.slug, |
|
|
publishedAt: posts.publishedAt, |
|
|
coverUrl: posts.coverUrl, |
|
|
} as const; |
|
|
publishedAt: posts.publishedAt, |
|
|
|
|
|
}) |
|
|
function publicPostsListWhere(publicSlug: string) { |
|
|
.from(posts) |
|
|
return and( |
|
|
.innerJoin(users, eq(posts.userId, users.id)) |
|
|
eq(users.publicSlug, publicSlug), |
|
|
.where( |
|
|
eq(users.status, "active"), |
|
|
and( |
|
|
eq(posts.visibility, "public"), |
|
|
eq(users.publicSlug, publicSlug), |
|
|
); |
|
|
eq(users.status, "active"), |
|
|
} |
|
|
eq(posts.visibility, "public"), |
|
|
|
|
|
), |
|
|
export async function getPublicPostsPreviewBySlug(publicSlug: string): Promise<{ |
|
|
) |
|
|
items: Array<{ |
|
|
.orderBy(desc(posts.publishedAt), desc(posts.id)); |
|
|
title: string; |
|
|
|
|
|
excerpt: string; |
|
|
|
|
|
slug: string; |
|
|
|
|
|
coverUrl: string | null; |
|
|
|
|
|
publishedAt: Date | null; |
|
|
|
|
|
}>; |
|
|
|
|
|
total: number; |
|
|
|
|
|
}> { |
|
|
|
|
|
const whereClause = publicPostsListWhere(publicSlug); |
|
|
|
|
|
const [countRows, items] = await Promise.all([ |
|
|
|
|
|
dbGlobal |
|
|
|
|
|
.select({ total: count() }) |
|
|
|
|
|
.from(posts) |
|
|
|
|
|
.innerJoin(users, eq(posts.userId, users.id)) |
|
|
|
|
|
.where(whereClause), |
|
|
|
|
|
dbGlobal |
|
|
|
|
|
.select(publicPostsListSelect) |
|
|
|
|
|
.from(posts) |
|
|
|
|
|
.innerJoin(users, eq(posts.userId, users.id)) |
|
|
|
|
|
.where(whereClause) |
|
|
|
|
|
.orderBy(desc(posts.publishedAt), desc(posts.id)) |
|
|
|
|
|
.limit(PUBLIC_PREVIEW_LIMIT), |
|
|
|
|
|
]); |
|
|
|
|
|
return { items, total: countRows[0]?.total ?? 0 }; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
export async function getPublicPostsPageBySlug( |
|
|
|
|
|
publicSlug: string, |
|
|
|
|
|
pageRaw: unknown, |
|
|
|
|
|
): Promise<{ |
|
|
|
|
|
items: Array<{ |
|
|
|
|
|
title: string; |
|
|
|
|
|
excerpt: string; |
|
|
|
|
|
slug: string; |
|
|
|
|
|
coverUrl: string | null; |
|
|
|
|
|
publishedAt: Date | null; |
|
|
|
|
|
}>; |
|
|
|
|
|
total: number; |
|
|
|
|
|
page: number; |
|
|
|
|
|
pageSize: number; |
|
|
|
|
|
}> { |
|
|
|
|
|
const page = normalizePublicListPage(pageRaw); |
|
|
|
|
|
const pageSize = PUBLIC_LIST_PAGE_SIZE; |
|
|
|
|
|
const offset = (page - 1) * pageSize; |
|
|
|
|
|
const whereClause = publicPostsListWhere(publicSlug); |
|
|
|
|
|
const [countRows, items] = await Promise.all([ |
|
|
|
|
|
dbGlobal |
|
|
|
|
|
.select({ total: count() }) |
|
|
|
|
|
.from(posts) |
|
|
|
|
|
.innerJoin(users, eq(posts.userId, users.id)) |
|
|
|
|
|
.where(whereClause), |
|
|
|
|
|
dbGlobal |
|
|
|
|
|
.select(publicPostsListSelect) |
|
|
|
|
|
.from(posts) |
|
|
|
|
|
.innerJoin(users, eq(posts.userId, users.id)) |
|
|
|
|
|
.where(whereClause) |
|
|
|
|
|
.orderBy(desc(posts.publishedAt), desc(posts.id)) |
|
|
|
|
|
.limit(pageSize) |
|
|
|
|
|
.offset(offset), |
|
|
|
|
|
]); |
|
|
|
|
|
return { items, total: countRows[0]?.total ?? 0, page, pageSize }; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
export async function getPublicPostByPublicSlugAndSlug(publicSlug: string, postSlug: string) { |
|
|
export async function getPublicPostByPublicSlugAndSlug(publicSlug: string, postSlug: string) { |
|
|
|