v3: fixed roles propagation bug, fixed inconsistent file drop zone, fixed chat attachments wrongfully pruned, some visual tweaks
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 41s

This commit is contained in:
2026-06-30 13:41:36 +02:00
parent d2d086831e
commit 7773a8a501
12 changed files with 317 additions and 237 deletions

View File

@@ -46,13 +46,17 @@ export async function authMiddleware<R extends string>(
throw new APIException(APIErrorCode.UNAUTHORIZED, 401, "Invalid token");
}
let user;
try {
getUserById(payload.userId);
user = getUserById(payload.userId);
} catch {
throw new APIException(APIErrorCode.UNAUTHORIZED, 401, "User not found");
}
ctx.state.user = payload;
// Trust the live role from the DB, not the role baked into the JWT at login.
// Tokens last 7 days, so a role change (e.g. promotion to admin or a demotion)
// would otherwise not take effect until the user re-logs in.
ctx.state.user = { ...payload, role: user.role };
await next();
}

View File

@@ -64,16 +64,16 @@ router.get("/ws", async (ctx) => {
const socket = ctx.upgrade();
const avatarMime = authPayload
? getUserById(authPayload.userId).avatarMime
: undefined;
// Read the live user so the role reflects the DB, not the (possibly stale)
// role embedded in the 7-day JWT.
const user = authPayload ? getUserById(authPayload.userId) : undefined;
const client: WsClient = {
socket,
userId: authPayload?.userId,
username: authPayload?.username,
role: authPayload?.role,
avatarMime,
role: user?.role,
avatarMime: user?.avatarMime,
};
// Use addEventListener — more reliable than onopen= with Deno.serve

View File

@@ -4,6 +4,7 @@ import {
type ChatMessage,
} from "../model/interfaces.ts";
import { chatMessageRowToApi, db, isChatMessageRow } from "../model/db.ts";
import { linkAttachments } from "./attachment-service.ts";
export const MAX_CHAT_LENGTH = 2000;
const DEFAULT_LIMIT = 50;
@@ -70,6 +71,9 @@ export function createChatMessage(
db.prepare(
`INSERT INTO chat_messages (id, user_id, body, created_at, reply_to_id) VALUES (?, ?, ?, ?, ?);`,
).run(id, userId, trimmed, createdAt, replyTo);
// Claim any pasted/dropped image attachments so the startup cleanup doesn't
// purge them as orphans (mirrors dumps/comments/playlists).
linkAttachments(trimmed, id);
return fetchMessage(id);
}
@@ -115,6 +119,8 @@ export function updateChatMessage(
}
db.prepare(`UPDATE chat_messages SET body = ?, updated_at = ? WHERE id = ?;`)
.run(trimmed, new Date().toISOString(), id);
// An edit may introduce a freshly pasted image; claim its attachment too.
linkAttachments(trimmed, id);
return fetchMessage(id);
}