import { readFile } from 'fs/promises' import { getServerDataPath } from '../../utils/paths.js' import { getUserFromToken, verifyToken, readUsers, isHiddenUser, normalizeUserEmail } from '../../utils/auth.js' import { readMembers } from '../../utils/members.js' const QTTR_FILE = getServerDataPath('qttr-values.json') function normalizeName(value) { return String(value || '') .trim() .toLowerCase() .normalize('NFKD') .replace(/[\u0300-\u036f]/g, '') .replace(/\s+/g, ' ') .replace(/[’'`]/g, '') } function buildBirthdateLookup(entries) { const lookup = new Map() for (const entry of entries || []) { const candidates = [ entry?.name, `${entry?.firstName || ''} ${entry?.lastName || ''}`.trim(), ] const birthdate = entry?.geburtsdatum || entry?.birthday || entry?.birthDate || '' if (!birthdate) continue for (const candidate of candidates) { const normalized = normalizeName(candidate) if (!normalized || lookup.has(normalized)) continue lookup.set(normalized, birthdate) } } return lookup } function addClubRanks(rows) { const addRankFor = (valueKey, rankKey) => { rows .filter((row) => row[valueKey] != null) .sort((a, b) => b[valueKey] - a[valueKey] || String(a.playerName || '').localeCompare(String(b.playerName || ''), 'de')) .forEach((row, index) => { row[rankKey] = index + 1 }) } addRankFor('currentQttr', 'clubQttrRank') addRankFor('currentTtr', 'clubTtrRank') return rows.sort((a, b) => (a.clubQttrRank ?? Number.POSITIVE_INFINITY) - (b.clubQttrRank ?? Number.POSITIVE_INFINITY) || (a.clubTtrRank ?? Number.POSITIVE_INFINITY) - (b.clubTtrRank ?? Number.POSITIVE_INFINITY) || String(a.playerName || '').localeCompare(String(b.playerName || ''), 'de') ) } export default defineEventHandler(async (event) => { const token = getCookie(event, 'auth_token') || getHeader(event, 'authorization')?.replace(/^Bearer\s+/i, '') if (!token || !verifyToken(token)) { throw createError({ statusCode: 401, message: 'Nicht authentifiziert.' }) } const currentUser = await getUserFromToken(token) if (!currentUser) { throw createError({ statusCode: 401, message: 'Ungültiges Token.' }) } try { const content = await readFile(QTTR_FILE, 'utf8') const payload = JSON.parse(content) const [manualMembers, registeredUsers] = await Promise.all([ readMembers(), readUsers() ]) const hiddenUserEmails = new Set(registeredUsers.filter(isHiddenUser).map(user => normalizeUserEmail(user.email)).filter(Boolean)) const visibleManualMembers = manualMembers.filter(member => { const email = normalizeUserEmail(member.email) return member.hidden !== true && member.invisible !== true && member.isHidden !== true && !hiddenUserEmails.has(email) }) const visibleUsers = registeredUsers.filter(user => !isHiddenUser(user)) const hiddenNames = new Set([ ...manualMembers.filter(member => member.hidden === true || member.invisible === true || member.isHidden === true || hiddenUserEmails.has(normalizeUserEmail(member.email))), ...registeredUsers.filter(isHiddenUser) ].flatMap(entry => [entry?.name, `${entry?.firstName || ''} ${entry?.lastName || ''}`.trim()]).map(normalizeName).filter(Boolean)) const birthdateLookup = buildBirthdateLookup([...visibleManualMembers, ...visibleUsers]) const rankedRows = addClubRanks(Array.isArray(payload.rows) ? payload.rows.map(row => ({ ...row })) : []) return { ...payload, rows: rankedRows .filter(row => !hiddenNames.has(normalizeName(row.playerName))) .map((row) => ({ ...row, birthdate: birthdateLookup.get(normalizeName(row.playerName)) || row.birthdate || '' })) } } catch (error) { if (error?.code === 'ENOENT') { throw createError({ statusCode: 404, message: 'QTTR-Datei nicht gefunden.' }) } console.error('Fehler beim Laden der QTTR-Werte:', error) throw createError({ statusCode: 500, message: 'Fehler beim Laden der QTTR-Werte.' }) } })