photo-objects 0.10.1__py3-none-any.whl → 0.10.3__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.
- photo_objects/django/forms.py +52 -1
- photo_objects/django/migrations/0008_sitesettings_copyright_notice.py +29 -0
- photo_objects/django/models.py +19 -3
- photo_objects/django/templatetags/photo_objects_extras.py +18 -0
- photo_objects/django/views/ui/album.py +13 -0
- {photo_objects-0.10.1.dist-info → photo_objects-0.10.3.dist-info}/METADATA +1 -1
- {photo_objects-0.10.1.dist-info → photo_objects-0.10.3.dist-info}/RECORD +10 -9
- {photo_objects-0.10.1.dist-info → photo_objects-0.10.3.dist-info}/WHEEL +0 -0
- {photo_objects-0.10.1.dist-info → photo_objects-0.10.3.dist-info}/licenses/LICENSE +0 -0
- {photo_objects-0.10.1.dist-info → photo_objects-0.10.3.dist-info}/top_level.txt +0 -0
photo_objects/django/forms.py
CHANGED
|
@@ -20,6 +20,10 @@ from .models import Album, Photo, PhotoChangeRequest
|
|
|
20
20
|
KEY_POSTFIX_CHARS = 'bcdfghjklmnpqrstvwxz2456789'
|
|
21
21
|
KEY_POSTFIX_LEN = 5
|
|
22
22
|
|
|
23
|
+
ALBUM_TITLE_HELP = _(
|
|
24
|
+
'When creating a new album, album key is generated based on the title. '
|
|
25
|
+
'Modifying the title later does not change the album key.'
|
|
26
|
+
)
|
|
23
27
|
ALT_TEXT_HELP = _('Alternative text content for the photo.')
|
|
24
28
|
|
|
25
29
|
|
|
@@ -37,6 +41,44 @@ def description_help(resource):
|
|
|
37
41
|
}
|
|
38
42
|
|
|
39
43
|
|
|
44
|
+
def visibility_help(visibility: str):
|
|
45
|
+
visibility = Album.Visibility(visibility)
|
|
46
|
+
if visibility == Album.Visibility.PUBLIC:
|
|
47
|
+
return _(
|
|
48
|
+
'The album is visible to anyone without authentication.')
|
|
49
|
+
if visibility == Album.Visibility.HIDDEN:
|
|
50
|
+
return _(
|
|
51
|
+
'The album is visible to anyone with the link. Only '
|
|
52
|
+
'authenticated users can see the album in albums list.')
|
|
53
|
+
if visibility == Album.Visibility.PRIVATE:
|
|
54
|
+
return _(
|
|
55
|
+
'The album is only visible to authenticated users.')
|
|
56
|
+
if visibility == Album.Visibility.ADMIN:
|
|
57
|
+
return _(
|
|
58
|
+
'The album is only visible to admin users.')
|
|
59
|
+
return None
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class VisibilityRadioSelect(RadioSelect):
|
|
63
|
+
def create_option(
|
|
64
|
+
self, name, value, label, selected, index, subindex=None, attrs=None
|
|
65
|
+
):
|
|
66
|
+
option = super().create_option(
|
|
67
|
+
name,
|
|
68
|
+
value,
|
|
69
|
+
label,
|
|
70
|
+
selected,
|
|
71
|
+
index,
|
|
72
|
+
subindex=subindex,
|
|
73
|
+
attrs=attrs)
|
|
74
|
+
option['label'] = mark_safe(f'''
|
|
75
|
+
<div>
|
|
76
|
+
<span class="label">{label}</span>
|
|
77
|
+
<p class="helptext">{visibility_help(option.get('value'))}</p>
|
|
78
|
+
</div>''')
|
|
79
|
+
return option
|
|
80
|
+
|
|
81
|
+
|
|
40
82
|
def _check_admin_visibility(form):
|
|
41
83
|
if form.user and form.user.is_staff:
|
|
42
84
|
return
|
|
@@ -60,7 +102,10 @@ class CreateAlbumForm(ModelForm):
|
|
|
60
102
|
fields = ['key', 'title', 'description', 'visibility']
|
|
61
103
|
help_texts = {
|
|
62
104
|
**description_help('album'),
|
|
105
|
+
'title': ALBUM_TITLE_HELP,
|
|
63
106
|
}
|
|
107
|
+
widgets = {'visibility': VisibilityRadioSelect(
|
|
108
|
+
attrs={'class': 'visibility-select'}), }
|
|
64
109
|
|
|
65
110
|
def __init__(self, *args, user=None, **kwargs):
|
|
66
111
|
super().__init__(*args, **kwargs)
|
|
@@ -136,9 +181,15 @@ class ModifyAlbumForm(ModelForm):
|
|
|
136
181
|
'cover_photo': _(
|
|
137
182
|
'Select a cover photo for the album. The cover photo is '
|
|
138
183
|
'visible on the albums list page and in album preview image.'),
|
|
184
|
+
'title': ALBUM_TITLE_HELP,
|
|
139
185
|
}
|
|
140
186
|
widgets = {
|
|
141
|
-
'cover_photo': RadioSelect(
|
|
187
|
+
'cover_photo': RadioSelect(
|
|
188
|
+
attrs={
|
|
189
|
+
'class': 'photo-select'}),
|
|
190
|
+
'visibility': VisibilityRadioSelect(
|
|
191
|
+
attrs={
|
|
192
|
+
'class': 'visibility-select'}),
|
|
142
193
|
}
|
|
143
194
|
|
|
144
195
|
def __init__(self, *args, user=None, **kwargs):
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Generated by Django 5.2.6 on 2025-12-20 18:09
|
|
2
|
+
|
|
3
|
+
import django.db.models.deletion
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
dependencies = [
|
|
10
|
+
('photo_objects', '0007_backup'),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
migrations.AddField(
|
|
15
|
+
model_name='sitesettings',
|
|
16
|
+
name='copyright_notice',
|
|
17
|
+
field=models.CharField(blank=True, help_text='Copyright notice to display in the site footer. Content will be HTML-escaped before rendering.'),
|
|
18
|
+
),
|
|
19
|
+
migrations.AlterField(
|
|
20
|
+
model_name='sitesettings',
|
|
21
|
+
name='description',
|
|
22
|
+
field=models.TextField(blank=True, help_text='Description of the site, used in site level meta description tags and social media previews.'),
|
|
23
|
+
),
|
|
24
|
+
migrations.AlterField(
|
|
25
|
+
model_name='sitesettings',
|
|
26
|
+
name='preview_image',
|
|
27
|
+
field=models.ForeignKey(blank=True, help_text='Photo to use as the site level social media preview image.', null=True, on_delete=django.db.models.deletion.SET_NULL, to='photo_objects.photo'),
|
|
28
|
+
),
|
|
29
|
+
]
|
photo_objects/django/models.py
CHANGED
|
@@ -211,10 +211,26 @@ class SiteSettings(models.Model):
|
|
|
211
211
|
site = models.OneToOneField(
|
|
212
212
|
Site, on_delete=models.CASCADE, related_name="settings")
|
|
213
213
|
|
|
214
|
-
description = models.TextField(
|
|
214
|
+
description = models.TextField(
|
|
215
|
+
blank=True,
|
|
216
|
+
help_text=_(
|
|
217
|
+
"Description of the site, used in site level meta description "
|
|
218
|
+
"tags and social media previews."),
|
|
219
|
+
)
|
|
215
220
|
preview_image = models.ForeignKey(
|
|
216
|
-
Photo,
|
|
217
|
-
|
|
221
|
+
Photo,
|
|
222
|
+
blank=True,
|
|
223
|
+
null=True,
|
|
224
|
+
on_delete=models.SET_NULL,
|
|
225
|
+
help_text=_(
|
|
226
|
+
"Photo to use as the site level social media preview image."),
|
|
227
|
+
)
|
|
228
|
+
copyright_notice = models.CharField(
|
|
229
|
+
blank=True,
|
|
230
|
+
help_text=_(
|
|
231
|
+
"Copyright notice to display in the site footer. Content will be "
|
|
232
|
+
"HTML-escaped before rendering."),
|
|
233
|
+
)
|
|
218
234
|
objects = SiteSettingsManager()
|
|
219
235
|
|
|
220
236
|
def __str__(self):
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
2
|
from django import template
|
|
3
|
+
from django.utils.safestring import mark_safe
|
|
4
|
+
from django.utils.html import escape
|
|
3
5
|
|
|
4
6
|
from photo_objects.django.models import SiteSettings
|
|
5
7
|
from photo_objects.django.views.utils import meta_description
|
|
@@ -59,3 +61,19 @@ def meta_og(context):
|
|
|
59
61
|
}
|
|
60
62
|
except Exception:
|
|
61
63
|
return context
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@register.simple_tag(takes_context=True)
|
|
67
|
+
def copyright_notice(context):
|
|
68
|
+
try:
|
|
69
|
+
request = context.get("request")
|
|
70
|
+
site = request.site
|
|
71
|
+
|
|
72
|
+
settings = SiteSettings.objects.get(site)
|
|
73
|
+
|
|
74
|
+
if settings.copyright_notice:
|
|
75
|
+
notice = escape(settings.copyright_notice)
|
|
76
|
+
return mark_safe(f"<div>{notice}</div>")
|
|
77
|
+
return ""
|
|
78
|
+
except Exception:
|
|
79
|
+
return ""
|
|
@@ -56,6 +56,18 @@ def get_info(request: HttpRequest, album_key: str):
|
|
|
56
56
|
return None
|
|
57
57
|
|
|
58
58
|
|
|
59
|
+
def _timeline(album: Album):
|
|
60
|
+
if not album.first_timestamp or not album.last_timestamp:
|
|
61
|
+
return None
|
|
62
|
+
|
|
63
|
+
start = album.first_timestamp.strftime("%Y %B")
|
|
64
|
+
end = album.last_timestamp.strftime("%Y %B")
|
|
65
|
+
|
|
66
|
+
if start == end:
|
|
67
|
+
return start
|
|
68
|
+
return f"{start} – {end}"
|
|
69
|
+
|
|
70
|
+
|
|
59
71
|
@json_problem_as_html
|
|
60
72
|
def show_album(request: HttpRequest, album_key: str):
|
|
61
73
|
album = api.check_album_access(request, album_key)
|
|
@@ -64,6 +76,7 @@ def show_album(request: HttpRequest, album_key: str):
|
|
|
64
76
|
back = BackLink("Albums", reverse('photo_objects:list_albums'))
|
|
65
77
|
details = {
|
|
66
78
|
"Description": render_markdown(album.description),
|
|
79
|
+
"Timeline": _timeline(album),
|
|
67
80
|
"Visibility": Album.Visibility(album.visibility).label,
|
|
68
81
|
}
|
|
69
82
|
|
|
@@ -8,8 +8,8 @@ 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=
|
|
12
|
-
photo_objects/django/models.py,sha256=
|
|
11
|
+
photo_objects/django/forms.py,sha256=DWCnVEznev3h5ztYXz0gjMGZ8QUwlqML4KUKHcUiiZ4,7848
|
|
12
|
+
photo_objects/django/models.py,sha256=DsbaFo3xhzy5MHgtZXYmZuaHYqJSPPCTaZWAy_lHndU,7746
|
|
13
13
|
photo_objects/django/objsto.py,sha256=kf-Tv-kDt47Mnx0xMolAct_lP4M0H9xg03M3BnfAnJM,6909
|
|
14
14
|
photo_objects/django/signals.py,sha256=_gb4vlZkeFNYWXxwhNreaUJoOsbIWvP8OovVLtzepaE,2161
|
|
15
15
|
photo_objects/django/urls.py,sha256=QHGjDj3XCArLtmMcP3DKp8H9Xfd2X4SEvEKmMnx2KDk,2551
|
|
@@ -32,9 +32,10 @@ photo_objects/django/migrations/0004_camera_setup_and_settings.py,sha256=CS5xyIH
|
|
|
32
32
|
photo_objects/django/migrations/0005_sitesettings.py,sha256=Ilf5vUwTFQfXVP37zz0NWo5dQdeHDh5e-MV3enm0ZKI,994
|
|
33
33
|
photo_objects/django/migrations/0006_photo_alt_text.py,sha256=5ZWR-bfS_72Mpb0SrvtnWzVME-zlcRPzDCofmFWkUeU,1003
|
|
34
34
|
photo_objects/django/migrations/0007_backup.py,sha256=tLHLAnojppT6mhFF3FokGdwDbIj40_yqO9qMFm0H3UI,649
|
|
35
|
+
photo_objects/django/migrations/0008_sitesettings_copyright_notice.py,sha256=PmSAR85zZ6YEqfjZJCBnTONroIf4GSGC2m9BUkb2xf4,1118
|
|
35
36
|
photo_objects/django/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
36
37
|
photo_objects/django/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
37
|
-
photo_objects/django/templatetags/photo_objects_extras.py,sha256=
|
|
38
|
+
photo_objects/django/templatetags/photo_objects_extras.py,sha256=FH5JlNigVf1StIphRrd87nRzEhbrB9FYDWSiS7M1cAY,1890
|
|
38
39
|
photo_objects/django/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
39
40
|
photo_objects/django/tests/test_album.py,sha256=Uik36QbhaEojed6g862xqj8YI0d2963StU-lOpqMqAc,13095
|
|
40
41
|
photo_objects/django/tests/test_auth.py,sha256=hgr1UMVLvSI1x5zY7wTEXSBKfM5E_sNMIFlx8mVWYPY,3928
|
|
@@ -53,14 +54,14 @@ photo_objects/django/views/api/auth.py,sha256=EN_ExegzmLN-bhSzu3L9-6UE9qodPd7_ZR
|
|
|
53
54
|
photo_objects/django/views/api/photo.py,sha256=WHSayWTi_wG6otq6Rz1IKqJ5ik5riclR3AWB15ge5RU,4613
|
|
54
55
|
photo_objects/django/views/api/utils.py,sha256=uQzKdSKHRAux5OZzqgWQr0gsK_FeweQP0cg_67OWA_Y,264
|
|
55
56
|
photo_objects/django/views/ui/__init__.py,sha256=Y3XrckZExbHpWVNwDUGLfb99_midb8-5j6Ouf_Yu_G4,128
|
|
56
|
-
photo_objects/django/views/ui/album.py,sha256=
|
|
57
|
+
photo_objects/django/views/ui/album.py,sha256=0n_c-5MYJouzg2plK6_ZBtE6iqOdaqttY1RdsFO2V9s,5495
|
|
57
58
|
photo_objects/django/views/ui/configuration.py,sha256=miEJTm_cRANu9Wt3SCcU-tYUwM7WLKgQm8zgApmKMxE,5464
|
|
58
59
|
photo_objects/django/views/ui/photo.py,sha256=EOu43klthhmG6ysCrw2NWb7Vcz8I3FBR6GZUFhLBLG4,6281
|
|
59
60
|
photo_objects/django/views/ui/photo_change_request.py,sha256=PGP98APOVTkTw3FTvzYn92BBshensFwA8U0w8l1vIjg,2127
|
|
60
61
|
photo_objects/django/views/ui/users.py,sha256=ABAtKwNoViYy2ht6X313BSm6wgvL302LVUNimp43gxc,649
|
|
61
62
|
photo_objects/django/views/ui/utils.py,sha256=fAEgG6cdL_u9TBLWgqQGG8zC0RX1a-9vC6C06ST7InM,823
|
|
62
|
-
photo_objects-0.10.
|
|
63
|
-
photo_objects-0.10.
|
|
64
|
-
photo_objects-0.10.
|
|
65
|
-
photo_objects-0.10.
|
|
66
|
-
photo_objects-0.10.
|
|
63
|
+
photo_objects-0.10.3.dist-info/licenses/LICENSE,sha256=V3w6hTjXfP65F4r_mejveHcV5igHrblxao3-2RlfVlA,1068
|
|
64
|
+
photo_objects-0.10.3.dist-info/METADATA,sha256=9I5HA3kH3eW3Sg5bY3GC1Yd24wv_0haEP2Jta8IEyOw,3616
|
|
65
|
+
photo_objects-0.10.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
66
|
+
photo_objects-0.10.3.dist-info/top_level.txt,sha256=SZeL8mhf-WMGdhRtTGFvZc3aIRBboQls9O0cFDMGdQ0,14
|
|
67
|
+
photo_objects-0.10.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|