From d188aeaa865db3a73fbd70f04a18014fa40f9f2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Pav=C3=A3o?= Date: Sun, 13 Apr 2025 15:26:40 -0300 Subject: [PATCH 01/11] Add remove button for cancelled submissions (#1808) * Add remove button for cancelled submissions * Allow remove of cancelled submissions --- src/apps/api/views/submissions.py | 2 +- src/static/riot/competitions/detail/submission_manager.tag | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/apps/api/views/submissions.py b/src/apps/api/views/submissions.py index 5bcbffc1a..4cc6c1180 100644 --- a/src/apps/api/views/submissions.py +++ b/src/apps/api/views/submissions.py @@ -204,7 +204,7 @@ def soft_delete(self, request, pk): return Response({'error': 'You are not allowed to delete a leaderboard submission'}, status=status.HTTP_403_FORBIDDEN) # Check if submission is in running state - if submission.status not in [Submission.FAILED, Submission.FINISHED]: + if submission.status not in [Submission.FAILED, Submission.FINISHED, Submission.CANCELLED]: return Response({'error': 'You are not allowed to delete a running submission'}, status=status.HTTP_403_FORBIDDEN) # Check if submission is not already soft deleted diff --git a/src/static/riot/competitions/detail/submission_manager.tag b/src/static/riot/competitions/detail/submission_manager.tag index e5a5f1f7c..74b746cc6 100644 --- a/src/static/riot/competitions/detail/submission_manager.tag +++ b/src/static/riot/competitions/detail/submission_manager.tag @@ -168,9 +168,9 @@ - + - From d7e8580f510693f67e808329ee24f49e90c5e2d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Pav=C3=A3o?= Date: Wed, 16 Apr 2025 10:49:55 +0200 Subject: [PATCH 02/11] Update compute_worker.py --- compute_worker/compute_worker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compute_worker/compute_worker.py b/compute_worker/compute_worker.py index 34ea6a303..4742e90f8 100644 --- a/compute_worker/compute_worker.py +++ b/compute_worker/compute_worker.py @@ -280,7 +280,7 @@ async def watch_detailed_results(self): else: logger.info(time.time() - start) if time.time() - start > expiration_seconds: - timeout_error_message = f"Detailed results not written to after {expiration_seconds} seconds, exiting!" + timeout_error_message = f"WARNING: Detailed results not written before the execution." logger.warning(timeout_error_message) await asyncio.sleep(5) file_path = self.get_detailed_results_file_path() From b2e86d9153c362b7c396d4579e3d2ff749b246f7 Mon Sep 17 00:00:00 2001 From: didayolo Date: Tue, 22 Apr 2025 18:19:00 +0200 Subject: [PATCH 03/11] Add permissions check for bulk download --- src/apps/api/views/submissions.py | 41 +++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/src/apps/api/views/submissions.py b/src/apps/api/views/submissions.py index 4cc6c1180..ff9bcf3c5 100644 --- a/src/apps/api/views/submissions.py +++ b/src/apps/api/views/submissions.py @@ -351,16 +351,47 @@ def re_run_many_submissions(self, request): @action(detail=False, methods=['get']) def download_many(self, request): + """ + Download a ZIP containing several submissions. + """ pks = request.query_params.get('pks') if pks: pks = json.loads(pks) # Convert JSON string to list - - # Doing a local import here to avoid circular imports + else: + return Response({"error": "`pks` query parameter is required"}, status=400) + + # Get submissions + submissions = Submission.objects.filter(pk__in=pks).select_related( + "owner", + "phase__competition", + "phase__competition__created_by", + ).prefetch_related("phase__competition__collaborators") + if submissions.count() != len(pks): + return Response({"error": "One or more submission IDs are invalid"}, status=404) + + # Check permissions + if not request.user.is_authenticated: + raise PermissionDenied("You must be logged in to download submissions") + # Allow admins + if request.user.is_superuser or request.user.is_staff: + allowed = True + else: + # Build one Q object for "owner OR organizer" + organiser_q = ( + Q(phase__competition__created_by=request.user) | + Q(phase__competition__collaborators=request.user) + ) + # Submissions that violate the rule + disallowed = submissions.exclude(Q(owner=request.user) | organiser_q) + allowed = not disallowed.exists() + if not allowed: + raise PermissionDenied( + "You do not have permission to download one or more of the requested submissions" + ) + + # Download from competitions.tasks import stream_batch_download - - # in_memory_zip = stream_batch_download.apply_async((pks,)).get() in_memory_zip = stream_batch_download(pks) - response = StreamingHttpResponse(in_memory_zip, content_type='application/zip') response['Content-Disposition'] = 'attachment; filename="bulk_submissions.zip"' return response From f120f095cc8a221374dcdd90572901e7542523a7 Mon Sep 17 00:00:00 2001 From: didayolo Date: Tue, 22 Apr 2025 18:24:08 +0200 Subject: [PATCH 04/11] flake8 fix --- src/apps/api/views/submissions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/api/views/submissions.py b/src/apps/api/views/submissions.py index ff9bcf3c5..afe14fb36 100644 --- a/src/apps/api/views/submissions.py +++ b/src/apps/api/views/submissions.py @@ -388,7 +388,7 @@ def download_many(self, request): raise PermissionDenied( "You do not have permission to download one or more of the requested submissions" ) - + # Download from competitions.tasks import stream_batch_download in_memory_zip = stream_batch_download(pks) From 5f167a747a3bcff3712328dd106749b4e856e498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Pav=C3=A3o?= Date: Tue, 29 Apr 2025 09:12:40 -0300 Subject: [PATCH 05/11] Add hide_score_output option (#1838) * Add hide_score_output option * Update test * Add the options for v1 bundles * Make more generic tests (v1, v2) --- src/apps/api/serializers/competitions.py | 2 ++ src/apps/api/serializers/submissions.py | 2 +- src/apps/api/views/competitions.py | 1 + .../migrations/0054_auto_20250321_1341.py | 18 ++++++++++++++++++ .../migrations/0056_merge_20250324_2128.py | 14 ++++++++++++++ .../migrations/0057_phase_hide_score_output.py | 18 ++++++++++++++++++ src/apps/competitions/models.py | 1 + src/apps/competitions/tasks.py | 1 + .../competitions/tests/unpacker_test_data.py | 12 ++++-------- src/apps/competitions/unpackers/v1.py | 2 ++ src/apps/competitions/unpackers/v2.py | 1 + .../competitions/detail/submission_modal.tag | 2 +- .../riot/competitions/editor/_phases.tag | 18 +++++++++++++++--- 13 files changed, 79 insertions(+), 13 deletions(-) create mode 100644 src/apps/competitions/migrations/0054_auto_20250321_1341.py create mode 100644 src/apps/competitions/migrations/0056_merge_20250324_2128.py create mode 100644 src/apps/competitions/migrations/0057_phase_hide_score_output.py 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 @@ - + Output from scoring step diff --git a/src/static/riot/competitions/editor/_phases.tag b/src/static/riot/competitions/editor/_phases.tag index fd0e09cd5..ef82ff274 100644 --- a/src/static/riot/competitions/editor/_phases.tag +++ b/src/static/riot/competitions/editor/_phases.tag @@ -190,10 +190,22 @@
- +
+
+
+ + +
+
@@ -641,7 +653,6 @@ return new Date(Date.parse(date)) } - self.edit = function (index) { self.selected_phase_index = index var phase = self.phases[index] @@ -649,11 +660,11 @@ self.phase_public_data = [phase.public_data] self.phase_starting_kit = [phase.starting_kit] - self.update() set_form_data(phase, self.refs.form) $(self.refs.auto_migrate).prop('checked', _.get(phase, 'auto_migrate_to_this_phase', false)) self.refs.hide_output.checked = phase.hide_output + self.refs.hide_score_output.checked = phase.hide_score_output // Setting description in markdown editor self.simple_markdown_editor.value(self.phases[index].description || '') @@ -812,6 +823,7 @@ } data.auto_migrate_to_this_phase = $(self.refs.auto_migrate).prop('checked') data.hide_output = self.refs.hide_output.checked + data.hide_score_output = self.refs.hide_score_output.checked _.forEach(number_fields, field => { let str = _.get(data, field) if (str) { From 578f5cc97b9a8f41626906ccdec80648795b803a Mon Sep 17 00:00:00 2001 From: Ihsan Ullah Date: Mon, 12 May 2025 15:51:15 +0500 Subject: [PATCH 06/11] version update workflow removed --- .github/workflows/release-version-update.yml | 69 -------------------- 1 file changed, 69 deletions(-) delete mode 100644 .github/workflows/release-version-update.yml diff --git a/.github/workflows/release-version-update.yml b/.github/workflows/release-version-update.yml deleted file mode 100644 index a5eebaabe..000000000 --- a/.github/workflows/release-version-update.yml +++ /dev/null @@ -1,69 +0,0 @@ -name: Update version.json and create PR - -# Trigger the github action when a new release is published -on: - release: - types: [published] - -jobs: - update-version: - runs-on: ubuntu-latest - - steps: - - # Step 1: Checkout repository - - name: Checkout repository - uses: actions/checkout@v3 - - # Step 2: Get latest release version information - - name: Get release information - id: get_release - run: | - response=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" https://api.github.com/repos/${{ github.repository }}/releases/latest) - echo "$response" | jq '.tag_name, .name, .published_at, .html_url' | tee /tmp/release_info - echo "tag_name=$(echo "$response" | jq -r .tag_name)" >> $GITHUB_ENV - echo "name=$(echo "$response" | jq -r .name)" >> $GITHUB_ENV - echo "published_at=$(echo "$response" | jq -r .published_at)" >> $GITHUB_ENV - echo "html_url=$(echo "$response" | jq -r .html_url)" >> $GITHUB_ENV - - # Step 3: Update version.json file with latest information - - name: Update version.json - run: | - echo '{ - "tag_name": "${{ env.tag_name }}", - "release_name": "${{ env.name }}", - "published_at": "${{ env.published_at }}", - "html_url": "${{ env.html_url }}" - }' > version.json - - # Step 4: Configure a user to create a branch and then push changes - - name: Configure Git user - run: | - git config --global user.name "GitHub Actions" - git config --global user.email "actions@github.com" - - # Step 5: Create a new branch for version updates - - name: Create new branch - run: | - git checkout -b update-version-${{ env.tag_name }} - git add version.json - git commit -m "Update version.json for release ${{ env.tag_name }}" - - # Step 6: Push branch - - name: Push branch - run: | - git push origin update-version-${{ env.tag_name }} - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - # Step 7: Create a pull request from the pushed branch - - name: Create Pull Request - run: | - curl -X POST -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" -H "Accept: application/vnd.github.v3+json" \ - https://api.github.com/repos/${{ github.repository }}/pulls \ - -d '{ - "title": "[RELEASE ${{ env.tag_name }}] Update version.json for release ${{ env.tag_name }}", - "body": "This PR updates version.json with the latest release information: ${{ env.tag_name }}", - "head": "update-version-${{ env.tag_name }}", - "base": "develop" - }' From 02694daf03dc93dd045b7da844e0197382845c4b Mon Sep 17 00:00:00 2001 From: didayolo Date: Wed, 14 May 2025 21:41:33 +0200 Subject: [PATCH 07/11] Add hide_prediction_output feature --- src/apps/api/serializers/competitions.py | 2 ++ src/apps/api/serializers/submissions.py | 2 +- src/apps/api/views/competitions.py | 1 + .../0058_phase_hide_prediction_output.py | 18 ++++++++++++++++++ src/apps/competitions/models.py | 1 + src/apps/competitions/tasks.py | 1 + .../competitions/tests/unpacker_test_data.py | 2 ++ src/apps/competitions/unpackers/v1.py | 1 + src/apps/competitions/unpackers/v2.py | 1 + .../competitions/detail/submission_modal.tag | 2 +- .../riot/competitions/editor/_phases.tag | 11 +++++++++++ 11 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/apps/competitions/migrations/0058_phase_hide_prediction_output.py diff --git a/src/apps/api/serializers/competitions.py b/src/apps/api/serializers/competitions.py index d77ec97a8..d35fed024 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_prediction_output', 'hide_score_output', 'leaderboard', 'public_data', @@ -125,6 +126,7 @@ class Meta: 'max_submissions_per_person', 'auto_migrate_to_this_phase', 'hide_output', + 'hide_prediction_output', 'hide_score_output', # no leaderboard 'public_data', diff --git a/src/apps/api/serializers/submissions.py b/src/apps/api/serializers/submissions.py index 7298d34f1..6def18976 100644 --- a/src/apps/api/serializers/submissions.py +++ b/src/apps/api/serializers/submissions.py @@ -261,7 +261,7 @@ def get_data_file(self, instance): def get_prediction_result(self, instance): if instance.prediction_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_prediction_output) and not instance.phase.competition.user_has_admin_permission(self.context['request'].user): return None return make_url_sassy(instance.prediction_result.name) diff --git a/src/apps/api/views/competitions.py b/src/apps/api/views/competitions.py index f9603f535..f5d464761 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_prediction_output=phase["hide_prediction_output"], hide_score_output=phase["hide_score_output"], competition=Competition.objects.get(id=data['id']) ) diff --git a/src/apps/competitions/migrations/0058_phase_hide_prediction_output.py b/src/apps/competitions/migrations/0058_phase_hide_prediction_output.py new file mode 100644 index 000000000..0c241ca2b --- /dev/null +++ b/src/apps/competitions/migrations/0058_phase_hide_prediction_output.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.28 on 2025-05-14 19:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('competitions', '0057_phase_hide_score_output'), + ] + + operations = [ + migrations.AddField( + model_name='phase', + name='hide_prediction_output', + field=models.BooleanField(default=False), + ), + ] diff --git a/src/apps/competitions/models.py b/src/apps/competitions/models.py index bda72df13..d8ce83dad 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_prediction_output = models.BooleanField(default=False) hide_score_output = models.BooleanField(default=False) has_max_submissions = models.BooleanField(default=True) diff --git a/src/apps/competitions/tasks.py b/src/apps/competitions/tasks.py index 419a13f23..9b685d1d7 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_prediction_output', 'hide_score_output', ] PHASE_FILES = [ diff --git a/src/apps/competitions/tests/unpacker_test_data.py b/src/apps/competitions/tests/unpacker_test_data.py index c93597671..b2ee7e075 100644 --- a/src/apps/competitions/tests/unpacker_test_data.py +++ b/src/apps/competitions/tests/unpacker_test_data.py @@ -214,6 +214,7 @@ 'tasks': [0], 'status': 'Previous', 'hide_output': False, + 'hide_prediction_output': False, 'hide_score_output': False, }, { @@ -233,6 +234,7 @@ 'status': 'Current', 'is_final_phase': True, 'hide_output': False, + 'hide_prediction_output': False, 'hide_score_output': False, } ] diff --git a/src/apps/competitions/unpackers/v1.py b/src/apps/competitions/unpackers/v1.py index d780c2e5d..535e9e2d5 100644 --- a/src/apps/competitions/unpackers/v1.py +++ b/src/apps/competitions/unpackers/v1.py @@ -89,6 +89,7 @@ def _unpack_phases(self): '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_prediction_output': phase.get('hide_prediction_output', False), 'hide_score_output': phase.get('hide_score_output', False), } execution_time_limit = phase.get('execution_time_limit') diff --git a/src/apps/competitions/unpackers/v2.py b/src/apps/competitions/unpackers/v2.py index 72a8b6abc..508479eba 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_prediction_output': phase_data.get('hide_prediction_output', False), 'hide_score_output': phase_data.get('hide_score_output', False), } try: diff --git a/src/static/riot/competitions/detail/submission_modal.tag b/src/static/riot/competitions/detail/submission_modal.tag index 3df256fba..0961c0b0b 100644 --- a/src/static/riot/competitions/detail/submission_modal.tag +++ b/src/static/riot/competitions/detail/submission_modal.tag @@ -22,7 +22,7 @@ - + Output from prediction step diff --git a/src/static/riot/competitions/editor/_phases.tag b/src/static/riot/competitions/editor/_phases.tag index ef82ff274..c048f920d 100644 --- a/src/static/riot/competitions/editor/_phases.tag +++ b/src/static/riot/competitions/editor/_phases.tag @@ -197,6 +197,15 @@
+
+
+ + +
+