meringue 1.2.0.dev6__tar.gz → 1.2.0.dev8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/.gitignore +1 -0
  2. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/PKG-INFO +1 -1
  3. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/__init__.py +1 -1
  4. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/conf/__init__.py +1 -0
  5. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/conf/default_settings.py +7 -1
  6. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/protected/fields.py +45 -8
  7. meringue-1.2.0.dev8/meringue/protected/utils.py +6 -0
  8. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/protected/views.py +7 -4
  9. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/AUTHORS +0 -0
  10. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/LICENSE +0 -0
  11. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/README.md +0 -0
  12. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/api/__init__.py +0 -0
  13. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/api/apps.py +0 -0
  14. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/api/docs/__init__.py +0 -0
  15. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/api/docs/patchers.py +0 -0
  16. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/api/docs/views.py +0 -0
  17. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/api/handlers.py +0 -0
  18. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/api/routers.py +0 -0
  19. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/api/utils.py +0 -0
  20. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/core/__init__.py +0 -0
  21. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/core/apps.py +0 -0
  22. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/core/locale/en/LC_MESSAGES/django.po +0 -0
  23. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/core/locale/ru/LC_MESSAGES/django.po +0 -0
  24. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/core/models.py +0 -0
  25. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/core/options.py +0 -0
  26. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/core/query.py +0 -0
  27. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/core/templatetags/__init__.py +0 -0
  28. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/core/templatetags/meringue_base.py +0 -0
  29. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/core/translation.py +0 -0
  30. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/core/upload_handlers.py +0 -0
  31. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/core/utils/__init__.py +0 -0
  32. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/core/utils/crypt.py +0 -0
  33. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/core/utils/datetime.py +0 -0
  34. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/core/utils/frontend.py +0 -0
  35. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/core/views.py +0 -0
  36. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/protected/__init__.py +0 -0
  37. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/protected/apps.py +0 -0
  38. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/thumbnail/__init__.py +0 -0
  39. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/thumbnail/actions.py +0 -0
  40. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/thumbnail/apps.py +0 -0
  41. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/thumbnail/constants.py +0 -0
  42. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/thumbnail/drf_fields.py +0 -0
  43. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/thumbnail/exceptions.py +0 -0
  44. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/thumbnail/generators.py +0 -0
  45. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/thumbnail/images.py +0 -0
  46. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/thumbnail/properties.py +0 -0
  47. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/thumbnail/shortcuts.py +0 -0
  48. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/thumbnail/storage.py +0 -0
  49. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/thumbnail/templatetags/__init__.py +0 -0
  50. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/thumbnail/templatetags/m_thumbnails.py +0 -0
  51. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/meringue/thumbnail/types.py +0 -0
  52. {meringue-1.2.0.dev6 → meringue-1.2.0.dev8}/pyproject.toml +0 -0
@@ -11,4 +11,5 @@ dist
11
11
  /build
12
12
  /stuff
13
13
  /venv
14
+ /media
14
15
  /_readthedocs
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: meringue
3
- Version: 1.2.0.dev6
3
+ Version: 1.2.0.dev8
4
4
  Summary: A set of various functionality for a Django based web application.
5
5
  Project-URL: Documentation, https://dd.github.io/Meringue
6
6
  Project-URL: Repository, https://github.com/dd/Meringue
@@ -1,4 +1,4 @@
1
- __version__ = "1.2.0.dev6"
1
+ __version__ = "1.2.0.dev8"
2
2
  """
3
3
  To update the version, use [hatch version](https://hatch.pypa.io/latest/version/#updating)
4
4
 
@@ -43,6 +43,7 @@ PARAMS_TO_IMPORT: Final[list[str]] = [
43
43
  "THUMBNAIL_IMAGE_CLASS",
44
44
  "THUMBNAIL_PROPERTIES",
45
45
  "THUMBNAIL_ACTIONS",
46
+ "PROTECTED_NGINX_LOCATION_GETTER",
46
47
  ]
47
48
  """
48
49
  List of options that contain the path to the module and must be imported.
@@ -123,5 +123,11 @@ PROTECTED_SERVE_WITH_NGINX: Final[bool] = not settings.DEBUG
123
123
  The option implies the distribution of protected files by nginx. Instead of serving the file in
124
124
  response.
125
125
 
