CineDev commited on
Commit
a44678f
·
1 Parent(s): 8ff54ff

Logic changed for existing user

Browse files
Files changed (1) hide show
  1. api/views.py +87 -41
api/views.py CHANGED
@@ -1,50 +1,92 @@
1
  from django.conf import settings
 
 
2
  from rest_framework.decorators import api_view
3
  from rest_framework.response import Response
4
  from .models import Participant, Match, Whitelist
5
- from django.db.models import Q
6
 
7
  # --- LOGIC HELPER ---
8
  def calculate_similarity(p1_data, p2_data):
9
- score = 0
 
 
 
 
 
10
  total_questions = 15
 
 
 
 
 
 
 
11
  for i in range(1, total_questions + 1):
12
  key = f'q{i}'
13
  val1 = p1_data.get(key)
14
  val2 = p2_data.get(key)
 
 
15
  if val1 and val2 and val1 == val2:
16
- score += 1
17
- return round((score / total_questions) * 100, 1)
 
 
 
 
18
 
19
  def run_matching_logic():
20
- unmatched_pool = list(Participant.objects.filter(is_matched=False))
 
 
 
21
  matches_created = []
22
-
23
- while len(unmatched_pool) >= 2:
24
- person_a = unmatched_pool.pop(0)
25
- best_partner = None
26
- best_score = -1
27
- best_partner_index = -1
28
-
29
- for i, candidate in enumerate(unmatched_pool):
30
- score = calculate_similarity(person_a.quiz_data, candidate.quiz_data)
31
- if score > best_score:
32
- best_score = score
33
- best_partner = candidate
34
- best_partner_index = i
35
 
