Skip to content

Commit fccb403

Browse files
authored
Merge pull request #19 from photos-network/feature/user_management
Feature/user management
2 parents cade920 + c3d09c9 commit fccb403

File tree

18 files changed

+672
-185
lines changed

18 files changed

+672
-185
lines changed

core/addon.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,22 @@ async def async_setup_addon(
233233

234234
return True
235235

236+
async def read(self, key):
237+
"""read key/value pair from addon."""
238+
try:
239+
component = importlib.import_module(f"core.addons.{self.domain}")
240+
except ImportError as err:
241+
_LOGGER.error(f"Unable to import addon '{self.domain}': {err}")
242+
return False
243+
except Exception: # pylint: disable=broad-except
244+
_LOGGER.exception(f"Setup failed for {self.domain}: unknown error")
245+
return False
246+
247+
if hasattr(component, "read"):
248+
await component.read(self.core, key)
249+
else:
250+
_LOGGER.error(f"Unable to read key from addon '{self.domain}'")
251+
236252
async def async_process_images_in_addons(self, images) -> bool:
237253
"""Trigger image addons with images to process."""
238254
if self.type == AddonType.IMAGE:

core/addons/api/__init__.py

Lines changed: 46 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@
44
import os
55
import pathlib
66
from datetime import datetime
7-
from typing import Optional
87

98
from aiohttp import web
9+
1010
from core.addons.api.dto.details import Details
1111
from core.addons.api.dto.location import Location
12-
from core.addons.api.dto.photo import (PhotoDetailsResponse, PhotoEncoder,
13-
PhotoResponse)
12+
from core.addons.api.dto.photo import PhotoDetailsResponse, PhotoEncoder, PhotoResponse
1413
from core.addons.api.dto.photo_response import PhotosResponse
1514
from core.base import Session
1615
from core.core import ApplicationCore
@@ -63,7 +62,7 @@ class PhotosView(RequestView):
6362

6463
async def get(self, core: ApplicationCore, request: web.Request) -> web.Response:
6564
"""Get a list of all photo resources."""
66-
_LOGGER.debug(f"GET /v1/photos")
65+
_LOGGER.debug("GET /v1/photos")
6766
await core.authentication.check_permission(request, "library:read")
6867

6968
user_id = await core.http.get_user_id(request)
@@ -79,7 +78,9 @@ async def get(self, core: ApplicationCore, request: web.Request) -> web.Response
7978
if "offset" in request.query:
8079
offset = int(request.query["offset"])
8180

82-
_LOGGER.debug(f"read {limit} photos for user_id {user_id} beginning with {offset}")
81+
_LOGGER.debug(
82+
f"read {limit} photos for user_id {user_id} beginning with {offset}"
83+
)
8384
user_photos = await core.storage.read_photos(user_id, offset, limit)
8485

8586
results = []
@@ -89,12 +90,16 @@ async def get(self, core: ApplicationCore, request: web.Request) -> web.Response
8990
PhotoResponse(
9091
id=photo.uuid,
9192
name=photo.filename,
92-
image_url=f"{core.config.external_url}/v1/file/{photo.uuid}"
93+
image_url=f"{core.config.external_url}/v1/file/{photo.uuid}",
9394
)
9495
)
9596

96-
response = PhotosResponse(offset=offset, limit=limit, size=len(results), results=results)
97-
return web.Response(text=json.dumps(response, cls=PhotoEncoder), content_type="application/json")
97+
response = PhotosResponse(
98+
offset=offset, limit=limit, size=len(results), results=results
99+
)
100+
return web.Response(
101+
text=json.dumps(response, cls=PhotoEncoder), content_type="application/json"
102+
)
98103

99104

100105
class PhotoDetailsView(RequestView):
@@ -103,7 +108,9 @@ class PhotoDetailsView(RequestView):
103108
url = "/v1/photo/{entity_id}"
104109
name = "v1:photo"
105110

106-
async def get(self, core: ApplicationCore, request: web.Request, entity_id: str) -> web.Response:
111+
async def get(
112+
self, core: ApplicationCore, request: web.Request, entity_id: str
113+
) -> web.Response:
107114
"""Return an entity."""
108115
_LOGGER.debug(f"GET /v1/photo/{entity_id}")
109116

