v3: code quality pass
This commit is contained in:
@@ -4,12 +4,7 @@ import {
|
||||
type Comment,
|
||||
} from "../model/interfaces.ts";
|
||||
import { type SQLOutputValue } from "node:sqlite";
|
||||
import {
|
||||
type CommentRow,
|
||||
commentRowToApi,
|
||||
db,
|
||||
isCommentRow,
|
||||
} from "../model/db.ts";
|
||||
import { commentRowToApi, db, isCommentRow } from "../model/db.ts";
|
||||
import { notifyMentions } from "./notification-service.ts";
|
||||
|
||||
const SELECT_COLS =
|
||||
@@ -23,7 +18,14 @@ function fetchComment(commentId: string): Comment {
|
||||
if (!row || !isCommentRow(row as Record<string, SQLOutputValue>)) {
|
||||
throw new APIException(APIErrorCode.NOT_FOUND, 404, "Comment not found");
|
||||
}
|
||||
return commentRowToApi(row as CommentRow);
|
||||
if (!isCommentRow(row)) {
|
||||
throw new APIException(
|
||||
APIErrorCode.SERVER_ERROR,
|
||||
500,
|
||||
"Malformed comment data",
|
||||
);
|
||||
}
|
||||
return commentRowToApi(row);
|
||||
}
|
||||
|
||||
export function getComments(dumpId: string): Comment[] {
|
||||
@@ -31,15 +33,14 @@ export function getComments(dumpId: string): Comment[] {
|
||||
`SELECT ${SELECT_COLS} FROM comments c JOIN users u ON c.user_id = u.id
|
||||
WHERE c.dump_id = ? ORDER BY c.created_at ASC;`,
|
||||
).all(dumpId);
|
||||
const typed = rows as Parameters<typeof isCommentRow>[0][];
|
||||
if (!typed.every(isCommentRow)) {
|
||||
if (!rows.every(isCommentRow)) {
|
||||
throw new APIException(
|
||||
APIErrorCode.SERVER_ERROR,
|
||||
500,
|
||||
"Malformed comment data",
|
||||
);
|
||||
}
|
||||
return typed.map(commentRowToApi);
|
||||
return rows.map(commentRowToApi);
|
||||
}
|
||||
|
||||
export function createComment(
|
||||
|
||||
@@ -448,11 +448,11 @@ export function getVotedDumpsByUser(
|
||||
const dumpCols = SELECT_COLS_ALIASED;
|
||||
|
||||
let totalRow: { count: number } | undefined;
|
||||
let rawRows: unknown[];
|
||||
let rows: unknown[];
|
||||
|
||||
if (requestingUserId === userId) {
|
||||
// Own profile: include private dumps the user themselves voted on and owns.
|
||||
rawRows = db.prepare(
|
||||
rows = db.prepare(
|
||||
`SELECT ${dumpCols}
|
||||
FROM dumps d
|
||||
INNER JOIN votes v ON d.id = v.dump_id
|
||||
@@ -465,7 +465,7 @@ export function getVotedDumpsByUser(
|
||||
WHERE v.user_id = ? AND (d.is_private = 0 OR d.user_id = ?);`,
|
||||
).get(userId, userId) as { count: number } | undefined;
|
||||
} else {
|
||||
rawRows = db.prepare(
|
||||
rows = db.prepare(
|
||||
`SELECT ${dumpCols}
|
||||
FROM dumps d
|
||||
INNER JOIN votes v ON d.id = v.dump_id
|
||||
@@ -479,7 +479,6 @@ export function getVotedDumpsByUser(
|
||||
).get(userId) as { count: number } | undefined;
|
||||
}
|
||||
|
||||
const rows = rawRows as Parameters<typeof isDumpRow>[0][];
|
||||
if (!rows.every(isDumpRow)) {
|
||||
throw new APIException(
|
||||
APIErrorCode.SERVER_ERROR,
|
||||
|
||||
@@ -114,12 +114,12 @@ export function getFollowStatus(followerId: string): FollowStatus {
|
||||
const rawUserRows = db.prepare(
|
||||
`SELECT id, follower_id, followed_user_id, followed_playlist_id, created_at
|
||||
FROM follows WHERE follower_id = ? AND followed_user_id IS NOT NULL;`,
|
||||
).all(followerId) as Parameters<typeof isFollowRow>[0][];
|
||||
).all(followerId);
|
||||
|
||||
const rawPlaylistRows = db.prepare(
|
||||
`SELECT id, follower_id, followed_user_id, followed_playlist_id, created_at
|
||||
FROM follows WHERE follower_id = ? AND followed_playlist_id IS NOT NULL;`,
|
||||
).all(followerId) as Parameters<typeof isFollowRow>[0][];
|
||||
).all(followerId);
|
||||
|
||||
if (!rawUserRows.every(isFollowRow) || !rawPlaylistRows.every(isFollowRow)) {
|
||||
throw new APIException(
|
||||
@@ -207,8 +207,7 @@ export function getFollowedPlaylistsDumpFeed(
|
||||
AND d.is_private = 0;`,
|
||||
).get(followerId) as { count: number } | undefined;
|
||||
|
||||
const playlistFeedRows = rawRows as Parameters<typeof isDumpRow>[0][];
|
||||
if (!playlistFeedRows.every(isDumpRow)) {
|
||||
if (!rawRows.every(isDumpRow)) {
|
||||
throw new APIException(
|
||||
APIErrorCode.SERVER_ERROR,
|
||||
500,
|
||||
@@ -216,7 +215,7 @@ export function getFollowedPlaylistsDumpFeed(
|
||||
);
|
||||
}
|
||||
return {
|
||||
items: playlistFeedRows.map(dumpRowToApi),
|
||||
items: rawRows.map(dumpRowToApi),
|
||||
total: totalRow?.count ?? 0,
|
||||
};
|
||||
}
|
||||
@@ -246,7 +245,7 @@ export function getFollowedPlaylistsByUser(
|
||||
AND p.is_public = 1
|
||||
ORDER BY f.created_at DESC
|
||||
LIMIT ? OFFSET ?;`,
|
||||
).all(userId, limit, offset) as Parameters<typeof isPlaylistRow>[0][];
|
||||
).all(userId, limit, offset);
|
||||
|
||||
if (!rawRows.every(isPlaylistRow)) {
|
||||
throw new APIException(
|
||||
|
||||
@@ -57,7 +57,7 @@ export function getNotificationsForUser(
|
||||
const offset = (page - 1) * limit;
|
||||
const rawRows = db.prepare(
|
||||
`SELECT * FROM notifications WHERE user_id = ? ORDER BY created_at DESC LIMIT ? OFFSET ?;`,
|
||||
).all(userId, limit, offset) as Parameters<typeof isNotificationRow>[0][];
|
||||
).all(userId, limit, offset);
|
||||
|
||||
const totalRow = db.prepare(
|
||||
`SELECT COUNT(*) as count FROM notifications WHERE user_id = ?;`,
|
||||
@@ -195,6 +195,7 @@ export function notifyUserFollowersNewDump(
|
||||
sendToUser(row.follower_id, {
|
||||
type: "notification_created",
|
||||
notification: {
|
||||
id: crypto.randomUUID(),
|
||||
userId: row.follower_id,
|
||||
type: "user_dump_posted",
|
||||
data,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import type { SQLOutputValue } from "node:sqlite";
|
||||
import {
|
||||
APIErrorCode,
|
||||
APIException,
|
||||
@@ -29,7 +28,7 @@ import {
|
||||
import { makeSlug, UUID_RE } from "../lib/slugify.ts";
|
||||
|
||||
const DUMP_SELECT_COLS =
|
||||
"id, kind, title, slug, comment, user_id, created_at, url, rich_content, file_name, file_mime, file_size, vote_count, is_private";
|
||||
"id, kind, title, slug, comment, user_id, created_at, updated_at, url, rich_content, file_name, file_mime, file_size, vote_count, is_private";
|
||||
|
||||
const PLAYLIST_SELECT = `p.*, u.username as owner_username,
|
||||
(SELECT COUNT(*) FROM playlist_dumps pd WHERE pd.playlist_id = p.id) as dump_count
|
||||
@@ -340,7 +339,7 @@ export function getPlaylistMembershipsForDump(
|
||||
LEFT JOIN playlist_dumps pd ON pd.playlist_id = p.id AND pd.dump_id = ?
|
||||
WHERE p.user_id = ?
|
||||
ORDER BY p.created_at DESC;`,
|
||||
).all(dumpId, userId) as Array<Record<string, SQLOutputValue>>;
|
||||
).all(dumpId, userId);
|
||||
|
||||
return rows.map((row) => {
|
||||
if (!isPlaylistRow(row)) {
|
||||
|
||||
@@ -3,6 +3,7 @@ import type {
|
||||
Dump,
|
||||
OnlineUser,
|
||||
Playlist,
|
||||
ServerToClientMessage,
|
||||
User,
|
||||
} from "../model/interfaces.ts";
|
||||
|
||||
@@ -51,13 +52,13 @@ export function getOnlineUsers(): OnlineUser[] {
|
||||
return Array.from(seen.values());
|
||||
}
|
||||
|
||||
function send(socket: WebSocket, data: unknown): void {
|
||||
function send(socket: WebSocket, data: ServerToClientMessage): void {
|
||||
if (socket.readyState === WebSocket.OPEN) {
|
||||
socket.send(JSON.stringify(data));
|
||||
}
|
||||
}
|
||||
|
||||
export function sendToUser(userId: string, data: unknown): void {
|
||||
export function sendToUser(userId: string, data: ServerToClientMessage): void {
|
||||
for (const client of clients) {
|
||||
if (client.userId === userId) {
|
||||
send(client.socket, data);
|
||||
@@ -109,7 +110,7 @@ export function broadcastVoteUpdate(
|
||||
|
||||
function sendToPlaylistAudience(
|
||||
playlist: Pick<Playlist, "isPublic" | "userId">,
|
||||
data: unknown,
|
||||
data: ServerToClientMessage,
|
||||
): void {
|
||||
for (const client of clients) {
|
||||
if (playlist.isPublic || client.userId === playlist.userId) {
|
||||
|
||||
Reference in New Issue
Block a user