chahinebrini 19b569927a fix(presence): missing imports in 3 endpoints
Same pattern as touchLastSeen: getLastSeenBatch, setPresenceVisible,
getFollowingIds wurden im db/profile.ts implementiert aber nicht in den
Endpoints importiert. Alle 3 warfen 500 ReferenceError → grüner Dot
zeigte sich nie + Toggle silently failed.

Nitro's auto-import covered nur defineEventHandler/getQuery etc., NICHT
unsere eigenen db-layer helper.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-18 07:16:18 +02:00

64 lines
1.9 KiB
TypeScript

/**
* GET /api/presence/last-seen?userIds=uuid1,uuid2,...
*
* Batch-fetch lastSeenAt for up to 50 users.
* Auth required — callers must be logged in (prevents anonymous enumeration).
*
* Query param:
* userIds — comma-separated UUIDs (max 50)
*
* Response:
* { success: true, data: { [userId: string]: string | null } }
* Value is lastSeenAt as ISO-8601 string, or null if never seen / user not found.
*
* Privacy filters (both must pass):
* 1. Requester follows the target (UserFollow row exists).
* 2. Target has presenceVisible = true (opt-out respected).
* Targets failing either filter → null in response map.
* Frontend: null = no indicator shown.
*
* Privacy note: only lastSeenAt is exposed — no nickname, avatar, email or any
* other profile field (feedback_anonymity_nickname.md).
*/
import { requireUser } from "../../utils/auth";
import { getLastSeenBatch } from "../../db/profile";
const MAX_USER_IDS = 50;
export default defineEventHandler(async (event) => {
const user = await requireUser(event);
const query = getQuery(event);
const raw = typeof query.userIds === "string" ? query.userIds.trim() : "";
if (!raw) {
throw createError({ statusCode: 400, message: "MISSING_USER_IDS" });
}
const userIds = raw
.split(",")
.map((id) => id.trim())
.filter(Boolean);
if (userIds.length === 0) {
throw createError({ statusCode: 400, message: "MISSING_USER_IDS" });
}
if (userIds.length > MAX_USER_IDS) {
throw createError({ statusCode: 400, message: "TOO_MANY_USER_IDS" });
}
const rows = await getLastSeenBatch(user.id, userIds);
// Build map — guarantee every requested ID has an entry (null for filtered/missing)
const result: Record<string, string | null> = {};
for (const id of userIds) {
result[id] = null;
}
for (const row of rows) {
result[row.id] = row.lastSeenAt ? row.lastSeenAt.toISOString() : null;
}
return { success: true, data: result };
});