diff --git a/photoapp/api.py b/photoapp/api.py index 810ccc0..adad605 100644 --- a/photoapp/api.py +++ b/photoapp/api.py @@ -19,24 +19,38 @@ class LibraryManager(object): self.storage = storage +@cherrypy.expose class PhotosApi(object): def __init__(self, library): self.library = library self.v1 = PhotosApiV1(self.library) +@cherrypy.expose class PhotosApiV1(object): def __init__(self, library): - self.library = library + self.library = library # TODO: move library to a cherrypy tool + self.upload = PhotosApiV1Upload(library) + self.byhash = PhotosApiV1ByHash() + self.set = PhotosApiV1Set() + self.download = PhotosApiV1Download() + self.user = PhotosApiV1User() + self.stats = PhotosApiV1Stats() + self.photos = PhotosApiV1Photos() + self.tags = PhotosApiV1PhotoTags() - @cherrypy.expose - def index(self): + def GET(self): cherrypy.response.headers["Content-type"] = "text/plain" return "Hello! This is the Photolib V1 API.\n" - @cherrypy.expose - @cherrypy.tools.json_out() - def upload(self, files, meta): + +@cherrypy.expose +@cherrypy.tools.json_out() +class PhotosApiV1Upload(object): + def __init__(self, library): + self.library = library + + def POST(self, files, meta): """ upload accepts one photoset (multiple images) """ @@ -150,24 +164,31 @@ class PhotosApiV1(object): return ps_json - @cherrypy.expose - @cherrypy.tools.json_out() - def byhash(self, sha): + +@cherrypy.expose +@cherrypy.tools.json_out() +class PhotosApiV1ByHash(object): + + def GET(self, sha): f = db.query(Photo).filter(Photo.hash == sha).first() if not f: raise cherrypy.HTTPError(404) return f.to_json() - @cherrypy.expose - @cherrypy.tools.json_out() - def set(self, uuid): + +@cherrypy.expose +@cherrypy.tools.json_out() +class PhotosApiV1Set(object): + def GET(self, uuid): s = db.query(PhotoSet).filter(PhotoSet.uuid == uuid).first() if not s: raise cherrypy.HTTPError(404) return s.to_json() - @cherrypy.expose - def download(self, uuid): + +@cherrypy.expose +class PhotosApiV1Download(object): + def GET(self, uuid): #TODO fix me f = db.query(Photo).filter(Photo.uuid == uuid).first() if not f: @@ -175,37 +196,45 @@ class PhotosApiV1(object): return cherrypy.lib.static.serve_file(os.path.abspath(os.path.join("./library", f.path)), f.format)#TODO no hardcode path - @cherrypy.expose - @cherrypy.tools.json_out() - def user(self, username=None, password_hash=None): - if username is None: # list all users - return [u.to_json() for u in db.query(User).all()] - elif username and cherrypy.request.method == "DELETE": # delete user - u = db.query(User).filter(User.name == username).first() - if not u: - raise cherrypy.HTTPError(404) - db.delete(u) - elif username and password_hash: # create/update user - u = db.query(User).filter(User.name == username).first() - if u: - u.password = password_hash - else: - db.add(User(name=username, password=password_hash)) + +@cherrypy.expose +@cherrypy.tools.json_out() +class PhotosApiV1User(object): + def GET(self): # list all users + return [u.to_json() for u in db.query(User).all()] + + def DELETE(self, username): # delete user + u = db.query(User).filter(User.name == username).first() + if not u: + raise cherrypy.HTTPError(404) + db.delete(u) return "ok" - @cherrypy.expose - @cherrypy.tools.json_out() - def stats(self): + def POST(self, username, password_hash): # create/update user + u = db.query(User).filter(User.name == username).first() + if u: + u.password = password_hash + else: + db.add(User(name=username, password=password_hash)) + return "ok" + + +@cherrypy.expose +@cherrypy.tools.json_out() +class PhotosApiV1Stats(object): + def GET(self): return {"photos": db.query(PhotoSet).count(), "files": db.query(Photo).count(), "tags": db.query(Tag).count(), "users": db.query(User).count(), "public_photos": db.query(PhotoSet).filter(PhotoSet.status == PhotoStatus.public).count()} - @cherrypy.expose - @cherrypy.tools.json_out() - @cherrypy.popargs("uuid") - def photos(self, uuid=None, page=0, pagesize=50): + +@cherrypy.expose +@cherrypy.tools.json_out() +@cherrypy.popargs("uuid") +class PhotosApiV1Photos(object): + def GET(self, uuid=None, page=0, pagesize=50): if uuid: p = db.query(PhotoSet).filter(PhotoSet.uuid == uuid).first() if not p: @@ -217,27 +246,13 @@ class PhotosApiV1(object): return [p.to_json() for p in db.query(PhotoSet).order_by(PhotoSet.id).offset(pagesize * page).limit(pagesize).all()] - @cherrypy.expose - @cherrypy.tools.json_out() - @cherrypy.popargs("uuid") - def tags(self, uuid=None, name=None, page=0, pagesize=50): - if cherrypy.request.method == "POST": # creating tag - tagdata = json.loads(cherrypy.request.body.read()) - tagname = tagdata.get("name") - db.add(Tag(name=tagname, - title=tagdata.get("title", None) or tagname.capitalize(), - description=tagdata.get("description", None), - slug=slugify(tagname))) - db.commit() - return {} - elif uuid and cherrypy.request.method == "DELETE": # deleting tag - tag = db.query(Tag).filter(Tag.uuid == uuid).first() - db.query(TagItem).fitler(TagItem.tag_id == tag.id).delete() - db.delete(tag) - db.commit() - return {} - elif uuid or name: # getting tag +@cherrypy.expose +@cherrypy.tools.json_out() +@cherrypy.popargs("uuid") +class PhotosApiV1PhotoTags(object): + def GET(self, uuid=None, name=None, page=0, pagesize=50): # getting tag/s + if uuid or name: q = db.query(Tag) if uuid: q = q.filter(Tag.uuid == uuid) @@ -252,3 +267,20 @@ class PhotosApiV1(object): page, pagesize = int(page), int(pagesize) return [t.to_json() for t in db.query(Tag).order_by(Tag.id).offset(pagesize * page).limit(pagesize).all()] + + def DELETE(self, uuid): # deleting tag + tag = db.query(Tag).filter(Tag.uuid == uuid).first() + db.query(TagItem).fitler(TagItem.tag_id == tag.id).delete() + db.delete(tag) + db.commit() + return {} + + def POST(self): # creating tag + tagdata = json.loads(cherrypy.request.body.read()) + tagname = tagdata.get("name") + db.add(Tag(name=tagname, + title=tagdata.get("title", None) or tagname.capitalize(), + description=tagdata.get("description", None), + slug=slugify(tagname))) + db.commit() + return {} diff --git a/photoapp/daemon.py b/photoapp/daemon.py index 93ea69b..065796a 100644 --- a/photoapp/daemon.py +++ b/photoapp/daemon.py @@ -689,7 +689,8 @@ def main(): 'tools.auth_basic.on': True, 'tools.auth_basic.realm': 'photolib', 'tools.auth_basic.checkpassword': validate_password, - 'tools.db.on': True}}) + 'tools.db.on': True, + 'request.dispatch': cherrypy.dispatch.MethodDispatcher()}}) # General config options cherrypy.config.update({