from rest_framework import views, viewsets, permissions, status from rest_framework.response import Response from rest_framework.authtoken.models import Token from django.contrib.auth import authenticate, get_user_model from django.shortcuts import get_object_or_404 from .models import RegistrationDomainRule, RegistrationRestrictionSetting, GuestClaimToken, EmailVerificationToken from .serializers import ( UserSerializer, AdminUserSerializer, RegisterSerializer, RegistrationDomainRuleSerializer, RegistrationRestrictionSettingSerializer ) from apps.events.models import ShiftSignup User = get_user_model() class AdminUserViewSet(viewsets.ModelViewSet): queryset = User.objects.all().order_by('-date_joined') serializer_class = AdminUserSerializer permission_classes = [permissions.IsAdminUser] class RegisterView(views.APIView): permission_classes = [permissions.AllowAny] def post(self, request): serializer = RegisterSerializer(data=request.data) if serializer.is_valid(): user = serializer.save() user.is_approved = False user.is_email_verified = False user.is_active = True user.save() setting = RegistrationRestrictionSetting.get_solo() claim_token_str = request.data.get('claim_token') claimed_target_name = None if claim_token_str: try: claim_obj = GuestClaimToken.objects.get(token=claim_token_str, is_claimed=False) claim_obj.is_claimed = True claim_obj.save() # Assign target signup target_signup = claim_obj.signup if target_signup and not target_signup.user: target_signup.user = user target_signup.guest_name = None target_signup.guest_session_key = None target_signup.save() claimed_target_name = claim_obj.guest_name except Exception: pass # Reassign any guest shift signups to this newly created user! session_key = request.session.session_key display_name = user.get_display_name() guest_signups = ShiftSignup.objects.filter(user=None) assigned_count = 0 for signup in guest_signups: matches_session = session_key and signup.guest_session_key == session_key matches_display = signup.guest_name and signup.guest_name.strip().lower() == display_name.strip().lower() matches_claimed_name = claimed_target_name and signup.guest_name and signup.guest_name.strip().lower() == claimed_target_name.strip().lower() if matches_session or matches_display or matches_claimed_name: signup.user = user signup.guest_name = None signup.guest_session_key = None signup.save() assigned_count += 1 v_token = EmailVerificationToken.objects.create(user=user) print("==================================================") print(f"[E-MAIL BESTÄTIGUNG]: http://localhost:3000/?verify_email={v_token.token}") print("==================================================") return Response({ 'requires_verification': True, 'verification_token': str(v_token.token), 'claimed_shifts_count': assigned_count, 'message': 'Konto erfolgreich erstellt! Bitte bestätige deine E-Mail-Adresse über den Link in der Bestätigungs-E-Mail oder warte auf die Admin-Freischaltung.' }, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class VerifyEmailView(views.APIView): permission_classes = [permissions.AllowAny] def post(self, request): token_str = request.data.get('token') if not token_str: return Response({'error': 'Token erforderlich.'}, status=status.HTTP_400_BAD_REQUEST) v_token = EmailVerificationToken.objects.filter(token=token_str, is_used=False).first() if not v_token: return Response({'error': 'Ungültiger oder bereits verwendeter Bestätigungslink.'}, status=status.HTTP_400_BAD_REQUEST) v_token.is_used = True v_token.save() user = v_token.user user.is_email_verified = True user.is_approved = True user.is_active = True user.save() token, _ = Token.objects.get_or_create(user=user) return Response({ 'token': token.key, 'user': UserSerializer(user).data, 'message': f'E-Mail-Adresse für {user.get_display_name()} wurde erfolgreich bestätigt! Du bist jetzt angemeldet.' }, status=status.HTTP_200_OK) class GenerateClaimLinkView(views.APIView): permission_classes = [permissions.IsAuthenticated] def post(self, request, signup_id): signup = get_object_or_404(ShiftSignup, pk=signup_id) if signup.user: return Response({'error': 'Diese Schicht ist bereits mit einem festen Benutzerkonto verknüpft.'}, status=status.HTTP_400_BAD_REQUEST) guest_name = signup.guest_name or "Gast" claim_obj, _ = GuestClaimToken.objects.get_or_create( signup=signup, created_by=request.user, defaults={'guest_name': guest_name} ) return Response({ 'token': str(claim_obj.token), 'guest_name': guest_name, 'event_title': signup.shift.task_area.event.title, 'shift_title': signup.shift.title, 'created_by': request.user.get_display_name() }) class ClaimInfoView(views.APIView): permission_classes = [permissions.AllowAny] def get(self, request, token_uuid): claim_obj = get_object_or_404(GuestClaimToken, token=token_uuid) return Response({ 'token': str(claim_obj.token), 'guest_name': claim_obj.guest_name, 'is_claimed': claim_obj.is_claimed, 'event_title': claim_obj.signup.shift.task_area.event.title if claim_obj.signup else 'Veranstaltung', 'shift_title': claim_obj.signup.shift.title if claim_obj.signup else 'Schicht', 'created_by': claim_obj.created_by.get_display_name() }) class LoginView(views.APIView): permission_classes = [permissions.AllowAny] def post(self, request): username = request.data.get('username') password = request.data.get('password') if not username or not password: return Response({'error': 'Benutzername und Passwort erforderlich.'}, status=status.HTTP_400_BAD_REQUEST) user_obj = None if '@' in username: try: user_obj = User.objects.get(email__iexact=username) username = user_obj.username except User.DoesNotExist: pass else: try: user_obj = User.objects.get(username__iexact=username) except User.DoesNotExist: pass if user_obj: if not (user_obj.is_approved or user_obj.is_email_verified or user_obj.is_superuser or user_obj.is_admin_user): return Response({ 'error': 'Anmeldung nicht möglich: Deine E-Mail-Adresse wurde noch nicht bestätigt und dein Konto wurde noch nicht vom Admin freigeschaltet.' }, status=status.HTTP_403_FORBIDDEN) user = authenticate(username=username, password=password) if not user: return Response({'error': 'Ungültige Anmeldedaten.'}, status=status.HTTP_401_UNAUTHORIZED) token, _ = Token.objects.get_or_create(user=user) return Response({ 'token': token.key, 'user': UserSerializer(user).data }) class MeView(views.APIView): permission_classes = [permissions.IsAuthenticated] def get(self, request): return Response(UserSerializer(request.user).data) def patch(self, request): serializer = UserSerializer(request.user, data=request.data, partial=True) if serializer.is_valid(): serializer.save() return Response(serializer.data) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class RegistrationDomainRuleViewSet(viewsets.ModelViewSet): queryset = RegistrationDomainRule.objects.all() serializer_class = RegistrationDomainRuleSerializer permission_classes = [permissions.IsAdminUser] class RegistrationRestrictionSettingView(views.APIView): def get_permissions(self): if self.request.method == 'GET': return [permissions.AllowAny()] return [permissions.IsAdminUser()] def get(self, request): setting = RegistrationRestrictionSetting.get_solo() active_domains = list(RegistrationDomainRule.objects.filter(is_active=True).values_list('domain', flat=True)) return Response({ 'is_restriction_enabled': setting.is_restriction_enabled, 'require_admin_approval': setting.require_admin_approval, 'active_domains': active_domains }) def post(self, request): setting = RegistrationRestrictionSetting.get_solo() if 'is_restriction_enabled' in request.data: setting.is_restriction_enabled = request.data['is_restriction_enabled'] if 'require_admin_approval' in request.data: setting.require_admin_approval = request.data['require_admin_approval'] setting.save() return Response({ 'is_restriction_enabled': setting.is_restriction_enabled, 'require_admin_approval': setting.require_admin_approval }) class PendingUsersView(views.APIView): permission_classes = [permissions.IsAdminUser] def get(self, request): pending_users = User.objects.filter(is_approved=False, is_email_verified=False, is_superuser=False).order_by('-date_joined') return Response(UserSerializer(pending_users, many=True).data) class ApproveUserView(views.APIView): permission_classes = [permissions.IsAdminUser] def post(self, request, user_id): user = get_object_or_404(User, pk=user_id) user.is_approved = True user.is_active = True user.save() return Response({'message': f'Nutzer {user.get_display_name()} wurde erfolgreich freigeschaltet.'}) def delete(self, request, user_id): user = get_object_or_404(User, pk=user_id) name = user.get_display_name() user.delete() return Response({'message': f'Registrierung von {name} wurde abgelehnt und gelöscht.'})