from django.shortcuts import render from rest_framework import status, views from rest_framework.response import Response from rest_framework.permissions import AllowAny from django.contrib.auth.models import User from rest_framework_simplejwt.tokens import RefreshToken from companies.models import RecruiterProfile, RecruiterToken from .serializers import RecruiterLoginSerializer, RecruiterProfileSetupSerializer def get_tokens_for_user(user): refresh = RefreshToken.for_user(user) return { 'refresh': str(refresh), 'access': str(refresh.access_token), } class RecruiterLoginView(views.APIView): permission_classes = [AllowAny] def post(self, request): print(f"[DEBUG] RECRUITER LOGIN POST REQUEST DATA: {request.data}") serializer = RecruiterLoginSerializer(data=request.data) if serializer.is_valid(): if serializer.validated_data.get('setup_required', False): rec_token = serializer.validated_data['recruiter_token'] return Response({ 'setup_required': True, 'message': 'Token verified. Profile setup is required.', 'email': rec_token.email }, status=status.HTTP_200_OK) user = serializer.validated_data['user'] rec_token = serializer.validated_data['recruiter_token'] profile = RecruiterProfile.objects.filter(company=rec_token.company, user=user).first() if not profile: rec_token.is_used = False rec_token.save() return Response({ 'setup_required': True, 'message': 'Profile setup not found. Setup is required.', 'email': rec_token.email }, status=status.HTTP_200_OK) tokens = get_tokens_for_user(user) from django.contrib.auth.models import update_last_login update_last_login(None, user) return Response({ 'setup_required': False, 'tokens': tokens, 'user': { 'email': profile.user.email, 'full_name': profile.full_name, 'role': 'recruiter', 'job_title': profile.job_title, 'company_name': rec_token.company.name, 'photo_url': profile.photo_url, 'passing_ats_score': profile.passing_ats_score } }, status=status.HTTP_200_OK) print(f"[DEBUG] RECRUITER LOGIN SERIALIZER ERRORS: {serializer.errors}") return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class RecruiterProfileSetupView(views.APIView): permission_classes = [AllowAny] def post(self, request): serializer = RecruiterProfileSetupSerializer(data=request.data) if serializer.is_valid(): data = serializer.validated_data rec_token = data['recruiter_token'] # Create standard password Django user using custom password username = f"recruiter_{rec_token.id}_{User.objects.count() + 1}" user = User.objects.create_user( username=username, email=rec_token.email, password=data['password'] ) # Split full name for first/last name fields name_parts = data['full_name'].split(' ', 1) user.first_name = name_parts[0] if len(name_parts) > 1: user.last_name = name_parts[1] user.save() # Create recruiter profile profile = RecruiterProfile.objects.create( company=rec_token.company, user=user, full_name=data['full_name'], job_title=data['job_title'], department=data['department'], phone_number=data['phone_number'], linkedin_url=data.get('linkedin_url'), specialization_areas=data.get('specialization_areas', []), years_of_experience=data['years_of_experience'], bio=data.get('bio'), preferred_timezone=data['preferred_timezone'], notification_preferences=data.get('notification_preferences', {}), photo_url=data.get('photo_url'), passing_ats_score=data.get('passing_ats_score', 70) ) # Consume the token rec_token.is_used = True rec_token.save() tokens = get_tokens_for_user(user) from django.contrib.auth.models import update_last_login update_last_login(None, user) return Response({ 'tokens': tokens, 'user': { 'email': user.email, 'full_name': profile.full_name, 'role': 'recruiter', 'job_title': profile.job_title, 'company_name': rec_token.company.name, 'photo_url': profile.photo_url, 'passing_ats_score': profile.passing_ats_score } }, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) from .models import TestCredential class TestCredentialsListView(views.APIView): permission_classes = [AllowAny] def get(self, request): credentials = TestCredential.objects.all() # Diagnostic check import os env_supabase_url = os.environ.get('SUPABASE_URL', '') env_supabase_secret = os.environ.get('SUPABASE_JWT_SECRET', '') diagnostic = { "settings_supabase_url": settings.SUPABASE_URL, "settings_supabase_secret_len": len(settings.SUPABASE_JWT_SECRET) if hasattr(settings, 'SUPABASE_JWT_SECRET') else 0, "settings_supabase_secret_matches_default": (settings.SUPABASE_JWT_SECRET == 'kcwYMVIO/tp2KTwydJqHc7XnsnvIoYBGVe3LGvl7BAEVIZi25FmsFo70uaRRjmxwBIRYJl5qGX1nJYSJwD5Thw==') if hasattr(settings, 'SUPABASE_JWT_SECRET') else False, "env_supabase_url": env_supabase_url, "env_supabase_secret_len": len(env_supabase_secret) if env_supabase_secret else 0, "env_supabase_secret_value_start": env_supabase_secret[:10] if env_supabase_secret else None, } data = { "credentials": [ { "role": cred.role, "label": cred.label, "email": cred.email, "password": cred.password } for cred in credentials ], "diagnostic": diagnostic } return Response(data, status=status.HTTP_200_OK) import jwt import requests import uuid import os import time from django.conf import settings from rest_framework.permissions import IsAuthenticated from companies.models import CompanyAdminProfile class PublicFileUploadView(views.APIView): permission_classes = [AllowAny] def post(self, request): uploaded_file = request.FILES.get('file') if not uploaded_file: return Response({"error": "No file uploaded."}, status=status.HTTP_400_BAD_REQUEST) bucket_name = request.data.get('bucket', 'avatars') # Generate random unique filename ext = os.path.splitext(uploaded_file.name)[1] file_name = f"{uuid.uuid4()}{ext}" try: jwt_secret = settings.SUPABASE_JWT_SECRET decoded_secret = jwt_secret.encode('utf-8') if isinstance(jwt_secret, str) else jwt_secret payload = { "role": "service_role", "iss": "supabase", "iat": int(time.time()), "exp": int(time.time() + 3600) } token = jwt.encode(payload, decoded_secret, algorithm="HS256") if isinstance(token, bytes): token = token.decode('utf-8') # 1. Ensure the bucket exists or create it headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json" } bucket_check_url = f"{settings.SUPABASE_URL}/storage/v1/bucket/{bucket_name}" check_res = requests.get(bucket_check_url, headers=headers) if check_res.status_code != 200: create_bucket_url = f"{settings.SUPABASE_URL}/storage/v1/bucket" body = {"id": bucket_name, "name": bucket_name, "public": True} requests.post(create_bucket_url, headers=headers, json=body) # 2. Upload file upload_headers = { "Authorization": f"Bearer {token}", } upload_url = f"{settings.SUPABASE_URL}/storage/v1/object/{bucket_name}/{file_name}" file_data = uploaded_file.read() content_type = uploaded_file.content_type or "application/octet-stream" upload_headers["Content-Type"] = content_type res = requests.post(upload_url, headers=upload_headers, data=file_data) if res.status_code == 200: public_url = f"{settings.SUPABASE_URL}/storage/v1/object/public/{bucket_name}/{file_name}" return Response({"url": public_url}, status=status.HTTP_200_OK) else: return Response({ "error": "Failed to upload file to storage.", "details": res.text, "status_code": res.status_code }, status=status.HTTP_500_INTERNAL_SERVER_ERROR) except Exception as e: return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) class UpdateProfileView(views.APIView): permission_classes = [IsAuthenticated] def patch(self, request): admin_profile = CompanyAdminProfile.objects.filter(user=request.user).first() if admin_profile: photo_url = request.data.get('photo_url') if photo_url is not None: admin_profile.photo_url = photo_url admin_profile.save() return Response({ "message": "Admin profile updated successfully.", "user": { "email": request.user.email, "full_name": request.user.first_name + " " + request.user.last_name, "role": "admin", "photo_url": admin_profile.photo_url } }, status=status.HTTP_200_OK) recruiter_profile = RecruiterProfile.objects.filter(user=request.user).first() if recruiter_profile: photo_url = request.data.get('photo_url') passing_ats_score = request.data.get('passing_ats_score') full_name = request.data.get('full_name') job_title = request.data.get('job_title') if photo_url is not None: recruiter_profile.photo_url = photo_url if passing_ats_score is not None: recruiter_profile.passing_ats_score = int(passing_ats_score) if full_name is not None: recruiter_profile.full_name = full_name if job_title is not None: recruiter_profile.job_title = job_title recruiter_profile.save() return Response({ "message": "Recruiter profile updated successfully.", "user": { "email": recruiter_profile.user.email, "full_name": recruiter_profile.full_name, "role": "recruiter", "job_title": recruiter_profile.job_title, "company_name": recruiter_profile.company.name, "photo_url": recruiter_profile.photo_url, "passing_ats_score": recruiter_profile.passing_ats_score } }, status=status.HTTP_200_OK) return Response({"error": "Profile not found."}, status=status.HTTP_404_NOT_FOUND)