From 780d066afc871bbc85bb242606064296ce989f3a Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Sat, 22 Jun 2024 12:56:09 +0200 Subject: [PATCH 1/5] feat: added list user documents view --- users/urls.py | 2 ++ users/views.py | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/users/urls.py b/users/urls.py index 8db44ee..7d645bc 100644 --- a/users/urls.py +++ b/users/urls.py @@ -9,6 +9,7 @@ UserCreateView, UserUpdatePasswordView, UserUpdateView, + ListUserFilesAPIView ) urlpatterns = [ @@ -17,6 +18,7 @@ path("logout/", LogoutView.as_view(), name="logout"), path("edit/", UserUpdateView.as_view(), name="edit"), path("edit_password/", UserUpdatePasswordView.as_view(), name="edit_password"), + path("listuserfiles/", ListUserFilesAPIView.as_view(), name="list_user_files"), path("departments/", DepartmentListView.as_view(), name="departments"), path("positions/", PositionListView.as_view(), name="positions"), path("registration/", UserCreateView.as_view(), name="registration"), diff --git a/users/views.py b/users/views.py index de2b530..e873b81 100644 --- a/users/views.py +++ b/users/views.py @@ -1,3 +1,5 @@ +import os.path + from django.dispatch import receiver from django_rest_passwordreset.signals import reset_password_token_created from rest_framework import generics, status @@ -70,6 +72,30 @@ class UserUpdatePasswordView(UserRelatedView): serializer_class = UserUpdatePasswordSerializer +# Отображение списка документов пользователя +class ListUserFilesAPIView(APIView): + permission_classes = (IsAuthenticated,) + + def get(self, request, *args, **kwargs): + user_folder = os.path.join("makedoc", "tempdoc", str(request.user.id)) + + if not os.path.exists(user_folder): + return Response({"error": "User folder not found"}, status=status.HTTP_404_NOT_FOUND) + + try: + files = os.listdir(user_folder) + except OSError as e: + return Response({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) + + files_list = [] + for file_name in files: + file_path = os.path.join(user_folder, file_name) + if os.path.isfile(file_path): + files_list.append(file_name) + + return Response({"files": files_list}, status=status.HTTP_200_OK) + + # Сброс пароля @receiver(reset_password_token_created) def password_reset_token_created(sender, instance, reset_password_token, *args, **kwargs): From 7ebdff0b4484cd6caca5f2cb4ad32f9ebd995d94 Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Sat, 22 Jun 2024 18:31:23 +0200 Subject: [PATCH 2/5] refactor: change get to post method for download file view, create serializer for file name, removed spaces in the name of the created archive --- makedoc/serializers.py | 4 ++++ makedoc/services.py | 5 +++-- makedoc/urls.py | 4 ++-- makedoc/views.py | 24 +++++++++++++++--------- 4 files changed, 24 insertions(+), 13 deletions(-) diff --git a/makedoc/serializers.py b/makedoc/serializers.py index 1db4ffd..6236825 100644 --- a/makedoc/serializers.py +++ b/makedoc/serializers.py @@ -20,3 +20,7 @@ class DataDocSerializer(serializers.Serializer[Any]): factory_id = serializers.IntegerField() destination = serializers.CharField() delivery_cost = serializers.IntegerField(min_value=0) + + +class FileNameSerializer(serializers.Serializer[Any]): + file_name = serializers.CharField(required=False, allow_blank=True) diff --git a/makedoc/services.py b/makedoc/services.py index 8f3f82b..c4b372a 100644 --- a/makedoc/services.py +++ b/makedoc/services.py @@ -10,7 +10,6 @@ get_formatted_date_agreement, get_formatted_date_shipment, ) - from .data_service import DataService @@ -194,8 +193,10 @@ def add_workbook_to_archive_xlsx(self, wb, user, client): tempdir = os.path.join("makedoc", "tempdoc", str(user.id)) os.makedirs(tempdir, exist_ok=True) + client_name = client.client_name.replace(' ', '_') + date_today = datetime.today().strftime('%d.%m.%Y_%H:%M:%S') self.archive_name = ( - f"{client.client_name} {datetime.today().strftime('%d.%m.%Y %H:%M:%S')}.zip" + f"{client_name}_{date_today}.zip" ) archive_path = f"{tempdir}/{self.archive_name}" diff --git a/makedoc/urls.py b/makedoc/urls.py index ce10cec..dd8cb65 100644 --- a/makedoc/urls.py +++ b/makedoc/urls.py @@ -1,9 +1,9 @@ from django.urls import path -from .views import DataDocView, CreateDocsView, DownloadDocView +from .views import DataDocView, CreateDocsView, DownloadDocAPIView urlpatterns = [ path("filemake/", CreateDocsView.as_view(), name="file"), - path("downloadfile/", DownloadDocView.as_view(), name="downloadfile"), + path("downloadfile/", DownloadDocAPIView.as_view(), name="downloadfile"), path("data/", DataDocView.as_view(), name="data"), ] diff --git a/makedoc/views.py b/makedoc/views.py index 4019b5f..366af27 100644 --- a/makedoc/views.py +++ b/makedoc/views.py @@ -11,7 +11,7 @@ from rest_framework.views import APIView from makedoc.services import Documents -from .serializers import DataDocSerializer, DocumentsSimpleSerializer +from .serializers import DataDocSerializer, DocumentsSimpleSerializer, FileNameSerializer class CreateDocsView(APIView): @@ -49,15 +49,24 @@ def get(self, request, *args, **kwargs): return Response({"message": "Documents saved"}, status=status.HTTP_200_OK) -class DownloadDocView(APIView): +class DownloadDocAPIView(APIView): permission_classes = [IsAuthenticated] - def get(self, request, *args, **kwargs): - cache_key = f"last_created_file_user:{request.user.id}" - file_name = cache.get(cache_key) + def post(self, request, *args, **kwargs): + serializer = FileNameSerializer(data=request.data) + if not serializer.is_valid(): + return Response({"error": "Incorrect file name"}, status=status.HTTP_404_NOT_FOUND) + + file_name = serializer.validated_data.get("file_name") if not file_name: - return Response({"error": "No file found"}, status=status.HTTP_404_NOT_FOUND) + cache_key = f"last_created_file_user:{request.user.id}" + file_name = cache.get(cache_key) + + if not file_name: + return Response({"error": "No file found"}, status=status.HTTP_404_NOT_FOUND) + + cache.delete(cache_key) file_path = os.path.join("makedoc", "tempdoc", str(request.user.id), file_name) @@ -66,9 +75,6 @@ def get(self, request, *args, **kwargs): response = FileResponse(open(file_path, "rb")) response["Content-Disposition"] = f'attachment; filename="{os.path.basename(file_name)}"' - - cache.delete(cache_key) - response["message"] = "File successfully downloaded" response.status_code = status.HTTP_200_OK From 919943dc7716c790b63c2d51be6bb4c9e0e49f14 Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Sat, 22 Jun 2024 18:32:24 +0200 Subject: [PATCH 3/5] test: fixed download doc view test --- makedoc/tests/test_views_makedoc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makedoc/tests/test_views_makedoc.py b/makedoc/tests/test_views_makedoc.py index 6b74bef..0d9669b 100644 --- a/makedoc/tests/test_views_makedoc.py +++ b/makedoc/tests/test_views_makedoc.py @@ -52,6 +52,6 @@ def test__create_docs_view__authorized_user_get_no_data(authorized_client): @pytest.mark.django_db def test__download_doc_view__returns_404_when_no_file_exists(authorized_client): url = reverse("downloadfile") - response = authorized_client.get(url) + response = authorized_client.post(url, {}, format="json") assert response.status_code == 404 assert response.json() == {"error": "No file found"} From f30b4871413c17f726e569fbb0d86fa34fe98c06 Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Sat, 22 Jun 2024 18:58:22 +0200 Subject: [PATCH 4/5] docs: added descriptions for listuserfilesview, create/data/download docs views --- makedoc/views.py | 18 ++++++++++++++++-- users/views.py | 4 +++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/makedoc/views.py b/makedoc/views.py index 366af27..e70d900 100644 --- a/makedoc/views.py +++ b/makedoc/views.py @@ -14,7 +14,10 @@ from .serializers import DataDocSerializer, DocumentsSimpleSerializer, FileNameSerializer -class CreateDocsView(APIView): +class CreateDocsAPIView(APIView): + """ + Responsible for creating documents based on data from the cache. + """ serializer_class = DocumentsSimpleSerializer permission_classes = [IsAuthenticated] @@ -49,7 +52,15 @@ def get(self, request, *args, **kwargs): return Response({"message": "Documents saved"}, status=status.HTTP_200_OK) +# Загрузка документа class DownloadDocAPIView(APIView): + """ + To download a file: + + - No parameters: get the last created file. + + - With the parameter {"file_name": "name your file"} - load a specific file from the list. + """ permission_classes = [IsAuthenticated] def post(self, request, *args, **kwargs): @@ -81,7 +92,10 @@ def post(self, request, *args, **kwargs): return response -class DataDocView(generics.GenericAPIView[Any]): +class DataDocAPIView(generics.GenericAPIView[Any]): + """ + Responsible for receiving data, validating it and storing it in cache. + """ serializer_class = DataDocSerializer permission_classes = (IsAuthenticated,) diff --git a/users/views.py b/users/views.py index e873b81..43b65ee 100644 --- a/users/views.py +++ b/users/views.py @@ -72,8 +72,10 @@ class UserUpdatePasswordView(UserRelatedView): serializer_class = UserUpdatePasswordSerializer -# Отображение списка документов пользователя class ListUserFilesAPIView(APIView): + """ + Responsible for displaying a list of documents of an authorized user. + """ permission_classes = (IsAuthenticated,) def get(self, request, *args, **kwargs): From e2c098a978c815e5755533313d1da631299354df Mon Sep 17 00:00:00 2001 From: Lymar Volodymyr Date: Sat, 22 Jun 2024 19:01:08 +0200 Subject: [PATCH 5/5] fix: urls imports --- makedoc/urls.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/makedoc/urls.py b/makedoc/urls.py index dd8cb65..3d7a290 100644 --- a/makedoc/urls.py +++ b/makedoc/urls.py @@ -1,9 +1,9 @@ from django.urls import path -from .views import DataDocView, CreateDocsView, DownloadDocAPIView +from .views import DataDocAPIView, CreateDocsAPIView, DownloadDocAPIView urlpatterns = [ - path("filemake/", CreateDocsView.as_view(), name="file"), + path("filemake/", CreateDocsAPIView.as_view(), name="file"), path("downloadfile/", DownloadDocAPIView.as_view(), name="downloadfile"), - path("data/", DataDocView.as_view(), name="data"), + path("data/", DataDocAPIView.as_view(), name="data"), ]