photo-objects 0.9.6__py3-none-any.whl → 0.10.1__py3-none-any.whl

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.
@@ -9,7 +9,6 @@ from photo_objects.django import objsto
9
9
  from photo_objects.django.forms import (
10
10
  CreatePhotoForm,
11
11
  ModifyPhotoForm,
12
- UploadPhotosForm,
13
12
  slugify,
14
13
  )
15
14
  from photo_objects.img import photo_details
@@ -17,7 +16,6 @@ from photo_objects.img import photo_details
17
16
  from .auth import check_album_access, check_photo_access
18
17
  from .utils import (
19
18
  FormValidationFailed,
20
- UploadPhotosFailed,
21
19
  JsonProblem,
22
20
  check_permissions,
23
21
  parse_input_data,
@@ -74,52 +72,6 @@ def upload_photo(request: HttpRequest, album_key: str):
74
72
  return _upload_photo(album_key, photo_file)
75
73
 
76
74
 
77
- def _join_errors(errors: dict) -> str:
78
- messages = []
79
- for _, errs in errors.items():
80
- for err in errs:
81
- try:
82
- messages.append(err.get('message'))
83
- except AttributeError:
84
- messages.append(str(err))
85
- return " ".join(messages) if messages else "Unknown error."
86
-
87
-
88
- def upload_photos(request: HttpRequest, album_key: str):
89
- check_permissions(
90
- request,
91
- 'photo_objects.add_photo',
92
- 'photo_objects.change_album')
93
-
94
- f = UploadPhotosForm(request.POST, request.FILES)
95
- if not f.is_valid():
96
- raise FormValidationFailed(f)
97
-
98
- photo_files = f.cleaned_data["photos"]
99
- if len(photo_files) < 1:
100
- f.add_error("photos", "Expected at least one file, got 0.")
101
- raise FormValidationFailed(f)
102
-
103
- photos = []
104
- for photo_file in f.cleaned_data["photos"]:
105
- try:
106
- photos.append(_upload_photo(album_key, photo_file))
107
- except FormValidationFailed as e:
108
- message = _join_errors(e.form.errors.get_json_data())
109
- f.add_error(
110
- "photos",
111
- f"Failed to upload {photo_file.name}. {message}")
112
- except JsonProblem as e:
113
- f.add_error(
114
- "photos",
115
- f"Failed to upload {photo_file.name}. {e.title}")
116
-
117
- if not f.is_valid():
118
- raise UploadPhotosFailed(f, [i.filename for i in photos])
119
-
120
- return photos
121
-
122
-
123
75
  def modify_photo(request: HttpRequest, album_key: str, photo_key: str):
124
76
  check_permissions(request, 'photo_objects.change_photo')
125
77
  photo = check_photo_access(request, album_key, photo_key, 'xs')
@@ -53,7 +53,8 @@ class JsonProblem(PhotoObjectsError):
53
53
  'Albums',
54
54
  reverse_lazy('photo_objects:list_albums')),
55
55
  "problem_title": self.title,
56
- "status": self.status
56
+ "status": self.status,
57
+ "width": "narrow",
57
58
  }, status=self.status)
58
59
 
59
60
 
@@ -137,12 +138,6 @@ class FormValidationFailed(JsonProblem):
137
138
  self.form = form
138
139
 
139
140
 
140
- class UploadPhotosFailed(FormValidationFailed):
141
- def __init__(self, form: ModelForm, uploaded_photos: list[str]):
142
- super().__init__(form)
143
- self.uploaded_photos = uploaded_photos
144
-
145
-
146
141
  def check_permissions(request: HttpRequest, *permissions: str):
147
142
  if not request.user.is_authenticated:
148
143
  raise Unauthorized()
@@ -3,9 +3,6 @@ import random
3
3
  from django import forms
