photo-objects 0.5.0__py3-none-any.whl → 0.7.0__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/api/photo.py +23 -5
- photo_objects/django/api/utils.py +6 -0
- photo_objects/django/conf.py +10 -5
- photo_objects/django/context_processors.py +6 -2
- photo_objects/django/forms.py +5 -1
- photo_objects/django/objsto.py +26 -2
- photo_objects/django/tests/test_og_meta.py +60 -0
- photo_objects/django/tests/test_photo.py +9 -0
- photo_objects/django/tests/utils.py +21 -0
- photo_objects/django/views/api/photo.py +13 -4
- photo_objects/django/views/ui/photo.py +14 -2
- photo_objects/img.py +7 -3
- {photo_objects-0.5.0.dist-info → photo_objects-0.7.0.dist-info}/METADATA +1 -1
- {photo_objects-0.5.0.dist-info → photo_objects-0.7.0.dist-info}/RECORD +17 -16
- {photo_objects-0.5.0.dist-info → photo_objects-0.7.0.dist-info}/WHEEL +0 -0
- {photo_objects-0.5.0.dist-info → photo_objects-0.7.0.dist-info}/licenses/LICENSE +0 -0
- {photo_objects-0.5.0.dist-info → photo_objects-0.7.0.dist-info}/top_level.txt +0 -0
|
@@ -17,6 +17,7 @@ from photo_objects.img import photo_details
|
|
|
17
17
|
from .auth import check_album_access, check_photo_access
|
|
18
18
|
from .utils import (
|
|
19
19
|
FormValidationFailed,
|
|
20
|
+
UploadPhotosFailed,
|
|
20
21
|
JsonProblem,
|
|
21
22
|
check_permissions,
|
|
22
23
|
parse_input_data,
|
|
@@ -57,7 +58,7 @@ def _upload_photo(album_key: str, photo_file: UploadedFile):
|
|
|
57
58
|
photo.delete()
|
|
58
59
|
|
|
59
60
|
msg = objsto.with_error_code(
|
|
60
|
-
"Could not save photo to object storage", e)
|
|
61
|
+
"Could not save photo to object storage.", e)
|
|
61
62
|
logger.error(f"{msg}: {str(e)}")
|
|
62
63
|
raise JsonProblem(f"{msg}.", 500) from e
|
|
63
64
|
|
|
@@ -73,6 +74,17 @@ def upload_photo(request: HttpRequest, album_key: str):
|
|
|
73
74
|
return _upload_photo(album_key, photo_file)
|
|
74
75
|
|
|
75
76
|
|
|
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
|
+
|
|
76
88
|
def upload_photos(request: HttpRequest, album_key: str):
|
|
77
89
|
check_permissions(
|
|
78
90
|
request,
|
|
@@ -92,12 +104,18 @@ def upload_photos(request: HttpRequest, album_key: str):
|
|
|
92
104
|
for photo_file in f.cleaned_data["photos"]:
|
|
93
105
|
try:
|
|
94
106
|
photos.append(_upload_photo(album_key, photo_file))
|
|
95
|
-
except
|
|
96
|
-
|
|
97
|
-
f.add_error(
|
|
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}")
|
|
98
116
|
|
|
99
117
|
if not f.is_valid():
|
|
100
|
-
raise
|
|
118
|
+
raise UploadPhotosFailed(f, [i.filename for i in photos])
|
|
101
119
|
|
|
102
120
|
return photos
|
|
103
121
|
|
|
@@ -129,6 +129,12 @@ class FormValidationFailed(JsonProblem):
|
|
|
129
129
|
self.form = form
|
|
130
130
|
|
|
131
131
|
|
|
132
|
+
class UploadPhotosFailed(FormValidationFailed):
|
|
133
|
+
def __init__(self, form: ModelForm, uploaded_photos: list[str]):
|
|
134
|
+
super().__init__(form)
|
|
135
|
+
self.uploaded_photos = uploaded_photos
|
|
136
|
+
|
|
137
|
+
|
|
132
138
|
def check_permissions(request: HttpRequest, *permissions: str):
|
|
133
139
|
if not request.user.is_authenticated:
|
|
134
140
|
raise Unauthorized()
|
photo_objects/django/conf.py
CHANGED
|
@@ -30,20 +30,25 @@ class PhotoSizeDimensions:
|
|
|
30
30
|
max_width: int = None
|
|
31
31
|
max_height: int = None
|
|
32
32
|
max_aspect_ratio: float = None
|
|
33
|
+
image_format: str = None
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
DEFAULT_SM = dict(
|
|
36
37
|
max_width=512,
|
|
37
38
|
max_height=512,
|
|
38
|
-
max_aspect_ratio=1.5
|
|
39
|
+
max_aspect_ratio=1.5,
|
|
40
|
+
image_format='WEBP'
|
|
39
41
|
)
|
|
40
42
|
DEFAULT_MD = dict(
|
|
41
|
-
max_width=
|
|
42
|
-
max_height=
|
|
43
|
+
max_width=1024,
|
|
44
|
+
max_height=1024,
|
|
45
|
+
max_aspect_ratio=1.5,
|
|
46
|
+
image_format="JPEG"
|
|
43
47
|
)
|
|
44
48
|
DEFAULT_LG = dict(
|
|
45
|
-
max_width=
|
|
46
|
-
max_height=
|
|
49
|
+
max_width=2048,
|
|
50
|
+
max_height=2048,
|
|
51
|
+
image_format='WEBP'
|
|
47
52
|
)
|
|
48
53
|
|
|
49
54
|
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
from importlib.metadata import version
|
|
1
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
class Metadata:
|
|
5
|
-
|
|
5
|
+
def __init__(self):
|
|
6
|
+
try:
|
|
7
|
+
self.version = version('photo_objects')
|
|
8
|
+
except PackageNotFoundError:
|
|
9
|
+
self.version = None
|
|
6
10
|
|
|
7
11
|
|
|
8
12
|
def metadata(_):
|
photo_objects/django/forms.py
CHANGED
|
@@ -195,7 +195,11 @@ class CreatePhotoForm(ModelForm):
|
|
|
195
195
|
error_messages = {
|
|
196
196
|
'album': {
|
|
197
197
|
'invalid_choice': _('Album with %(value)s key does not exist.')
|
|
198
|
-
}
|
|
198
|
+
},
|
|
199
|
+
'key': {
|
|
200
|
+
'unique': _(
|
|
201
|
+
'Photo with this filename already exists in the album.'),
|
|
202
|
+
},
|
|
199
203
|
}
|
|
200
204
|
|
|
201
205
|
|
photo_objects/django/objsto.py
CHANGED
|
@@ -2,6 +2,7 @@ from dataclasses import asdict
|
|
|
2
2
|
from io import BytesIO
|
|
3
3
|
import json
|
|
4
4
|
import mimetypes
|
|
5
|
+
import re
|
|
5
6
|
import urllib3
|
|
6
7
|
|
|
7
8
|
from minio import Minio, S3Error
|
|
@@ -60,8 +61,30 @@ def photo_path(album_key, photo_key, size_key):
|
|
|
60
61
|
return f"{size_key}/{album_key}/{photo_key}"
|
|
61
62
|
|
|
62
63
|
|
|
63
|
-
def
|
|
64
|
-
|
|
64
|
+
def _photo_filename(photo_key: str, image_format: str = None) -> str:
|
|
65
|
+
if image_format:
|
|
66
|
+
filename = re.sub(r'\.[^.]+$', '', photo_key)
|
|
67
|
+
return f"{filename}.{image_format.lower()}"
|
|
68
|
+
|
|
69
|
+
return photo_key
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def photo_content_headers(
|
|
73
|
+
photo_key: str,
|
|
74
|
+
image_format: str = None,
|
|
75
|
+
) -> tuple[str, dict[str, str]]:
|
|
76
|
+
filename = _photo_filename(photo_key, image_format)
|
|
77
|
+
|
|
78
|
+
content_type = mimetypes.guess_type(filename, strict=False)[0]
|
|
79
|
+
headers = {
|
|
80
|
+
"Content-Disposition": f"inline; filename={filename}"
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return content_type, headers
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def put_photo(album_key, photo_key, size_key, photo_file, image_format=None):
|
|
87
|
+
content_type, headers = photo_content_headers(photo_key, image_format)
|
|
65
88
|
|
|
66
89
|
client, bucket = _objsto_access()
|
|
67
90
|
return client.put_object(
|
|
@@ -71,6 +94,7 @@ def put_photo(album_key, photo_key, size_key, photo_file):
|
|
|
71
94
|
length=-1,
|
|
72
95
|
part_size=10 * MEGABYTE,
|
|
73
96
|
content_type=content_type,
|
|
97
|
+
metadata=headers
|
|
74
98
|
)
|
|
75
99
|
|
|
76
100
|
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
from django.contrib.sites.models import Site
|
|
2
|
+
|
|
3
|
+
from photo_objects.django.models import Album, Photo, SiteSettings
|
|
4
|
+
|
|
5
|
+
from .utils import TestCase, create_dummy_photo, temp_static_files
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
PHOTOS_DIRECTORY = "photos"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class OgMetaTests(TestCase):
|
|
12
|
+
@classmethod
|
|
13
|
+
def setUpTestData(cls):
|
|
14
|
+
album = Album.objects.create(
|
|
15
|
+
key="paris", visibility=Album.Visibility.PUBLIC)
|
|
16
|
+
|
|
17
|
+
create_dummy_photo(album, "tower.jpeg")
|
|
18
|
+
|
|
19
|
+
@temp_static_files
|
|
20
|
+
def test_albums_og_meta(self):
|
|
21
|
+
og_title = '<meta property="og:title" content="Test" />'
|
|
22
|
+
|
|
23
|
+
response = self.client.get("/albums")
|
|
24
|
+
self.assertNotContains(
|
|
25
|
+
response,
|
|
26
|
+
og_title,
|
|
27
|
+
status_code=200,
|
|
28
|
+
html=True)
|
|
29
|
+
|
|
30
|
+
site = Site.objects.get(id=1)
|
|
31
|
+
site.name = "Test"
|
|
32
|
+
site.domain = "test.example.com"
|
|
33
|
+
site.save()
|
|
34
|
+
|
|
35
|
+
response = self.client.get("/albums")
|
|
36
|
+
self.assertNotContains(
|
|
37
|
+
response,
|
|
38
|
+
og_title,
|
|
39
|
+
status_code=200,
|
|
40
|
+
html=True)
|
|
41
|
+
|
|
42
|
+
site_settings = SiteSettings.objects.get(site=site)
|
|
43
|
+
site_settings.description = "Description"
|
|
44
|
+
site_settings.preview_image = Photo.objects.get(key="paris/tower.jpeg")
|
|
45
|
+
site_settings.save()
|
|
46
|
+
|
|
47
|
+
tags = [
|
|
48
|
+
og_title,
|
|
49
|
+
'<meta property="og:description" content="Description" />',
|
|
50
|
+
'<meta property="og:image" content="https://test.example.com/img/paris/tower.jpeg/md"/>', # noqa: E501
|
|
51
|
+
'<meta property="og:url" content="https://test.example.com/albums" />', # noqa: E501
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
response = self.client.get("/albums")
|
|
55
|
+
for tag in tags:
|
|
56
|
+
self.assertContains(
|
|
57
|
+
response,
|
|
58
|
+
tag,
|
|
59
|
+
status_code=200,
|
|
60
|
+
html=True)
|
|
@@ -184,6 +184,15 @@ class PhotoViewTests(TestCase):
|
|
|
184
184
|
{filename: file})
|
|
185
185
|
self.assertStatus(response, 500)
|
|
186
186
|
|
|
187
|
+
response = self.client.get(
|
|
188
|
+
"/api/albums/test-photo-a/photos/tower.jpg")
|
|
189
|
+
self.assertStatus(response, 404)
|
|
190
|
+
|
|
191
|
+
response = self.client.get(
|
|
192
|
+
"/api/albums/test-photo-a/photos")
|
|
193
|
+
self.assertStatus(response, 200)
|
|
194
|
+
self.assertEqual(len(response.json()), 0)
|
|
195
|
+
|
|
187
196
|
def test_get_image_scales_the_image(self):
|
|
188
197
|
login_success = self.client.login(
|
|
189
198
|
username='has_permission', password='test')
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
|
+
from io import StringIO
|
|
2
3
|
import os
|
|
4
|
+
import shutil
|
|
5
|
+
import tempfile
|
|
3
6
|
|
|
4
7
|
from django.conf import settings
|
|
8
|
+
from django.core.management import call_command
|
|
5
9
|
from django.test import TestCase as DjangoTestCase, override_settings
|
|
6
10
|
from django.utils import timezone
|
|
7
11
|
from django.utils.dateparse import parse_datetime
|
|
@@ -120,3 +124,20 @@ def parse_timestamps(data):
|
|
|
120
124
|
return Timestamps(
|
|
121
125
|
created_at=data.get('created_at'),
|
|
122
126
|
updated_at=data.get('updated_at'))
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
# Based on https://stackoverflow.com/a/76745063
|
|
130
|
+
def temp_static_files(func):
|
|
131
|
+
'''Decorator that creates a temporary directory, configures that as
|
|
132
|
+
STATIC_ROOT, and collects static files there.'''
|
|
133
|
+
def wrapper(*args, **kwargs):
|
|
134
|
+
static_root = tempfile.mkdtemp(prefix="test_static_")
|
|
135
|
+
with override_settings(STATIC_ROOT=static_root):
|
|
136
|
+
try:
|
|
137
|
+
out = StringIO()
|
|
138
|
+
call_command("collectstatic", "--noinput", stdout=out)
|
|
139
|
+
func(*args, **kwargs)
|
|
140
|
+
finally:
|
|
141
|
+
shutil.rmtree(static_root)
|
|
142
|
+
|
|
143
|
+
return wrapper
|
|
@@ -91,14 +91,23 @@ def get_img(request: HttpRequest, album_key: str, photo_key: str):
|
|
|
91
91
|
404 if code == "NoSuchKey" else 500,
|
|
92
92
|
).json_response
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
size_params = getattr(photo_sizes(), size)
|
|
95
95
|
# TODO: handle error
|
|
96
96
|
scaled_photo = scale_photo(
|
|
97
|
-
original_photo, photo_key, **asdict(
|
|
97
|
+
original_photo, photo_key, **asdict(size_params))
|
|
98
98
|
|
|
99
99
|
# TODO: handle error
|
|
100
100
|
scaled_photo.seek(0)
|
|
101
|
-
objsto.put_photo(
|
|
101
|
+
objsto.put_photo(
|
|
102
|
+
album_key,
|
|
103
|
+
photo_key,
|
|
104
|
+
size,
|
|
105
|
+
scaled_photo,
|
|
106
|
+
size_params.image_format)
|
|
107
|
+
|
|
108
|
+
content_type, headers = objsto.photo_content_headers(
|
|
109
|
+
photo_key, size_params.image_format)
|
|
102
110
|
|
|
103
111
|
scaled_photo.seek(0)
|
|
104
|
-
return HttpResponse(
|
|
112
|
+
return HttpResponse(
|
|
113
|
+
scaled_photo.read(), content_type=content_type, headers=headers)
|
|
@@ -3,7 +3,11 @@ from django.shortcuts import render
|
|
|
3
3
|
from django.urls import reverse
|
|
4
4
|
|
|
5
5
|
from photo_objects.django import api
|
|
6
|
-
from photo_objects.django.api.utils import
|
|
6
|
+
from photo_objects.django.api.utils import (
|
|
7
|
+
AlbumNotFound,
|
|
8
|
+
FormValidationFailed,
|
|
9
|
+
UploadPhotosFailed,
|
|
10
|
+
)
|
|
7
11
|
from photo_objects.django.forms import ModifyPhotoForm, UploadPhotosForm
|
|
8
12
|
from photo_objects.django.models import Photo
|
|
9
13
|
from photo_objects.django.views.utils import (
|
|
@@ -24,10 +28,17 @@ def upload_photos(request: HttpRequest, album_key: str):
|
|
|
24
28
|
reverse(
|
|
25
29
|
'photo_objects:show_album',
|
|
26
30
|
kwargs={"album_key": album_key}))
|
|
27
|
-
except
|
|
31
|
+
except UploadPhotosFailed as e:
|
|
28
32
|
form = e.form
|
|
33
|
+
uploaded_count = len(e.uploaded_photos)
|
|
34
|
+
if uploaded_count > 0:
|
|
35
|
+
plural = 's' if uploaded_count != 1 else ''
|
|
36
|
+
info = f"Successfully uploaded {uploaded_count} photo{plural}."
|
|
37
|
+
else:
|
|
38
|
+
info = None
|
|
29
39
|
else:
|
|
30
40
|
form = UploadPhotosForm()
|
|
41
|
+
info = None
|
|
31
42
|
|
|
32
43
|
album = api.check_album_access(request, album_key)
|
|
33
44
|
target = album.title or album.key
|
|
@@ -38,6 +49,7 @@ def upload_photos(request: HttpRequest, album_key: str):
|
|
|
38
49
|
|
|
39
50
|
return render(request, 'photo_objects/photo/upload.html', {
|
|
40
51
|
"form": form,
|
|
52
|
+
"info": info,
|
|
41
53
|
"title": "Upload photos",
|
|
42
54
|
"back": back,
|
|
43
55
|
"photo": album.cover_photo,
|
photo_objects/img.py
CHANGED
|
@@ -66,7 +66,10 @@ def _read_camera_setup_and_settings(image: Image) -> dict:
|
|
|
66
66
|
raise e
|
|
67
67
|
|
|
68
68
|
|
|
69
|
-
def _image_format(filename):
|
|
69
|
+
def _image_format(image_format, filename):
|
|
70
|
+
if image_format:
|
|
71
|
+
return image_format
|
|
72
|
+
|
|
70
73
|
image_format = filename.split('.')[-1].upper()
|
|
71
74
|
|
|
72
75
|
if image_format == "JPG":
|
|
@@ -131,7 +134,8 @@ def scale_photo(
|
|
|
131
134
|
filename,
|
|
132
135
|
max_width=None,
|
|
133
136
|
max_height=None,
|
|
134
|
-
max_aspect_ratio=None
|
|
137
|
+
max_aspect_ratio=None,
|
|
138
|
+
image_format=None):
|
|
135
139
|
image = Image.open(photo_file)
|
|
136
140
|
width, height = image.size
|
|
137
141
|
|
|
@@ -164,5 +168,5 @@ def scale_photo(
|
|
|
164
168
|
resized = image.resize(new_size, Image.Resampling.LANCZOS)
|
|
165
169
|
|
|
166
170
|
b = BytesIO()
|
|
167
|
-
resized.save(b, _image_format(filename))
|
|
171
|
+
resized.save(b, _image_format(image_format, filename))
|
|
168
172
|
return b
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
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
|
-
photo_objects/img.py,sha256=
|
|
4
|
+
photo_objects/img.py,sha256=2HVGS2g7rS2hnomozYL92oxrcN6zjDTHvWNr-UAqtGQ,4620
|
|
5
5
|
photo_objects/utils.py,sha256=sYliXid-bv2EgNA97woRaOnWU75yZFq7fuqzWaseiDg,139
|
|
6
6
|
photo_objects/django/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
7
|
photo_objects/django/admin.py,sha256=ubYfhsWQ85_2moYGZCVneLQ2DVEetbVpvBNisIrtuhw,170
|
|
8
8
|
photo_objects/django/apps.py,sha256=Apqu6o6fpoxda18NQgKupvQRvTAZxVviIK_-dUR3rck,1444
|
|
9
|
-
photo_objects/django/conf.py,sha256=
|
|
10
|
-
photo_objects/django/context_processors.py,sha256=
|
|
11
|
-
photo_objects/django/forms.py,sha256=
|
|
9
|
+
photo_objects/django/conf.py,sha256=ZpeIulEc1tpr8AO52meNKOF30Xf5osbDtDyHvQRtkx4,2593
|
|
10
|
+
photo_objects/django/context_processors.py,sha256=XacUmcYV-4NMMMNXPWrHKdvNd6lfyamisngaVerREiU,306
|
|
11
|
+
photo_objects/django/forms.py,sha256=LcznhXrqPfqRY5b2SwHBbC9-uux1FiZFdQBlHsKX5NU,6649
|
|
12
12
|
photo_objects/django/models.py,sha256=M40ZFSIX3WgyVXfHQY9SXQOY0s3fpFqfCxNV3CBD5M8,5753
|
|
13
|
-
photo_objects/django/objsto.py,sha256=
|
|
13
|
+
photo_objects/django/objsto.py,sha256=B7DxPWuqFaPFXPLhsHCFlqIzYl7EXLxcHde6zJDe89A,4238
|
|
14
14
|
photo_objects/django/signals.py,sha256=Q_Swjl_9z6B6zP-97D_ep5zGSAEgmQfwUz0utMDY93A,1624
|
|
15
15
|
photo_objects/django/urls.py,sha256=pCUTxg4xSd3ZD8BZVjULb9QpJQ03Ek6-sKoVnYG3-OY,1975
|
|
16
16
|
photo_objects/django/api/__init__.py,sha256=BnEHlm3mwyBy-1xhk-NFasgZa4fjCDjtfkBUoH0puPY,62
|
|
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/photo.py,sha256
|
|
20
|
-
photo_objects/django/api/utils.py,sha256=
|
|
19
|
+
photo_objects/django/api/photo.py,sha256=-lo1g6jfBr884wy-WV2DAEPxzH9V-tFUTRtitmA6i28,4471
|
|
20
|
+
photo_objects/django/api/utils.py,sha256=xilnQndd1DXkNs6K6OqXpzUKkDSZFOG25xX3O2oJggU,5364
|
|
21
21
|
photo_objects/django/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
22
22
|
photo_objects/django/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
23
23
|
photo_objects/django/management/commands/clean-scaled-photos.py,sha256=KJY6phgTCxcmbMUsUfCRQjatvCmKyFninM8zT-tB3Kc,2008
|
|
@@ -35,24 +35,25 @@ photo_objects/django/tests/test_album.py,sha256=yjxP_M0bddS9Xpg1d1Wk5OyJsmxmkdYu
|
|
|
35
35
|
photo_objects/django/tests/test_auth.py,sha256=hgr1UMVLvSI1x5zY7wTEXSBKfM5E_sNMIFlx8mVWYPY,3928
|
|
36
36
|
photo_objects/django/tests/test_commands.py,sha256=e3lE1ZhFR39WIq2VSKDNcQHUkSJqSWDYuAcAfu29svs,2955
|
|
37
37
|
photo_objects/django/tests/test_img.py,sha256=HEAWcr5fpTkzePkhoQ4YrWsDO9TvFOr7my_0LqVbaO4,829
|
|
38
|
-
photo_objects/django/tests/
|
|
38
|
+
photo_objects/django/tests/test_og_meta.py,sha256=Kk5a9KvE88KZ60gLqXSe6rTz5YU-gdjteksYolHd-nw,1804
|
|
39
|
+
photo_objects/django/tests/test_photo.py,sha256=aZCZw7PIXIfIYX3q1lUxn8C53mLRBNK0qp18t7X4ZQ4,13696
|
|
39
40
|
photo_objects/django/tests/test_utils.py,sha256=zBLv8lkvcLMCaH4D6GR1KZqUe-rPowhcBkQX19-Kshs,2007
|
|
40
|
-
photo_objects/django/tests/utils.py,sha256=
|
|
41
|
+
photo_objects/django/tests/utils.py,sha256=s_3hzQEY4tdja_8406s_SQyRC6fCYI_MBPqvFjC8fB4,4345
|
|
41
42
|
photo_objects/django/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
42
43
|
photo_objects/django/views/utils.py,sha256=oP9B6QtHPaukX97rqIlCHxanduktPGFVSCGkGxf4lzI,1691
|
|
43
44
|
photo_objects/django/views/api/__init__.py,sha256=SxK-b7MgMtD9VRMz46rDV5qtm6AvkRcg3Moa1AWl5pY,108
|
|
44
45
|
photo_objects/django/views/api/album.py,sha256=EZMOkxYzLSWr9wwXnd4yAO64JtXZq2k3FYohiNMFbGQ,1602
|
|
45
46
|
photo_objects/django/views/api/auth.py,sha256=EN_ExegzmLN-bhSzu3L9-6UE9qodPd7_ZRLilzrvc8Y,819
|
|
46
|
-
photo_objects/django/views/api/photo.py,sha256=
|
|
47
|
+
photo_objects/django/views/api/photo.py,sha256=iWDTBWrzztIKcfW7G6vh1eYTuH2JW129iOLSHjTfXCE,3743
|
|
47
48
|
photo_objects/django/views/api/utils.py,sha256=uQzKdSKHRAux5OZzqgWQr0gsK_FeweQP0cg_67OWA_Y,264
|
|
48
49
|
photo_objects/django/views/ui/__init__.py,sha256=N3ro5KggdV-JnfyHwoStX73b3SbVbpcsMuQNlxntVJs,92
|
|
49
50
|
photo_objects/django/views/ui/album.py,sha256=PmVXAmqVjKLAie1NyB-qXO3eLqOmhIA8PTAGJewgxko,4738
|
|
50
51
|
photo_objects/django/views/ui/configuration.py,sha256=oX6SV0TFBpbaxfp4cXIdSL41YJhy_aOy30TkBxOpq0M,5065
|
|
51
|
-
photo_objects/django/views/ui/photo.py,sha256=
|
|
52
|
+
photo_objects/django/views/ui/photo.py,sha256=fVpKI-XqSV8KfoTpDYxceCHR3rJzuVYfmRRQx1I0YIQ,6649
|
|
52
53
|
photo_objects/django/views/ui/users.py,sha256=nb73cnzuV98QkJb0j8F2hqPgOGFIWpUFTFu6dXMeVwM,722
|
|
53
54
|
photo_objects/django/views/ui/utils.py,sha256=YV_YcUbX-zUkdFnBlezPChR6aPDhZJ9loSOHBSzF6Cc,273
|
|
54
|
-
photo_objects-0.
|
|
55
|
-
photo_objects-0.
|
|
56
|
-
photo_objects-0.
|
|
57
|
-
photo_objects-0.
|
|
58
|
-
photo_objects-0.
|
|
55
|
+
photo_objects-0.7.0.dist-info/licenses/LICENSE,sha256=V3w6hTjXfP65F4r_mejveHcV5igHrblxao3-2RlfVlA,1068
|
|
56
|
+
photo_objects-0.7.0.dist-info/METADATA,sha256=wHfCOuVG8iXwYP6V0arHPNUURsF2HV0PvBEBEcmnB0Q,3605
|
|
57
|
+
photo_objects-0.7.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
58
|
+
photo_objects-0.7.0.dist-info/top_level.txt,sha256=SZeL8mhf-WMGdhRtTGFvZc3aIRBboQls9O0cFDMGdQ0,14
|
|
59
|
+
photo_objects-0.7.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|