photo-objects 0.9.0__py3-none-any.whl → 0.9.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.
@@ -1,13 +1,15 @@
1
1
  from django.contrib.auth import get_user_model
2
2
  from django.contrib.auth.models import Group, Permission
3
+ from django.contrib.sites.models import Site
3
4
  from django.db import transaction
4
5
 
5
- from photo_objects.django.models import Album, Backup, Photo
6
+ from photo_objects.django.models import Album, Backup, Photo, SiteSettings
6
7
  from photo_objects.django.objsto import (
7
8
  backup_data_key,
8
9
  backup_info_key,
9
10
  delete_backup_objects,
10
11
  get_backup_data,
12
+ get_backup_object,
11
13
  get_backup_objects,
12
14
  put_backup_json,
13
15
  )
@@ -55,6 +57,12 @@ def _group_dict(group: Group):
55
57
 
56
58
 
57
59
  def create_backup(backup: Backup):
60
+ # Check if backup already exists
61
+ if get_backup_object(backup.id):
62
+ backup.status = "ready"
63
+ backup.save()
64
+ return
65
+
58
66
  user_model = get_user_model()
59
67
 
60
68
  backup.status = "pending"
@@ -99,10 +107,34 @@ def create_backup(backup: Backup):
99
107
  user.username),
100
108
  _user_dict(user))
101
109
 
110
+ sites = Site.objects.all()
111
+ for site in sites:
112
+ put_backup_json(
113
+ backup_data_key(backup.id, 'site', site.id),
114
+ {
115
+ "id": site.id,
116
+ "domain": site.domain,
117
+ "name": site.name,
118
+ }
119
+ )
120
+
121
+ site_settings = SiteSettings.objects.all()
122
+ for settings in site_settings:
123
+ put_backup_json(
124
+ backup_data_key(backup.id, 'settings', settings.site.id),
125
+ {
126
+ "site_id": settings.site.id,
127
+ "description": settings.description,
128
+ "preview_image_key": settings.preview_image.key
129
+ if settings.preview_image else None,
130
+ }
131
+ )
132
+
102
133
  put_backup_json(backup_info_key(backup.id), backup.to_json())
103
134
  except Exception:
104
135
  backup.status = "create_failed"
105
136
  backup.save()
137
+ raise
106
138
 
107
139
  backup.status = "ready"
108
140
  backup.save()
@@ -160,3 +192,24 @@ def restore_backup(backup_id: int):
160
192
  if cover_photo == filename:
161
193
  album.cover_photo = photo
162
194
  album.save()
195
+
196
+ for i in get_backup_data(backup_id, "site"):
197
+ site, _ = Site.objects.get_or_create(id=i.get("id"))
198
+ site.domain = i.get("domain")
199
+ site.name = i.get("name")
200
+ site.save()
201
+
202
+ for i in get_backup_data(backup_id, "settings"):
203
+ site = Site.objects.get(id=i.get("site_id"))
204
+
205
+ preview_image = None
206
+ if key := i.get("preview_image_key"):
207
+ preview_image = Photo.objects.get(key=key)
208
+
209
+ settings = SiteSettings.objects.create(
210
+ site=site,
211
+ description=i.get("description"),
212
+ preview_image=preview_image
213
+ if i.get("preview_image_key") else None
214
+ )
215
+ settings.save()
@@ -1,7 +1,11 @@
1
1
  # pylint: disable=invalid-name
2
+ from io import StringIO
3
+
4
+ from django.core.management import call_command
2
5
  from django.core.management.base import BaseCommand
3
6
  from django.contrib.auth import get_user_model
4
7
  from django.contrib.auth.models import Group
8
+ from django.db import connection
5
9
 
6
10
  from photo_objects.django.api.backup import get_backups, restore_backup
7
11
  from photo_objects.django.models import Album, Photo
@@ -28,6 +32,23 @@ class DatabaseStatus:
28
32
  )
29
33
 
30
34
 
35
+ def reset_sequences():
36
+ output = StringIO()
37
+ call_command(
38
+ 'sqlsequencereset',
39
+ 'photo_objects',
40
+ 'auth',
41
+ 'sites',
42
+ stdout=output,
43
+ no_color=True)
44
+
45
+ sql = output.getvalue()
46
+ with connection.cursor() as cursor:
47
+ cursor.execute(sql)
48
+
49
+ output.close()
50
+
51
+
31
52
  class Command(BaseCommand):
32
53
  help = "Restore latest backup if database is empty."
33
54
 
@@ -59,6 +80,7 @@ class Command(BaseCommand):
59
80
  )
60
81
  )
61
82
  restore_backup(id_)
83
+ reset_sequences()
62
84
  status = DatabaseStatus()
63
85
  self.stdout.write(
64
86
  self.style.SUCCESS(
@@ -71,4 +93,4 @@ class Command(BaseCommand):
71
93
  f'Failed to restore backup: {e}'
72
94
  )
73
95
  )
74
- exit(1)
96
+ raise
@@ -137,6 +137,14 @@ def put_backup_json(key: str, data: dict):
137
137
  return _put_json(key, data, _backup_access)