36
- if best_partner:
37
- Match.objects.create(
38
- participant_1=person_a,
39
- participant_2=best_partner,
40
- compatibility_score=best_score
41
- )
42
- person_a.is_matched = True
43
- best_partner.is_matched = True
44
- person_a.save()
45
- best_partner.save()
46
- unmatched_pool.pop(best_partner_index)
47
- matches_created.append(f"{person_a.name} & {best_partner.name}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
  return matches_created
50
 
@@ -53,20 +95,23 @@ def run_matching_logic():
53
  @api_view(['POST'])
54
  def verify_user(request):
55
  """
56
- Checks if Email exists in the Supabase Whitelist table.
57
  """
58
  email_input = request.data.get('email', '').strip().lower()
59
 
60
- # 1. Check if already registered (Prevent duplicate work)
61
  if Participant.objects.filter(email__iexact=email_input).exists():
62
- return Response({'success': False, 'message': 'You are already registered!'}, status=400)
 
 
 
 
63
 
64
- # 2. Check the Whitelist Table (Database)
65
- # iexact makes it case-insensitive
66
  is_allowed = Whitelist.objects.filter(email__iexact=email_input).exists()
67
 
68
  if is_allowed:
69
- return Response({'success': True, 'message': 'Verified'})
70
  else:
71
  return Response({'success': False, 'message': 'Access Denied: Email not in whitelist.'}, status=403)
72
 
@@ -75,26 +120,27 @@ def register_participant(request):
75
  data = request.data
76
  email = data.get('email')
77
 
78
- # Double check whitelist (security best practice)
79
  if not Whitelist.objects.filter(email__iexact=email).exists():
80
  return Response({'success': False, 'message': 'Email removed from whitelist.'}, status=403)
81
 
82
  if Participant.objects.filter(email=email).exists():
83
- return Response({
84
- 'success': False,
85
- 'message': 'This email is already registered.'
86
- }, status=400)
87
 
 
88
  participant = Participant.objects.create(
89
  name=data.get('name'),
90
  email=email,
91
  student_id=data.get('student_id'),
92
  role=data.get('role', 'fullstack'),
 
93
  quiz_data={k: v for k, v in data.items() if k.startswith('q')},
94
  is_matched=False
95
  )
96
 
 
97
  run_matching_logic()
 
98
  return Response({'success': True, 'id': participant.id})
99
 
100
  @api_view(['GET'])
 
1
  from django.conf import settings
2
+ from django.db import transaction
3
+ from django.db.models import Q
4
  from rest_framework.decorators import api_view
5
  from rest_framework.response import Response
6
  from .models import Participant, Match, Whitelist
 
7
 
8
  # --- LOGIC HELPER ---
9
  def calculate_similarity(p1_data, p2_data):
10
+ """
11
+ Advanced Matching Logic:
12
+ - Starts with 30% Base Compatibility.
13
+ - Remaining 70% is distributed among the 15 questions.
14
+ """
15
+ base_score = 30.0
16
  total_questions = 15
17
+ matches_found = 0
18
+
19
+ # Calculate points per question (approx 4.66%)
20
+ points_per_match = 70.0 / total_questions
21
+
22
+ print(f"--- COMPARING {p1_data.get('name', 'User A')} vs {p2_data.get('name', 'User B')} ---")
23
+
24
  for i in range(1, total_questions + 1):
25
  key = f'q{i}'
26
  val1 = p1_data.get(key)
27
  val2 = p2_data.get(key)
28
+
29
+ # Check for exact match (A==A, B==B)
30
  if val1 and val2 and val1 == val2:
31
+ matches_found += 1
32
+
33
+ final_score = base_score + (matches_found * points_per_match)
34
+ print(f"Matches: {matches_found}/{total_questions} | Final Score: {round(final_score, 1)}%")
35
+
36
+ return min(round(final_score, 1), 100.0)
37
 
38
  def run_matching_logic():
39
+ """
40
+ The Core Matching Algorithm (Thread-Safe Version).
41
+ Uses transaction.atomic() to ensure no double-booking of users.
42
+ """
43
  matches_created = []
44
+
45
+ # Lock the database rows to prevent concurrent matches
46
+ with transaction.atomic():
47
+ # Fetch only users who are strictly NOT matched yet
48
+ # select_for_update() locks these rows until the transaction finishes
49
+ unmatched_pool = list(
50
+ Participant.objects.select_for_update()
51
+ .filter(is_matched=False)
52
+ .order_by('created_at') # Order ensures consistent locking
53
+ )
 
 
 
54
 
55
+ while len(unmatched_pool) >= 2:
56
+ person_a = unmatched_pool.pop(0)
57
+
58
+ best_partner = None
59
+ best_score = -1
60
+ best_partner_index = -1
61
+
62
+ # Compare person_a against everyone else waiting
63
+ for i, candidate in enumerate(unmatched_pool):
64
+ score = calculate_similarity(person_a.quiz_data, candidate.quiz_data)
65
+ if score > best_score:
66
+ best_score = score
67
+ best_partner = candidate
68
+ best_partner_index = i
69
+
70
+ if best_partner:
71
+ # Double check status (redundant but safe)
72
+ if person_a.is_matched or best_partner.is_matched:
73
+ continue
74
+
75
+ Match.objects.create(
76
+ participant_1=person_a,
77
+ participant_2=best_partner,
78
+ compatibility_score=best_score
79
+ )
80
+
81
+ # Mark both as matched
82
+ person_a.is_matched = True
83
+ best_partner.is_matched = True
84
+ person_a.save()
85
+ best_partner.save()
86
+
87
+ # Remove partner from the pool so they aren't matched again
88
+ unmatched_pool.pop(best_partner_index)
89
+ matches_created.append(f"{person_a.name} & {best_partner.name} ({best_score}%)")
90
 
91
  return matches_created
92
 
 
95
  @api_view(['POST'])
96
  def verify_user(request):
97
  """
98
+ Checks if Email exists in Whitelist AND if they are already registered.
99
  """
100
  email_input = request.data.get('email', '').strip().lower()
101
 
102
+ # 1. CHECK IF ALREADY REGISTERED (Redirect Logic)
103
  if Participant.objects.filter(email__iexact=email_input).exists():
104
+ return Response({
105
+ 'success': True,
106
+ 'status': 'registered', # Special flag for frontend
107
+ 'message': 'User already registered. Redirecting...'
108
+ })
109
 
110
+ # 2. CHECK WHITELIST (Supabase Table)
 
111
  is_allowed = Whitelist.objects.filter(email__iexact=email_input).exists()
112
 
113
  if is_allowed:
114
+ return Response({'success': True, 'status': 'new', 'message': 'Verified'})
115
  else:
116
  return Response({'success': False, 'message': 'Access Denied: Email not in whitelist.'}, status=403)
117
 
 
120
  data = request.data
121
  email = data.get('email')
122
 
123
+ # Security: Double check whitelist before saving
124
  if not Whitelist.objects.filter(email__iexact=email).exists():
125
  return Response({'success': False, 'message': 'Email removed from whitelist.'}, status=403)
126
 
127
  if Participant.objects.filter(email=email).exists():
128
+ return Response({'success': False, 'message': 'Already registered.'}, status=400)
 
 
 
129
 
130
+ # Save User
131
  participant = Participant.objects.create(
132
  name=data.get('name'),
133
  email=email,
134
  student_id=data.get('student_id'),
135
  role=data.get('role', 'fullstack'),
136
+ # Save only question answers (q1, q2...)
137
  quiz_data={k: v for k, v in data.items() if k.startswith('q')},
138
  is_matched=False
139
  )
140
 
141
+ # Run Matching Immediately
142
  run_matching_logic()
143
+
144
  return Response({'success': True, 'id': participant.id})
145
 
146
  @api_view(['GET'])