""" Authentication URL Configuration """ from django.urls import path, include from django.views.decorators.csrf import csrf_exempt from rest_framework.routers import DefaultRouter from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import status, permissions from .views import ( GroupsViewSet, UsersViewSet, AccountsViewSet, SubscriptionsViewSet, SiteUserAccessViewSet, PlanViewSet, SiteViewSet, SectorViewSet, IndustryViewSet, SeedKeywordViewSet, AuthViewSet ) from .serializers import RegisterSerializer, LoginSerializer, ChangePasswordSerializer, UserSerializer from .models import User router = DefaultRouter() # Main structure: Groups, Users, Accounts, Subscriptions, Site User Access router.register(r'groups', GroupsViewSet, basename='group') router.register(r'users', UsersViewSet, basename='user') router.register(r'accounts', AccountsViewSet, basename='account') router.register(r'subscriptions', SubscriptionsViewSet, basename='subscription') router.register(r'site-access', SiteUserAccessViewSet, basename='site-access') # Supporting viewsets router.register(r'plans', PlanViewSet, basename='plan') router.register(r'sites', SiteViewSet, basename='site') router.register(r'sectors', SectorViewSet, basename='sector') router.register(r'industries', IndustryViewSet, basename='industry') router.register(r'seed-keywords', SeedKeywordViewSet, basename='seed-keyword') router.register(r'auth', AuthViewSet, basename='auth') class RegisterView(APIView): """Registration endpoint.""" permission_classes = [permissions.AllowAny] def post(self, request): serializer = RegisterSerializer(data=request.data) if serializer.is_valid(): user = serializer.save() user_serializer = UserSerializer(user) return Response({ 'success': True, 'message': 'Registration successful', 'user': user_serializer.data }, status=status.HTTP_201_CREATED) return Response({ 'success': False, 'errors': serializer.errors }, status=status.HTTP_400_BAD_REQUEST) class LoginView(APIView): """Login endpoint.""" permission_classes = [permissions.AllowAny] def post(self, request): serializer = LoginSerializer(data=request.data) if serializer.is_valid(): email = serializer.validated_data['email'] password = serializer.validated_data['password'] try: user = User.objects.get(email=email) except User.DoesNotExist: return Response({ 'success': False, 'message': 'Invalid credentials' }, status=status.HTTP_401_UNAUTHORIZED) if user.check_password(password): # Log the user in (create session for session authentication) from django.contrib.auth import login login(request, user) # Get account from user account = getattr(user, 'account', None) # Generate JWT tokens from .utils import generate_access_token, generate_refresh_token, get_token_expiry access_token = generate_access_token(user, account) refresh_token = generate_refresh_token(user, account) access_expires_at = get_token_expiry('access') refresh_expires_at = get_token_expiry('refresh') # Serialize user data safely, handling missing account relationship try: user_serializer = UserSerializer(user) user_data = user_serializer.data except Exception as e: # Fallback if serializer fails (e.g., missing account_id column) user_data = { 'id': user.id, 'username': user.username, 'email': user.email, 'role': user.role, 'account': None, 'accessible_sites': [], } return Response({ 'success': True, 'message': 'Login successful', 'user': user_data, 'tokens': { 'access': access_token, 'refresh': refresh_token, 'access_expires_at': access_expires_at.isoformat(), 'refresh_expires_at': refresh_expires_at.isoformat(), } }) return Response({ 'success': False, 'message': 'Invalid credentials' }, status=status.HTTP_401_UNAUTHORIZED) return Response({ 'success': False, 'errors': serializer.errors }, status=status.HTTP_400_BAD_REQUEST) class ChangePasswordView(APIView): """Change password endpoint.""" permission_classes = [permissions.IsAuthenticated] def post(self, request): serializer = ChangePasswordSerializer(data=request.data, context={'request': request}) if serializer.is_valid(): user = request.user if not user.check_password(serializer.validated_data['old_password']): return Response({ 'success': False, 'message': 'Current password is incorrect' }, status=status.HTTP_400_BAD_REQUEST) user.set_password(serializer.validated_data['new_password']) user.save() return Response({ 'success': True, 'message': 'Password changed successfully' }) return Response({ 'success': False, 'errors': serializer.errors }, status=status.HTTP_400_BAD_REQUEST) class MeView(APIView): """Get current user information.""" permission_classes = [permissions.IsAuthenticated] def get(self, request): # Refresh user from DB to get latest account/plan data # This ensures account/plan changes are reflected immediately from .models import User as UserModel user = UserModel.objects.select_related('account', 'account__plan').get(id=request.user.id) serializer = UserSerializer(user) return Response({ 'success': True, 'user': serializer.data }) urlpatterns = [ path('', include(router.urls)), path('register/', csrf_exempt(RegisterView.as_view()), name='auth-register'), path('login/', csrf_exempt(LoginView.as_view()), name='auth-login'), path('change-password/', ChangePasswordView.as_view(), name='auth-change-password'), path('me/', MeView.as_view(), name='auth-me'), ]