4
4
  from django.forms import (
5
5
  CharField,
6
- ClearableFileInput,
7
- FileField,
8
- Form,
9
6
  HiddenInput,
10
7
  ModelForm,
11
8
  RadioSelect,
@@ -220,26 +217,3 @@ class ReviewPhotoChangeRequestForm(ModelForm):
220
217
  help_texts = {
221
218
  'alt_text': ALT_TEXT_HELP,
222
219
  }
223
-
224
-
225
- class MultipleFileInput(ClearableFileInput):
226
- allow_multiple_selected = True
227
-
228
-
229
- class MultipleFileField(FileField):
230
- def __init__(self, *args, **kwargs):
231
- kwargs.setdefault('widget', MultipleFileInput())
232
- super().__init__(*args, **kwargs)
233
-
234
- def clean(self, data, initial=None):
235
- single_file_clean = super().clean
236
- if isinstance(data, (list, tuple)):
237
- result = [single_file_clean(d, initial) for d in data]
238
- else:
239
- result = [single_file_clean(data, initial)]
240
- return result
241
-
242
-
243
- class UploadPhotosForm(Form):
244
- photos = MultipleFileField(label=_(
245
- 'Drag and drop photos here or click to open upload dialog.'))
@@ -9,7 +9,11 @@ urlpatterns = [
9
9
  path("_auth", api.has_permission),
10
10
  path("api/albums", api.albums),
11
11
  path("api/albums/<str:album_key>", api.album),
12
- path("api/albums/<str:album_key>/photos", api.photos),
12
+ path(
13
+ "api/albums/<str:album_key>/photos",
14
+ api.photos,
15
+ name="api_photos",
16
+ ),
13
17
  path("api/albums/<str:album_key>/photos/<str:photo_key>", api.photo),
14
18
  path(
15
19
  "api/albums/<str:album_key>/photos/<str:photo_key>/change-requests",
@@ -108,6 +108,7 @@ def edit_album(request: HttpRequest, album_key: str):
108
108
  reverse(
109
109
  'photo_objects:show_album',
110
110
  kwargs={"album_key": album_key}))
111
+ empty = album.cover_photo is None
111
112
 
112
113
  return render(
113
114
  request,
@@ -120,7 +121,10 @@ def edit_album(request: HttpRequest, album_key: str):
120
121
  request,
121
122
  album_key),
122
123
  "width": "narrow",
123
- "preview": Preview(request, album, preview_helptext("album")),
124
+ "preview": Preview(
125
+ request,
126
+ album,
127
+ preview_helptext("album", empty)),
124
128
  })
125
129
 
126
130
 
@@ -148,12 +152,14 @@ def delete_album(request: HttpRequest, album_key: str):
148
152
  error = {'error': _(
149
153
  'This album is managed by the system and can not be deleted.')}
150
154
 
155
+ empty = album.cover_photo is None
156
+
151
157
  return render(request, 'photo_objects/delete.html', {
152
158
  "title": "Delete album",
153
159
  "back": back,
154
160
  "photo": album.cover_photo,
155
161
  "resource": target,
156
162
  "width": "narrow",
157
- "preview": Preview(request, album, preview_helptext("album")),
163
+ "preview": Preview(request, album, preview_helptext("album", empty)),
158
164
  **error,
159
165
  })
@@ -6,9 +6,8 @@ from photo_objects.django import api
6
6
  from photo_objects.django.api.utils import (
7
7
  AlbumNotFound,
8
8
  FormValidationFailed,
9
- UploadPhotosFailed,
10
9
  )
11
- from photo_objects.django.forms import ModifyPhotoForm, UploadPhotosForm
10
+ from photo_objects.django.forms import ModifyPhotoForm
12
11
  from photo_objects.django.models import Photo
