diff --git a/src/apps/api/serializers/tasks.py b/src/apps/api/serializers/tasks.py index 35dcfe66a..7cf13d1cc 100644 --- a/src/apps/api/serializers/tasks.py +++ b/src/apps/api/serializers/tasks.py @@ -1,7 +1,5 @@ from drf_writable_nested import WritableNestedModelSerializer from rest_framework import serializers -from rest_framework.exceptions import ValidationError - from api.mixins import DefaultUserCreateMixin from api.serializers.datasets import DataDetailSerializer, DataSimpleSerializer from competitions.models import PhaseTaskInstance, Phase @@ -79,12 +77,6 @@ class Meta: 'created_by', ) - def validate_is_public(self, is_public): - validated = Task.objects.get(id=self.instance.id)._validated - if is_public and not validated: - raise ValidationError('Task must be validated before it can be published') - return is_public - def get_validated(self, instance): return hasattr(instance, 'validated') and instance.validated is not None @@ -107,7 +99,6 @@ class Meta: 'id', 'name', 'description', - 'key', 'created_by', 'owner_display_name', 'created_when', @@ -124,6 +115,9 @@ class Meta: 'solutions', ) + def get_validated(self, instance): + return hasattr(instance, 'validated') and instance.validated is not None + def get_competitions(self, instance): # Fech competitions which hase phases with this task @@ -132,11 +126,10 @@ def get_competitions(self, instance): return competitions - def get_validated(self, task): - return task.validated is not None - def get_shared_with(self, instance): - return self.context['shared_with'][instance.pk] + # Fetch the users with whom the task is shared + shared_users = instance.shared_with.all() + return [user.username for user in shared_users] def get_owner_display_name(self, instance): # Get the user's display name if not None, otherwise return username diff --git a/src/apps/api/views/tasks.py b/src/apps/api/views/tasks.py index 71bfb59bd..385c4a8a5 100644 --- a/src/apps/api/views/tasks.py +++ b/src/apps/api/views/tasks.py @@ -42,7 +42,11 @@ def get_queryset(self): ) task_filter = Q(created_by=self.request.user) | Q(shared_with=self.request.user) - if self.request.query_params.get('public'): + # when there is `public` in the query params, it means user has checked on the front-end + # the Show public tasks checkbox. + # When a user clicks that public task that may not belong to the user, we want to show + # the public task to the user and hence we check the `retrieve` action + if self.request.query_params.get('public') or self.action == 'retrieve': task_filter |= Q(is_public=True) qs = qs.filter(task_filter) @@ -92,19 +96,34 @@ def update(self, request, *args, **kwargs): if request.user != task.created_by and not request.user.is_superuser: raise PermissionDenied("Cannot update a task that is not yours") - # If the key is not in the request data, set the corresponding field to None - # No condition for scoring program because a task must have a scoring program - if "ingestion_program" not in request.data: - task.ingestion_program = None - if "input_data" not in request.data: - task.input_data = None - if "reference_data" not in request.data: - task.reference_data = None - - # Save the task to apply the changes - task.save() - - return super().update(request, *args, **kwargs) + # Check if 'is_public' is sent in the data + # This means that from the front end the update is_public api is calle + # with `is_public` in the data + if 'is_public' in request.data: + # Perform the update using the parent class's update method + super().update(request, *args, **kwargs) + else: + # If the key is not in the request data, set the corresponding field to None + # No condition for scoring program because a task must have a scoring program + if "ingestion_program" not in request.data: + task.ingestion_program = None + if "input_data" not in request.data: + task.input_data = None + if "reference_data" not in request.data: + task.reference_data = None + + # Save the task to apply the changes + task.save() + super().update(request, *args, **kwargs) + + # Fetch the updated task from the database to ensure it reflects all changes + task.refresh_from_db() + + # Serialize the updated task using TaskDetailSerializer + task_detail_serializer = serializers.TaskSerializer(task) + + # Return the serialized data as a response + return Response(task_detail_serializer.data) def destroy(self, request, *args, **kwargs): instance = self.get_object() diff --git a/src/apps/tasks/models.py b/src/apps/tasks/models.py index 3b38efe9b..c93d2b60a 100644 --- a/src/apps/tasks/models.py +++ b/src/apps/tasks/models.py @@ -66,10 +66,6 @@ def get_chahub_data(self, include_solutions=True): data['solutions'] = [solution.get_chahub_data(include_tasks=False) for solution in self.solutions.all()] return self.clean_private_data(data) - def save(self, *args, **kwargs): - self.is_public = self.is_public and self._validated - return super().save(*args, **kwargs) - class Solution(ChaHubSaveMixin, models.Model): name = models.CharField(max_length=256) diff --git a/src/static/riot/competitions/editor/_phases.tag b/src/static/riot/competitions/editor/_phases.tag index 371d7a3e6..e7d5a98fe 100644 --- a/src/static/riot/competitions/editor/_phases.tag +++ b/src/static/riot/competitions/editor/_phases.tag @@ -216,7 +216,7 @@ // semantic multiselect $(self.refs.multiselect).dropdown({ apiSettings: { - url: `${URLS.API}tasks/?search={query}`, + url: `${URLS.API}tasks/?public=true&search={query}`, cache: false, onResponse: (data) => { return {success: true, results: _.values(data.results)} diff --git a/src/static/riot/tasks/management.tag b/src/static/riot/tasks/management.tag index 927bdad3b..5f6cb1cc7 100644 --- a/src/static/riot/tasks/management.tag +++ b/src/static/riot/tasks/management.tag @@ -114,7 +114,8 @@ : {selected_task.validated ? "Yes" : "No"}