Coverage for src/mesh/views/views_file.py: 23%
46 statements
« prev ^ index » next coverage.py v7.7.0, created at 2025-04-28 07:45 +0000
« prev ^ index » next coverage.py v7.7.0, created at 2025-04-28 07:45 +0000
1import os
2import re
4from django.http import HttpRequest, HttpResponse, HttpResponseNotFound
5from django.views.generic import View
6from django_sendfile import sendfile
7from ptf.url_utils import decode_from_url
9from mesh.views.mixins import RoleMixin
11from ..models.editorial_models import EditorialDecisionFile
12from ..models.file_models import BaseFileWrapperModel
13from ..models.review_models import ReviewAdditionalFile
14from ..models.submission_models import SubmissionAdditionalFile, SubmissionMainFile
16# Django Models inheriting from our custom BaseFileWrapperModel.
17# cf. FileServingView.
18FILE_MODELS = [
19 SubmissionMainFile,
20 SubmissionAdditionalFile,
21 ReviewAdditionalFile,
22 EditorialDecisionFile,
23]
26class FileServingView(RoleMixin, View):
27 """
28 This view is used to check the user rights before serving a file.
30 File models protected by this process must be registered in the `FILE_MODELS`
31 variable. The requested file is identified by iterating over the registered models
32 and asking if the URL match their unique pattern.
33 """
35 def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
36 bad_response = HttpResponseNotFound("The requested file was not found on this server.")
38 # Decode the base64 encoded file_identifier
39 file_identifier = kwargs["file_identifier"]
40 try:
41 file_identifier = decode_from_url(file_identifier)
42 except Exception:
43 return bad_response
45 # Loop over the registered models to find the requested file
46 for model in FILE_MODELS:
47 lookup_func = getattr(model, "reverse_file_path", None)
48 if not lookup_func:
49 continue
51 instance: BaseFileWrapperModel | None = lookup_func(file_identifier)
52 if instance is None:
53 continue
55 # Make sure the file exists
56 if not os.path.exists(instance.file.path):
57 break
59 # Check if the user can access the requested file
60 # We need to check the right over the file with all roles
61 right_check_func = getattr(instance, "check_access_right", None)
62 if not right_check_func or not right_check_func(self.role_handler, "read"):
63 break
65 response = sendfile(request, instance.file.path)
67 # Set the original name of the served file for display to the
68 # download client
69 if not hasattr(response, "headers"):
70 return response
72 resp_headers = response.headers
73 content_disposition = resp_headers.get("Content-Disposition")
74 if not content_disposition:
75 return response
77 filename_match = re.search(r"(?P<filename>filename=\".+?\")", content_disposition)
78 if not filename_match:
79 return response
81 filename = filename_match.group("filename")
82 resp_headers["Content-Disposition"] = content_disposition.replace(
83 filename, f'filename="{instance.name}"'
84 )
85 return response
87 return bad_response