diff --git a/src/apps/api/serializers/competitions.py b/src/apps/api/serializers/competitions.py index f617fa6b9..d77ec97a8 100644 --- a/src/apps/api/serializers/competitions.py +++ b/src/apps/api/serializers/competitions.py @@ -43,6 +43,7 @@ class Meta: 'max_submissions_per_person', 'auto_migrate_to_this_phase', 'hide_output', + 'hide_score_output', 'leaderboard', 'public_data', 'starting_kit', @@ -124,6 +125,7 @@ class Meta: 'max_submissions_per_person', 'auto_migrate_to_this_phase', 'hide_output', + 'hide_score_output', # no leaderboard 'public_data', 'starting_kit', diff --git a/src/apps/api/serializers/submissions.py b/src/apps/api/serializers/submissions.py index d14df9e11..7298d34f1 100644 --- a/src/apps/api/serializers/submissions.py +++ b/src/apps/api/serializers/submissions.py @@ -271,7 +271,7 @@ def get_detailed_result(self, instance): def get_scoring_result(self, instance): if instance.scoring_result.name: - if instance.phase.hide_output and not instance.phase.competition.user_has_admin_permission(self.context['request'].user): + if (instance.phase.hide_output or instance.phase.hide_score_output) and not instance.phase.competition.user_has_admin_permission(self.context['request'].user): return None return make_url_sassy(instance.scoring_result.name) diff --git a/src/apps/api/views/competitions.py b/src/apps/api/views/competitions.py index 4f53f7f31..f9603f535 100644 --- a/src/apps/api/views/competitions.py +++ b/src/apps/api/views/competitions.py @@ -275,6 +275,7 @@ def update(self, request, *args, **kwargs): name=phase["name"], description=phase["description"], hide_output=phase["hide_output"], + hide_score_output=phase["hide_score_output"], competition=Competition.objects.get(id=data['id']) ) # Get phase id diff --git a/src/apps/competitions/migrations/0054_auto_20250321_1341.py b/src/apps/competitions/migrations/0054_auto_20250321_1341.py new file mode 100644 index 000000000..e5b7a6451 --- /dev/null +++ b/src/apps/competitions/migrations/0054_auto_20250321_1341.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.28 on 2025-03-21 13:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('competitions', '0053_auto_20250218_1151'), + ] + + operations = [ + migrations.AlterField( + model_name='submissiondetails', + name='file_size', + field=models.DecimalField(blank=True, decimal_places=2, max_digits=15, null=True), + ), + ] diff --git a/src/apps/competitions/migrations/0056_merge_20250324_2128.py b/src/apps/competitions/migrations/0056_merge_20250324_2128.py new file mode 100644 index 000000000..16554ffa0 --- /dev/null +++ b/src/apps/competitions/migrations/0056_merge_20250324_2128.py @@ -0,0 +1,14 @@ +# Generated by Django 2.2.28 on 2025-03-24 21:28 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('competitions', '0054_auto_20250321_1341'), + ('competitions', '0055_merge_20250324_0650'), + ] + + operations = [ + ] diff --git a/src/apps/competitions/migrations/0057_phase_hide_score_output.py b/src/apps/competitions/migrations/0057_phase_hide_score_output.py new file mode 100644 index 000000000..1f805e0f4 --- /dev/null +++ b/src/apps/competitions/migrations/0057_phase_hide_score_output.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.28 on 2025-04-25 09:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('competitions', '0056_merge_20250324_2128'), + ] + + operations = [ + migrations.AddField( + model_name='phase', + name='hide_score_output', + field=models.BooleanField(default=False), + ), + ] diff --git a/src/apps/competitions/models.py b/src/apps/competitions/models.py index 4d938895f..bda72df13 100644 --- a/src/apps/competitions/models.py +++ b/src/apps/competitions/models.py @@ -342,6 +342,7 @@ class Phase(ChaHubSaveMixin, models.Model): auto_migrate_to_this_phase = models.BooleanField(default=False) has_been_migrated = models.BooleanField(default=False) hide_output = models.BooleanField(default=False) + hide_score_output = models.BooleanField(default=False) has_max_submissions = models.BooleanField(default=True) max_submissions_per_day = models.PositiveIntegerField(default=5, null=True, blank=True) diff --git a/src/apps/competitions/tasks.py b/src/apps/competitions/tasks.py index 87501be20..419a13f23 100644 --- a/src/apps/competitions/tasks.py +++ b/src/apps/competitions/tasks.py @@ -82,6 +82,7 @@ 'execution_time_limit', 'auto_migrate_to_this_phase', 'hide_output', + 'hide_score_output', ] PHASE_FILES = [ "input_data", diff --git a/src/apps/competitions/tests/unpacker_test_data.py b/src/apps/competitions/tests/unpacker_test_data.py index db69ec6dd..c93597671 100644 --- a/src/apps/competitions/tests/unpacker_test_data.py +++ b/src/apps/competitions/tests/unpacker_test_data.py @@ -213,6 +213,8 @@ 'starting_kit': None, 'tasks': [0], 'status': 'Previous', + 'hide_output': False, + 'hide_score_output': False, }, { 'index': 1, @@ -230,14 +232,11 @@ 'tasks': [1], 'status': 'Current', 'is_final_phase': True, + 'hide_output': False, + 'hide_score_output': False, } ] -V2_SPECIFIC_PHASE_DATA = [ - # Tuples of (key, value) of data specific to v2 unpacker. - ('hide_output', False) -] - def get_phases(version): if version == 1: @@ -246,9 +245,6 @@ def get_phases(version): # Make a copy of the list so we aren't mutating the original phases object. May not be strictly necessary, # but if we ever write a test comparing v1 to v2 or something, this would avoid bugs. v2 = [{k: v for k, v in phase.items()} for phase in PHASES] - for phase in v2: - for key, value in V2_SPECIFIC_PHASE_DATA: - phase[key] = value return v2 diff --git a/src/apps/competitions/unpackers/v1.py b/src/apps/competitions/unpackers/v1.py index dc476a5c2..d780c2e5d 100644 --- a/src/apps/competitions/unpackers/v1.py +++ b/src/apps/competitions/unpackers/v1.py @@ -88,6 +88,8 @@ def _unpack_phases(self): 'max_submissions_per_day': phase.get('max_submissions_per_day', 5), 'max_submissions_per_person': phase.get('max_submissions', 100), 'auto_migrate_to_this_phase': phase.get('auto_migration', False), + 'hide_output': phase.get('hide_output', False), + 'hide_score_output': phase.get('hide_score_output', False), } execution_time_limit = phase.get('execution_time_limit') if execution_time_limit: diff --git a/src/apps/competitions/unpackers/v2.py b/src/apps/competitions/unpackers/v2.py index 85eddefcb..72a8b6abc 100644 --- a/src/apps/competitions/unpackers/v2.py +++ b/src/apps/competitions/unpackers/v2.py @@ -198,6 +198,7 @@ def _unpack_phases(self): 'max_submissions_per_person': phase_data.get('max_submissions', 100), 'auto_migrate_to_this_phase': phase_data.get('auto_migrate_to_this_phase', False), 'hide_output': phase_data.get('hide_output', False), + 'hide_score_output': phase_data.get('hide_score_output', False), } try: new_phase['tasks'] = phase_data['tasks'] diff --git a/src/static/riot/competitions/detail/submission_modal.tag b/src/static/riot/competitions/detail/submission_modal.tag index 55cb5dde4..3df256fba 100644 --- a/src/static/riot/competitions/detail/submission_modal.tag +++ b/src/static/riot/competitions/detail/submission_modal.tag @@ -27,7 +27,7 @@