86 lines
2.1 KiB
TypeScript
86 lines
2.1 KiB
TypeScript
import { allow, deny } from "@/lib/decision"
|
|
import { toApiError } from "@/lib/errors"
|
|
import type { Comment } from "@/lib/types"
|
|
|
|
import { httpJson } from "./http"
|
|
|
|
type Paginated<T> = {
|
|
items: T[]
|
|
meta: {
|
|
total: number
|
|
offset: number
|
|
limit: number
|
|
}
|
|
}
|
|
|
|
type ListOptions = {
|
|
offset?: number
|
|
limit?: number
|
|
}
|
|
|
|
function withOffsetLimit(path: string, options?: ListOptions): string {
|
|
const offset = options?.offset ?? 0
|
|
const limit = options?.limit ?? 1000
|
|
const searchParams = new URLSearchParams({
|
|
offset: String(offset),
|
|
limit: String(limit),
|
|
})
|
|
return `${path}?${searchParams.toString()}`
|
|
}
|
|
|
|
export async function listCommentsByPost(
|
|
postId: string,
|
|
options?: ListOptions,
|
|
): Promise<Comment[]> {
|
|
const encodedId = encodeURIComponent(postId)
|
|
const res = await httpJson<Paginated<Comment>>(
|
|
withOffsetLimit(`/api/v1/posts/${encodedId}/comments`, options),
|
|
{
|
|
cache: "no-store",
|
|
},
|
|
)
|
|
return res.items
|
|
}
|
|
|
|
export async function addComment(postId: string, content: string) {
|
|
const encodedId = encodeURIComponent(postId)
|
|
try {
|
|
await httpJson<unknown>(`/api/v1/posts/${encodedId}/comments`, {
|
|
method: "POST",
|
|
cache: "no-store",
|
|
json: { content },
|
|
})
|
|
return allow()
|
|
} catch (err: unknown) {
|
|
if (err instanceof Error && err.message === "UNAUTHORIZED") {
|
|
return deny(401, "请先登录")
|
|
}
|
|
const apiError = toApiError(err)
|
|
return deny(apiError.code, apiError.msg)
|
|
}
|
|
}
|
|
|
|
export async function toggleCommentLike(commentId: string, currentlyLiked: boolean) {
|
|
const encodedId = encodeURIComponent(commentId)
|
|
try {
|
|
if (currentlyLiked) {
|
|
await httpJson<unknown>(`/api/v1/comments/${encodedId}/like`, {
|
|
method: "DELETE",
|
|
cache: "no-store",
|
|
})
|
|
} else {
|
|
await httpJson<unknown>(`/api/v1/comments/${encodedId}/like`, {
|
|
method: "POST",
|
|
cache: "no-store",
|
|
})
|
|
}
|
|
return allow()
|
|
} catch (err: unknown) {
|
|
if (err instanceof Error && err.message === "UNAUTHORIZED") {
|
|
return deny(401, "请先登录")
|
|
}
|
|
const apiError = toApiError(err)
|
|
return deny(apiError.code, apiError.msg)
|
|
}
|
|
}
|