@@ -813,15 +813,6 @@ def get_leaderboard(self, request, pk):
813813
814814 serialized_submissions = list (query .get ('submissions' , []))
815815
816- for s in serialized_submissions :
817- logger .error (
818- f"SUBMISSION { s .get ('id' )} task={ s .get ('task' )} parent={ s .get ('parent' )} scores={ s .get ('scores' )} "
819- )
820-
821- logger .error (f"RAW QUERY KEYS: { query .keys ()} " )
822- logger .error (f"RAW SUBMISSIONS COUNT: { len (query .get ('submissions' , []))} " )
823- logger .error (f"RAW FIRST SUBMISSION: { query .get ('submissions' , [])[:1 ]} " )
824-
825816 logger .warning ("===== LEADERBOARD DEBUG START =====" )
826817 logger .warning (f"Phase ID: { getattr (phase , 'id' , None )} " )
827818 logger .warning (f"Number of serialized submissions: { len (serialized_submissions )} " )
@@ -840,10 +831,6 @@ def get_leaderboard(self, request, pk):
840831 columns = [col for col in query .get ('columns' , []) or []]
841832 logger .debug (f"Columns loaded: { [c .get ('key' ) for c in columns ]} " )
842833
843- logger .error ("COLUMNS DEBUG:" )
844- for c in columns :
845- logger .error (f"Column key={ c .get ('key' )} index={ c .get ('index' )} " )
846-
847834 group_order = []
848835 try :
849836 part_groups = getattr (phase .competition , "participant_groups" , None )
@@ -857,32 +844,30 @@ def get_leaderboard(self, request, pk):
857844 group_order = []
858845 except Exception :
859846 logger .exception ("Error reading competition.participant_groups; ignoring." )
860-
861847 logger .debug (f"Initial group_order from competition: { group_order } " )
862848
849+ tasks_in_query = query .get ('tasks' ) or []
850+ logger .debug (f"Tasks in query count: { len (tasks_in_query )} " )
851+
863852 child_parent_group = defaultdict (dict )
864853 children_by_parent = defaultdict (list )
865854 seen_groups = set ()
866-
867855 for s in serialized_submissions :
868856 if not s .get ('parent' ):
869857 continue
870858 parent_id = s ['parent' ]
871-
872859 gid_raw = None
873860 org = s .get ('organization' )
874861 if isinstance (org , dict ):
875862 gid_raw = org .get ('name' )
876863 elif isinstance (org , str ) and org :
877864 gid_raw = org
878-
879865 if not gid_raw :
880866 sd = s .get ('status_details' )
881867 if isinstance (sd , dict ):
882868 gid_raw = sd .get ('group' ) or sd .get ('group_name' ) or sd .get ('name' )
883869 elif sd :
884870 gid_raw = str (sd )
885-
886871 if not gid_raw :
887872 owner = s .get ('owner' )
888873 if isinstance (owner , dict ) and owner .get ('username' ):
@@ -897,10 +882,8 @@ def get_leaderboard(self, request, pk):
897882 if group_order :
898883 low_raw = (gid_raw or "" ).lower ()
899884 group_order_lower = [g .lower () for g in group_order ]
900-
901885 if low_raw in group_order_lower :
902886 matched = group_order [group_order_lower .index (low_raw )]
903-
904887 if not matched :
905888 for g in group_order :
906889 if low_raw and low_raw in (g or "" ).lower ():
@@ -909,7 +892,6 @@ def get_leaderboard(self, request, pk):
909892 if (g or "" ).lower () and (g or "" ).lower () in low_raw :
910893 matched = g
911894 break
912-
913895 if not matched :
914896 digits = re .findall (r'\d+' , gid_raw or "" )
915897 if digits :
@@ -920,7 +902,6 @@ def get_leaderboard(self, request, pk):
920902 break
921903 if matched :
922904 break
923-
924905 if matched :
925906 gid_final = matched
926907 logger .info (f"Child { s .get ('id' )} gid_raw='{ gid_raw } ' matched to canonical group '{ gid_final } '" )
@@ -933,8 +914,15 @@ def get_leaderboard(self, request, pk):
933914 logger .debug (f"Mapped child { s .get ('id' )} -> parent { parent_id } as group key '{ gid_final } ' (raw='{ gid_raw } ')" )
934915
935916 if not group_order and seen_groups :
936- group_order = sorted (list (seen_groups ))
937- logger .info (f"Fallback group_order from seen_groups: { group_order } " )
917+ if len (seen_groups ) > 1 :
918+ group_order = sorted (list (seen_groups ))
919+ logger .info (f"Fallback group_order from seen_groups (multiple keys): { group_order } " )
920+ else :
921+ if len (tasks_in_query ) > 1 :
922+ logger .info ("Detected multi-task phase and only one seen_group -> skip using seen_groups as groups (treat as multi-task legacy)." )
923+ else :
924+ group_order = sorted (list (seen_groups ))
925+ logger .info (f"Fallback group_order from seen_groups (single key, single-task): { group_order } " )
938926
939927 if group_order :
940928 response ['groups' ] = [{'name' : g , 'colCount' : len (columns )} for g in group_order ]
@@ -944,74 +932,128 @@ def get_leaderboard(self, request, pk):
944932
945933 submissions_keys = {}
946934 submission_detailed_results = {}
947- row_parent_map = {}
935+ row_parent_map = {}
948936
949- for submission in serialized_submissions :
950- submission_key = f"{ submission .get ('owner' )} { submission .get ('parent' ) or submission .get ('id' )} "
951- submission_detailed_results .setdefault (submission_key , []).append ({
952- 'task' : submission .get ('task' ),
953- 'id' : submission .get ('id' )
954- })
937+ is_multi_task = (not group_order ) and (len (tasks_in_query ) > 1 )
938+ logger .debug (f"is_multi_task={ is_multi_task } (group_order present? { bool (group_order )} tasks_count={ len (tasks_in_query )} )" )
955939
956- if submission_key not in submissions_keys :
957- submissions_keys [submission_key ] = len (response ['submissions' ])
958- response ['submissions' ].append ({
959- 'id' : submission .get ('id' ),
960- 'owner' : submission .get ('display_name' ) or submission .get ('owner' ),
961- 'scores' : [],
962- 'detailed_results' : [],
963- 'fact_sheet_answers' : submission .get ('fact_sheet_answers' ),
964- 'slug_url' : submission .get ('slug_url' ),
965- 'organization' : submission .get ('organization' ),
966- 'created_when' : submission .get ('created_when' )
967- })
968- row_parent_map [submission_key ] = submission .get ('parent' ) if submission .get ('parent' ) else submission .get ('id' )
940+ if group_order :
941+ parent_ids = set ()
969942
970- parent_candidates = set ()
971- for s in serialized_submissions :
972- if s .get ('parent' ):
973- parent_candidates .add (s .get ('parent' ))
974- else :
975- parent_candidates .add (s .get ('id' ))
943+ for s in serialized_submissions :
944+ if s .get ('parent' ):
945+ parent_ids .add (s .get ('parent' ))
946+ else :
947+ parent_ids .add (s .get ('id' ))
976948
977- for parent_id in parent_candidates :
978- parent_entry = next ((x for x in serialized_submissions if x .get ('id' ) == parent_id and not x .get ('parent' )), None )
979- if parent_entry :
980- parent_owner = parent_entry .get ('owner' )
981- else :
982- first_child = children_by_parent .get (parent_id , [None ])[0 ]
983- parent_owner = first_child .get ('owner' ) if first_child else f'unknown-{ parent_id } '
949+ for parent_id in parent_ids :
950+ parent_entry = next (
951+ (x for x in serialized_submissions if x .get ('id' ) == parent_id and not x .get ('parent' )),
952+ None
953+ )
984954
985- submission_key = f"{ parent_owner } { parent_id } "
986- if submission_key not in submissions_keys :
987- logger .info (f"Creating synthetic parent row for parent_id={ parent_id } submission_key='{ submission_key } '" )
988- submissions_keys [submission_key ] = len (response ['submissions' ])
989955 if parent_entry :
990- row_owner = parent_entry .get ('display_name' ) or parent_entry .get ('owner' )
956+ owner = parent_entry .get ('display_name' ) or parent_entry .get ('owner' )
991957 slug = parent_entry .get ('slug_url' )
992958 org = parent_entry .get ('organization' )
993959 created = parent_entry .get ('created_when' )
994960 fact_sheet = parent_entry .get ('fact_sheet_answers' )
995961 else :
996962 child = children_by_parent .get (parent_id , [None ])[0 ]
997- row_owner = (child .get ('display_name' ) or child .get ('owner' )) if child else parent_owner
963+ owner = (child .get ('display_name' ) or child .get ('owner' )) if child else "unknown"
998964 slug = child .get ('slug_url' ) if child else None
999965 org = child .get ('organization' ) if child else None
1000966 created = child .get ('created_when' ) if child else None
1001967 fact_sheet = child .get ('fact_sheet_answers' ) if child else {}
1002968
969+ submission_key = str (parent_id )
970+ submissions_keys [submission_key ] = len (response ['submissions' ])
971+
1003972 response ['submissions' ].append ({
1004973 'id' : parent_id ,
1005- 'owner' : row_owner ,
974+ 'owner' : owner ,
1006975 'scores' : [],
1007976 'detailed_results' : [],
1008977 'fact_sheet_answers' : fact_sheet ,
1009978 'slug_url' : slug ,
1010979 'organization' : org ,
1011980 'created_when' : created
1012981 })
982+
1013983 row_parent_map [submission_key ] = parent_id
1014984
985+ else :
986+ for submission in serialized_submissions :
987+ if is_multi_task :
988+ submission_key = f"{ submission .get ('owner' )} "
989+ else :
990+ submission_key = f"{ submission .get ('owner' )} { submission .get ('parent' ) or submission .get ('id' )} "
991+
992+ submission_detailed_results .setdefault (submission_key , []).append ({
993+ 'task' : submission .get ('task' ),
994+ 'id' : submission .get ('id' )
995+ })
996+
997+ if submission_key not in submissions_keys :
998+ submissions_keys [submission_key ] = len (response ['submissions' ])
999+ response ['submissions' ].append ({
1000+ 'id' : submission .get ('id' ),
1001+ 'owner' : submission .get ('display_name' ) or submission .get ('owner' ),
1002+ 'scores' : [],
1003+ 'detailed_results' : [],
1004+ 'fact_sheet_answers' : submission .get ('fact_sheet_answers' ),
1005+ 'slug_url' : submission .get ('slug_url' ),
1006+ 'organization' : submission .get ('organization' ),
1007+ 'created_when' : submission .get ('created_when' )
1008+ })
1009+ row_parent_map [submission_key ] = submission .get ('parent' ) if submission .get ('parent' ) else submission .get ('id' )
1010+
1011+ if not group_order and not is_multi_task :
1012+ parent_candidates = set ()
1013+ for s in serialized_submissions :
1014+ if s .get ('parent' ):
1015+ parent_candidates .add (s .get ('parent' ))
1016+ else :
1017+ parent_candidates .add (s .get ('id' ))
1018+
1019+ for parent_id in parent_candidates :
1020+ parent_entry = next ((x for x in serialized_submissions if x .get ('id' ) == parent_id and not x .get ('parent' )), None )
1021+ if parent_entry :
1022+ parent_owner = parent_entry .get ('owner' )
1023+ else :
1024+ first_child = children_by_parent .get (parent_id , [None ])[0 ]
1025+ parent_owner = first_child .get ('owner' ) if first_child else f'unknown-{ parent_id } '
1026+
1027+ submission_key = f"{ parent_owner } { parent_id } "
1028+ if submission_key not in submissions_keys :
1029+ logger .info (f"Creating synthetic parent row for parent_id={ parent_id } submission_key='{ submission_key } '" )
1030+ submissions_keys [submission_key ] = len (response ['submissions' ])
1031+ if parent_entry :
1032+ row_owner = parent_entry .get ('display_name' ) or parent_entry .get ('owner' )
1033+ slug = parent_entry .get ('slug_url' )
1034+ org = parent_entry .get ('organization' )
1035+ created = parent_entry .get ('created_when' )
1036+ fact_sheet = parent_entry .get ('fact_sheet_answers' )
1037+ else :
1038+ child = children_by_parent .get (parent_id , [None ])[0 ]
1039+ row_owner = (child .get ('display_name' ) or child .get ('owner' )) if child else parent_owner
1040+ slug = child .get ('slug_url' ) if child else None
1041+ org = child .get ('organization' ) if child else None
1042+ created = child .get ('created_when' ) if child else None
1043+ fact_sheet = child .get ('fact_sheet_answers' ) if child else {}
1044+
1045+ response ['submissions' ].append ({
1046+ 'id' : parent_id ,
1047+ 'owner' : row_owner ,
1048+ 'scores' : [],
1049+ 'detailed_results' : [],
1050+ 'fact_sheet_answers' : fact_sheet ,
1051+ 'slug_url' : slug ,
1052+ 'organization' : org ,
1053+ 'created_when' : created
1054+ })
1055+ row_parent_map [submission_key ] = parent_id
1056+
10151057 for k , v in submissions_keys .items ():
10161058 response ['submissions' ][v ]['detailed_results' ] = submission_detailed_results .get (k , [])
10171059
@@ -1040,7 +1082,6 @@ def get_leaderboard(self, request, pk):
10401082 columns_by_index [int (idx )] = col
10411083
10421084 task_fallback_id = None
1043- tasks_in_query = query .get ('tasks' ) or []
10441085 if tasks_in_query :
10451086 try :
10461087 task_fallback_id = tasks_in_query [0 ].get ('id' )
@@ -1050,7 +1091,10 @@ def get_leaderboard(self, request, pk):
10501091 if not group_order :
10511092 logger .debug ("Filling scores in legacy (no groups) mode." )
10521093 for submission in serialized_submissions :
1053- submission_key = f"{ submission .get ('owner' )} { submission .get ('parent' ) or submission .get ('id' )} "
1094+ if is_multi_task :
1095+ submission_key = f"{ submission .get ('owner' )} "
1096+ else :
1097+ submission_key = f"{ submission .get ('owner' )} { submission .get ('parent' ) or submission .get ('id' )} "
10541098 row_idx = submissions_keys .get (submission_key )
10551099 if row_idx is None :
10561100 continue
@@ -1096,9 +1140,12 @@ def get_leaderboard(self, request, pk):
10961140 for col in columns :
10971141 found = None
10981142 for s_score in child .get ('scores' , []) or []:
1099- if s_score .get ('index' ) == col .get ('index' ):
1100- found = s_score
1101- break
1143+ try :
1144+ if int (s_score .get ('index' )) == int (col .get ('index' )):
1145+ found = s_score
1146+ break
1147+ except Exception :
1148+ continue
11021149 if found :
11031150 precision = col .get ('precision' ) if col .get ('precision' ) is not None else 2
11041151 try :
@@ -1186,7 +1233,7 @@ def get_leaderboard(self, request, pk):
11861233 logger .exception ("Unhandled exception in get_leaderboard." )
11871234 return Response ({"detail" : "Internal server error building leaderboard." }, status = status .HTTP_500_INTERNAL_SERVER_ERROR )
11881235
1189-
1236+
11901237class CompetitionParticipantViewSet (ModelViewSet ):
11911238 queryset = CompetitionParticipant .objects .all ()
11921239 serializer_class = CompetitionParticipantSerializer
0 commit comments