126
- The view [protected_file_view][meringue.protected.views.protected_file_view] adds the X-Accel-Redirect header with a link to the file.
126
+ The view [x_accel_redirect_view][meringue.protected.views.x_accel_redirect_view] adds the
127
+ X-Accel-Redirect header with a link to the file.
128
+ """
129
+
130
+ PROTECTED_NGINX_LOCATION_GETTER: Final[str] = "meringue.protected.utils.nginx_location_getter"
131
+ """
132
+ Default getter for the link to the file where nginx should serve it after access verification.
127
133
  """
@@ -9,16 +9,23 @@ try:
9
9
  except ImportError:
10
10
  hosts_reverse = None
11
11
 
12
+ from meringue.conf import m_settings
13
+
12
14
 
13
15
  class ProtectedFileMixin:
14
16
  @property
15
17
  def url(self):
18
+ """
19
+ Link to the view with access verification to the file
20
+ """
21
+
16
22
  self._require_file()
17
23
 
18
24
  reverse_kwargs = {
19
25
  "cid": ContentType.objects.get_for_model(self.instance.__class__).id,
20
26
  "field": self.field.name,
21
27
  "pk": self.instance.pk,
28
+ "disp": self.field.m_protected_disposition,
22
29
  }
23
30
  if self.field.m_protected_host_name:
24
31
  result_url = hosts_reverse(
@@ -30,8 +37,20 @@ class ProtectedFileMixin:
30
37
  result_url = reverse(self.field.m_protected_view_name, kwargs=reverse_kwargs)
31
38
  return result_url
32
39
 
40
+ @property
41
+ def redirect_url(self):
42
+ """
43
+ Link to the file where nginx should serve it after access verification.
44
+ """
45
+
46
+ return self.field.m_protected_nginx_location_getter(self)
47
+
33
48
  @property
34
49
  def original_url(self):
50
+ """
51
+ The original link to the file.
52
+ """
53
+
35
54
  self._require_file()
36
55
  return self.storage.url(self.name)
37
56
 
@@ -49,18 +68,27 @@ class ProtectedFileField(FileField):
49
68
 
50
69
  def __init__(
51
70
  self,
71
+ view_name,
52
72
  verbose_name=None,
53
73
  name=None,
54
74
  upload_to="protected",
55
75
  storage=None,
56
- protected_view_name="meringue-protected-file",
57
- protected_host_name=None,
76
+ host_name=None,
77
+ disposition="attachment",
78
+ nginx_location_getter=m_settings.PROTECTED_NGINX_LOCATION_GETTER,
58
79
  **kwargs,
59
80
  ):
60
- self.m_protected_view_name = protected_view_name
61
- self.m_protected_host_name = protected_host_name
81
+ self.m_protected_view_name = view_name
82
+ self.m_protected_host_name = host_name
83
+ self.m_protected_disposition = disposition
84
+ self.m_protected_nginx_location_getter = nginx_location_getter
62
85
  super().__init__(verbose_name, name, upload_to, storage, **kwargs)
63
86
 
87
+ def deconstruct(self):
88
+ name, path, args, kwargs = super().deconstruct()
89
+ kwargs['view_name'] = self.m_protected_view_name
90
+ return name, path, args, kwargs
91
+
64
92
 
65
93
  class ProtectedImageFieldFile(ProtectedFileMixin, ImageFieldFile):
66
94
  pass
@@ -75,15 +103,24 @@ class ProtectedImageField(ImageField):
75
103
 
76
104
  def __init__(
77
105
  self,
106
+ view_name,
78
107
  verbose_name=None,
79
108
  name=None,
80
109
  width_field=None,
81
110
  height_field=None,
82
- protected_view_name="meringue-protected-file",
83
- protected_host_name=None,
111
+ host_name=None,
112
+ disposition="attachment",
113
+ nginx_location_getter=m_settings.PROTECTED_NGINX_LOCATION_GETTER,
84
114
  **kwargs,
85
115
  ):
86
116
  kwargs.setdefault("upload_to", "protected")
87
- self.m_protected_view_name = protected_view_name
88
- self.m_protected_host_name = protected_host_name
117
+ self.m_protected_view_name = view_name
118
+ self.m_protected_host_name = host_name
119
+ self.m_protected_disposition = disposition
120
+ self.m_protected_nginx_location_getter = nginx_location_getter
89
121
  super().__init__(verbose_name, name, width_field, height_field, **kwargs)
122
+
123
+ def deconstruct(self):
124
+ name, path, args, kwargs = super().deconstruct()
125
+ kwargs['view_name'] = self.m_protected_view_name
126
+ return name, path, args, kwargs
@@ -0,0 +1,6 @@
1
+ def nginx_location_getter(field_file):
2
+ """
3
+ Getter for the link to the file where nginx should serve it after access verification
4
+ """
5
+
6
+ return field_file.original_url
@@ -15,7 +15,7 @@ from meringue.protected.fields import ProtectedFieldFile
15
15
  from meringue.protected.fields import ProtectedImageFieldFile
16
16
 
17
17
 
18
- def protected_file_view(request, cid, field, pk):
18
+ def x_accel_redirect_view(request, cid, field, pk, disp="inline"):
19
19
  """
20
20
  The view checks the user's access to view and serves the file.
21
21
 
@@ -41,14 +41,17 @@ def protected_file_view(request, cid, field, pk):
41
41
  file_name = Path(file.name).name
42
42
  response = HttpResponse()
43
43
  response["Content-Type"] = mimetypes.guess_type(file.path)[0]
44
- response["Content-Disposition"] = f"inline; filename={quote(file_name)}"
44
+ response["Content-Disposition"] = f"{disp}; filename={quote(file_name)}"
45
45
 
46
46
  if isinstance(file, ProtectedFieldFile | ProtectedImageFieldFile):
47
- redirect_url = file.original_url
47
+ redirect_url = file.redirect_url
48
48
  else:
49
49
  redirect_url = file.url
50
50
 
51
51
  response["X-Accel-Redirect"] = redirect_url
52
52
  return response
53
53
 
54
- return FileResponse(open(file.path, "rb"))
54
+ return FileResponse(
55
+ open(file.path, "rb"),
56
+ as_attachment = disp == "attachment",
57
+ )
File without changes
File without changes
File without changes