1
0
mirror of https://github.com/spl0k/supysonic.git synced 2024-12-22 08:56:17 +00:00

Reworked star/unstar error handling

Don't stop at the first error anymore, instead treat all provided ids
Potential errors are aggregated, if there's only one it is returned
as-is, if there are more they are all nested in a top-level error whose
code is 0 if there are different error codes, or their value if all
error codes are the same.
This error-nesting doesn't validate against the XSD, but the Subsonic
API gives absolutely no information on how errors should be handled.
And reverse-engineering is not in my line of work
This commit is contained in:
spl0k 2017-11-14 23:16:58 +01:00
parent 5084c745dc
commit da857b9ceb

View File

@ -28,84 +28,108 @@ from supysonic.db import Track, Album, Artist, Folder
from supysonic.db import StarredTrack, StarredAlbum, StarredArtist, StarredFolder
from supysonic.db import RatingTrack, RatingFolder
def try_star(ent, starred_ent, eid):
""" Stars an entity
:param ent: entity class, Folder, Artist, Album or Track
:param starred_ent: class used for the db representation of the starring of ent
:param eid: id of the entity to star
:return error dict, if any. None otherwise
"""
try:
uid = uuid.UUID(eid)
except:
return { 'code': 0, 'message': 'Invalid {} id {}'.format(ent.__name__, eid) }
if store.get(starred_ent, (request.user.id, uid)):
return { 'code': 0, 'message': '{} {} already starred'.format(ent.__name__, eid) }
e = store.get(ent, uid)
if not e:
return { 'code': 70, 'message': 'Unknown {} id {}'.format(ent.__name__, eid) }
starred = starred_ent()
starred.user_id = request.user.id
starred.starred_id = uid
store.add(starred)
return None
def try_unstar(starred_ent, eid):
""" Unstars an entity
:param starred_ent: class used for the db representation of the starring of the entity
:param eid: id of the entity to unstar
:return error dict, if any. None otherwise
"""
try:
uid = uuid.UUID(eid)
except:
return { 'code': 0, 'message': 'Invalid id {}'.format(eid) }
store.find(starred_ent, starred_ent.user_id == request.user.id, starred_ent.starred_id == uid).remove()
return None
def merge_errors(errors):
error = None
errors = filter(None, errors)
if len(errors) == 1:
error = errors[0]
elif len(errors) > 1:
codes = set(map(lambda e: e['code'], errors))
error = { 'code': list(codes)[0] if len(codes) == 1 else 0, 'error': errors }
return error
@app.route('/rest/star.view', methods = [ 'GET', 'POST' ])
def star():
id, albumId, artistId = map(request.values.getlist, [ 'id', 'albumId', 'artistId' ])
def try_star(ent, starred_ent, eid):
try:
uid = uuid.UUID(eid)
except:
return 2, request.error_formatter(0, 'Invalid %s id' % ent.__name__)
if store.get(starred_ent, (request.user.id, uid)):
return 2, request.error_formatter(0, '%s already starred' % ent.__name__)
e = store.get(ent, uid)
if e:
starred = starred_ent()
starred.user_id = request.user.id
starred.starred_id = uid
store.add(starred)
else:
return 1, request.error_formatter(70, 'Unknown %s id' % ent.__name__)
return 0, None
if not id and not albumId and not artistId:
return request.error_formatter(10, 'Missing parameter')
errors = []
for eid in id:
err, ferror = try_star(Track, StarredTrack, eid)
if err == 1:
err, ferror = try_star(Folder, StarredFolder, eid)
if err:
return ferror
elif err == 2:
return ferror
terr = try_star(Track, StarredTrack, eid)
ferr = try_star(Folder, StarredFolder, eid)
if terr and ferr:
errors += [ terr, ferr ]
for alId in albumId:
err, ferror = try_star(Album, StarredAlbum, alId)
if err:
return ferror
errors.append(try_star(Album, StarredAlbum, alId))
for arId in artistId:
err, ferror = try_star(Artist, StarredArtist, arId)
if err:
return ferror
errors.append(try_star(Artist, StarredArtist, arId))
store.commit()
return request.formatter({})
error = merge_errors(errors)
return request.formatter({ 'error': error }, error = True) if error else request.formatter({})
@app.route('/rest/unstar.view', methods = [ 'GET', 'POST' ])
def unstar():
id, albumId, artistId = map(request.values.getlist, [ 'id', 'albumId', 'artistId' ])
def try_unstar(ent, eid):
try:
uid = uuid.UUID(eid)
except:
return request.error_formatter(0, 'Invalid id')
store.find(ent, ent.user_id == request.user.id, ent.starred_id == uid).remove()
return None
if not id and not albumId and not artistId:
return request.error_formatter(10, 'Missing parameter')
errors = []
for eid in id:
err = try_unstar(StarredTrack, eid)
if err:
return err
err = try_unstar(StarredFolder, eid)
if err:
return err
terr = try_unstar(StarredTrack, eid)
ferr = try_unstar(StarredFolder, eid)
if terr and ferr:
errors += [ terr, ferr ]
for alId in albumId:
err = try_unstar(StarredAlbum, alId)
if err:
return err
errors.append(try_unstar(StarredAlbum, alId))
for arId in artistId:
err = try_unstar(StarredArtist, arId)
if err:
return err
errors.append(try_unstar(StarredArtist, arId))
store.commit()
return request.formatter({})
error = merge_errors(errors)
return request.formatter({ 'error': error }, error = True) if error else request.formatter({})
@app.route('/rest/setRating.view', methods = [ 'GET', 'POST' ])
def rate():