From ba19412d31c57e7f22a99f730458d3deb7877954 Mon Sep 17 00:00:00 2001 From: Keannu Bernasol Date: Sun, 24 Nov 2024 02:20:18 +0800 Subject: [PATCH] Add document requests app --- .env.sample | 3 + .../accounts/migrations/0001_initial.py | 9 +- .../migrations/0002_alter_customuser_email.py | 18 --- docmanager_backend/accounts/models.py | 4 - docmanager_backend/accounts/permissions.py | 22 ++++ docmanager_backend/api/urls.py | 1 + docmanager_backend/config/settings.py | 27 +++- .../document_requests/__init__.py | 0 docmanager_backend/document_requests/admin.py | 26 ++++ docmanager_backend/document_requests/apps.py | 6 + .../migrations/0001_initial.py | 94 ++++++++++++++ .../document_requests/migrations/__init__.py | 0 .../document_requests/models.py | 28 +++++ .../document_requests/serializers.py | 119 ++++++++++++++++++ docmanager_backend/document_requests/urls.py | 12 ++ docmanager_backend/document_requests/views.py | 53 ++++++++ .../documents/migrations/0001_initial.py | 9 +- docmanager_backend/documents/models.py | 5 +- docmanager_backend/documents/permissions.py | 10 -- docmanager_backend/documents/serializers.py | 47 ++++++- docmanager_backend/documents/urls.py | 8 +- docmanager_backend/documents/views.py | 35 +++++- requirements.txt | 1 + 23 files changed, 484 insertions(+), 53 deletions(-) delete mode 100644 docmanager_backend/accounts/migrations/0002_alter_customuser_email.py create mode 100644 docmanager_backend/accounts/permissions.py create mode 100644 docmanager_backend/document_requests/__init__.py create mode 100644 docmanager_backend/document_requests/admin.py create mode 100644 docmanager_backend/document_requests/apps.py create mode 100644 docmanager_backend/document_requests/migrations/0001_initial.py create mode 100644 docmanager_backend/document_requests/migrations/__init__.py create mode 100644 docmanager_backend/document_requests/models.py create mode 100644 docmanager_backend/document_requests/serializers.py create mode 100644 docmanager_backend/document_requests/urls.py create mode 100644 docmanager_backend/document_requests/views.py delete mode 100644 docmanager_backend/documents/permissions.py diff --git a/.env.sample b/.env.sample index 2693570..3463b14 100644 --- a/.env.sample +++ b/.env.sample @@ -18,3 +18,6 @@ EMAIL_ADDRESS = 'noreply.dev@mehdns.06222001.xyz' # Admin Credentials ADMIN_EMAIL = 'admin@test.com' ADMIN_PASSWORD = '' + +# To insert test data or not +TEST_DATA = "True" \ No newline at end of file diff --git a/docmanager_backend/accounts/migrations/0001_initial.py b/docmanager_backend/accounts/migrations/0001_initial.py index 534d287..401bc5f 100644 --- a/docmanager_backend/accounts/migrations/0001_initial.py +++ b/docmanager_backend/accounts/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.1.3 on 2024-11-23 13:04 +# Generated by Django 5.1.3 on 2024-11-23 17:01 import django.contrib.auth.models import django.contrib.auth.validators @@ -69,12 +69,6 @@ class Migration(migrations.Migration): blank=True, max_length=150, verbose_name="last name" ), ), - ( - "email", - models.EmailField( - blank=True, max_length=254, verbose_name="email address" - ), - ), ( "is_staff", models.BooleanField( @@ -91,6 +85,7 @@ class Migration(migrations.Migration): verbose_name="active", ), ), + ("email", models.EmailField(max_length=254, unique=True)), ( "role", models.CharField( diff --git a/docmanager_backend/accounts/migrations/0002_alter_customuser_email.py b/docmanager_backend/accounts/migrations/0002_alter_customuser_email.py deleted file mode 100644 index e6c601e..0000000 --- a/docmanager_backend/accounts/migrations/0002_alter_customuser_email.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 5.1.3 on 2024-11-23 13:36 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ("accounts", "0001_initial"), - ] - - operations = [ - migrations.AlterField( - model_name="customuser", - name="email", - field=models.EmailField(max_length=254, unique=True), - ), - ] diff --git a/docmanager_backend/accounts/models.py b/docmanager_backend/accounts/models.py index 402b336..1731900 100644 --- a/docmanager_backend/accounts/models.py +++ b/docmanager_backend/accounts/models.py @@ -32,8 +32,4 @@ class CustomUser(AbstractUser): def save(self, **kwargs): self.username = self.email - if self.is_staff: - self.role = "staff" - elif self.is_superuser: - self.role = "admin" super().save(**kwargs) diff --git a/docmanager_backend/accounts/permissions.py b/docmanager_backend/accounts/permissions.py new file mode 100644 index 0000000..75297e1 --- /dev/null +++ b/docmanager_backend/accounts/permissions.py @@ -0,0 +1,22 @@ +from rest_framework.permissions import BasePermission + + +class IsStaff(BasePermission): + """ + Allows access only to users with staff role + """ + + def has_permission(self, request, view): + return bool( + request.user and request.user.role in ("head", "admin", "planning", "staff") + ) + + +class IsHead(BasePermission): + """ + Allows access only to users with staff role + """ + + def has_permission(self, request, view): + print(request.user.role) + return bool(request.user and request.user.role == "head") diff --git a/docmanager_backend/api/urls.py b/docmanager_backend/api/urls.py index d0e3e96..888b05d 100644 --- a/docmanager_backend/api/urls.py +++ b/docmanager_backend/api/urls.py @@ -12,6 +12,7 @@ from drf_spectacular.views import ( urlpatterns = [ path("accounts/", include("accounts.urls")), path("documents/", include("documents.urls")), + path("requests/", include("document_requests.urls")), path("admin/", admin.site.urls), path("schema/", SpectacularAPIView.as_view(), name="schema"), path( diff --git a/docmanager_backend/config/settings.py b/docmanager_backend/config/settings.py index dfcff58..9dd1854 100644 --- a/docmanager_backend/config/settings.py +++ b/docmanager_backend/config/settings.py @@ -45,7 +45,30 @@ SECRET_KEY = get_secret("SECRET_KEY") # SECURITY WARNING: don"t run with debug turned on in production! DEBUG = get_secret("DEBUG") +# URL Prefixes +USE_HTTPS = get_secret("USE_HTTPS") +URL_SCHEME = "https" if USE_HTTPS else "http" +# Building Backend URL +BACKEND_ADDRESS = get_secret("BACKEND_ADDRESS") +BACKEND_PORT = get_secret("BACKEND_PORT") +# Building Frontend URL +FRONTEND_ADDRESS = get_secret("FRONTEND_ADDRESS") +FRONTEND_PORT = get_secret("FRONTEND_PORT") +# Full URLs +BACKEND_URL = f"{URL_SCHEME}://{BACKEND_ADDRESS}" +FRONTEND_URL = f"{URL_SCHEME}://{BACKEND_ADDRESS}" + +# Append port to full URLs if deployed locally +if not USE_HTTPS: + BACKEND_URL += f":{BACKEND_PORT}" + FRONTEND_URL += f":{FRONTEND_PORT}" + ALLOWED_HOSTS = ["*"] +CSRF_TRUSTED_ORIGINS = [ + FRONTEND_URL, + BACKEND_URL, + # You can also set up https://*.name.xyz for wildcards here +] # Application definition @@ -67,12 +90,14 @@ INSTALLED_APPS = [ "drf_spectacular_sidecar", "accounts", "documents", + "document_requests", "django_cleanup.apps.CleanupConfig", ] MIDDLEWARE = [ "django.middleware.security.SecurityMiddleware", "django.contrib.sessions.middleware.SessionMiddleware", + "corsheaders.middleware.CorsMiddleware", "django.middleware.common.CommonMiddleware", "django.middleware.csrf.CsrfViewMiddleware", "django.contrib.auth.middleware.AuthenticationMiddleware", @@ -163,7 +188,7 @@ USE_TZ = True # https://docs.djangoproject.com/en/5.1/howto/static-files/ STATICFILES_STORAGE = "whitenoise.storage.CompressedManifestStaticFilesStorage" -MEDIA_URL = "api/v1/media/" +MEDIA_URL = f"{BACKEND_URL}/api/v1/media/" MEDIA_ROOT = os.path.join(BASE_DIR, "media") ROOT_URLCONF = "config.urls" STATIC_URL = "static/" diff --git a/docmanager_backend/document_requests/__init__.py b/docmanager_backend/document_requests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/docmanager_backend/document_requests/admin.py b/docmanager_backend/document_requests/admin.py new file mode 100644 index 0000000..c7100a0 --- /dev/null +++ b/docmanager_backend/document_requests/admin.py @@ -0,0 +1,26 @@ +from django.contrib import admin +from unfold.admin import ModelAdmin +from .models import DocumentRequestUnit, DocumentRequest +from unfold.contrib.filters.admin import RangeDateFilter + +# Register your models here. + + +@admin.register(DocumentRequestUnit) +class DocumentRequestUnitAdmin(ModelAdmin): + search_fields = ["id"] + list_display = ["id", "get_document_title", "copies"] + + def get_document_title(self, obj): + return obj.documents.title # Assuming the Document model has a 'title' field + + get_document_title.short_description = "Document" + + +@admin.register(DocumentRequest) +class DocumentRequestAdmin(ModelAdmin): + list_filter = [ + ("date_requested", RangeDateFilter), + ] + + list_display = ["id", "date_requested", "status", "college"] diff --git a/docmanager_backend/document_requests/apps.py b/docmanager_backend/document_requests/apps.py new file mode 100644 index 0000000..4890169 --- /dev/null +++ b/docmanager_backend/document_requests/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class DocumentRequestsConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "document_requests" diff --git a/docmanager_backend/document_requests/migrations/0001_initial.py b/docmanager_backend/document_requests/migrations/0001_initial.py new file mode 100644 index 0000000..84281fb --- /dev/null +++ b/docmanager_backend/document_requests/migrations/0001_initial.py @@ -0,0 +1,94 @@ +# Generated by Django 5.1.3 on 2024-11-23 17:01 + +import django.db.models.deletion +import django.utils.timezone +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ("documents", "0001_initial"), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name="DocumentRequest", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "date_requested", + models.DateTimeField( + default=django.utils.timezone.now, editable=False + ), + ), + ("college", models.CharField(max_length=64)), + ("purpose", models.TextField(max_length=512)), + ( + "status", + models.CharField( + choices=[ + ("pending", "Pending"), + ("approved", "Approved"), + ("denied", "Denied"), + ], + default="pending", + max_length=32, + ), + ), + ( + "requester", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to=settings.AUTH_USER_MODEL, + ), + ), + ], + ), + migrations.CreateModel( + name="DocumentRequestUnit", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("copies", models.IntegerField(default=1)), + ( + "document", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="documents.document", + ), + ), + ( + "document_request", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + to="document_requests.documentrequest", + ), + ), + ], + ), + migrations.AddField( + model_name="documentrequest", + name="documents", + field=models.ManyToManyField(to="document_requests.documentrequestunit"), + ), + ] diff --git a/docmanager_backend/document_requests/migrations/__init__.py b/docmanager_backend/document_requests/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/docmanager_backend/document_requests/models.py b/docmanager_backend/document_requests/models.py new file mode 100644 index 0000000..e848eed --- /dev/null +++ b/docmanager_backend/document_requests/models.py @@ -0,0 +1,28 @@ +from django.db import models +from django.utils.timezone import now + + +class DocumentRequestUnit(models.Model): + document_request = models.ForeignKey( + "document_requests.DocumentRequest", on_delete=models.CASCADE + ) + document = models.ForeignKey("documents.Document", on_delete=models.CASCADE) + copies = models.IntegerField(default=1, null=False, blank=False) + + +class DocumentRequest(models.Model): + requester = models.ForeignKey("accounts.CustomUser", on_delete=models.CASCADE) + documents = models.ManyToManyField("document_requests.DocumentRequestUnit") + date_requested = models.DateTimeField(default=now, editable=False) + college = models.CharField(max_length=64, blank=False, null=False) + purpose = models.TextField(max_length=512, blank=False, null=False) + + STATUS_CHOICES = ( + ("pending", "Pending"), + ("approved", "Approved"), + ("denied", "Denied"), + ) + + status = models.CharField(max_length=32, choices=STATUS_CHOICES, default="pending") + + # TODO: Add request type (Softcopy/Hardcopy) diff --git a/docmanager_backend/document_requests/serializers.py b/docmanager_backend/document_requests/serializers.py new file mode 100644 index 0000000..a759d67 --- /dev/null +++ b/docmanager_backend/document_requests/serializers.py @@ -0,0 +1,119 @@ +from rest_framework import serializers +from documents.models import Document +from documents.serializers import DocumentSerializer, DocumentFileSerializer +from accounts.models import CustomUser +from .models import DocumentRequest, DocumentRequestUnit + + +class DocumentRequestUnitCreationSerializer(serializers.ModelSerializer): + document = serializers.SlugRelatedField( + many=False, slug_field="id", queryset=Document.objects.all(), required=True + ) + + class Meta: + model = DocumentRequestUnit + fields = ["document", "copies"] + + +class DocumentRequestCreationSerializer(serializers.ModelSerializer): + requester = serializers.SlugRelatedField( + many=False, slug_field="id", queryset=CustomUser.objects.all(), required=False + ) + documents = DocumentRequestUnitCreationSerializer(many=True, required=True) + college = serializers.CharField(allow_blank=False) + purpose = serializers.CharField(max_length=512, allow_blank=False) + + class Meta: + model = DocumentRequest + fields = ["requester", "college", "purpose", "documents"] + + def create(self, validated_data): + user = self.context["request"].user + documents_data = validated_data.pop("documents") + # Set requester to user who sent HTTP request to prevent spoofing + validated_data["requester"] = user + + DOCUMENT_REQUEST = DocumentRequest.objects.create(**validated_data) + + DOCUMENT_REQUEST_UNITS = [] + for DOCUMENT_REQUEST_UNIT in documents_data: + DOCUMENT_REQUEST_UNIT = DocumentRequestUnit.objects.create( + document_request=DOCUMENT_REQUEST, + document=DOCUMENT_REQUEST_UNIT["document"], + copies=DOCUMENT_REQUEST_UNIT["copies"], + ) + DOCUMENT_REQUEST_UNITS.append(DOCUMENT_REQUEST_UNIT) + + DOCUMENT_REQUEST.documents.set(DOCUMENT_REQUEST_UNITS) + DOCUMENT_REQUEST.save() + + return DOCUMENT_REQUEST + + +class DocumentRequestUnitSerializer(serializers.ModelSerializer): + document = DocumentSerializer(many=False) + + class Meta: + model = DocumentRequestUnit + fields = ["document", "copies"] + read_only_fields = ["document", "copies"] + + +class DocumentRequestUnitWithFileSerializer(serializers.ModelSerializer): + document = DocumentFileSerializer(many=False) + + class Meta: + model = DocumentRequestUnit + fields = ["document", "copies"] + read_only_fields = ["document", "copies"] + + +class DocumentRequestSerializer(serializers.ModelSerializer): + documents = serializers.SerializerMethodField() + college = serializers.CharField(allow_blank=False) + purpose = serializers.CharField(max_length=512, allow_blank=False) + + class Meta: + model = DocumentRequest + fields = ["id", "requester", "college", + "purpose", "documents", "status"] + read_only_fields = [ + "id", + "requester", + "college", + "purpose", + "documents", + "status", + ] + + def get_documents(self, obj): + if obj.status != "approved": + serializer_class = DocumentRequestUnitSerializer + else: + serializer_class = DocumentRequestUnitWithFileSerializer + return serializer_class(obj.documents, many=True).data + + +class DocumentRequestUpdateSerializer(serializers.ModelSerializer): + status = serializers.ChoiceField( + choices=DocumentRequest.STATUS_CHOICES, required=True + ) + + class Meta: + model = DocumentRequest + fields = ["id", "status"] + read_only_fields = ["id", "status"] + + def update(self, instance, validated_data): + if instance.status == "denied": + raise serializers.ValidationError( + { + "error": "Denied requests cannot be updated. It is advised you create a new request and approve it from there" + } + ) + elif validated_data["status"] == instance.status: + raise serializers.ValidationError( + {"error": "Request form status provided is the same as current status"} + ) + + return super().update(instance, validated_data) diff --git a/docmanager_backend/document_requests/urls.py b/docmanager_backend/document_requests/urls.py new file mode 100644 index 0000000..15d71f3 --- /dev/null +++ b/docmanager_backend/document_requests/urls.py @@ -0,0 +1,12 @@ +from django.urls import path, include +from .views import ( + DocumentRequestCreateView, + DocumentRequestListView, + DocumentRequestUpdateView, +) + +urlpatterns = [ + path("create/", DocumentRequestCreateView.as_view()), + path("list/", DocumentRequestListView.as_view()), + path("update//", DocumentRequestUpdateView.as_view()), +] diff --git a/docmanager_backend/document_requests/views.py b/docmanager_backend/document_requests/views.py new file mode 100644 index 0000000..9c496ca --- /dev/null +++ b/docmanager_backend/document_requests/views.py @@ -0,0 +1,53 @@ +from rest_framework import generics +from rest_framework.permissions import IsAuthenticated +from rest_framework.pagination import PageNumberPagination +from accounts.permissions import IsHead +from rest_framework.pagination import PageNumberPagination +from .serializers import ( + DocumentRequestCreationSerializer, + DocumentRequestSerializer, + DocumentRequestUpdateSerializer, +) + +from .models import DocumentRequest + + +class DocumentRequestCreateView(generics.CreateAPIView): + """ + Used by clients to create document requests. Requires passing in request information in addition to the documents themselves + """ + + http_method_names = ["post"] + serializer_class = DocumentRequestCreationSerializer + permission_classes = [IsAuthenticated] + + +class DocumentRequestListView(generics.ListAPIView): + """ + Returns document requests. If document requests are approved, also returns the link to download the document. + Staff are able to view all document requests here. Clients are only able to view their own requests. + """ + + http_method_names = ["get"] + serializer_class = DocumentRequestSerializer + pagination_class = PageNumberPagination + permission_classes = [IsAuthenticated] + + def get_queryset(self): + user = self.request.user + if user.role == "client": + queryset = DocumentRequest.objects.filter(requester=user) + else: + queryset = DocumentRequest.objects.all() + return queryset + + +class DocumentRequestUpdateView(generics.UpdateAPIView): + """ + Used by head approve or deny document requests. + """ + + http_method_names = ["patch"] + serializer_class = DocumentRequestUpdateSerializer + permission_classes = [IsAuthenticated, IsHead] + queryset = DocumentRequest.objects.all() diff --git a/docmanager_backend/documents/migrations/0001_initial.py b/docmanager_backend/documents/migrations/0001_initial.py index 91590c5..7005565 100644 --- a/docmanager_backend/documents/migrations/0001_initial.py +++ b/docmanager_backend/documents/migrations/0001_initial.py @@ -1,6 +1,7 @@ -# Generated by Django 5.1.3 on 2024-11-23 14:13 +# Generated by Django 5.1.3 on 2024-11-23 17:01 import django.utils.timezone +import documents.models from django.db import migrations, models @@ -38,7 +39,11 @@ class Migration(migrations.Migration): max_length=32, ), ), - ("file", models.FileField(upload_to="documents/")), + ("number_pages", models.IntegerField()), + ( + "file", + models.FileField(upload_to=documents.models.Document.upload_to), + ), ( "date_uploaded", models.DateTimeField( diff --git a/docmanager_backend/documents/models.py b/docmanager_backend/documents/models.py index f0fa80a..be7d83d 100644 --- a/docmanager_backend/documents/models.py +++ b/docmanager_backend/documents/models.py @@ -17,14 +17,15 @@ class Document(models.Model): document_type = models.CharField( max_length=32, choices=DOCUMENT_TYPE_CHOICES, null=False, blank=False ) + number_pages = models.IntegerField(null=False, blank=False) def upload_to(instance, filename): _, extension = filename.split(".") - return "documents/%s_%s.%s" % (now, str(uuid.uuid4()), extension) + return "documents/%s_%s.%s" % (now(), str(uuid.uuid4()), extension) file = models.FileField(upload_to=upload_to) date_uploaded = models.DateTimeField(default=now, editable=False) def __str__(self): - return self.name + return f"{self.name} ({self.document_type})" diff --git a/docmanager_backend/documents/permissions.py b/docmanager_backend/documents/permissions.py deleted file mode 100644 index 2e797df..0000000 --- a/docmanager_backend/documents/permissions.py +++ /dev/null @@ -1,10 +0,0 @@ -from rest_framework.permissions import BasePermission - - -class IsStaff(BasePermission): - """ - Allows access only to users with staff role - """ - - def has_permission(self, request, view): - return bool(request.user and request.user.role == "staff") diff --git a/docmanager_backend/documents/serializers.py b/docmanager_backend/documents/serializers.py index 839e330..394141e 100644 --- a/docmanager_backend/documents/serializers.py +++ b/docmanager_backend/documents/serializers.py @@ -1,4 +1,5 @@ from rest_framework import serializers +from config import settings from .models import Document @@ -11,7 +12,14 @@ class DocumentUploadSerializer(serializers.ModelSerializer): class Meta: model = Document - fields = ["id", "name", "file", "document_type", "date_uploaded"] + fields = [ + "id", + "name", + "file", + "document_type", + "number_pages", + "date_uploaded", + ] read_only_fields = ["id", "date-uploaded"] @@ -29,5 +37,38 @@ class DocumentSerializer(serializers.ModelSerializer): class Meta: model = Document - fields = ["id", "name", "document_type", "date_uploaded"] - read_only_fields = ["id", "name", "document_type", "date_uploaded"] + fields = ["id", "name", "document_type", "number_pages", "date_uploaded"] + read_only_fields = [ + "id", + "name", + "document_type", + "number_pages", + "date_uploaded", + ] + + +class DocumentFileSerializer(serializers.ModelSerializer): + # Read-only serializer which includes the actual link to the file + date_uploaded = serializers.DateTimeField( + format="%m-%d-%Y %I:%M %p", read_only=True + ) + file = serializers.FileField() + + class Meta: + model = Document + fields = [ + "id", + "name", + "document_type", + "file", + "number_pages", + "date_uploaded", + ] + read_only_fields = [ + "id", + "name", + "document_type", + "number_pages", + "date_uploaded", + "file", + ] diff --git a/docmanager_backend/documents/urls.py b/docmanager_backend/documents/urls.py index 47e6240..0438f73 100644 --- a/docmanager_backend/documents/urls.py +++ b/docmanager_backend/documents/urls.py @@ -1,8 +1,14 @@ from django.urls import include, path -from .views import DocumentUploadView, DocumentDeleteView, DocumentListView +from .views import ( + DocumentUploadView, + DocumentDeleteView, + DocumentListView, + DocumentStaffListView, +) urlpatterns = [ path("upload/", DocumentUploadView.as_view()), path("delete//", DocumentDeleteView.as_view()), path("list/", DocumentListView.as_view()), + path("list/staff/", DocumentStaffListView.as_view()), ] diff --git a/docmanager_backend/documents/views.py b/docmanager_backend/documents/views.py index 2964425..60a5e8a 100644 --- a/docmanager_backend/documents/views.py +++ b/docmanager_backend/documents/views.py @@ -1,31 +1,56 @@ from rest_framework import generics from .serializers import ( DocumentSerializer, + DocumentFileSerializer, DocumentUploadSerializer, DocumentDeleteSerializer, ) -from .permissions import IsStaff -from .models import Document from rest_framework.permissions import IsAuthenticated from rest_framework.pagination import PageNumberPagination +from accounts.permissions import IsStaff +from .models import Document class DocumentUploadView(generics.CreateAPIView): + """ + Used by staff to upload documents. + """ + http_method_names = ["post"] serializer_class = DocumentUploadSerializer - # permission_classes = [IsAuthenticated, IsStaff] + permission_classes = [IsAuthenticated, IsStaff] class DocumentDeleteView(generics.DestroyAPIView): + """ + Used by staff to delete documents. Accepts the document id as a URL parameter + """ + http_method_names = ["delete"] serializer_class = DocumentDeleteSerializer queryset = Document.objects.all() - # permission_classes = [IsAuthenticated, IsStaff] + permission_classes = [IsAuthenticated, IsStaff] class DocumentListView(generics.ListAPIView): + """ + Used by clients to view documents. Does not include actual download links to documents + """ + http_method_names = ["get"] serializer_class = DocumentSerializer queryset = Document.objects.all() pagination_class = PageNumberPagination - # permission_classes = [IsAuthenticated] + permission_classes = [IsAuthenticated] + + +class DocumentStaffListView(generics.ListAPIView): + """ + Used by staff to view documents. Includes actual download links to documents + """ + + http_method_names = ["get"] + serializer_class = DocumentFileSerializer + queryset = Document.objects.all() + pagination_class = PageNumberPagination + permission_classes = [IsAuthenticated, IsStaff] diff --git a/requirements.txt b/requirements.txt index d1a0c97..d86a6b3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,6 +9,7 @@ colorama==0.4.6 cryptography==43.0.3 defusedxml==0.8.0rc2 Django==5.1.3 +django-cleanup==9.0.0 django-cors-headers==4.6.0 django-rest-framework==0.1.0 django-unfold==0.41.0