|
| 1 | +import warnings |
1 | 2 | from copy import deepcopy
|
| 3 | +from pathlib import Path |
2 | 4 |
|
3 | 5 | from django.apps import apps
|
4 | 6 | from django.conf import settings
|
5 | 7 | from django.contrib import messages
|
6 | 8 | from django.core.exceptions import PermissionDenied
|
| 9 | +from django.core.files.base import ContentFile |
7 | 10 | from django.shortcuts import get_object_or_404
|
8 | 11 | from django.shortcuts import redirect
|
9 | 12 | from django.urls import NoReverseMatch
|
@@ -107,29 +110,61 @@ def get_context_data(self, **kwargs):
|
107 | 110 |
|
108 | 111 |
|
109 | 112 | class DashboardComponentFormSignalMixin(edit.FormMixin):
|
| 113 | + """Mixin which sends a project_component_updated or module_component_updated signal |
| 114 | + when creating, updating or deleting an object via the HTTP POST method |
| 115 | + (e.g. from the dashboard). |
| 116 | + """ |
| 117 | + |
110 | 118 | def form_valid(self, form):
|
| 119 | + # The call to super.form_valid() may delete self.project or self.module, |
| 120 | + # to be able to still reference them below we need to store them in separate |
| 121 | + # variables before they are deleted. |
| 122 | + project = self.project |
| 123 | + module = self.module |
| 124 | + |
111 | 125 | response = super().form_valid(form)
|
112 | 126 |
|
113 | 127 | component = self.component
|
114 | 128 | if component.identifier in components.projects:
|
115 | 129 | signals.project_component_updated.send(
|
116 | 130 | sender=component.__class__,
|
117 |
| - project=self.project, |
| 131 | + project=project, |
118 | 132 | component=component,
|
119 | 133 | user=self.request.user,
|
120 | 134 | )
|
121 | 135 | else:
|
122 | 136 | signals.module_component_updated.send(
|
123 | 137 | sender=component.__class__,
|
124 |
| - module=self.module, |
| 138 | + module=module, |
125 | 139 | component=component,
|
126 | 140 | user=self.request.user,
|
127 | 141 | )
|
128 | 142 | return response
|
129 | 143 |
|
130 | 144 |
|
131 | 145 | class DashboardComponentDeleteSignalMixin(edit.DeletionMixin):
|
| 146 | + """Deprecated, use DashboardComponentFormSignalMixin for POST requests instead. |
| 147 | + This mixin will be removed in the next version. |
| 148 | + """ |
| 149 | + |
| 150 | + def __init__(self): |
| 151 | + warnings.warn( |
| 152 | + "dashboard.mixins.DashboardComponentDeleteSignalMixin is deprecated, " |
| 153 | + "use dashboard.mixins.DashboardComponentFormSignalMixin for forms / POST " |
| 154 | + "requests. This mixin will be removed in the next version.", |
| 155 | + DeprecationWarning, |
| 156 | + ) |
| 157 | + |
| 158 | + super().__init__() |
| 159 | + |
132 | 160 | def delete(self, request, *args, **kwargs):
|
| 161 | + warnings.warn( |
| 162 | + "dashboard.mixins.DashboardComponentDeleteSignalMixin.delete()" |
| 163 | + "is deprecated, use dashboard.mixins.DashboardComponentFormSignalMixin " |
| 164 | + "for forms / POST requests. This mixin will be removed in the next " |
| 165 | + "version.", |
| 166 | + DeprecationWarning, |
| 167 | + ) |
133 | 168 | # Project and module have to be stored before delete is called as
|
134 | 169 | # they may rely on the still existing db object.
|
135 | 170 | project = self.project
|
@@ -167,16 +202,31 @@ def post(self, request, *args, **kwargs):
|
167 | 202 |
|
168 | 203 | project_clone = deepcopy(project)
|
169 | 204 | project_clone.pk = None
|
170 |
| - if project_clone.tile_image: |
171 |
| - project_clone.tile_image.save( |
172 |
| - project.tile_image.name, project.tile_image, False |
173 |
| - ) |
174 |
| - if project_clone.image: |
175 |
| - project_clone.image.save(project.image.name, project.image, False) |
176 | 205 | project_clone.created = timezone.now()
|
177 | 206 | project_clone.is_draft = True
|
178 | 207 | project_clone.is_archived = False
|
| 208 | + |
| 209 | + if project.tile_image: |
| 210 | + # django's image.name contains the file storage location defined in 'upload_to' |
| 211 | + tile_file_name = Path( |
| 212 | + project.tile_image.name |
| 213 | + ).name # retreives only the filename |
| 214 | + tile_copy = ContentFile( |
| 215 | + project.tile_image.read() |
| 216 | + ) # retreives the image bytes |
| 217 | + project_clone.tile_image.save(tile_file_name, tile_copy, False) |
| 218 | + |
| 219 | + if project.image: |
| 220 | + # django's image.name contains the file storage location defined in 'upload_to' |
| 221 | + image_file_name = Path(project.image.name).name |
| 222 | + image_copy = ContentFile(project.image.read()) |
| 223 | + project_clone.image.save(image_file_name, image_copy, False) |
| 224 | + |
179 | 225 | project_clone.save()
|
| 226 | + if project.topics: |
| 227 | + for topic in project.topics.all(): |
| 228 | + project_clone.topics.add(topic) |
| 229 | + |
180 | 230 | signals.project_created.send(
|
181 | 231 | sender=None, project=project_clone, user=self.request.user
|
182 | 232 | )
|
|
0 commit comments