From 8c8bbe869c50f1d7e8f486fb358b9920feb632ef Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Wed, 3 Apr 2019 12:01:07 -0400 Subject: [PATCH] Fixed contours and popup assets in shared tasks --- app/api/tasks.py | 22 +++++++++++++++++----- app/api/urls.py | 4 +++- app/tests/test_api_task.py | 13 +++++++++---- plugins/contours/public/ContoursPanel.jsx | 2 +- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/app/api/tasks.py b/app/api/tasks.py index 0cf51e66..ce0cfa92 100644 --- a/app/api/tasks.py +++ b/app/api/tasks.py @@ -77,12 +77,23 @@ class TaskViewSet(viewsets.ViewSet): """ queryset = models.Task.objects.all().defer('orthophoto_extent', 'dsm_extent', 'dtm_extent', 'console_output', ) - # We don't use object level permissions on tasks, relying on - # project's object permissions instead (but standard model permissions still apply) - permission_classes = (permissions.DjangoModelPermissions, ) parser_classes = (parsers.MultiPartParser, parsers.JSONParser, parsers.FormParser, ) ordering_fields = '__all__' + def get_permissions(self): + """ + Instantiates and returns the list of permissions that this view requires. + We don't use object level permissions on tasks, relying on + project's object permissions instead (but standard model permissions still apply) + and with the exception of 'retrieve' (task GET) for public tasks access + """ + if self.action == 'retrieve': + permission_classes = [permissions.AllowAny] + else: + permission_classes = [permissions.DjangoModelPermissions, ] + + return [permission() for permission in permission_classes] + def set_pending_action(self, pending_action, request, pk=None, project_pk=None, perms=('change_project', )): get_and_check_project(request, project_pk, perms) try: @@ -128,7 +139,6 @@ class TaskViewSet(viewsets.ViewSet): output = task.console_output or "" return Response('\n'.join(output.rstrip().split('\n')[line_num:])) - def list(self, request, project_pk=None): get_and_check_project(request, project_pk) tasks = self.queryset.filter(project=project_pk) @@ -137,12 +147,14 @@ class TaskViewSet(viewsets.ViewSet): return Response(serializer.data) def retrieve(self, request, pk=None, project_pk=None): - get_and_check_project(request, project_pk) try: task = self.queryset.get(pk=pk, project=project_pk) except (ObjectDoesNotExist, ValidationError): raise exceptions.NotFound() + if not task.public: + get_and_check_project(request, task.project.id) + serializer = TaskSerializer(task) return Response(serializer.data) diff --git a/app/api/urls.py b/app/api/urls.py index 16b15609..de462cb2 100644 --- a/app/api/urls.py +++ b/app/api/urls.py @@ -2,7 +2,6 @@ from django.conf.urls import url, include from app.api.presets import PresetViewSet from app.plugins import get_api_url_patterns -from webodm import settings from .projects import ProjectViewSet from .tasks import TaskViewSet, TaskTiles, TaskTilesJson, TaskDownloads, TaskAssets, TaskAssetsImport from .processingnodes import ProcessingNodeViewSet, ProcessingNodeOptionsView @@ -22,8 +21,11 @@ urlpatterns = [ url(r'processingnodes/options/$', ProcessingNodeOptionsView.as_view()), url(r'^', include(router.urls)), + url(r'^', include(tasks_router.urls)), + # url(r'projects/(?P[^/.]+)/tasks/(?P[^/.]+)/', TaskGet.as_view()), + url(r'projects/(?P[^/.]+)/tasks/(?P[^/.]+)/(?Porthophoto|dsm|dtm)/tiles/(?P[\d]+)/(?P[\d]+)/(?P[\d]+)\.png$', TaskTiles.as_view()), url(r'projects/(?P[^/.]+)/tasks/(?P[^/.]+)/(?Porthophoto|dsm|dtm)/tiles\.json$', TaskTilesJson.as_view()), url(r'projects/(?P[^/.]+)/tasks/(?P[^/.]+)/download/(?P.+)$', TaskDownloads.as_view()), diff --git a/app/tests/test_api_task.py b/app/tests/test_api_task.py index 7a93bd58..3474da57 100644 --- a/app/tests/test_api_task.py +++ b/app/tests/test_api_task.py @@ -371,6 +371,9 @@ class TestApiTask(BootTransactionTestCase): res = other_client.get("/api/projects/{}/tasks/{}/{}/tiles/16/16020/42443.png".format(project.id, task.id, tile_type)) self.assertTrue(res.status_code == expectedStatus) + res = other_client.get("/api/projects/{}/tasks/{}/".format(project.id, task.id)) + self.assertTrue(res.status_code == expectedStatus) + accessResources(status.HTTP_404_NOT_FOUND) # Original owner enables sharing @@ -382,16 +385,18 @@ class TestApiTask(BootTransactionTestCase): # Now other user can acccess resources accessResources(status.HTTP_200_OK) + # He cannot change a task + res = other_client.patch("/api/projects/{}/tasks/{}/".format(project.id, task.id), { + 'name': "Changed! Uh oh" + }) + self.assertEqual(res.status_code, status.HTTP_404_NOT_FOUND) + # User logs out other_client.logout() # He can still access the resources as anonymous accessResources(status.HTTP_200_OK) - # Other user still does not have access to certain parts of the API - res = other_client.get("/api/projects/{}/tasks/{}/".format(project.id, task.id)) - self.assertTrue(res.status_code == status.HTTP_403_FORBIDDEN) - # Restart a task testWatch.clear() res = client.post("/api/projects/{}/tasks/{}/restart/".format(project.id, task.id)) diff --git a/plugins/contours/public/ContoursPanel.jsx b/plugins/contours/public/ContoursPanel.jsx index aee0b8e7..0855ec29 100644 --- a/plugins/contours/public/ContoursPanel.jsx +++ b/plugins/contours/public/ContoursPanel.jsx @@ -56,7 +56,7 @@ export default class ContoursPanel extends React.Component { } }) .fail(() => { - this.setState({permanentError: `Cannot retrieve information for task ${id}. Are you are connected to the internet.`}) + this.setState({permanentError: `Cannot retrieve information for task ${id}. Are you are connected to the internet?`}) }) .always(() => { this.setState({loading: false});