138
138
 
139
139
 
140
+ def get_backup_object(backup_id: int):
141
+ client, bucket = _backup_access()
142
+ return json.loads(
143
+ client.get_object(
144
+ bucket,
145
+ backup_info_key(backup_id)).read())
146
+
147
+
140
148
  def get_backup_objects():
141
149
  client, bucket = _backup_access()
142
150
  return [json.loads(i.read()) for i in _get_all(client, bucket, 'info_')]
@@ -25,6 +25,9 @@ class TestUtils(TestCase):
25
25
  def test_slugify_lower(self):
26
26
  self.assertEqual(slugify("QwErTy!", True), "qwerty-")
27
27
 
28
+ def test_slugify_number(self):
29
+ self.assertEqual(slugify(123), "123")
30
+
28
31
  def test_slugify_replace_leading_underscores(self):
29
32
  self.assertEqual(
30
33
  slugify(
photo_objects/utils.py CHANGED
@@ -31,9 +31,12 @@ def timestamp_str(timestamp: datetime):
31
31
  return timestamp.isoformat() if timestamp else None
32
32
 
33
33
 
34
- def slugify(title: str, lower=False, replace_leading_underscores=False) -> str:
34
+ def slugify(
35
+ title: str | int,
36
+ lower=False,
37
+ replace_leading_underscores=False) -> str:
35
38
  key = unicodedata.normalize(
36
- 'NFKD', title).encode(
39
+ 'NFKD', str(title)).encode(
37
40
  'ascii', 'ignore').decode('ascii')
38
41
  if lower:
39
42
  key = key.lower()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: photo-objects
3
- Version: 0.9.0
3
+ Version: 0.9.1
4
4
  Summary: Application for storing photos in S3 compatible object-storage.
5
5
  Author: Toni Kangas
6
6
  License: MIT License
@@ -2,7 +2,7 @@ photo_objects/__init__.py,sha256=I1508w_ntomEqTFQgC74SurhxVXfCiDWZLRsny2f59g,60
2
2
  photo_objects/config.py,sha256=0-Aeo-z-d_fxx-cjAjxSwPJZUgYaAi7NTodiErlxIXo,861
3
3
  photo_objects/error.py,sha256=7afLYjxM0EaYioxVw_XUqHTvfSMSuQPUwwle0OVlaDY,45
4
4
  photo_objects/img.py,sha256=2HVGS2g7rS2hnomozYL92oxrcN6zjDTHvWNr-UAqtGQ,4620
5
- photo_objects/utils.py,sha256=V0THzeLSGkgLTWdVhP-ee1nb-vl051mtF4AQqdgMo88,1145
5
+ photo_objects/utils.py,sha256=M4SeHC_R4B-2LUHx_dQrY9vuzTTKjY31uwU0Vy1Hj7Q,1181
6
6
  photo_objects/django/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
7
  photo_objects/django/admin.py,sha256=pvyQKs2FMtKtSS2PE_NKR_jsSi7-GKz3bbsqDNgjt6w,352
8
8
  photo_objects/django/apps.py,sha256=Apqu6o6fpoxda18NQgKupvQRvTAZxVviIK_-dUR3rck,1444
@@ -10,13 +10,13 @@ photo_objects/django/conf.py,sha256=ZpeIulEc1tpr8AO52meNKOF30Xf5osbDtDyHvQRtkx4,
10
10
  photo_objects/django/context_processors.py,sha256=XacUmcYV-4NMMMNXPWrHKdvNd6lfyamisngaVerREiU,306
11
11
  photo_objects/django/forms.py,sha256=zSSmdIYn4PEx1Nnw-tuo4h4otKj3C099lB4-vp2BRUc,6861
12
12
  photo_objects/django/models.py,sha256=OxkkczIBg7TaFWWm4VdtbRMJOK_OQKrV29g-X2cm5BQ,7247
13
- photo_objects/django/objsto.py,sha256=lYOd1PJzrcmqtqw-Xci85MX_9yWqzeisYx4uJjXhHdQ,6046
13
+ photo_objects/django/objsto.py,sha256=NSimuKvS06dERaEPevM6v9PDxFsgz6JUhlcKmUxnnP0,6243
14
14
  photo_objects/django/signals.py,sha256=_gb4vlZkeFNYWXxwhNreaUJoOsbIWvP8OovVLtzepaE,2161
15
15
  photo_objects/django/urls.py,sha256=XnOSEB8YtAJamlEsjKYz6U1DfDu7HHZpAinpqdulR8k,2501
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=Lq9fTjuoZssQG86QJFIxlLpQi2FU0AS8yCZklvu_ues,4379
19
+ photo_objects/django/api/backup.py,sha256=_D1KMkIp7A8iPs2LxQ-MsaFcAHwCwhE7un5NRHHIvOc,6099
20
20
  photo_objects/django/api/photo.py,sha256=-lo1g6jfBr884wy-WV2DAEPxzH9V-tFUTRtitmA6i28,4471
21
21
  photo_objects/django/api/photo_change_request.py,sha256=v94RA7SUM60tC9mIZdz8HppbNKfHWeTFNPr_BPw3pys,3075
22
22
  photo_objects/django/api/utils.py,sha256=8r51YgFgKPD05Zjzhstl4jlQ4JM8DtsxUyAzhjXi5Pk,5567
@@ -24,7 +24,7 @@ photo_objects/django/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
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
26
26
  photo_objects/django/management/commands/create-initial-admin-account.py,sha256=PhC7jnRxsph8rML384vKfXzYfJqMQdd8oUHxUY7JEW8,1178
27
- photo_objects/django/management/commands/restore-backup.py,sha256=pnlHWcEgFDlgKaslC5PdhVcm491uRylCD3ZdRwGS0B0,2157
27
+ photo_objects/django/management/commands/restore-backup.py,sha256=7Hc-6O_4hv8m66CoWbedjH20KVzURFstLPGPq6ooBuk,2607
28
28
  photo_objects/django/migrations/0001_initial.py,sha256=BLW-EZ38sBgDhOYyprc-h_vuPpRxA11qxt4ZuYNO1Wo,2424
29
29
  photo_objects/django/migrations/0002_created_at_updated_at.py,sha256=7OT2VvDffAkX9XKBHVY-jvzxeIl2yU0Jr1ByCNGcUfw,1039
30
30
  photo_objects/django/migrations/0003_admin_visibility.py,sha256=PdxPOJzr-ViRBlOYUHEEGhe0hLtDysZJdMqvbjKVpEg,529
@@ -43,7 +43,7 @@ photo_objects/django/tests/test_img.py,sha256=HEAWcr5fpTkzePkhoQ4YrWsDO9TvFOr7my
43
43
  photo_objects/django/tests/test_og_meta.py,sha256=Kk5a9KvE88KZ60gLqXSe6rTz5YU-gdjteksYolHd-nw,1804
44
44
  photo_objects/django/tests/test_photo.py,sha256=JWXN3fF2VtuByMKm2o5b19HnxwDr6ecRwuGzgc5RsBw,13471
45
45
  photo_objects/django/tests/test_photo_change_requests.py,sha256=Ld5ytqxxZiEWrqfX8htJ6-5ARU7tqTYD-iUhb7EMcnU,3078
46
- photo_objects/django/tests/test_utils.py,sha256=zBLv8lkvcLMCaH4D6GR1KZqUe-rPowhcBkQX19-Kshs,2007
46
+ photo_objects/django/tests/test_utils.py,sha256=0Xl0ReS2X9GsEH-jmLg8xC79hJ4nhbfULo0BOVjiykQ,2089
47
47
  photo_objects/django/tests/utils.py,sha256=LiObyRARkmO4arnY2gXNi_T8XxT9eSKKszENMo2UIh8,4639
48
48
  photo_objects/django/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
49
49
  photo_objects/django/views/utils.py,sha256=AjJK5r5HmTF63E9Q4W3pKggDESuhNXUvbROpS8m70KM,1319
@@ -59,8 +59,8 @@ photo_objects/django/views/ui/photo.py,sha256=flwcET5nSChzfyAEWRTUlklTW2o64przNX
59
59
  photo_objects/django/views/ui/photo_change_request.py,sha256=eaYGXFqtHj8qonDAmPyn4nrEHkL13EBD-1s8Phs0XP4,2098
60
60
  photo_objects/django/views/ui/users.py,sha256=nb73cnzuV98QkJb0j8F2hqPgOGFIWpUFTFu6dXMeVwM,722
61
61
  photo_objects/django/views/ui/utils.py,sha256=YV_YcUbX-zUkdFnBlezPChR6aPDhZJ9loSOHBSzF6Cc,273
62
- photo_objects-0.9.0.dist-info/licenses/LICENSE,sha256=V3w6hTjXfP65F4r_mejveHcV5igHrblxao3-2RlfVlA,1068
63
- photo_objects-0.9.0.dist-info/METADATA,sha256=54uuCEzSyejSGgQ2AlWFlCjuwawJFHfLBxRE_EQ47D4,3605
64
- photo_objects-0.9.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
65
- photo_objects-0.9.0.dist-info/top_level.txt,sha256=SZeL8mhf-WMGdhRtTGFvZc3aIRBboQls9O0cFDMGdQ0,14
66
- photo_objects-0.9.0.dist-info/RECORD,,
62
+ photo_objects-0.9.1.dist-info/licenses/LICENSE,sha256=V3w6hTjXfP65F4r_mejveHcV5igHrblxao3-2RlfVlA,1068
63
+ photo_objects-0.9.1.dist-info/METADATA,sha256=GoExSl5yt_qDGeEaIzeeue4bGNcIC-mcx2RgDe1i1EY,3605
64
+ photo_objects-0.9.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
65
+ photo_objects-0.9.1.dist-info/top_level.txt,sha256=SZeL8mhf-WMGdhRtTGFvZc3aIRBboQls9O0cFDMGdQ0,14
66
+ photo_objects-0.9.1.dist-info/RECORD,,