photo-objects 0.10.3__py3-none-any.whl → 0.10.5__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.
@@ -1,4 +1,5 @@
1
1
  from threading import Thread
2
+ from time import sleep
2
3
 
3
4
  from django.contrib.auth import get_user_model
4
5
  from django.contrib.auth.models import Group, Permission
@@ -59,7 +60,20 @@ def _group_dict(group: Group):
59
60
 
60
61
 
61
62
  def _create_backup(backup_id: int):
62
- backup = Backup.objects.get(id=backup_id)
63
+ # Backup might not be available immediately.
64
+ # Retry getting the backup a few times.
65
+ for _ in range(5):
66
+ try:
67
+ backup = Backup.objects.get(id=backup_id)
68
+ break
69
+ except Backup.DoesNotExist:
70
+ sleep(2)
71
+
72
+ if not backup:
73
+ return
74
+
75
+ backup.status = "processing"
76
+ backup.save()
63
77
 
64
78
  user_model = get_user_model()
65
79
 
@@ -256,6 +256,7 @@ class Backup(models.Model):
256
256
  return _str(
257
257
  f'Backup {self.id}',
258
258
  created_at=self.created_at,
259
+ status=self.status,
259
260
  comment=self.comment,
260
261
  )
261
262
 
@@ -78,6 +78,8 @@ def show_album(request: HttpRequest, album_key: str):
78
78
  "Description": render_markdown(album.description),
79
79
  "Timeline": _timeline(album),
80
80
  "Visibility": Album.Visibility(album.visibility).label,
81
+ "Created at": album.created_at,
82
+ "Updated at": album.updated_at,
81
83
  }
82
84
 
