@@ -46,12 +46,17 @@ def get_context_data(self, **kwargs):
4646 Q (id__in = comp .participant_groups .values_list ('id' , flat = True ))
4747 ).select_related ('queue' ).prefetch_related ('user_set' )
4848
49+ participant_user_ids = list (
50+ CompetitionParticipant .objects .filter (competition = comp )
51+ .values_list ('user_id' , flat = True )
52+ )
53+
4954 ctx ['available_groups_json' ] = json .dumps ([
5055 {
5156 'id' : g .id ,
5257 'name' : g .name ,
5358 'queue' : g .queue .name if g .queue else None ,
54- 'members' : [u .username for u in g .user_set .all ( )],
59+ 'members' : [u .username for u in g .user_set .filter ( pk__in = participant_user_ids )],
5560 }
5661 for g in groups_qs
5762 ], cls = DjangoJSONEncoder )
@@ -69,15 +74,13 @@ def get_context_data(self, **kwargs):
6974 ctx ['available_users_json' ] = json .dumps (
7075 list (
7176 User .objects
72- .filter (is_active = True )
77+ .filter (pk__in = participant_user_ids , is_active = True )
7378 .values ('id' , 'username' , 'email' )
7479 ),
7580 cls = DjangoJSONEncoder
7681 )
77-
7882 return ctx
7983
80-
8184 def get_object (self , * args , ** kwargs ):
8285 competition = super ().get_object (* args , ** kwargs )
8386
@@ -190,6 +193,11 @@ def competition_create_group(request, pk):
190193 if not name :
191194 return HttpResponseBadRequest ("Missing name" )
192195
196+ allowed_user_ids = set (
197+ CompetitionParticipant .objects .filter (competition = competition )
198+ .values_list ('user_id' , flat = True )
199+ )
200+
193201 try :
194202 with transaction .atomic ():
195203 group = CustomGroup (name = name )
@@ -201,15 +209,19 @@ def competition_create_group(request, pk):
201209 group .queue = None
202210 group .save ()
203211
204- if user_ids :
205- # normalize to ints
206- try :
207- user_ids_int = [int (u ) for u in user_ids ]
208- except Exception :
209- user_ids_int = []
210- if user_ids_int :
211- users_qs = User .objects .filter (pk__in = user_ids_int )
212- group .user_set .set (users_qs )
212+ user_ids_int = []
213+ try :
214+ user_ids_int = [int (u ) for u in user_ids ]
215+ except Exception :
216+ user_ids_int = []
217+
218+ if user_ids_int :
219+ invalid = [uid for uid in user_ids_int if uid not in allowed_user_ids ]
220+ if invalid :
221+ raise ValueError (f"Some users are not participants of this competition: { invalid } " )
222+
223+ users_qs = User .objects .filter (pk__in = user_ids_int )
224+ group .user_set .set (users_qs )
213225
214226 competition .participant_groups .add (group )
215227
@@ -220,6 +232,8 @@ def competition_create_group(request, pk):
220232 'queue' : group .queue .name if group .queue else None ,
221233 'members' : members ,
222234 }
235+ except ValueError as e :
236+ return HttpResponseBadRequest (str (e ))
223237 except Exception as e :
224238 return HttpResponseBadRequest ("Error creating group: %s" % str (e ))
225239
@@ -240,6 +254,9 @@ def competition_update_group(request, pk, group_id):
240254 if not (user .is_superuser or user == competition .created_by or user in competition .collaborators .all ()):
241255 return HttpResponseForbidden ("Not allowed" )
242256
257+ if not competition .participant_groups .filter (pk = group .pk ).exists ():
258+ return HttpResponseBadRequest ("Group does not belong to this competition" )
259+
243260 if request .content_type == 'application/json' :
244261 try :
245262 payload = json .loads (request .body .decode ())
@@ -258,6 +275,11 @@ def competition_update_group(request, pk, group_id):
258275 if not name :
259276 return HttpResponseBadRequest ("Missing name" )
260277
278+ allowed_user_ids = set (
279+ CompetitionParticipant .objects .filter (competition = competition )
280+ .values_list ('user_id' , flat = True )
281+ )
282+
261283 try :
262284 with transaction .atomic ():
263285 group .name = name
@@ -267,12 +289,19 @@ def competition_update_group(request, pk, group_id):
267289 group .queue = None
268290 group .save ()
269291
270- # normalize user ids and set membership
271292 try :
272293 user_ids_int = [int (u ) for u in user_ids ]
273294 except Exception :
274295 user_ids_int = []
296+
297+ if user_ids_int :
298+ invalid = [uid for uid in user_ids_int if uid not in allowed_user_ids ]
299+ if invalid :
300+ raise ValueError (f"Some users are not participants of this competition: { invalid } " )
301+
275302 group .user_set .set (User .objects .filter (pk__in = user_ids_int ))
303+ except ValueError as e :
304+ return HttpResponseBadRequest (str (e ))
276305 except Exception as e :
277306 return HttpResponseBadRequest ("Error updating group: %s" % str (e ))
278307
@@ -303,6 +332,9 @@ def competition_delete_group(request, pk, group_id):
303332 if not (user .is_superuser or user == competition .created_by or user in competition .collaborators .all ()):
304333 return HttpResponseForbidden ("Not allowed" )
305334
335+ if not competition .participant_groups .filter (pk = group .pk ).exists ():
336+ return HttpResponseBadRequest ("Group does not belong to this competition" )
337+
306338 try :
307339 with transaction .atomic ():
308340 competition .participant_groups .remove (group )
0 commit comments