13
12
  from photo_objects.django.views.utils import (
14
13
  BackLink,
@@ -22,40 +21,21 @@ from .utils import json_problem_as_html, preview_helptext
22
21
 
23
22
  @json_problem_as_html
24
23
  def upload_photos(request: HttpRequest, album_key: str):
25
- if request.method == "POST":
26
- try:
27
- api.upload_photos(request, album_key)
28
- return HttpResponseRedirect(
29
- reverse(
30
- 'photo_objects:show_album',
31
- kwargs={"album_key": album_key}))
32
- except UploadPhotosFailed as e:
33
- form = e.form
34
- uploaded_count = len(e.uploaded_photos)
35
- if uploaded_count > 0:
36
- plural = 's' if uploaded_count != 1 else ''
37
- info = f"Successfully uploaded {uploaded_count} photo{plural}."
38
- else:
39
- info = None
40
- else:
41
- form = UploadPhotosForm()
42
- info = None
43
-
44
24
  album = api.check_album_access(request, album_key)
45
25
  target = album.title or album.key
46
26
  back = BackLink(
47
27
  target, reverse(
48
28
  'photo_objects:show_album', kwargs={
49
29
  "album_key": album_key}))
30
+ empty = album.cover_photo is None
50
31
 
51
32
  return render(request, 'photo_objects/photo/upload.html', {
52
- "form": form,
53
- "info": info,
54
33
  "title": "Upload photos",
55
34
  "back": back,
35
+ "album": album,
56
36
  "photo": album.cover_photo,
57
37
  "width": "narrow",
58
- "preview": Preview(request, album, preview_helptext("album")),
38
+ "preview": Preview(request, album, preview_helptext("album", empty)),
59
39
  })
60
40
 
61
41
 
@@ -7,7 +7,7 @@ from photo_objects.django.api.utils import (
7
7
  FormValidationFailed,
8
8
  )
9
9
  from photo_objects.django.forms import ReviewPhotoChangeRequestForm
10
- from photo_objects.django.views.utils import BackLink
10
+ from photo_objects.django.views.utils import BackLink, Preview
11
11
  from photo_objects.utils import render_markdown
12
12
 
13
13
  from .utils import json_problem_as_html
@@ -49,13 +49,14 @@ def review_photo_change_request(request: HttpRequest, cr_id: str):
49
49
 
50
50
  back = BackLink("Albums", reverse('photo_objects:list_albums'))
51
51
 
52
+ helptext = render_markdown(
53
+ f'The current alt text for `{photo.key}` is: _"{photo.alt_text}"_.')
54
+
52
55
  return render(request, 'photo_objects/form.html', {
53
56
  "form": form,
54
57
  "title": "Review photo change request",
55
58
  "back": back,
56
59
  "info": info,
57
- "instructions": render_markdown(
58
- f'The current alt text for `{photo.key}` is: '
59
- f'_"{photo.alt_text}"_.'),
60
60
  "width": "narrow",
61
+ "preview": Preview(request, photo, helptext),
61
62
  })
@@ -10,7 +10,15 @@ def json_problem_as_html(func):
10
10
  return wrapper
11
11
 
12
12
 
13
- def preview_helptext(resource_type: str) -> str:
13
+ def preview_helptext(resource_type: str, empty: bool = False) -> str:
14
+ if resource_type == "album" and empty:
15
+ return (
16
+ f"This is an example on how the {resource_type} would appear "
17
+ "when sharing on social media. Upload photos and select a cover "
18
+ "photo to use this album specific preview instead of the server "
19
+ "level default preview."
20
+ )
21
+
14
22
  return (
15
23
  f"This is an example on how the {resource_type} will currently appear "
16
24
  "when sharing on social media."
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: photo-objects
3
- Version: 0.9.6
3
+ Version: 0.10.1
4
4
  Summary: Application for storing photos in S3 compatible object-storage.
5
5
  Author: Toni Kangas
6
6
  License: MIT License
@@ -8,18 +8,18 @@ photo_objects/django/admin.py,sha256=pvyQKs2FMtKtSS2PE_NKR_jsSi7-GKz3bbsqDNgjt6w
8
8
  photo_objects/django/apps.py,sha256=Apqu6o6fpoxda18NQgKupvQRvTAZxVviIK_-dUR3rck,1444
9
9
  photo_objects/django/conf.py,sha256=ZpeIulEc1tpr8AO52meNKOF30Xf5osbDtDyHvQRtkx4,2593
10
10
  photo_objects/django/context_processors.py,sha256=XacUmcYV-4NMMMNXPWrHKdvNd6lfyamisngaVerREiU,306
11
- photo_objects/django/forms.py,sha256=zSSmdIYn4PEx1Nnw-tuo4h4otKj3C099lB4-vp2BRUc,6861
11
+ photo_objects/django/forms.py,sha256=HIkDRQhSMzvj0D4BdKEuEndB3bV-3NTH_h0gMRQ9UlQ,6123
12
12
  photo_objects/django/models.py,sha256=OxkkczIBg7TaFWWm4VdtbRMJOK_OQKrV29g-X2cm5BQ,7247
13
13
  photo_objects/django/objsto.py,sha256=kf-Tv-kDt47Mnx0xMolAct_lP4M0H9xg03M3BnfAnJM,6909
14
14
  photo_objects/django/signals.py,sha256=_gb4vlZkeFNYWXxwhNreaUJoOsbIWvP8OovVLtzepaE,2161
15
- photo_objects/django/urls.py,sha256=XnOSEB8YtAJamlEsjKYz6U1DfDu7HHZpAinpqdulR8k,2501
15
+ photo_objects/django/urls.py,sha256=QHGjDj3XCArLtmMcP3DKp8H9Xfd2X4SEvEKmMnx2KDk,2551
16
16
  photo_objects/django/api/__init__.py,sha256=51CRTiE975ufVhvI5x-M_2D28JP8FZWyLFiuV5EaQSg,120
17
17
  photo_objects/django/api/album.py,sha256=CJDeGLCuYoxGUDcjssZRpFnToxG_KVE9Ii7NduFW2ks,2003
18
18
  photo_objects/django/api/auth.py,sha256=lS0S1tMVH2uN30g4jlixklv3eMnQ2FbQVQvuRXeMGYo,1420
19
19
  photo_objects/django/api/backup.py,sha256=lu-lDSGpEV9ASCIA5o0kNOZcg6_cmkVPCy1TFRvYyyY,6344
20
- photo_objects/django/api/photo.py,sha256=-lo1g6jfBr884wy-WV2DAEPxzH9V-tFUTRtitmA6i28,4471
20
+ photo_objects/django/api/photo.py,sha256=GtrLMQAQRDQa79cAiEnYVeZ9Wr9CIpHC9ApDqAh5uiQ,2999
21
21
  photo_objects/django/api/photo_change_request.py,sha256=v94RA7SUM60tC9mIZdz8HppbNKfHWeTFNPr_BPw3pys,3075
22
- photo_objects/django/api/utils.py,sha256=M7GdTZAkeAWSRjZeI51dlv8qaw2CjX3ruKsa1amc1Es,5559
22
+ photo_objects/django/api/utils.py,sha256=73yT8s5N7MtgHbIs7us7GQX3t5vOue_2-wHiUGyD81s,5394
23
23
  photo_objects/django/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
24
  photo_objects/django/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
25
  photo_objects/django/management/commands/clean-scaled-photos.py,sha256=KJY6phgTCxcmbMUsUfCRQjatvCmKyFninM8zT-tB3Kc,2008
@@ -53,14 +53,14 @@ photo_objects/django/views/api/auth.py,sha256=EN_ExegzmLN-bhSzu3L9-6UE9qodPd7_ZR
53
53
  photo_objects/django/views/api/photo.py,sha256=WHSayWTi_wG6otq6Rz1IKqJ5ik5riclR3AWB15ge5RU,4613
54
54
  photo_objects/django/views/api/utils.py,sha256=uQzKdSKHRAux5OZzqgWQr0gsK_FeweQP0cg_67OWA_Y,264
55
55
  photo_objects/django/views/ui/__init__.py,sha256=Y3XrckZExbHpWVNwDUGLfb99_midb8-5j6Ouf_Yu_G4,128
56
- photo_objects/django/views/ui/album.py,sha256=EQleU9ZyF3T0OABer3YMJbUNU4Vw9q-iY3WBPN872e8,5027
56
+ photo_objects/django/views/ui/album.py,sha256=IYjhjBj9MOffUDUSTm3IMjJoz-xGfvA_LVa0Vc_aXV8,5167
57
57
  photo_objects/django/views/ui/configuration.py,sha256=miEJTm_cRANu9Wt3SCcU-tYUwM7WLKgQm8zgApmKMxE,5464
58
- photo_objects/django/views/ui/photo.py,sha256=o7U0KimIWhreKSwIdVot1laEqqXprqvdbDZbRIvkJic,6966
59
- photo_objects/django/views/ui/photo_change_request.py,sha256=KAfk69RbDTdN3I4fMUx6j7idqZ6IHZ4li6KKVS3yAYM,2093
58
+ photo_objects/django/views/ui/photo.py,sha256=EOu43klthhmG6ysCrw2NWb7Vcz8I3FBR6GZUFhLBLG4,6281
59
+ photo_objects/django/views/ui/photo_change_request.py,sha256=PGP98APOVTkTw3FTvzYn92BBshensFwA8U0w8l1vIjg,2127
60
60
  photo_objects/django/views/ui/users.py,sha256=ABAtKwNoViYy2ht6X313BSm6wgvL302LVUNimp43gxc,649
61
- photo_objects/django/views/ui/utils.py,sha256=65hSFZ_rlWWprE5kJdqwL9P-Lwlin9qvO8GjFuajdnM,463
62
- photo_objects-0.9.6.dist-info/licenses/LICENSE,sha256=V3w6hTjXfP65F4r_mejveHcV5igHrblxao3-2RlfVlA,1068
63
- photo_objects-0.9.6.dist-info/METADATA,sha256=onytwijT-TLdeooruS21ZT_E7q7GOoOwJPv5wm1kCzc,3615
64
- photo_objects-0.9.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
65
- photo_objects-0.9.6.dist-info/top_level.txt,sha256=SZeL8mhf-WMGdhRtTGFvZc3aIRBboQls9O0cFDMGdQ0,14
66
- photo_objects-0.9.6.dist-info/RECORD,,
61
+ photo_objects/django/views/ui/utils.py,sha256=fAEgG6cdL_u9TBLWgqQGG8zC0RX1a-9vC6C06ST7InM,823
62
+ photo_objects-0.10.1.dist-info/licenses/LICENSE,sha256=V3w6hTjXfP65F4r_mejveHcV5igHrblxao3-2RlfVlA,1068
63
+ photo_objects-0.10.1.dist-info/METADATA,sha256=-epYO3uZXgbPW4MgGPKBKAb6JBG-ByGD0ID_3ts2gtA,3616
64
+ photo_objects-0.10.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
65
+ photo_objects-0.10.1.dist-info/top_level.txt,sha256=SZeL8mhf-WMGdhRtTGFvZc3aIRBboQls9O0cFDMGdQ0,14
66
+ photo_objects-0.10.1.dist-info/RECORD,,