Spaces:
Sleeping
Sleeping
| from django.db import transaction | |
| from django.db.models import Q | |
| from rest_framework.decorators import api_view | |
| from rest_framework.response import Response | |
| from .models import Participant, Match | |
| # --- LOGIC HELPER --- | |
| def calculate_similarity(p1_data, p2_data): | |
| base_score = 30.0 | |
| total_questions = 15 | |
| matches_found = 0 | |
| points_per_match = 70.0 / total_questions | |
| for i in range(1, total_questions + 1): | |
| key = f'q{i}' | |
| val1 = p1_data.get(key) | |
| val2 = p2_data.get(key) | |
| if val1 and val2 and val1 == val2: | |
| matches_found += 1 | |
| final_score = base_score + (matches_found * points_per_match) | |
| return min(round(final_score, 1), 100.0) | |
| def run_matching_logic(): | |
| matches_created = [] | |
| with transaction.atomic(): | |
| unmatched_pool = list( | |
| Participant.objects.select_for_update() | |
| .filter(is_matched=False) | |
| .order_by('created_at') | |
| ) | |
| while len(unmatched_pool) >= 2: | |
| person_a = unmatched_pool.pop(0) | |
| best_partner = None | |
| best_score = -1 | |
| best_partner_index = -1 | |
| for i, candidate in enumerate(unmatched_pool): | |
| score = calculate_similarity(person_a.quiz_data, candidate.quiz_data) | |
| if score > best_score: | |
| best_score = score | |
| best_partner = candidate | |
| best_partner_index = i | |
| if best_partner: | |
| if person_a.is_matched or best_partner.is_matched: continue | |
| Match.objects.create( | |
| participant_1=person_a, participant_2=best_partner, compatibility_score=best_score | |
| ) | |
| person_a.is_matched = True | |
| best_partner.is_matched = True | |
| person_a.save() | |
| best_partner.save() | |
| unmatched_pool.pop(best_partner_index) | |
| matches_created.append(f"{person_a.name} & {best_partner.name} ({best_score}%)") | |
| return matches_created | |
| # --- ENDPOINTS --- | |
| def verify_user(request): | |
| email_input = request.data.get('email', '').strip().lower() | |
| # ONLY CHECK: IS THE USER ALREADY REGISTERED? | |
| if Participant.objects.filter(email__iexact=email_input).exists(): | |
| return Response({ | |
| 'success': True, | |
| 'status': 'registered', | |
| 'message': 'User already registered.' | |
| }) | |
| # If not registered, they are allowed to proceed | |
| return Response({'success': True, 'status': 'new', 'message': 'Verified'}) | |
| def register_participant(request): | |
| data = request.data | |
| email = data.get('email', '').strip().lower() | |
| # Prevent double registration | |
| if Participant.objects.filter(email__iexact=email).exists(): | |
| return Response({'success': False, 'message': 'Already registered.'}, status=400) | |
| participant = Participant.objects.create( | |
| name=data.get('name'), | |
| email=email, | |
| student_id=data.get('student_id'), | |
| role=data.get('role', 'fullstack'), | |
| quiz_data={k: v for k, v in data.items() if k.startswith('q')}, | |
| is_matched=False | |
| ) | |
| run_matching_logic() | |
| return Response({'success': True, 'id': participant.id}) | |
| def register_duo(request): | |
| data = request.data | |
| p1_data = data.get('p1', {}) | |
| p2_data = data.get('p2', {}) | |
| email1 = p1_data.get('email', '').strip().lower() | |
| email2 = p2_data.get('email', '').strip().lower() | |
| # 1. Validation | |
| if not email1 or not email2: | |
| return Response({'success': False, 'message': 'Both emails required'}, status=400) | |
| # 2. Check Existence (Prevent Re-registration) | |
| if Participant.objects.filter(email__iexact=email1).exists() or \ | |
| Participant.objects.filter(email__iexact=email2).exists(): | |
| return Response({'success': False, 'message': 'One or both users already registered'}, status=400) | |
| try: | |
| with transaction.atomic(): | |
| # Create P1 | |
| p1 = Participant.objects.create( | |
| name=p1_data.get('name'), | |
| email=email1, | |
| student_id=p1_data.get('student_id'), | |
| role="duo", | |
| quiz_data={k: v for k, v in p1_data.items() if k.startswith('q')}, | |
| is_matched=True | |
| ) | |
| # Create P2 | |
| p2 = Participant.objects.create( | |
| name=p2_data.get('name'), | |
| email=email2, | |
| student_id=p2_data.get('student_id'), | |
| role="duo", | |
| quiz_data={k: v for k, v in p2_data.items() if k.startswith('q')}, | |
| is_matched=True | |
| ) | |
| score = calculate_similarity(p1.quiz_data, p2.quiz_data) | |
| Match.objects.create( | |
| participant_1=p1, | |
| participant_2=p2, | |
| compatibility_score=score | |
| ) | |
| return Response({'success': True, 'score': score}) | |
| except Exception as e: | |
| print(f"Duo Register Error: {e}") | |
| return Response({'success': False, 'message': 'Registration Error'}, status=500) | |
| def get_my_match(request): | |
| email = request.GET.get('email') | |
| if not email: return Response({'success': False, 'message': 'Email required'}, status=400) | |
| try: | |
| me = Participant.objects.get(email=email) | |
| response_data = { | |
| 'success': True, 'match_found': False, | |
| 'participant': {'name': me.name, 'email': me.email, 'student_id': me.student_id} | |
| } | |
| if me.is_matched: | |
| match = Match.objects.filter(Q(participant_1=me) | Q(participant_2=me)).first() | |
| if match: | |
| partner = match.participant_2 if match.participant_1 == me else match.participant_1 | |
| response_data['match_found'] = True | |
| response_data['compatibility_percentage'] = match.compatibility_score | |
| response_data['partner'] = {'name': partner.name, 'email': partner.email, 'student_id': partner.student_id} | |
| return Response(response_data) | |
| except Participant.DoesNotExist: | |
| return Response({'success': False, 'message': 'User not found'}, status=404) | |
| def trigger_matching(request): | |
| matches = run_matching_logic() | |
| return Response({'success': True, 'matches_generated': matches}) | |
| def get_participants(request): | |
| participants = Participant.objects.all().order_by('-created_at') | |
| data = [] | |
| for p in participants: | |
| data.append({ | |
| 'id': p.id, | |
| 'name': p.name, | |
| 'email': p.email, | |
| 'role_display': p.role, | |
| 'preferred_language': p.quiz_data.get('preferred_language', 'N/A'), | |
| 'is_matched': p.is_matched | |
| }) | |
| return Response({'success': True, 'participants': data}) | |
| def get_matches(request): | |
| matches = Match.objects.all().order_by('-compatibility_score') | |
| data = [] | |
| for m in matches: | |
| data.append({ | |
| 'participant1': {'name': m.participant_1.name}, | |
| 'participant2': {'name': m.participant_2.name}, | |
| 'compatibility_percentage': m.compatibility_score | |
| }) | |
| return Response({'success': True, 'matches': data}) |