Skip to content

Commit

Permalink
Public tasks -- updates to ensure public tasks can be viewed and used (
Browse files Browse the repository at this point in the history
…#1581)

* condition removed to make tasks public when they are validated

* Removed key from front-end. Removed validated condition to show making task public/private buttion. Updated task update method to enable updating is_public status. Once a task is_public was updated, the response was not serialized, now fixed. Removed key from the task detail serializer. Modified validated and shared with methods to return correct responses. Added is_public to TaskListSerializer to show checkmark in the tasks list table.

* Taskview set updated to add a condition for showing public task details from other users

* In edit competition, now users can select a public task in their phases

* condition added to show make task public/private to owners of the tasks only

* Remove unused import from tasks.py

* reversed the change of task validation

* task update failure fixed by using TaskSerializer, get_validated function updated to not raise error in the future

---------

Co-authored-by: Adrien Pavão <[email protected]>
  • Loading branch information
ihsaan-ullah and Didayolo authored Oct 25, 2024
1 parent 231fe22 commit 1bd7c6f
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 33 deletions.
19 changes: 6 additions & 13 deletions src/apps/api/serializers/tasks.py
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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

Expand All @@ -107,7 +99,6 @@ class Meta:
'id',
'name',
'description',
'key',
'created_by',
'owner_display_name',
'created_when',
Expand All @@ -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
Expand All @@ -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
Expand Down
47 changes: 33 additions & 14 deletions src/apps/api/views/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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()
Expand Down
4 changes: 0 additions & 4 deletions src/apps/tasks/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/static/riot/competitions/editor/_phases.tag
Original file line number Diff line number Diff line change
Expand Up @@ -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)}
Expand Down
3 changes: 2 additions & 1 deletion src/static/riot/tasks/management.tag
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@
<i class="question circle icon"></i>
</span>:</strong> {selected_task.validated ? "Yes" : "No"}</div>
<div><strong>Is Public:</strong> {selected_task.is_public ? "Yes" : "No"}</div>
<div if="{selected_task.validated}"
<div
if="{selected_task.created_by === CODALAB.state.user.username}"
class="ui right floated small green icon button"
onclick="{toggle_task_is_public}">
<i class="share icon"></i> {selected_task.is_public ? 'Make Private' : 'Make Public'}
Expand Down

0 comments on commit 1bd7c6f

Please sign in to comment.