import { getSession } from './auth-simple'; import { prisma } from './prisma'; export type UserRole = 'player' | 'tournament_admin' | 'club_admin' | 'site_admin'; export interface PermissionCheck { allowed: boolean; reason?: string; } /** * Check if the current user has the required role * Reads role from database to avoid session cache issues */ export async function hasRole(requiredRole: UserRole): Promise { const session = await getSession(); if (!session) { return { allowed: false, reason: 'Not authenticated' }; } const userId = session.user?.id; if (!userId) { return { allowed: false, reason: 'User ID not found in session' }; } // Fetch user from database to get current role (bypasses session cache) const user = await prisma.user.findUnique({ where: { id: userId }, select: { role: true } }); if (!user) { return { allowed: false, reason: 'User not found in database' }; } const userRole = user.role as UserRole; // Role hierarchy: player < tournament_admin < club_admin < site_admin const roleHierarchy: Record = { 'player': 1, 'tournament_admin': 2, 'club_admin': 3, 'site_admin': 4 }; const hasRequiredRole = roleHierarchy[userRole] >= roleHierarchy[requiredRole]; return { allowed: hasRequiredRole, reason: hasRequiredRole ? undefined : `Requires ${requiredRole} role, but user has ${userRole}` }; } /** * Check if the user owns the tournament (for tournament_admin) */ export async function ownsTournament(tournamentId: number): Promise { const session = await getSession(); if (!session) { return { allowed: false, reason: 'Not authenticated' }; } const userId = session.user?.id; if (!userId) { return { allowed: false, reason: 'User ID not found in session' }; } const tournament = await prisma.event.findUnique({ where: { id: tournamentId }, select: { ownerId: true } }); if (!tournament) { return { allowed: false, reason: 'Tournament not found' }; } const isOwner = tournament.ownerId === userId; return { allowed: isOwner, reason: isOwner ? undefined : 'User does not own this tournament' }; } /** * Check if the user can manage a specific tournament * Tournament admins can only manage their own tournaments * Club admins can manage all tournaments * Reads role from database to avoid session cache issues */ export async function canManageTournament(tournamentId: number): Promise { const session = await getSession(); if (!session) { return { allowed: false, reason: 'Not authenticated' }; } const userId = session.user?.id; if (!userId) { return { allowed: false, reason: 'User ID not found in session' }; } // Fetch user from database to get current role (bypasses session cache) const user = await prisma.user.findUnique({ where: { id: userId }, select: { role: true } }); if (!user) { return { allowed: false, reason: 'User not found in database' }; } const userRole = user.role as UserRole; // Club admins can manage all tournaments if (userRole === 'club_admin') { return { allowed: true }; } // Tournament admins can only manage their own tournaments if (userRole === 'tournament_admin') { return ownsTournament(tournamentId); } return { allowed: false, reason: 'Insufficient permissions to manage tournament' }; } /** * Check if the user can create tournaments */ export async function canCreateTournaments(): Promise { return hasRole('tournament_admin'); } /** * Check if the user can manage a specific match * Tournament admins can manage matches in their own tournaments * Club admins can manage all matches */ export async function canManageMatch(matchId: number): Promise { const session = await getSession(); if (!session) { return { allowed: false, reason: 'Not authenticated' }; } const userRole = session.user?.role as UserRole; // Club admins can manage all matches if (userRole === 'club_admin') { return { allowed: true }; } // Tournament admins can only manage matches in their own tournaments if (userRole === 'tournament_admin') { const match = await prisma.match.findUnique({ where: { id: matchId }, include: { event: true } }); if (!match || !match.event) { return { allowed: false, reason: 'Match or tournament not found' }; } return ownsTournament(match.event.id); } return { allowed: false, reason: 'Insufficient permissions to manage match' }; } /** * Check if the user can assign tournament_admin privileges * Only club admins can assign tournament_admin role */ export async function canAssignTournamentAdmin(): Promise { return hasRole('club_admin'); } /** * Get tournaments that the current user can manage */ export async function getManageableTournaments() { const session = await getSession(); if (!session) { return []; } const userRole = session.user?.role as UserRole; const userId = session.user?.id; if (userRole === 'club_admin') { // Club admins can see all tournaments return prisma.event.findMany({ where: { eventType: 'tournament' }, include: { participants: true }, orderBy: { createdAt: 'desc' } }); } if (userRole === 'tournament_admin') { // Tournament admins can only see their own tournaments return prisma.event.findMany({ where: { eventType: 'tournament', ownerId: userId }, include: { participants: true }, orderBy: { createdAt: 'desc' } }); } // Regular players can only view tournaments (not manage them) return prisma.event.findMany({ where: { eventType: 'tournament', status: { not: 'draft' } }, include: { participants: true }, orderBy: { createdAt: 'desc' } }); } /** * Check if the user can edit user profiles (only club_admin) */ export async function canEditUserProfiles(): Promise { return hasRole('club_admin'); } /** * Check if the user can recalculate ELO ratings (only club_admin) */ export async function canRecalculateElo(): Promise { return hasRole('club_admin'); } /** * Check if the user can delete tournaments * Site admins can delete all tournaments * Club admins can delete tournaments they can manage * Tournament admins can only delete their own tournaments */ export async function canDeleteTournament(tournamentId: number): Promise { const session = await getSession(); if (!session) { return { allowed: false, reason: 'Not authenticated' }; } const userId = session.user?.id; if (!userId) { return { allowed: false, reason: 'User ID not found in session' }; } // Fetch user from database to get current role const user = await prisma.user.findUnique({ where: { id: userId }, select: { role: true } }); if (!user) { return { allowed: false, reason: 'User not found in database' }; } const userRole = user.role as UserRole; // Site admins can delete any tournament if (userRole === 'site_admin') { return { allowed: true }; } // Club admins can delete tournaments they can manage if (userRole === 'club_admin') { return { allowed: true }; } // Tournament admins can only delete their own tournaments if (userRole === 'tournament_admin') { const tournament = await prisma.event.findUnique({ where: { id: tournamentId }, select: { ownerId: true } }); if (!tournament) { return { allowed: false, reason: 'Tournament not found' }; } if (tournament.ownerId === userId) { return { allowed: true }; } return { allowed: false, reason: 'Tournament admin can only delete their own tournaments' }; } return { allowed: false, reason: 'Players cannot delete tournaments' }; }