83
85
  return render(request, "photo_objects/album/show.html", {
@@ -1,6 +1,7 @@
1
1
  from django.http import HttpRequest, HttpResponseRedirect
2
2
  from django.shortcuts import render
3
3
  from django.urls import reverse
4
+ from django.utils.safestring import mark_safe
4
5
 
5
6
  from photo_objects.django import api
6
7
  from photo_objects.django.api.utils import (
@@ -64,25 +65,34 @@ def _lens(photo: Photo):
64
65
  return None
65
66
 
66
67
 
68
+ def _sec(text: str):
69
+ return f'<span class="secondary">{text}</span>'
70
+
71
+
67
72
  def _exposure_time_to_string(exposure_time: float | None):
68
73
  if exposure_time is None:
69
74
  return None
70
75
  if exposure_time < 1:
71
- return f"1/{int(1 / exposure_time)}\u202Fs"
76
+ return mark_safe(
77
+ f"{_sec('1/')}{int(1 / exposure_time)}\u202F{_sec('s')}")
72
78
  else:
73
- return f"{int(exposure_time)}\u202Fs"
79
+ return mark_safe(
80
+ f"{int(exposure_time)}\u202F{_sec('s')}")
74
81
 
75
82
 
76
83
  def _camera_settings(photo: Photo):
77
84
  r = []
78
85
  if photo.focal_length:
79
- r.append(f"{round(photo.focal_length)}\u202Fmm")
86
+ r.append(mark_safe(
87
+ f"{round(photo.focal_length)}\u202F{_sec('mm')}"))
80
88
  if photo.f_number:
81
- r.append(f"f/{photo.f_number}")
89
+ r.append(
90
+ mark_safe(f"{_sec('f/')}{photo.f_number}"))
82
91
  if photo.exposure_time:
83
92
  r.append(_exposure_time_to_string(photo.exposure_time))
84
93
  if photo.iso_speed:
85
- r.append(f"ISO\u202F{photo.iso_speed}")
94
+ r.append(mark_safe(
95
+ f"{_sec('ISO')}\u202F{photo.iso_speed}"))
86
96
  return r
87
97
 
88
98
 
@@ -120,6 +130,8 @@ def show_photo(request: HttpRequest, album_key: str, photo_key: str):
120
130
  "Camera": _camera(photo),
121
131
  "Lens": _lens(photo),
122
132
  "Settings": _camera_settings(photo),
133
+ "Created at": photo.created_at,
134
+ "Updated at": photo.updated_at,
123
135
  }
124
136
 
125
137
  return render(request, "photo_objects/photo/show.html", {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: photo-objects
3
- Version: 0.10.3
3
+ Version: 0.10.5
4
4
  Summary: Application for storing photos in S3 compatible object-storage.
5
5
  Author: Toni Kangas
6
6
  License: MIT License
@@ -29,7 +29,7 @@ Project-URL: Homepage, https://github.com/kangasta/photo-objects
29
29
  Project-URL: Repository, https://github.com/kangasta/photo-objects.git
30
30
  Classifier: Environment :: Web Environment
31
31
  Classifier: Framework :: Django
32
- Classifier: Framework :: Django :: 5.0
32
+ Classifier: Framework :: Django :: 6.0
33
33
  Classifier: Intended Audience :: Developers
34
34
  Classifier: License :: OSI Approved :: MIT License
35
35
  Classifier: Operating System :: OS Independent
@@ -43,18 +43,40 @@ Description-Content-Type: text/markdown
43
43
  License-File: LICENSE
44
44
  Requires-Dist: markdown~=3.7
45
45
  Requires-Dist: minio<7.2.19,>=7.2.0
46
- Requires-Dist: pillow~=10.4
46
+ Requires-Dist: pillow~=12.0
47
47
  Dynamic: license-file
48
48
 
49
49
  # Photo Objects
50
50
 
51
51
  [![CI](https://github.com/kangasta/photo-objects/actions/workflows/ci.yml/badge.svg)](https://github.com/kangasta/photo-objects/actions/workflows/ci.yml)
52
+ [![Release](https://github.com/kangasta/photo-objects/actions/workflows/release.yml/badge.svg)](https://github.com/kangasta/photo-objects/actions/workflows/release.yml)
52
53
 
53
- Application for storing photos in S3 compatible object-storage.
54
+ Application for storing photos in S3 compatible object-storage. Key features:
55
+
56
+ - Automatically scales photos according to different sizes defined in settings.
57
+ - Provides simple grouping and access control for the photos with albums.
54
58
 
55
59
  ## Developing
56
60
 
57
- Make migrations:
61
+ Build containers:
62
+
63
+ ```sh
64
+ docker compose build
65
+ ```
66
+
67
+ Start or update development environment:
68
+
69
+ ```sh
70
+ docker compose up -d
71
+ ```
72
+
73
+ Print initial admin password (username of the initial administrator account is `admin`):
74
+
75
+ ```sh
76
+ docker compose exec api cat /var/photo_objects/initial_admin_password
77
+ ```
78
+
79
+ Make database migrations (requires development environment to be running):
58
80
 
59
81
  ```sh
60
82
  python3 back/manage.py makemigrations --pythonpath="$(pwd)"
@@ -9,14 +9,14 @@ photo_objects/django/apps.py,sha256=Apqu6o6fpoxda18NQgKupvQRvTAZxVviIK_-dUR3rck,
9
9
  photo_objects/django/conf.py,sha256=ZpeIulEc1tpr8AO52meNKOF30Xf5osbDtDyHvQRtkx4,2593
10
10
  photo_objects/django/context_processors.py,sha256=XacUmcYV-4NMMMNXPWrHKdvNd6lfyamisngaVerREiU,306
11
11
  photo_objects/django/forms.py,sha256=DWCnVEznev3h5ztYXz0gjMGZ8QUwlqML4KUKHcUiiZ4,7848
12
- photo_objects/django/models.py,sha256=DsbaFo3xhzy5MHgtZXYmZuaHYqJSPPCTaZWAy_lHndU,7746
12
+ photo_objects/django/models.py,sha256=0UeCaeDj3bfRPnVCtmbH1jNmhhg15eJSQEi_WuG9FEA,7778
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
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
- photo_objects/django/api/backup.py,sha256=lu-lDSGpEV9ASCIA5o0kNOZcg6_cmkVPCy1TFRvYyyY,6344
19
+ photo_objects/django/api/backup.py,sha256=I6C-VQSN86CZ1FbWfk0jvvLLGeXZNP3zQyjJqSnLmwI,6666
20
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
22
  photo_objects/django/api/utils.py,sha256=73yT8s5N7MtgHbIs7us7GQX3t5vOue_2-wHiUGyD81s,5394
@@ -54,14 +54,14 @@ photo_objects/django/views/api/auth.py,sha256=EN_ExegzmLN-bhSzu3L9-6UE9qodPd7_ZR
54
54
  photo_objects/django/views/api/photo.py,sha256=WHSayWTi_wG6otq6Rz1IKqJ5ik5riclR3AWB15ge5RU,4613
55
55
  photo_objects/django/views/api/utils.py,sha256=uQzKdSKHRAux5OZzqgWQr0gsK_FeweQP0cg_67OWA_Y,264
56
56
  photo_objects/django/views/ui/__init__.py,sha256=Y3XrckZExbHpWVNwDUGLfb99_midb8-5j6Ouf_Yu_G4,128
57
- photo_objects/django/views/ui/album.py,sha256=0n_c-5MYJouzg2plK6_ZBtE6iqOdaqttY1RdsFO2V9s,5495
57
+ photo_objects/django/views/ui/album.py,sha256=BOZbacGQtmUKC5BwzFlfb4pOAZ77DkP4CUYXZuU8Wq8,5575
58
58
  photo_objects/django/views/ui/configuration.py,sha256=miEJTm_cRANu9Wt3SCcU-tYUwM7WLKgQm8zgApmKMxE,5464
59
- photo_objects/django/views/ui/photo.py,sha256=EOu43klthhmG6ysCrw2NWb7Vcz8I3FBR6GZUFhLBLG4,6281
59
+ photo_objects/django/views/ui/photo.py,sha256=VCJYV_xJbKNC9Vk1dJuEH0Nka96ufyxNL64apvgXY9c,6662
60
60
  photo_objects/django/views/ui/photo_change_request.py,sha256=PGP98APOVTkTw3FTvzYn92BBshensFwA8U0w8l1vIjg,2127
61
61
  photo_objects/django/views/ui/users.py,sha256=ABAtKwNoViYy2ht6X313BSm6wgvL302LVUNimp43gxc,649
62
62
  photo_objects/django/views/ui/utils.py,sha256=fAEgG6cdL_u9TBLWgqQGG8zC0RX1a-9vC6C06ST7InM,823
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,,
63
+ photo_objects-0.10.5.dist-info/licenses/LICENSE,sha256=V3w6hTjXfP65F4r_mejveHcV5igHrblxao3-2RlfVlA,1068
64
+ photo_objects-0.10.5.dist-info/METADATA,sha256=dDktYzqKzwViZrX94r_XNn9GmmLsVrUvkPvMYt1B3q4,4308
65
+ photo_objects-0.10.5.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
66
+ photo_objects-0.10.5.dist-info/top_level.txt,sha256=SZeL8mhf-WMGdhRtTGFvZc3aIRBboQls9O0cFDMGdQ0,14
67
+ photo_objects-0.10.5.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5