From 45b1f787b152d4fbb547eb622b6b5ec0c51a4f37 Mon Sep 17 00:00:00 2001 From: Jacek Lebioda Date: Wed, 6 Jul 2022 15:51:56 +0200 Subject: [PATCH 1/7] feat: only local custodians can delete the document --- core/models/data_declaration.py | 1 - core/models/document.py | 12 ++++++++++++ web/views/documents.py | 7 ++++++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/core/models/data_declaration.py b/core/models/data_declaration.py index e8c3ead8..615f2722 100644 --- a/core/models/data_declaration.py +++ b/core/models/data_declaration.py @@ -114,7 +114,6 @@ class Meta: null=False, help_text='How has the data been de-identified, is it pseudonymized or anonymized?') - embargo_date = models.DateField(verbose_name='Embargo date', blank=True, null=True, diff --git a/core/models/document.py b/core/models/document.py index 2eeba9a4..534ca306 100644 --- a/core/models/document.py +++ b/core/models/document.py @@ -72,6 +72,18 @@ def shortname(self): def size(self): return self.content.size + def can_user_delete(self, user): + # Don't allow people who are not local custodians to delete + if self.contracts.count(): + for contract in self.contracts.all(): + if user in contract.local_custodians.all(): + return True + if self.projects.count(): + for project in self.projects.all(): + if user in project.local_custodians.all(): + return True + return False + @receiver(post_delete, sender=Document, dispatch_uid='document_delete') def document_cleanup(sender, instance, **kwargs): if hasattr(instance.content, 'path') and os.path.exists(instance.content.path): diff --git a/web/views/documents.py b/web/views/documents.py index d28ecfc7..a9a1d354 100644 --- a/web/views/documents.py +++ b/web/views/documents.py @@ -98,13 +98,18 @@ def download_document(request, pk): @permission_required(Permissions.PROTECTED, (Document, 'pk', 'pk')) def delete_document(request, pk): document = get_object_or_404(Document, pk=pk) + + if not request.user.is_superuser and not document.can_user_delete(request.user): + msg = 'you are not a local custodian of the project/contract related to this document' + return JsonResponse({'message': msg}, status=403) + # perm = PERMISSION_MAPPING[document.content_type.name].DELETE.value # if not request.user.has_perm(perm, document.content_object): # raise PermissionDenied try: document.delete() except Exception as e: - return JsonResponse({'message': str(e)}) + return JsonResponse({'message': str(e)}, status=403) return JsonResponse({'message': 'document deleted'}) From ee0083242fc56bfee8cc826f3c545d3c746ca0d4 Mon Sep 17 00:00:00 2001 From: Vilem Ded Date: Thu, 7 Jul 2022 08:42:12 +0200 Subject: [PATCH 2/7] feat: upload document requires PROTECTED premission --- web/views/documents.py | 1 + 1 file changed, 1 insertion(+) diff --git a/web/views/documents.py b/web/views/documents.py index a9a1d354..f24ebb8f 100644 --- a/web/views/documents.py +++ b/web/views/documents.py @@ -26,6 +26,7 @@ def rfc5987_content_disposition(file_name): return header +@permission_required(Permissions.PROTECTED, (Document, 'pk', 'pk')) def upload_document(request, object_id, content_type): log.debug('uploading document', post=request.POST, files=request.FILES) if request.method == 'POST': From d1912dfd9826845b3bf3080297eaccd3ec3846ff Mon Sep 17 00:00:00 2001 From: Vilem Ded Date: Thu, 7 Jul 2022 09:08:56 +0200 Subject: [PATCH 3/7] feat: AUDITORS cannot delete document --- web/views/documents.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/views/documents.py b/web/views/documents.py index f24ebb8f..396f83bf 100644 --- a/web/views/documents.py +++ b/web/views/documents.py @@ -7,7 +7,7 @@ from django.utils.http import urlquote from django.views.decorators.http import require_http_methods from django.contrib import messages -from core.constants import Permissions +from core.constants import Permissions, Groups from core.forms import DocumentForm from core.models import Document from core.permissions import permission_required @@ -100,8 +100,8 @@ def download_document(request, pk): def delete_document(request, pk): document = get_object_or_404(Document, pk=pk) - if not request.user.is_superuser and not document.can_user_delete(request.user): - msg = 'you are not a local custodian of the project/contract related to this document' + if request.user.is_part_of(Groups.AUDITOR.value): + msg = 'You cannot delete document as AUDITOR.' return JsonResponse({'message': msg}, status=403) # perm = PERMISSION_MAPPING[document.content_type.name].DELETE.value From 0af99cc1c31026aa28a6be95821b01bcf9adf636 Mon Sep 17 00:00:00 2001 From: Vilem Ded Date: Thu, 7 Jul 2022 09:09:14 +0200 Subject: [PATCH 4/7] feat: AUDITORS cannot upload document --- web/views/documents.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/web/views/documents.py b/web/views/documents.py index 396f83bf..117376f6 100644 --- a/web/views/documents.py +++ b/web/views/documents.py @@ -29,6 +29,11 @@ def rfc5987_content_disposition(file_name): @permission_required(Permissions.PROTECTED, (Document, 'pk', 'pk')) def upload_document(request, object_id, content_type): log.debug('uploading document', post=request.POST, files=request.FILES) + + if request.user.is_part_of(Groups.AUDITOR.value): + msg = 'You cannot upload document as AUDITOR.' + return JsonResponse({'message': msg}, status=403) + if request.method == 'POST': print(object_id, content_type) if not request.FILES: From 79fad63a655e44a016d00e32e7bcdc41b2c7e4ce Mon Sep 17 00:00:00 2001 From: Vilem Ded Date: Thu, 7 Jul 2022 10:46:57 +0200 Subject: [PATCH 5/7] fix: document upload validation is done using content type checker --- web/views/documents.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/views/documents.py b/web/views/documents.py index 117376f6..62bd5092 100644 --- a/web/views/documents.py +++ b/web/views/documents.py @@ -10,7 +10,7 @@ from core.constants import Permissions, Groups from core.forms import DocumentForm from core.models import Document -from core.permissions import permission_required +from core.permissions import permission_required, permission_required_from_content_type from core.utils import DaisyLogger @@ -26,7 +26,7 @@ def rfc5987_content_disposition(file_name): return header -@permission_required(Permissions.PROTECTED, (Document, 'pk', 'pk')) +@permission_required_from_content_type(Permissions.PROTECTED, content_type_attr='content_type', object_id_attr='object_id') def upload_document(request, object_id, content_type): log.debug('uploading document', post=request.POST, files=request.FILES) From b2b31d26d1c53cfa65f9e1de4e66ce9737e78873 Mon Sep 17 00:00:00 2001 From: Vilem Ded Date: Thu, 7 Jul 2022 11:17:43 +0200 Subject: [PATCH 6/7] refactor: remove unused function --- core/models/document.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/core/models/document.py b/core/models/document.py index 534ca306..adb30318 100644 --- a/core/models/document.py +++ b/core/models/document.py @@ -72,17 +72,6 @@ def shortname(self): def size(self): return self.content.size - def can_user_delete(self, user): - # Don't allow people who are not local custodians to delete - if self.contracts.count(): - for contract in self.contracts.all(): - if user in contract.local_custodians.all(): - return True - if self.projects.count(): - for project in self.projects.all(): - if user in project.local_custodians.all(): - return True - return False @receiver(post_delete, sender=Document, dispatch_uid='document_delete') def document_cleanup(sender, instance, **kwargs): From bccb967980933ec7d41c2e81cfde5324e5a86e9a Mon Sep 17 00:00:00 2001 From: Vilem Ded Date: Thu, 7 Jul 2022 11:26:09 +0200 Subject: [PATCH 7/7] fix: EDIT permission is required to upload or delete document --- web/views/documents.py | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/web/views/documents.py b/web/views/documents.py index 62bd5092..e919c432 100644 --- a/web/views/documents.py +++ b/web/views/documents.py @@ -7,7 +7,7 @@ from django.utils.http import urlquote from django.views.decorators.http import require_http_methods from django.contrib import messages -from core.constants import Permissions, Groups +from core.constants import Permissions from core.forms import DocumentForm from core.models import Document from core.permissions import permission_required, permission_required_from_content_type @@ -27,13 +27,9 @@ def rfc5987_content_disposition(file_name): @permission_required_from_content_type(Permissions.PROTECTED, content_type_attr='content_type', object_id_attr='object_id') +@permission_required_from_content_type(Permissions.EDIT, content_type_attr='content_type', object_id_attr='object_id') def upload_document(request, object_id, content_type): log.debug('uploading document', post=request.POST, files=request.FILES) - - if request.user.is_part_of(Groups.AUDITOR.value): - msg = 'You cannot upload document as AUDITOR.' - return JsonResponse({'message': msg}, status=403) - if request.method == 'POST': print(object_id, content_type) if not request.FILES: @@ -102,13 +98,9 @@ def download_document(request, pk): @require_http_methods(["DELETE"]) @permission_required(Permissions.PROTECTED, (Document, 'pk', 'pk')) +@permission_required(Permissions.EDIT, (Document, 'pk', 'pk')) def delete_document(request, pk): document = get_object_or_404(Document, pk=pk) - - if request.user.is_part_of(Groups.AUDITOR.value): - msg = 'You cannot delete document as AUDITOR.' - return JsonResponse({'message': msg}, status=403) - # perm = PERMISSION_MAPPING[document.content_type.name].DELETE.value # if not request.user.has_perm(perm, document.content_object): # raise PermissionDenied