mirror of
https://github.com/spl0k/supysonic.git
synced 2024-12-22 17:06:17 +00:00
Refactoring API error handling
This commit is contained in:
parent
86892f375d
commit
177b0cce0d
@ -30,6 +30,7 @@ from pony.orm import ObjectNotFound
|
||||
from ..managers.user import UserManager
|
||||
from ..py23 import dict
|
||||
|
||||
from .exceptions import Unauthorized
|
||||
from .formatters import JSONFormatter, JSONPFormatter, XMLFormatter
|
||||
|
||||
api = Blueprint('api', __name__)
|
||||
@ -56,33 +57,28 @@ def decode_password(password):
|
||||
|
||||
@api.before_request
|
||||
def authorize():
|
||||
error = request.formatter.error(40, 'Unauthorized'), 401
|
||||
|
||||
if request.authorization:
|
||||
status, user = UserManager.try_auth(request.authorization.username, request.authorization.password)
|
||||
if status == UserManager.SUCCESS:
|
||||
request.username = request.authorization.username
|
||||
request.user = user
|
||||
return
|
||||
raise Unauthorized()
|
||||
|
||||
(username, password) = map(request.values.get, [ 'u', 'p' ])
|
||||
if not username or not password:
|
||||
return error
|
||||
|
||||
username = request.values['u']
|
||||
password = request.values['p']
|
||||
password = decode_password(password)
|
||||
|
||||
status, user = UserManager.try_auth(username, password)
|
||||
if status != UserManager.SUCCESS:
|
||||
return error
|
||||
raise Unauthorized()
|
||||
|
||||
request.username = username
|
||||
request.user = user
|
||||
|
||||
@api.before_request
|
||||
def get_client_prefs():
|
||||
if 'c' not in request.values:
|
||||
return request.formatter.error(10, 'Missing required parameter')
|
||||
|
||||
client = request.values.get('c')
|
||||
client = request.values['c']
|
||||
try:
|
||||
ClientPrefs[request.user, client]
|
||||
except ObjectNotFound:
|
||||
@ -90,24 +86,13 @@ def get_client_prefs():
|
||||
|
||||
request.client = client
|
||||
|
||||
#@api.errorhandler(404)
|
||||
@api.route('/<path:invalid>', methods = [ 'GET', 'POST' ]) # blueprint 404 workaround
|
||||
def not_found(*args, **kwargs):
|
||||
return request.formatter.error(0, 'Not implemented'), 501
|
||||
|
||||
def get_entity(cls, param = 'id'):
|
||||
eid = request.values.get(param)
|
||||
if not eid:
|
||||
return False, request.formatter.error(10, 'Missing %s id' % cls.__name__)
|
||||
eid = request.values[param]
|
||||
eid = uuid.UUID(eid)
|
||||
entity = cls[eid]
|
||||
return entity
|
||||
|
||||
try:
|
||||
eid = uuid.UUID(eid)
|
||||
entity = cls[eid]
|
||||
return True, entity
|
||||
except ValueError:
|
||||
return False, request.formatter.error(0, 'Invalid %s id' % cls.__name__)
|
||||
except ObjectNotFound:
|
||||
return False, (request.formatter.error(70, '%s not found' % cls.__name__), 404)
|
||||
from .errors import *
|
||||
|
||||
from .system import *
|
||||
from .browse import *
|
||||
|
@ -35,13 +35,10 @@ def rand_songs():
|
||||
size = request.values.get('size', '10')
|
||||
genre, fromYear, toYear, musicFolderId = map(request.values.get, [ 'genre', 'fromYear', 'toYear', 'musicFolderId' ])
|
||||
|
||||
try:
|
||||
size = int(size) if size else 10
|
||||
fromYear = int(fromYear) if fromYear else None
|
||||
toYear = int(toYear) if toYear else None
|
||||
fid = uuid.UUID(musicFolderId) if musicFolderId else None
|
||||
except ValueError:
|
||||
return request.formatter.error(0, 'Invalid parameter format')
|
||||
size = int(size) if size else 10
|
||||
fromYear = int(fromYear) if fromYear else None
|
||||
toYear = int(toYear) if toYear else None
|
||||
fid = uuid.UUID(musicFolderId) if musicFolderId else None
|
||||
|
||||
query = Track.select()
|
||||
if fromYear:
|
||||
@ -65,11 +62,9 @@ def album_list():
|
||||
ltype, size, offset = map(request.values.get, [ 'type', 'size', 'offset' ])
|
||||
if not ltype:
|
||||
return request.formatter.error(10, 'Missing type')
|
||||
try:
|
||||
size = int(size) if size else 10
|
||||
offset = int(offset) if offset else 0
|
||||
except ValueError:
|
||||
return request.formatter.error(0, 'Invalid parameter format')
|
||||
|
||||
size = int(size) if size else 10
|
||||
offset = int(offset) if offset else 0
|
||||
|
||||
query = select(t.folder for t in Track)
|
||||
if ltype == 'random':
|
||||
@ -102,11 +97,9 @@ def album_list_id3():
|
||||
ltype, size, offset = map(request.values.get, [ 'type', 'size', 'offset' ])
|
||||
if not ltype:
|
||||
return request.formatter.error(10, 'Missing type')
|
||||
try:
|
||||
size = int(size) if size else 10
|
||||
offset = int(offset) if offset else 0
|
||||
except ValueError:
|
||||
return request.formatter.error(0, 'Invalid parameter format')
|
||||
|
||||
size = int(size) if size else 10
|
||||
offset = int(offset) if offset else 0
|
||||
|
||||
query = Album.select()
|
||||
if ltype == 'random':
|
||||
|
@ -175,10 +175,7 @@ def rate():
|
||||
|
||||
@api.route('/scrobble.view', methods = [ 'GET', 'POST' ])
|
||||
def scrobble():
|
||||
status, res = get_entity(Track)
|
||||
if not status:
|
||||
return res
|
||||
|
||||
res = get_entity(Track)
|
||||
t, submission = map(request.values.get, [ 'time', 'submission' ])
|
||||
|
||||
if t:
|
||||
|
@ -43,23 +43,16 @@ def list_indexes():
|
||||
musicFolderId = request.values.get('musicFolderId')
|
||||
ifModifiedSince = request.values.get('ifModifiedSince')
|
||||
if ifModifiedSince:
|
||||
try:
|
||||
ifModifiedSince = int(ifModifiedSince) / 1000
|
||||
except ValueError:
|
||||
return request.formatter.error(0, 'Invalid timestamp')
|
||||
ifModifiedSince = int(ifModifiedSince) / 1000
|
||||
|
||||
if musicFolderId is None:
|
||||
folders = Folder.select(lambda f: f.root)[:]
|
||||
else:
|
||||
try:
|
||||
mfid = uuid.UUID(musicFolderId)
|
||||
folder = Folder[mfid]
|
||||
except ValueError:
|
||||
return request.formatter.error(0, 'Invalid id')
|
||||
except ObjectNotFound:
|
||||
return request.formatter.error(70, 'Folder not found')
|
||||
mfid = uuid.UUID(musicFolderId)
|
||||
folder = Folder[mfid]
|
||||
if not folder.root:
|
||||
return request.formatter.error(70, 'Folder not found')
|
||||
raise ObjectNotFound(Folder, mfid)
|
||||
|
||||
folders = [ folder ]
|
||||
|
||||
last_modif = max(map(lambda f: f.last_scan, folders))
|
||||
@ -100,10 +93,7 @@ def list_indexes():
|
||||
|
||||
@api.route('/getMusicDirectory.view', methods = [ 'GET', 'POST' ])
|
||||
def show_directory():
|
||||
status, res = get_entity(Folder)
|
||||
if not status:
|
||||
return res
|
||||
|
||||
res = get_entity(Folder)
|
||||
directory = dict(
|
||||
id = str(res.id),
|
||||
name = res.name,
|
||||
@ -139,10 +129,7 @@ def list_artists():
|
||||
|
||||
@api.route('/getArtist.view', methods = [ 'GET', 'POST' ])
|
||||
def artist_info():
|
||||
status, res = get_entity(Artist)
|
||||
if not status:
|
||||
return res
|
||||
|
||||
res = get_entity(Artist)
|
||||
info = res.as_subsonic_artist(request.user)
|
||||
albums = set(res.albums)
|
||||
albums |= { t.album for t in res.tracks }
|
||||
@ -152,10 +139,7 @@ def artist_info():
|
||||
|
||||
@api.route('/getAlbum.view', methods = [ 'GET', 'POST' ])
|
||||
def album_info():
|
||||
status, res = get_entity(Album)
|
||||
if not status:
|
||||
return res
|
||||
|
||||
res = get_entity(Album)
|
||||
info = res.as_subsonic_album(request.user)
|
||||
info['song'] = [ t.as_subsonic_child(request.user, request.client) for t in sorted(res.tracks, key = lambda t: t.sort_key()) ]
|
||||
|
||||
@ -163,10 +147,7 @@ def album_info():
|
||||
|
||||
@api.route('/getSong.view', methods = [ 'GET', 'POST' ])
|
||||
def track_info():
|
||||
status, res = get_entity(Track)
|
||||
if not status:
|
||||
return res
|
||||
|
||||
res = get_entity(Track)
|
||||
return request.formatter('song', res.as_subsonic_child(request.user, request.client))
|
||||
|
||||
@api.route('/getVideos.view', methods = [ 'GET', 'POST' ])
|
||||
|
@ -27,10 +27,7 @@ from . import api
|
||||
@api.route('/getChatMessages.view', methods = [ 'GET', 'POST' ])
|
||||
def get_chat():
|
||||
since = request.values.get('since')
|
||||
try:
|
||||
since = int(since) / 1000 if since else None
|
||||
except ValueError:
|
||||
return request.formatter.error(0, 'Invalid parameter')
|
||||
since = int(since) / 1000 if since else None
|
||||
|
||||
query = ChatMessage.select().order_by(ChatMessage.time)
|
||||
if since:
|
||||
|
45
supysonic/api/errors.py
Normal file
45
supysonic/api/errors.py
Normal file
@ -0,0 +1,45 @@
|
||||
# coding: utf-8
|
||||
#
|
||||
# This file is part of Supysonic.
|
||||
# Supysonic is a Python implementation of the Subsonic server API.
|
||||
#
|
||||
# Copyright (C) 2018 Alban 'spl0k' Féron
|
||||
#
|
||||
# Distributed under terms of the GNU AGPLv3 license.
|
||||
|
||||
from flask import current_app
|
||||
from pony.orm import rollback
|
||||
from pony.orm import ObjectNotFound
|
||||
from werkzeug.exceptions import BadRequestKeyError
|
||||
|
||||
from . import api
|
||||
from .exceptions import GenericError, MissingParameter, NotFound
|
||||
|
||||
@api.errorhandler(ValueError)
|
||||
def value_error(e):
|
||||
rollback()
|
||||
return GenericError(e)
|
||||
|
||||
@api.errorhandler(BadRequestKeyError)
|
||||
def key_error(e):
|
||||
rollback()
|
||||
return MissingParameter(e.args[0])
|
||||
|
||||
@api.errorhandler(ObjectNotFound)
|
||||
def not_found(e):
|
||||
rollback()
|
||||
return NotFound(e.entity.__name__)
|
||||
|
||||
@api.errorhandler(Exception)
|
||||
def generic_error(e): # pragma: nocover
|
||||
rollback()
|
||||
if not current_app.testing:
|
||||
return GenericError(e), 500
|
||||
else:
|
||||
raise e
|
||||
|
||||
#@api.errorhandler(404)
|
||||
@api.route('/<path:invalid>', methods = [ 'GET', 'POST' ]) # blueprint 404 workaround
|
||||
def not_found(*args, **kwargs):
|
||||
return GenericError('Not implemented'), 501
|
||||
|
74
supysonic/api/exceptions.py
Normal file
74
supysonic/api/exceptions.py
Normal file
@ -0,0 +1,74 @@
|
||||
# coding: utf-8
|
||||
#
|
||||
# This file is part of Supysonic.
|
||||
# Supysonic is a Python implementation of the Subsonic server API.
|
||||
#
|
||||
# Copyright (C) 2018 Alban 'spl0k' Féron
|
||||
#
|
||||
# Distributed under terms of the GNU AGPLv3 license.
|
||||
|
||||
from flask import request
|
||||
from werkzeug.exceptions import HTTPException
|
||||
|
||||
class SubsonicAPIError(HTTPException):
|
||||
code = 400
|
||||
api_code = None
|
||||
message = None
|
||||
|
||||
def get_response(self, environ = None):
|
||||
rv = request.formatter.error(self.api_code, self.message)
|
||||
rv.status_code = self.code
|
||||
return rv
|
||||
|
||||
def __str__(self):
|
||||
code = self.api_code if self.api_code is not None else '??'
|
||||
return '{}: {}'.format(code, self.message)
|
||||
|
||||
class GenericError(SubsonicAPIError):
|
||||
api_code = 0
|
||||
|
||||
def __init__(self, message, *args, **kwargs):
|
||||
super(GenericError, self).__init__(*args, **kwargs)
|
||||
self.message = message
|
||||
|
||||
class MissingParameter(SubsonicAPIError):
|
||||
api_code = 10
|
||||
|
||||
def __init__(self, param, *args, **kwargs):
|
||||
super(MissingParameter, self).__init__(*args, **kwargs)
|
||||
self.message = "Required parameter '{}' is missing.".format(param)
|
||||
|
||||
class ClientMustUpgrade(SubsonicAPIError):
|
||||
api_code = 20
|
||||
message = 'Incompatible Subsonic REST protocol version. Client must upgrade.'
|
||||
|
||||
class ServerMustUpgrade(SubsonicAPIError):
|
||||
code = 501
|
||||
api_code = 30
|
||||
message = 'Incompatible Subsonic REST protocol version. Server must upgrade.'
|
||||
|
||||
class Unauthorized(SubsonicAPIError):
|
||||
code = 401
|
||||
api_code = 40
|
||||
message = 'Wrong username or password.'
|
||||
|
||||
class Forbidden(SubsonicAPIError):
|
||||
code = 403
|
||||
api_code = 50
|
||||
message = 'User is not authorized for the given operation.'
|
||||
|
||||
class TrialExpired(SubsonicAPIError):
|
||||
code = 402
|
||||
api_code = 60
|
||||
message = ("The trial period for the Supysonic server is over."
|
||||
"But since it doesn't use any licensing you shouldn't be seeing this error ever."
|
||||
"So something went wrong or you got scammed.")
|
||||
|
||||
class NotFound(SubsonicAPIError):
|
||||
code = 404
|
||||
api_code = 70
|
||||
|
||||
def __init__(self, entity, *args, **kwargs):
|
||||
super(NotFound, self).__init__(*args, **kwargs)
|
||||
self.message = '{} not found'.format(entity)
|
||||
|
@ -47,9 +47,7 @@ def prepare_transcoding_cmdline(base_cmdline, input_file, input_format, output_f
|
||||
|
||||
@api.route('/stream.view', methods = [ 'GET', 'POST' ])
|
||||
def stream_media():
|
||||
status, res = get_entity(Track)
|
||||
if not status:
|
||||
return res
|
||||
res = get_entity(Track)
|
||||
|
||||
maxBitRate, format, timeOffset, size, estimateContentLength = map(request.values.get, [ 'maxBitRate', 'format', 'timeOffset', 'size', 'estimateContentLength' ])
|
||||
if format:
|
||||
@ -67,10 +65,7 @@ def stream_media():
|
||||
dst_bitrate = prefs.bitrate
|
||||
|
||||
if maxBitRate:
|
||||
try:
|
||||
maxBitRate = int(maxBitRate)
|
||||
except ValueError:
|
||||
return request.formatter.error(0, 'Invalid bitrate value')
|
||||
maxBitRate = int(maxBitRate)
|
||||
|
||||
if dst_bitrate > maxBitRate and maxBitRate != 0:
|
||||
dst_bitrate = maxBitRate
|
||||
@ -133,27 +128,18 @@ def stream_media():
|
||||
|
||||
@api.route('/download.view', methods = [ 'GET', 'POST' ])
|
||||
def download_media():
|
||||
status, res = get_entity(Track)
|
||||
if not status:
|
||||
return res
|
||||
|
||||
res = get_entity(Track)
|
||||
return send_file(res.path, mimetype = res.content_type, conditional=True)
|
||||
|
||||
@api.route('/getCoverArt.view', methods = [ 'GET', 'POST' ])
|
||||
def cover_art():
|
||||
status, res = get_entity(Folder)
|
||||
if not status:
|
||||
return res
|
||||
|
||||
res = get_entity(Folder)
|
||||
if not res.has_cover_art or not os.path.isfile(os.path.join(res.path, 'cover.jpg')):
|
||||
return request.formatter.error(70, 'Cover art not found')
|
||||
|
||||
size = request.values.get('size')
|
||||
if size:
|
||||
try:
|
||||
size = int(size)
|
||||
except ValueError:
|
||||
return request.formatter.error(0, 'Invalid size value')
|
||||
size = int(size)
|
||||
else:
|
||||
return send_file(os.path.join(res.path, 'cover.jpg'))
|
||||
|
||||
|
@ -21,8 +21,6 @@
|
||||
import uuid
|
||||
|
||||
from flask import request
|
||||
from pony.orm import rollback
|
||||
from pony.orm import ObjectNotFound
|
||||
|
||||
from ..db import Playlist, User, Track
|
||||
from ..py23 import dict
|
||||
@ -48,10 +46,7 @@ def list_playlists():
|
||||
|
||||
@api.route('/getPlaylist.view', methods = [ 'GET', 'POST' ])
|
||||
def show_playlist():
|
||||
status, res = get_entity(Playlist)
|
||||
if not status:
|
||||
return res
|
||||
|
||||
res = get_entity(Playlist)
|
||||
if res.user.id != request.user.id and not request.user.admin:
|
||||
return request.formatter.error('50', 'Private playlist')
|
||||
|
||||
@ -64,16 +59,10 @@ def create_playlist():
|
||||
playlist_id, name = map(request.values.get, [ 'playlistId', 'name' ])
|
||||
# songId actually doesn't seem to be required
|
||||
songs = request.values.getlist('songId')
|
||||
try:
|
||||
playlist_id = uuid.UUID(playlist_id) if playlist_id else None
|
||||
except ValueError:
|
||||
return request.formatter.error(0, 'Invalid playlist id')
|
||||
playlist_id = uuid.UUID(playlist_id) if playlist_id else None
|
||||
|
||||
if playlist_id:
|
||||
try:
|
||||
playlist = Playlist[playlist_id]
|
||||
except ObjectNotFound:
|
||||
return request.formatter.error(70, 'Unknwon playlist')
|
||||
playlist = Playlist[playlist_id]
|
||||
|
||||
if playlist.user.id != request.user.id and not request.user.admin:
|
||||
return request.formatter.error(50, "You're not allowed to modify a playlist that isn't yours")
|
||||
@ -86,26 +75,16 @@ def create_playlist():
|
||||
else:
|
||||
return request.formatter.error(10, 'Missing playlist id or name')
|
||||
|
||||
try:
|
||||
songs = map(uuid.UUID, songs)
|
||||
for sid in songs:
|
||||
track = Track[sid]
|
||||
playlist.add(track)
|
||||
except ValueError:
|
||||
rollback()
|
||||
return request.formatter.error(0, 'Invalid song id')
|
||||
except ObjectNotFound:
|
||||
rollback()
|
||||
return request.formatter.error(70, 'Unknown song')
|
||||
songs = map(uuid.UUID, songs)
|
||||
for sid in songs:
|
||||
track = Track[sid]
|
||||
playlist.add(track)
|
||||
|
||||
return request.formatter.empty
|
||||
|
||||
@api.route('/deletePlaylist.view', methods = [ 'GET', 'POST' ])
|
||||
def delete_playlist():
|
||||
status, res = get_entity(Playlist)
|
||||
if not status:
|
||||
return res
|
||||
|
||||
res = get_entity(Playlist)
|
||||
if res.user.id != request.user.id and not request.user.admin:
|
||||
return request.formatter.error(50, "You're not allowed to delete a playlist that isn't yours")
|
||||
|
||||
@ -114,10 +93,7 @@ def delete_playlist():
|
||||
|
||||
@api.route('/updatePlaylist.view', methods = [ 'GET', 'POST' ])
|
||||
def update_playlist():
|
||||
status, res = get_entity(Playlist, 'playlistId')
|
||||
if not status:
|
||||
return res
|
||||
|
||||
res = get_entity(Playlist, 'playlistId')
|
||||
if res.user.id != request.user.id and not request.user.admin:
|
||||
return request.formatter.error(50, "You're not allowed to delete a playlist that isn't yours")
|
||||
|
||||
@ -132,19 +108,14 @@ def update_playlist():
|
||||
if public:
|
||||
playlist.public = public in (True, 'True', 'true', 1, '1')
|
||||
|
||||
try:
|
||||
to_add = map(uuid.UUID, to_add)
|
||||
to_remove = map(int, to_remove)
|
||||
to_add = map(uuid.UUID, to_add)
|
||||
to_remove = map(int, to_remove)
|
||||
|
||||
for sid in to_add:
|
||||
track = Track[sid]
|
||||
playlist.add(track)
|
||||
for sid in to_add:
|
||||
track = Track[sid]
|
||||
playlist.add(track)
|
||||
|
||||
playlist.remove_at_indexes(to_remove)
|
||||
except ValueError:
|
||||
return request.formatter.error(0, 'Invalid parameter')
|
||||
except ObjectNotFound:
|
||||
return request.formatter.error(70, 'Unknown song')
|
||||
playlist.remove_at_indexes(to_remove)
|
||||
|
||||
return request.formatter.empty
|
||||
|
||||
|
@ -30,13 +30,10 @@ from . import api
|
||||
@api.route('/search.view', methods = [ 'GET', 'POST' ])
|
||||
def old_search():
|
||||
artist, album, title, anyf, count, offset, newer_than = map(request.values.get, [ 'artist', 'album', 'title', 'any', 'count', 'offset', 'newerThan' ])
|
||||
try:
|
||||
count = int(count) if count else 20
|
||||
offset = int(offset) if offset else 0
|
||||
newer_than = int(newer_than) / 1000 if newer_than else 0
|
||||
except ValueError:
|
||||
return request.formatter.error(0, 'Invalid parameter')
|
||||
|
||||
count = int(count) if count else 20
|
||||
offset = int(offset) if offset else 0
|
||||
newer_than = int(newer_than) / 1000 if newer_than else 0
|
||||
min_date = datetime.fromtimestamp(newer_than)
|
||||
|
||||
if artist:
|
||||
@ -74,15 +71,12 @@ def new_search():
|
||||
query, artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map(
|
||||
request.values.get, [ 'query', 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ])
|
||||
|
||||
try:
|
||||
artist_count = int(artist_count) if artist_count else 20
|
||||
artist_offset = int(artist_offset) if artist_offset else 0
|
||||
album_count = int(album_count) if album_count else 20
|
||||
album_offset = int(album_offset) if album_offset else 0
|
||||
song_count = int(song_count) if song_count else 20
|
||||
song_offset = int(song_offset) if song_offset else 0
|
||||
except ValueError:
|
||||
return request.formatter.error(0, 'Invalid parameter')
|
||||
artist_count = int(artist_count) if artist_count else 20
|
||||
artist_offset = int(artist_offset) if artist_offset else 0
|
||||
album_count = int(album_count) if album_count else 20
|
||||
album_offset = int(album_offset) if album_offset else 0
|
||||
song_count = int(song_count) if song_count else 20
|
||||
song_offset = int(song_offset) if song_offset else 0
|
||||
|
||||
if not query:
|
||||
return request.formatter.error(10, 'Missing query parameter')
|
||||
@ -102,15 +96,12 @@ def search_id3():
|
||||
query, artist_count, artist_offset, album_count, album_offset, song_count, song_offset = map(
|
||||
request.values.get, [ 'query', 'artistCount', 'artistOffset', 'albumCount', 'albumOffset', 'songCount', 'songOffset' ])
|
||||
|
||||
try:
|
||||
artist_count = int(artist_count) if artist_count else 20
|
||||
artist_offset = int(artist_offset) if artist_offset else 0
|
||||
album_count = int(album_count) if album_count else 20
|
||||
album_offset = int(album_offset) if album_offset else 0
|
||||
song_count = int(song_count) if song_count else 20
|
||||
song_offset = int(song_offset) if song_offset else 0
|
||||
except ValueError:
|
||||
return request.formatter.error(0, 'Invalid parameter')
|
||||
artist_count = int(artist_count) if artist_count else 20
|
||||
artist_offset = int(artist_offset) if artist_offset else 0
|
||||
album_count = int(album_count) if album_count else 20
|
||||
album_offset = int(album_offset) if album_offset else 0
|
||||
song_count = int(song_count) if song_count else 20
|
||||
song_offset = int(song_offset) if song_offset else 0
|
||||
|
||||
if not query:
|
||||
return request.formatter.error(10, 'Missing query parameter')
|
||||
|
@ -63,9 +63,9 @@ class ApiSetupTestCase(TestBase):
|
||||
def test_auth_basic(self):
|
||||
# No auth info
|
||||
rv = self.client.get('/rest/ping.view?c=tests')
|
||||
self.assertEqual(rv.status_code, 401)
|
||||
self.assertEqual(rv.status_code, 400)
|
||||
self.assertIn('status="failed"', rv.data)
|
||||
self.assertIn('code="40"', rv.data)
|
||||
self.assertIn('code="10"', rv.data)
|
||||
|
||||
self.__test_auth(self.__basic_auth_get)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user