@@ -133,31 +140,38 @@ async def get(self, core: ApplicationCore, request: web.Request, entity_id: str)
133140
if latitude is not None and longitude is not None:
134141
altitude = await core.storage.read("altitude")
135142
if altitude is not None:
136-
location = Location(latitude=latitude, longitude=longitude, altitude=altitude)
143+
location = Location(
144+
latitude=latitude, longitude=longitude, altitude=altitude
145+
)
137146
else:
138-
location = Location(latitude=latitude, longitude=longitude, altitude="0.0")
147+
location = Location(
148+
latitude=latitude, longitude=longitude, altitude="0.0"
149+
)
139150

140151
# photo tags
141152
tags = await core.storage.read("tags")
142153

143154
result = PhotoDetailsResponse(
144155
id=photo.uuid,
145156
name=photo.filename,
146-
author=photo.owner,
157+
owner=photo.owner,
147158
created_at=ctime.isoformat(),
159+
modified_at=mtime.isoformat(),
148160
details=Details(
149-
camera="Nikon Z7",
150-
lens="Nikkor 200mm F1.8",
151-
focal_length="200",
152-
iso="400",
153-
shutter_speed="1/2000",
154-
aperture="4.0",
161+
camera="Nikon Z7",
162+
lens="Nikkor 200mm F1.8",
163+
focal_length="200",
164+
iso="400",
165+
shutter_speed="1/2000",
166+
aperture="4.0",
155167
),
156168
tags=tags,
157169
location=location,
158-
image_url=f"{core.config.external_url}/v1/file/{entity_id}"
170+
image_url=f"{core.config.external_url}/v1/file/{entity_id}",
171+
)
172+
return web.Response(
173+
text=json.dumps(result, cls=PhotoEncoder), content_type="application/json"
159174
)
160-
return web.Response(text=json.dumps(result, cls=PhotoEncoder), content_type="application/json")
161175

162176

163177
class PhotoView(RequestView):
@@ -168,7 +182,9 @@ class PhotoView(RequestView):
168182
url = "/v1/file/{entity_id}"
169183
name = "v1:file"
170184

171-
async def get(self, core: ApplicationCore, request: web.Request, entity_id: str) -> web.Response:
185+
async def get(
186+
self, core: ApplicationCore, request: web.Request, entity_id: str
187+
) -> web.Response:
172188
"""Return an entity."""
173189
_LOGGER.debug(f"GET /v1/file/{entity_id}")
174190

@@ -179,10 +195,12 @@ async def get(self, core: ApplicationCore, request: web.Request, entity_id: str)
179195
# -d remove exif data
180196

181197
result = Session.query(Photo).filter(Photo.uuid == entity_id).first()
182-
183-
file = os.path.join(result.directory, result.filename)
184-
if os.path.exists(os.path.join(file)):
185-
return web.FileResponse(path=file, status=200)
198+
if result:
199+
file = os.path.join(result.directory, result.filename)
200+
if os.path.exists(os.path.join(file)):
201+
return web.FileResponse(path=file, status=200)
202+
else:
203+
raise web.HTTPNotFound()
186204
else:
187205
raise web.HTTPNotFound()
188206

@@ -224,7 +242,9 @@ async def post(self, core: ApplicationCore, request: web.Request) -> web.Respons
224242

225243
status_code = HTTP_CREATED if new_entity_created else HTTP_OK
226244

227-
resp = self.json_message(f"File successfully added with ID: {new_entity_id}", status_code)
245+
resp = self.json_message(
246+
f"File successfully added with ID: {new_entity_id}", status_code
247+
)
228248
resp.headers.add("Location", f"/api/photo/{new_entity_id}")
229249

230250
return resp

core/addons/api/dto/photo.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,11 @@ def default(self, o):
99
"""Encode all properties."""
1010
return o.__dict__
1111

12+
1213
class PhotoResponse:
1314
"""Photo response object."""
1415

15-
def __init__(
16-
self, id, name, image_url
17-
):
16+
def __init__(self, id, name, image_url):
1817
"""Initialize photo response object."""
1918
self.id = id
2019
self.name = name
@@ -25,13 +24,23 @@ class PhotoDetailsResponse:
2524
"""Photo response object."""
2625

2726
def __init__(
28-
self, id, name, owner, created_at, details, tags, location, image_url
27+
self,
28+
id,
29+
name,
30+
owner,
31+
created_at,
32+
modified_at,
33+
details,
34+
tags,
35+
location,
36+
image_url,
2937
):
3038
"""Initialize photo response object."""
3139
self.id = id
3240
self.name = name
3341
self.owner = owner
3442
self.created_at = created_at
43+
self.modified_at = modified_at
3544
self.details = details
3645
self.tags = tags
3746
self.location = location

0 commit comments

Comments
 (0)