diff --git a/scripts/check-visibility.js b/scripts/check-visibility.js new file mode 100644 index 0000000..3a4c459 --- /dev/null +++ b/scripts/check-visibility.js @@ -0,0 +1,80 @@ +#!/usr/bin/env node +(async () => { + try { + const { readMembers } = await import('../server/utils/members.js') + const auth = await import('../server/utils/auth.js') + const { readUsers } = auth + + const manual = await readMembers() + const users = await readUsers() + + // Build simple merged list similar to members.get + const merged = [] + + // Add manual members + for (const m of manual) { + const fullName = `${m.firstName || ''} ${m.lastName || ''}`.trim() + const vis = m.visibility || {} + const visibility = { + showEmail: vis.showEmail === undefined ? false : Boolean(vis.showEmail), + showPhone: vis.showPhone === undefined ? false : Boolean(vis.showPhone), + showAddress: vis.showAddress === undefined ? false : Boolean(vis.showAddress) + } + merged.push({ + id: m.id || null, + name: fullName || m.name || '(kein name)', + email: m.email || '', + phone: m.phone || '', + address: m.address || '', + source: 'manual', + visibility, + raw: m + }) + } + + // Add registered users (default visibility: false unless stored) + for (const u of users) { + if (!u.active) continue + const visibility = u.visibility || { showEmail: false, showPhone: false, showAddress: false } + merged.push({ + id: u.id, + name: u.name, + email: u.email || '', + phone: u.phone || '', + address: u.address || '', + source: 'login', + visibility, + raw: u + }) + } + + merged.sort((a, b) => a.name.localeCompare(b.name)) + + const viewers = [ + { label: 'unauthenticated', isPrivileged: false }, + { label: 'admin', isPrivileged: false }, + { label: 'vorstand', isPrivileged: true } + ] + + for (const v of viewers) { + console.log('\n=== Viewer:', v.label, ' (vorstand override:', v.isPrivileged, ') ===') + for (const m of merged) { + const hadEmail = !!m.email + const hadPhone = !!m.phone + const showEmail = v.isPrivileged || Boolean(m.visibility.showEmail) + const showPhone = v.isPrivileged || Boolean(m.visibility.showPhone) + const contactHidden = (!showEmail && hadEmail) || (!showPhone && hadPhone) + console.log(`- ${m.name}`) + console.log(` source: ${m.source} roles?: ${m.raw.roles || m.raw.role || ''}`) + console.log(` email: ${hadEmail ? (showEmail ? m.email : '') : '-'}`) + console.log(` phone: ${hadPhone ? (showPhone ? m.phone : '') : '-'}`) + if (contactHidden) console.log(' -> contactHidden = true') + } + } + + process.exit(0) + } catch (e) { + console.error('ERROR', e) + process.exit(2) + } +})() diff --git a/scripts/set-visibility.js b/scripts/set-visibility.js new file mode 100644 index 0000000..0d97748 --- /dev/null +++ b/scripts/set-visibility.js @@ -0,0 +1,69 @@ +#!/usr/bin/env node +import arg from 'arg' + +async function main() { + const args = arg({ + '--email': String, + '--showEmail': Boolean, + '--showPhone': Boolean, + '--showAddress': Boolean, + '--target': String // 'members'|'users'|'both' + }) + + const email = args['--email'] + if (!email) { + console.error('Usage: node scripts/set-visibility.js --email [--showEmail] [--showPhone] [--showAddress] [--target both|members|users]') + process.exit(2) + } + + const showEmail = '--showEmail' in args ? Boolean(args['--showEmail']) : undefined + const showPhone = '--showPhone' in args ? Boolean(args['--showPhone']) : undefined + const showAddress = '--showAddress' in args ? Boolean(args['--showAddress']) : undefined + const target = args['--target'] || 'both' + + const membersUtils = await import('../server/utils/members.js') + const authUtils = await import('../server/utils/auth.js') + + if (target === 'both' || target === 'members') { + const members = await membersUtils.readMembers() + let changed = false + for (const m of members) { + if ((m.email || '').toLowerCase() === email.toLowerCase()) { + m.visibility = m.visibility || {} + if (showEmail !== undefined) m.visibility.showEmail = showEmail + if (showPhone !== undefined) m.visibility.showPhone = showPhone + if (showAddress !== undefined) m.visibility.showAddress = showAddress + changed = true + console.log('Updated manual member visibility for', email) + } + } + if (changed) { + await membersUtils.writeMembers(members) + console.log('Wrote members.json') + } + } + + if (target === 'both' || target === 'users') { + const users = await authUtils.readUsers() + let changed = false + for (const u of users) { + if ((u.email || '').toLowerCase() === email.toLowerCase()) { + u.visibility = u.visibility || {} + if (showEmail !== undefined) u.visibility.showEmail = showEmail + if (showPhone !== undefined) u.visibility.showPhone = showPhone + if (showAddress !== undefined) u.visibility.showAddress = showAddress + changed = true + console.log('Updated user visibility for', email) + } + } + if (changed) { + await authUtils.writeUsers(users) + console.log('Wrote users.json') + } + } +} + +main().catch(e => { + console.error(e) + process.exit(1) +}) diff --git a/server/api/members.get.js b/server/api/members.get.js index 1fbf6c6..916ac17 100644 --- a/server/api/members.get.js +++ b/server/api/members.get.js @@ -131,11 +131,22 @@ export default defineEventHandler(async (event) => { lastLogin: user.lastLogin, isMannschaftsspieler: user.isMannschaftsspieler === true || mergedMembers[matchedManualIndex].isMannschaftsspieler === true } + // If the registered user has visibility preferences, apply them (coerce to booleans) + if (user.visibility && typeof user.visibility === 'object') { + const vis = mergedMembers[matchedManualIndex].visibility || {} + mergedMembers[matchedManualIndex].visibility = { + showEmail: user.visibility.showEmail === undefined ? Boolean(vis.showEmail) : Boolean(user.visibility.showEmail), + showPhone: user.visibility.showPhone === undefined ? Boolean(vis.showPhone) : Boolean(user.visibility.showPhone), + showAddress: user.visibility.showAddress === undefined ? Boolean(vis.showAddress) : Boolean(user.visibility.showAddress) + } + } } else { // Add as new member (from login system) const migratedUser = migrateUserRoles({ ...user }) const roles = Array.isArray(migratedUser.roles) ? migratedUser.roles : (migratedUser.role ? [migratedUser.role] : ['mitglied']) // Registered-only user: default to privacy-preserving visibility (hidden) unless user explicitly set visibility elsewhere + // Use stored visibility from user if present, otherwise default to false + const userVis = user.visibility || {} mergedMembers.push({ id: user.id, name: user.name, @@ -143,9 +154,9 @@ export default defineEventHandler(async (event) => { phone: user.phone || '', address: '', visibility: { - showEmail: false, - showPhone: false, - showAddress: false + showEmail: userVis.showEmail === undefined ? false : Boolean(userVis.showEmail), + showPhone: userVis.showPhone === undefined ? false : Boolean(userVis.showPhone), + showAddress: userVis.showAddress === undefined ? false : Boolean(userVis.showAddress) }, notes: `Rolle(n): ${roles.join(', ')}`, source: 'login',