Coverage for crateweb/consent/storage.py: 79%
14 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-08-27 10:34 -0500
« prev ^ index » next coverage.py v7.8.0, created at 2025-08-27 10:34 -0500
1"""
2crate_anon/crateweb/consent/storage.py
4===============================================================================
6 Copyright (C) 2015, University of Cambridge, Department of Psychiatry.
7 Created by Rudolf Cardinal (rnc1001@cam.ac.uk).
9 This file is part of CRATE.
11 CRATE is free software: you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 CRATE is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with CRATE. If not, see <https://www.gnu.org/licenses/>.
24===============================================================================
26**File system storage class and instance for the consent-to-contact system.**
28"""
30import logging
31from urllib.parse import urljoin
32from django.core.files.storage import FileSystemStorage
33from django.conf import settings
34from django.urls import get_script_prefix
35from django.utils.encoding import filepath_to_uri
37from crate_anon.crateweb.config.constants import (
38 DOWNLOAD_PRIVATESTORAGE_URL_STEM,
39)
41log = logging.getLogger(__name__)
44class CustomFileSystemStorage(FileSystemStorage):
45 """
46 Subclasses :class:`django.core.files.storage.FileSystemStorage` to improve
47 URL processing, as below.
49 *Notes:*
51 In order to use :func:`reverse`, ``config/urls.py`` can't import views that
52 import models that use this... so use string, not actual Python object,
53 references for ``urls.py``.
55 However, in ``urls.py``, we also need things like ``mgr_admin_site.urls``,
56 and ``consent/admin.py`` also imports ``models`` (which imports
57 ``storage``). Problem. Specifically, a problem for making the URLs
58 non-absolute for non-root hosting.
60 So we use :func:`get_script_prefix` instead?
62 - https://docs.djangoproject.com/en/1.8/ref/urlresolvers/
64 But that isn't set at the time this is loaded, so that's no good either.
65 The only other way to handle this would be to override the view form,
66 or offer the private storage via Apache (but the latter would prevent
67 proper security, so that's a no-no).
69 Therefore, let's subclass
70 :class:`django.core.files.storage.FileSystemStorage`, so we can make the
71 change at runtime.
73 """
75 def url(self, name: str) -> str:
76 """
77 Returns the URL for a given filename.
78 """
79 if self.base_url is None:
80 raise ValueError("This file is not accessible via a URL.")
81 # log.debug("get_script_prefix(): %s" % get_script_prefix())
82 return urljoin(
83 get_script_prefix() + self.base_url, filepath_to_uri(name)
84 )
87privatestorage = CustomFileSystemStorage(
88 location=settings.PRIVATE_FILE_STORAGE_ROOT,
89 base_url=DOWNLOAD_PRIVATESTORAGE_URL_STEM, # NB must match urls.py
90)
93# log.debug("privatestorage.base_url: %s" % privatestorage.base_url)
94# log.debug("get_script_prefix(): %s" % get_script_prefix())