|
|
@ -1,7 +1,9 @@ |
|
|
import { dbGlobal } from "drizzle-pkg/lib/db"; |
|
|
import { dbGlobal } from "drizzle-pkg/lib/db"; |
|
|
import { rssFeeds, rssItems } from "drizzle-pkg/lib/schema/rss"; |
|
|
import { rssFeeds, rssItems } from "drizzle-pkg/lib/schema/rss"; |
|
|
import { users } from "drizzle-pkg/lib/schema/auth"; |
|
|
import { users } from "drizzle-pkg/lib/schema/auth"; |
|
|
import { and, desc, eq } from "drizzle-orm"; |
|
|
import { PUBLIC_LIST_PAGE_SIZE, PUBLIC_PREVIEW_LIMIT } from "#server/constants/public-profile-lists"; |
|
|
|
|
|
import { normalizePublicListPage } from "#server/utils/public-pagination"; |
|
|
|
|
|
import { and, count, desc, eq } from "drizzle-orm"; |
|
|
import { XMLParser } from "fast-xml-parser"; |
|
|
import { XMLParser } from "fast-xml-parser"; |
|
|
import { assertSafeRssUrl } from "#server/utils/rss-url"; |
|
|
import { assertSafeRssUrl } from "#server/utils/rss-url"; |
|
|
import { RssUrlUnsafeError } from "#server/utils/rss-url"; |
|
|
import { RssUrlUnsafeError } from "#server/utils/rss-url"; |
|
|
@ -76,21 +78,54 @@ export async function updateItemVisibility(userId: number, itemId: number, visib |
|
|
return row ?? null; |
|
|
return row ?? null; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
export async function listPublicRssItemsBySlug(publicSlug: string) { |
|
|
function publicRssListWhere(publicSlug: string) { |
|
|
const rows = await dbGlobal |
|
|
return and( |
|
|
.select({ it: rssItems }) |
|
|
eq(users.publicSlug, publicSlug), |
|
|
.from(rssItems) |
|
|
eq(users.status, "active"), |
|
|
.innerJoin(users, eq(rssItems.userId, users.id)) |
|
|
eq(rssItems.visibility, "public"), |
|
|
.where( |
|
|
); |
|
|
and( |
|
|
} |
|
|
eq(users.publicSlug, publicSlug), |
|
|
|
|
|
eq(users.status, "active"), |
|
|
export async function getPublicRssPreviewBySlug(publicSlug: string) { |
|
|
eq(rssItems.visibility, "public"), |
|
|
const whereClause = publicRssListWhere(publicSlug); |
|
|
), |
|
|
const [countRows, rows] = await Promise.all([ |
|
|
) |
|
|
dbGlobal |
|
|
.orderBy(desc(rssItems.publishedAt), desc(rssItems.id)) |
|
|
.select({ total: count() }) |
|
|
.limit(200); |
|
|
.from(rssItems) |
|
|
return rows.map((r) => r.it); |
|
|
.innerJoin(users, eq(rssItems.userId, users.id)) |
|
|
|
|
|
.where(whereClause), |
|
|
|
|
|
dbGlobal |
|
|
|
|
|
.select({ it: rssItems }) |
|
|
|
|
|
.from(rssItems) |
|
|
|
|
|
.innerJoin(users, eq(rssItems.userId, users.id)) |
|
|
|
|
|
.where(whereClause) |
|
|
|
|
|
.orderBy(desc(rssItems.publishedAt), desc(rssItems.id)) |
|
|
|
|
|
.limit(PUBLIC_PREVIEW_LIMIT), |
|
|
|
|
|
]); |
|
|
|
|
|
return { items: rows.map((r) => r.it), total: countRows[0]?.total ?? 0 }; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
export async function getPublicRssPageBySlug(publicSlug: string, pageRaw: unknown) { |
|
|
|
|
|
const page = normalizePublicListPage(pageRaw); |
|
|
|
|
|
const pageSize = PUBLIC_LIST_PAGE_SIZE; |
|
|
|
|
|
const offset = (page - 1) * pageSize; |
|
|
|
|
|
const whereClause = publicRssListWhere(publicSlug); |
|
|
|
|
|
const [countRows, rows] = await Promise.all([ |
|
|
|
|
|
dbGlobal |
|
|
|
|
|
.select({ total: count() }) |
|
|
|
|
|
.from(rssItems) |
|
|
|
|
|
.innerJoin(users, eq(rssItems.userId, users.id)) |
|
|
|
|
|
.where(whereClause), |
|
|
|
|
|
dbGlobal |
|
|
|
|
|
.select({ it: rssItems }) |
|
|
|
|
|
.from(rssItems) |
|
|
|
|
|
.innerJoin(users, eq(rssItems.userId, users.id)) |
|
|
|
|
|
.where(whereClause) |
|
|
|
|
|
.orderBy(desc(rssItems.publishedAt), desc(rssItems.id)) |
|
|
|
|
|
.limit(pageSize) |
|
|
|
|
|
.offset(offset), |
|
|
|
|
|
]); |
|
|
|
|
|
return { items: rows.map((r) => r.it), total: countRows[0]?.total ?? 0, page, pageSize }; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
export async function getUnlistedRssItem(publicSlug: string, shareToken: string) { |
|
|
export async function getUnlistedRssItem(publicSlug: string, shareToken: string) { |
|
|
|