From adf14da76114ef230d40655edde6576ba0ee69b8 Mon Sep 17 00:00:00 2001 From: Aleks <152979255+a1eksb@users.noreply.github.com> Date: Tue, 2 Jul 2024 16:07:07 +0200 Subject: [PATCH 01/11] [ FEAT ]: Add support for file uploads without owner --- api/django-common/django_common/models.py | 2 +- .../django_fileupload/admin.py | 4 +-- .../django_fileupload/apps.py | 1 + .../0007_alter_fileuploadbatch_owner.py | 26 +++++++++++++++++++ .../django_fileupload/views.py | 6 ++++- 5 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 api/django-fileupload/django_fileupload/migrations/0007_alter_fileuploadbatch_owner.py diff --git a/api/django-common/django_common/models.py b/api/django-common/django_common/models.py index 1328161..8bb1bdb 100644 --- a/api/django-common/django_common/models.py +++ b/api/django-common/django_common/models.py @@ -22,7 +22,7 @@ class OwnedModel(models.Model): A model that has a relationship to the owner in the user model. """ - owner = models.ForeignKey(get_user_model(), on_delete=models.RESTRICT) + owner = models.ForeignKey(get_user_model(), on_delete=models.RESTRICT, null=True, blank=True) class Meta: abstract = True diff --git a/api/django-fileupload/django_fileupload/admin.py b/api/django-fileupload/django_fileupload/admin.py index 76a312c..68f5867 100644 --- a/api/django-fileupload/django_fileupload/admin.py +++ b/api/django-fileupload/django_fileupload/admin.py @@ -18,12 +18,12 @@ def hr_size(self, file_upload: FileUpload): hr_size.short_description = "Size" def uploaded_on(self, file_upload: FileUpload): - return dt.strftime(file_upload.batch.uploaded_on, DATE_TIME_FORMAT) + return dt.strftime(file_upload.file_upload_batch.uploaded_on, DATE_TIME_FORMAT) uploaded_on.short_description = "Uploaded on" def uploaded_by(self, file_upload: FileUpload): - return file_upload.batch.owner + return file_upload.file_upload_batch.owner uploaded_by.short_description = "Uploaded by" diff --git a/api/django-fileupload/django_fileupload/apps.py b/api/django-fileupload/django_fileupload/apps.py index 0e0fdd1..a77d459 100644 --- a/api/django-fileupload/django_fileupload/apps.py +++ b/api/django-fileupload/django_fileupload/apps.py @@ -3,3 +3,4 @@ class CoreConfig(AppConfig): name = "django_fileupload" + verbose_name = "File Uploads" diff --git a/api/django-fileupload/django_fileupload/migrations/0007_alter_fileuploadbatch_owner.py b/api/django-fileupload/django_fileupload/migrations/0007_alter_fileuploadbatch_owner.py new file mode 100644 index 0000000..33fdb4a --- /dev/null +++ b/api/django-fileupload/django_fileupload/migrations/0007_alter_fileuploadbatch_owner.py @@ -0,0 +1,26 @@ +# Generated by Django 5.0 on 2024-07-02 13:16 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("django_fileupload", "0006_rename_mime_type_fileupload_detected_mime_type"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.AlterField( + model_name="fileuploadbatch", + name="owner", + field=models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.RESTRICT, + to=settings.AUTH_USER_MODEL, + ), + ), + ] diff --git a/api/django-fileupload/django_fileupload/views.py b/api/django-fileupload/django_fileupload/views.py index 2fc5ff7..b1648d2 100644 --- a/api/django-fileupload/django_fileupload/views.py +++ b/api/django-fileupload/django_fileupload/views.py @@ -26,6 +26,7 @@ class FileUploadBatchViewSet( queryset = FileUploadBatch.objects.all() serializer_class = FileUploadBatchSerializer parser_classes = (MultiPartParser,) + has_owner = True # Workaround for "drf-yasg" (see https://github.com/axnsan12/drf-yasg/issues/503). def get_serializer_class(self): @@ -59,7 +60,10 @@ def create(self, request, *args, **kwargs): raise ValidationError(_("Files with incorrect extension in the request.")) response = [] with exclusive_insert_table_lock(FileUploadBatch): - file_upload_batch = FileUploadBatch.objects.create(owner=request.user) + if self.has_owner: + file_upload_batch = FileUploadBatch.objects.create(owner=request.user) + else: + file_upload_batch = FileUploadBatch.objects.create() # Metadata needs to be added here as FileUpload.objects.create(...) may depend on it. self.add_metadata(request, file_upload_batch) for file_position, file in enumerate(files): From b6f1ee106d8a25675ff31b7ca6da816b7f9bdc69 Mon Sep 17 00:00:00 2001 From: Aleks <152979255+a1eksb@users.noreply.github.com> Date: Thu, 4 Jul 2024 21:44:54 +0200 Subject: [PATCH 02/11] [ FEAT ]: Add keep after deletion option for file deletions --- .../django_fileupload/admin.py | 12 ++++++++++-- .../migrations/0008_fileupload_deleted_on.py | 18 ++++++++++++++++++ .../django_fileupload/models.py | 1 + .../django_fileupload/views.py | 12 ++++++++++++ 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 api/django-fileupload/django_fileupload/migrations/0008_fileupload_deleted_on.py diff --git a/api/django-fileupload/django_fileupload/admin.py b/api/django-fileupload/django_fileupload/admin.py index 68f5867..ee63bc5 100644 --- a/api/django-fileupload/django_fileupload/admin.py +++ b/api/django-fileupload/django_fileupload/admin.py @@ -9,8 +9,8 @@ class FileUploadAdmin(admin.ModelAdmin): - list_display = ("name", "uploaded_by", "uploaded_on", "detected_mime_type", "hr_size", "checksum") - readonly_fields = ("file_upload_batch", "position", "file", "detected_mime_type", "checksum") + list_display = ("name", "uploaded_by", "uploaded_on", "deleted_on", "detected_mime_type", "hr_size", "checksum") + readonly_fields = ("deleted_on", "file_upload_batch", "position", "file", "detected_mime_type", "checksum") def hr_size(self, file_upload: FileUpload): return hr_size(file_upload.size) @@ -22,6 +22,14 @@ def uploaded_on(self, file_upload: FileUpload): uploaded_on.short_description = "Uploaded on" + def deleted_on(self, file_upload: FileUpload): + if file_upload.deleted_on: + return dt.strftime(file_upload.deleted_on, DATE_TIME_FORMAT) + else: + return "Not deleted" + + deleted_on.short_description = "Deleted on" + def uploaded_by(self, file_upload: FileUpload): return file_upload.file_upload_batch.owner diff --git a/api/django-fileupload/django_fileupload/migrations/0008_fileupload_deleted_on.py b/api/django-fileupload/django_fileupload/migrations/0008_fileupload_deleted_on.py new file mode 100644 index 0000000..1f21316 --- /dev/null +++ b/api/django-fileupload/django_fileupload/migrations/0008_fileupload_deleted_on.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0 on 2024-07-04 19:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("django_fileupload", "0007_alter_fileuploadbatch_owner"), + ] + + operations = [ + migrations.AddField( + model_name="fileupload", + name="deleted_on", + field=models.DateTimeField(editable=False, null=True), + ), + ] diff --git a/api/django-fileupload/django_fileupload/models.py b/api/django-fileupload/django_fileupload/models.py index 9c9ae6d..fb40058 100644 --- a/api/django-fileupload/django_fileupload/models.py +++ b/api/django-fileupload/django_fileupload/models.py @@ -50,6 +50,7 @@ class FileUpload(models.Model): file = models.FileField(upload_to=_generate_complete_file_path, storage=FileUploadFileStorage()) detected_mime_type = models.CharField(max_length=100, editable=False) checksum = models.CharField(max_length=64, editable=False) + deleted_on = models.DateTimeField(null=True, editable=False) def __str__(self): return self.file.path diff --git a/api/django-fileupload/django_fileupload/views.py b/api/django-fileupload/django_fileupload/views.py index b1648d2..59f7b97 100644 --- a/api/django-fileupload/django_fileupload/views.py +++ b/api/django-fileupload/django_fileupload/views.py @@ -9,6 +9,7 @@ from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response from rest_framework.serializers import ValidationError +from django.utils import timezone from django_common.postgresql import exclusive_insert_table_lock from django_common.renderers import PassthroughRenderer @@ -100,4 +101,15 @@ class FileUploadViewSet( mixins.DestroyModelMixin, viewsets.GenericViewSet, ): + keep_after_deletion = False + + def destroy(self, request, *args, **kwargs): + file_upload = self.get_object() + if self.keep_after_deletion: + file_upload.deleted_on = timezone.now() + file_upload.save() + else: + file_upload.delete() + + return Response(status=status.HTTP_204_NO_CONTENT) pass From f8640d8bee82ef4421198fd5336e2658b04446b6 Mon Sep 17 00:00:00 2001 From: Aleks <152979255+a1eksb@users.noreply.github.com> Date: Wed, 10 Jul 2024 17:58:23 +0200 Subject: [PATCH 03/11] [ FEAT ]: Add deleted_on field in the FileUploadSerializer --- api/django-fileupload/django_fileupload/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/django-fileupload/django_fileupload/serializers.py b/api/django-fileupload/django_fileupload/serializers.py index 08d6ade..ffb503c 100644 --- a/api/django-fileupload/django_fileupload/serializers.py +++ b/api/django-fileupload/django_fileupload/serializers.py @@ -10,7 +10,7 @@ class FileUploadSerializer(serializers.ModelSerializer): class Meta: model = FileUpload - fields = ("id", "name", "checksum") + fields = ("id", "name", "checksum", "deleted_on") class FileUploadBatchSerializer(serializers.ModelSerializer): From 60a3f507b924efd2a087b86e375cf10fbbe1273a Mon Sep 17 00:00:00 2001 From: Aleks <152979255+a1eksb@users.noreply.github.com> Date: Wed, 10 Jul 2024 17:58:56 +0200 Subject: [PATCH 04/11] [ FEAT ]: Add option to configure max_file_size --- api/django-fileupload/django_fileupload/views.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/api/django-fileupload/django_fileupload/views.py b/api/django-fileupload/django_fileupload/views.py index 59f7b97..4ba56f9 100644 --- a/api/django-fileupload/django_fileupload/views.py +++ b/api/django-fileupload/django_fileupload/views.py @@ -28,6 +28,8 @@ class FileUploadBatchViewSet( serializer_class = FileUploadBatchSerializer parser_classes = (MultiPartParser,) has_owner = True + # Maximum file size in bytes. For example 5 * 1024 * 1024 is 5 MB. + max_file_size = None # Workaround for "drf-yasg" (see https://github.com/axnsan12/drf-yasg/issues/503). def get_serializer_class(self): @@ -52,6 +54,10 @@ def create(self, request, *args, **kwargs): files = request.FILES.getlist("files") if self.verify_file_count(request, len(files)): for file_position, file in enumerate(files): + + if self.max_file_size and file.size > self.max_file_size: + raise ValidationError(_(f"File size exceeds the maximum allowed size of {self.max_file_size / (1024 ** 2)} MB.")) + file_name_parts = os.path.splitext(file.name) if self.verify_file_extension(request, file_position, file_name_parts): if self.verify_file_checksum(request, file_position, file_name_parts, From 7344fd6fa368a5844175751e10325aaa11d4af0f Mon Sep 17 00:00:00 2001 From: Aleks <152979255+a1eksb@users.noreply.github.com> Date: Mon, 15 Jul 2024 17:48:14 +0200 Subject: [PATCH 05/11] [ DEP ]: Remove token from download script --- download.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/download.sh b/download.sh index f82439a..54410bb 100755 --- a/download.sh +++ b/download.sh @@ -4,7 +4,7 @@ set -euo pipefail readonly nexus_app_stack_contrib_path="/nexus-app-stack-contrib" -git clone -n --depth=1 --filter=tree:0 https://"$TOKEN"@$(echo "$BRANCH" | sed -r 's/@([a-z]+)$/ -b \1/') $nexus_app_stack_contrib_path +git clone -n --depth=1 --filter=tree:0 https://$(echo "$BRANCH" | sed -r 's/@([a-z]+)$/ -b \1/') $nexus_app_stack_contrib_path cd $nexus_app_stack_contrib_path From 9cc1aabe41c1cf94287fd6572d1065ad51b501ba Mon Sep 17 00:00:00 2001 From: Aleks <152979255+a1eksb@users.noreply.github.com> Date: Fri, 19 Jul 2024 17:45:54 +0200 Subject: [PATCH 06/11] [ DOC ]: Initial documentation --- .github/workflows/main.yml | 29 ++++++ docker-compose.yml | 9 ++ docs/Dockerfile | 4 + docs/docs/.pages | 5 ++ docs/docs/assets/logo.png | Bin 0 -> 73457 bytes docs/docs/django_apps/.pages | 4 + docs/docs/django_apps/file_upload.md | 10 +++ docs/docs/django_apps/index.md | 1 + docs/docs/django_apps/notifications.md | 10 +++ docs/docs/index.md | 7 ++ docs/docs/setup.md | 119 +++++++++++++++++++++++++ docs/docs/stylesheets/extra.css | 16 ++++ docs/docs/vue_components/index.md | 1 + docs/mkdocs.yml | 75 ++++++++++++++++ 14 files changed, 290 insertions(+) create mode 100644 .github/workflows/main.yml create mode 100644 docker-compose.yml create mode 100644 docs/Dockerfile create mode 100644 docs/docs/.pages create mode 100644 docs/docs/assets/logo.png create mode 100644 docs/docs/django_apps/.pages create mode 100644 docs/docs/django_apps/file_upload.md create mode 100644 docs/docs/django_apps/index.md create mode 100644 docs/docs/django_apps/notifications.md create mode 100644 docs/docs/index.md create mode 100644 docs/docs/setup.md create mode 100644 docs/docs/stylesheets/extra.css create mode 100644 docs/docs/vue_components/index.md create mode 100644 docs/mkdocs.yml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..87e1cbe --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,29 @@ +name: Documentation deployment workflow + +on: + push: + branches: + - main + paths: + - docs/**/* + pull_request: + branches: + - main + paths: + - docs/**/* + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Install curl + run: sudo apt-get update && sudo apt-get install -y curl + + - name: Deploying the docs + run: | + echo "Deploying the docs" + curl --request POST ${{ secrets.ACINT_URL }} -H "Content-Type: application/json" -d "{\"action\": \"${{ secrets.ACINT_ACTION }}\", \"token\": \"${{ secrets.ACINT_TOKEN }}\"}" diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..28a9328 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,9 @@ +services: + mkdocs: + build: + context: docs + dockerfile: Dockerfile + ports: + - "8000:8000" + volumes: + - ./docs/:/docs/:z diff --git a/docs/Dockerfile b/docs/Dockerfile new file mode 100644 index 0000000..b4c9cf4 --- /dev/null +++ b/docs/Dockerfile @@ -0,0 +1,4 @@ +FROM squidfunk/mkdocs-material +WORKDIR /docs +COPY ./mkdocs.yml /docs/mkdocs.yml +RUN pip install mkdocs-glightbox mkdocs-awesome-pages-plugin \ No newline at end of file diff --git a/docs/docs/.pages b/docs/docs/.pages new file mode 100644 index 0000000..aa03178 --- /dev/null +++ b/docs/docs/.pages @@ -0,0 +1,5 @@ +nav: + - index.md + - setup.md + - django_apps + - vue_components \ No newline at end of file diff --git a/docs/docs/assets/logo.png b/docs/docs/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..652ca373e04721cf32926c58ad1d921ec07b9610 GIT binary patch literal 73457 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⪙Itx*__da9p# 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 Date: Tue, 6 Aug 2024 17:45:32 +0200 Subject: [PATCH 07/11] [FIX]: Introduce multiple adjustments based on PR comments --- .vscode/settings.json | 2 +- api/django-common/django_common/models.py | 1 + api/django-fileupload/django_fileupload/views.py | 13 ++++++++----- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 232c562..cecc541 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,7 +10,7 @@ "editor.defaultFormatter": "ms-python.black-formatter", "editor.formatOnSave": true, "editor.codeActionsOnSave": { - "source.organizeImports": false + "source.organizeImports": "never" } }, "python.testing.pytestArgs": ["api/app"], diff --git a/api/django-common/django_common/models.py b/api/django-common/django_common/models.py index 8bb1bdb..97ccaee 100644 --- a/api/django-common/django_common/models.py +++ b/api/django-common/django_common/models.py @@ -22,6 +22,7 @@ class OwnedModel(models.Model): A model that has a relationship to the owner in the user model. """ + # Null is allowed for the case that the owner is anonymous. owner = models.ForeignKey(get_user_model(), on_delete=models.RESTRICT, null=True, blank=True) class Meta: diff --git a/api/django-fileupload/django_fileupload/views.py b/api/django-fileupload/django_fileupload/views.py index 4ba56f9..b9982a7 100644 --- a/api/django-fileupload/django_fileupload/views.py +++ b/api/django-fileupload/django_fileupload/views.py @@ -29,7 +29,9 @@ class FileUploadBatchViewSet( parser_classes = (MultiPartParser,) has_owner = True # Maximum file size in bytes. For example 5 * 1024 * 1024 is 5 MB. - max_file_size = None + + def get_max_file_size(self, request): + return None # Workaround for "drf-yasg" (see https://github.com/axnsan12/drf-yasg/issues/503). def get_serializer_class(self): @@ -55,8 +57,8 @@ def create(self, request, *args, **kwargs): if self.verify_file_count(request, len(files)): for file_position, file in enumerate(files): - if self.max_file_size and file.size > self.max_file_size: - raise ValidationError(_(f"File size exceeds the maximum allowed size of {self.max_file_size / (1024 ** 2)} MB.")) + if self.get_max_file_size(request) and file.size > self.get_max_file_size(request): + raise ValidationError(_(f"File size exceeds the maximum allowed size of {self.get_max_file_size(request) / (1024 ** 2)} MB.")) file_name_parts = os.path.splitext(file.name) if self.verify_file_extension(request, file_position, file_name_parts): @@ -107,11 +109,12 @@ class FileUploadViewSet( mixins.DestroyModelMixin, viewsets.GenericViewSet, ): - keep_after_deletion = False + def keep_after_deletion(self): + return False def destroy(self, request, *args, **kwargs): file_upload = self.get_object() - if self.keep_after_deletion: + if self.keep_after_deletion(): file_upload.deleted_on = timezone.now() file_upload.save() else: From 00008f6ba9473a7c686ba6ca3ac023a727ccc586 Mon Sep 17 00:00:00 2001 From: Aleks <152979255+a1eksb@users.noreply.github.com> Date: Tue, 6 Aug 2024 18:56:25 +0200 Subject: [PATCH 08/11] [FIX]: Add enforcement for user model type --- api/django-common/django_common/models.py | 11 +++++++++++ api/django-fileupload/django_fileupload/views.py | 7 +------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/api/django-common/django_common/models.py b/api/django-common/django_common/models.py index 97ccaee..399f287 100644 --- a/api/django-common/django_common/models.py +++ b/api/django-common/django_common/models.py @@ -3,6 +3,8 @@ from django.contrib.auth import get_user_model from django.db import models from django.utils.translation import gettext_lazy as _ +from django.contrib.auth.models import AnonymousUser +from django.core.exceptions import ValidationError def model_with_custom_manager(model_class, manager_instance): @@ -28,6 +30,15 @@ class OwnedModel(models.Model): class Meta: abstract = True + def clean(self): + User = get_user_model() + if not isinstance(self.owner, (User, AnonymousUser)): + raise ValidationError("Owner must be a user or an anonymous user.") + + def save(self, *args, **kwargs): + self.full_clean() # This will call the clean method + super().save(*args, **kwargs) + class Encoding(models.TextChoices): ASCII = "ascii", _("ASCII") diff --git a/api/django-fileupload/django_fileupload/views.py b/api/django-fileupload/django_fileupload/views.py index b9982a7..c9a3701 100644 --- a/api/django-fileupload/django_fileupload/views.py +++ b/api/django-fileupload/django_fileupload/views.py @@ -27,8 +27,6 @@ class FileUploadBatchViewSet( queryset = FileUploadBatch.objects.all() serializer_class = FileUploadBatchSerializer parser_classes = (MultiPartParser,) - has_owner = True - # Maximum file size in bytes. For example 5 * 1024 * 1024 is 5 MB. def get_max_file_size(self, request): return None @@ -69,10 +67,7 @@ def create(self, request, *args, **kwargs): raise ValidationError(_("Files with incorrect extension in the request.")) response = [] with exclusive_insert_table_lock(FileUploadBatch): - if self.has_owner: - file_upload_batch = FileUploadBatch.objects.create(owner=request.user) - else: - file_upload_batch = FileUploadBatch.objects.create() + file_upload_batch = FileUploadBatch.objects.create(owner=request.user) # Metadata needs to be added here as FileUpload.objects.create(...) may depend on it. self.add_metadata(request, file_upload_batch) for file_position, file in enumerate(files): From 16b00f73aa1cef1664d6bab58814e76f23b3fd4e Mon Sep 17 00:00:00 2001 From: Aleks <152979255+a1eksb@users.noreply.github.com> Date: Tue, 6 Aug 2024 22:51:22 +0200 Subject: [PATCH 09/11] [FIX]: Remove anonymous user constraint --- api/django-common/django_common/models.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/api/django-common/django_common/models.py b/api/django-common/django_common/models.py index 399f287..97ccaee 100644 --- a/api/django-common/django_common/models.py +++ b/api/django-common/django_common/models.py @@ -3,8 +3,6 @@ from django.contrib.auth import get_user_model from django.db import models from django.utils.translation import gettext_lazy as _ -from django.contrib.auth.models import AnonymousUser -from django.core.exceptions import ValidationError def model_with_custom_manager(model_class, manager_instance): @@ -30,15 +28,6 @@ class OwnedModel(models.Model): class Meta: abstract = True - def clean(self): - User = get_user_model() - if not isinstance(self.owner, (User, AnonymousUser)): - raise ValidationError("Owner must be a user or an anonymous user.") - - def save(self, *args, **kwargs): - self.full_clean() # This will call the clean method - super().save(*args, **kwargs) - class Encoding(models.TextChoices): ASCII = "ascii", _("ASCII") From 49897870db517b220683b9ce6728828e14e505f1 Mon Sep 17 00:00:00 2001 From: Aleks <152979255+a1eksb@users.noreply.github.com> Date: Tue, 6 Aug 2024 22:59:32 +0200 Subject: [PATCH 10/11] [FEAT]: Reintroduce the has_owner flag --- api/django-fileupload/django_fileupload/views.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/django-fileupload/django_fileupload/views.py b/api/django-fileupload/django_fileupload/views.py index c9a3701..b67e396 100644 --- a/api/django-fileupload/django_fileupload/views.py +++ b/api/django-fileupload/django_fileupload/views.py @@ -27,6 +27,7 @@ class FileUploadBatchViewSet( queryset = FileUploadBatch.objects.all() serializer_class = FileUploadBatchSerializer parser_classes = (MultiPartParser,) + has_owner = True def get_max_file_size(self, request): return None @@ -67,7 +68,10 @@ def create(self, request, *args, **kwargs): raise ValidationError(_("Files with incorrect extension in the request.")) response = [] with exclusive_insert_table_lock(FileUploadBatch): - file_upload_batch = FileUploadBatch.objects.create(owner=request.user) + if self.has_owner: + file_upload_batch = FileUploadBatch.objects.create(owner=request.user) + else: + file_upload_batch = FileUploadBatch.objects.create() # Metadata needs to be added here as FileUpload.objects.create(...) may depend on it. self.add_metadata(request, file_upload_batch) for file_position, file in enumerate(files): From 69cfc4ba319e4610e7b7529c4e269da2f0f9a0b6 Mon Sep 17 00:00:00 2001 From: Aleks <152979255+a1eksb@users.noreply.github.com> Date: Tue, 6 Aug 2024 23:52:09 +0200 Subject: [PATCH 11/11] [DOC]: Add documentation on file upload app --- docs/docs/django_apps/file_upload.md | 99 ++++++++++++++++++++++++++-- docs/docs/django_apps/index.md | 6 +- 2 files changed, 100 insertions(+), 5 deletions(-) diff --git a/docs/docs/django_apps/file_upload.md b/docs/docs/django_apps/file_upload.md index dca6400..980d128 100644 --- a/docs/docs/django_apps/file_upload.md +++ b/docs/docs/django_apps/file_upload.md @@ -3,8 +3,99 @@ title: File Upload App --- ### Features -Describe all the features as well as the class flags +The file upload app enables you to easily handle file uploads in your application. Whenever one or more files are uploaded using the file upload app a single batch entry is created and a set of file entries are created in their respective models. + +The batches keep information about the `owner`, `upload date` and `references to the associated files`. The files, on the other hand, keep information about the `deletion date`, `referece to the file upload batch`, `position in the batch`, `file location`, `file type` and a `checksum`. + +Uploading multiple files with the same name will cause the latest file with that name to be retrieved when retrieving files. Deleting the file will only delete the latest version of the file but the previous versions will be kept and will also be returned. Custom implementations are required to enable a different behavior (for example deleting files by name). + +#### Anonymous Owners +In cases where an owner is not needed you simply extend the FileUploadBatchViewSet and set the `has_owner` property to `False`. This will result in the owner value being set to `None` in the database entries. + +```python title="views.py" +from django_fileupload.views import FileUploadBatchViewSet + +class CustomFileUploadBatchViewSet(FileUploadBatchViewSet): + has_owner = True +``` + +!!! note + + In this case you also have to use your newly defined view class in your route definitions. + + +#### Max File Size +There might be cases where you want to provide a max file upload size per upload request. In such cases you can take a similar approach to the one above but instead of setting a flag you can implement the `get_max_file_size` method. + +```python title="views.py" +from django_fileupload.views import FileUploadBatchViewSet + +class CustomFileUploadBatchViewSet(FileUploadBatchViewSet): + def get_max_file_size(self, request): + + # Extract data from the request object or do some other calculations + + if some_condition: + # The max_file_size is in megabytes + # The get_max_file_size should return bytes or None + return max_file_size * 1024 * 1024 + else: + return None +``` + +!!! warning "Large file protection" + + If a user uploads a very large file, our application may get overwhelmed while checking its size (as it would attempt to load it onto the file system before reading the size). Therefore, we need to introduce additional measures as described below. + +Introduce custom file upload handlers by adding them to your `settings.py` using the following snippet: + +```python title="settings.py" +FILE_UPLOAD_HANDLERS = [ + "django_common.uploadhandlers.HardLimitMemoryFileUploadHandler", + "django_common.uploadhandlers.HardLimitTemporaryFileUploadHandler", +] +``` + +Furthermore, you must set the following argument and environment variable in your backend `Dockerfile`: + +```dockerfile title="api/Dockerfile" +ARG HARD_UPLOAD_SIZE_LIMIT=524288000 +ENV DJANGO_HARD_UPLOAD_SIZE_LIMIT $HARD_UPLOAD_SIZE_LIMIT +``` +This will ensure that there is a global django upper size limit that will prevent users from uploading files larger than it. + +#### Keeping Files After Deletion +To keep files after deletion we must overwrite the method `keep_after_deletion` of the `FileUploadViewSet` class: + +```python title="views.py" +from django_fileupload.views import FileUploadViewSet + +class CustomFileUploadViewSet(FileUploadViewSet): + def keep_after_deletion(self): + return True +``` +!!! info "Listing only files that are not marked as deleted" + + To retrieve only files that have not been marked as deleted you need to provide custom logic in the list method of the FileUploadViewSet class. + + +#### Other Customizations +Other methods of the `FileUploadBatchViewSet` class and the `FileUploadViewSet` class may be overwriten or extended in order to provide more custom behavior and also for providing additional metadata. + ### Setup -Describe any file upload app specific config (for example what are the dependencies and what apps need to be added where to make it run) -### Customizations -Describe how to customize urls, models etc. \ No newline at end of file +1. Add the following two apps under INSTALLED_APPS in settings.py: +```python +"django_common", +"django_fileupload", +``` +2. The following three packages need to be added to the `requirements.txt` of your django project: +```text +-e /nexus-app-stack-contrib/cli/python-utilities +-e /nexus-app-stack-contrib/api/django-common +-e /nexus-app-stack-contrib/api/django-fileupload +``` +3. Make sure to setup the `FileUploadBatchViewSet` and `FileUploadViewSet` class endpoints by importing their routers / urls and defining them in your own routes. + +!!! info "Use Swagger" + + To help you with your debugging process and to enable you to better understand what are the available methods and routes use swagger in your project. \ No newline at end of file diff --git a/docs/docs/django_apps/index.md b/docs/docs/django_apps/index.md index 7c846fb..baace67 100644 --- a/docs/docs/django_apps/index.md +++ b/docs/docs/django_apps/index.md @@ -1 +1,5 @@ -Should present list of django apps available in app stack contrib together with their features \ No newline at end of file +--- +title: "Django Apps" +--- + +These are helpful django apps that can be included in your project. Generally the `django_common` app is used by the others and should therfore be always included. \ No newline at end of file