Skip to content

Commit 932ef1a

Browse files
committed
feature ok, needs to be tested
1 parent b7e4e8d commit 932ef1a

3 files changed

Lines changed: 208 additions & 77 deletions

File tree

src/apps/api/views/competitions.py

Lines changed: 117 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
11901237
class CompetitionParticipantViewSet(ModelViewSet):
11911238
queryset = CompetitionParticipant.objects.all()
11921239
serializer_class = CompetitionParticipantSerializer

0 commit comments

Comments
 (0)