mirror of
https://github.com/beetbox/beets.git
synced 2026-01-18 14:11:35 +01:00
Web API handles multiple ids
This commit is contained in:
parent
b0d8fdfea6
commit
f706e58409
2 changed files with 123 additions and 30 deletions
|
|
@ -67,6 +67,64 @@ def json_generator(items, root):
|
|||
yield json.dumps(_rep(item))
|
||||
yield ']}'
|
||||
|
||||
def _extract_ids(string_ids):
|
||||
"""Parses ``string_ids`` as a comme separated list of integers and returns
|
||||
that list of integers.
|
||||
"""
|
||||
ids = []
|
||||
for id in string_ids.split(','):
|
||||
try:
|
||||
ids.append(int(id))
|
||||
except ValueError:
|
||||
pass
|
||||
return ids
|
||||
|
||||
def resource(name):
|
||||
"""Decorates a function to handle RESTful HTTP requests for a resource.
|
||||
"""
|
||||
def make_responder(retriever):
|
||||
def responder(entity_ids):
|
||||
entity_ids = _extract_ids(entity_ids)
|
||||
entities = [retriever(id) for id in entity_ids]
|
||||
entities = [entity for entity in entities if entity]
|
||||
|
||||
if len(entities) == 1:
|
||||
return flask.jsonify(_rep(entities[0]))
|
||||
elif entities:
|
||||
return app.response_class(
|
||||
json_generator(entities, root=name),
|
||||
mimetype='application/json')
|
||||
else:
|
||||
return flask.abort(404)
|
||||
responder.__name__ = 'get_%s' % name
|
||||
return responder
|
||||
return make_responder
|
||||
|
||||
def resource_query(name):
|
||||
"""Decorates a function to handle RESTful HTTP queries for resources.
|
||||
"""
|
||||
def make_responder(query_func):
|
||||
def responder(query):
|
||||
parts = query.split('/')
|
||||
entities = query_func(parts)
|
||||
return flask.jsonify(results=[_rep(entities) for item in items])
|
||||
responder.__name__ = 'query_%s' % name
|
||||
return responder
|
||||
return make_responder
|
||||
|
||||
def resource_list(name):
|
||||
"""Decorates a function to handle RESTful HTTP request for a list of
|
||||
resources.
|
||||
"""
|
||||
def make_responder(list_all):
|
||||
def responder():
|
||||
return app.response_class(
|
||||
json_generator(g.lib.items(), root=name),
|
||||
mimetype='application/json')
|
||||
responder.__name__ = 'all_%s' % name
|
||||
return responder
|
||||
return make_responder
|
||||
|
||||
|
||||
# Flask setup.
|
||||
|
||||
|
|
@ -79,17 +137,17 @@ def before_request():
|
|||
|
||||
# Items.
|
||||
|
||||
@app.route('/item/<int:item_id>')
|
||||
def single_item(item_id):
|
||||
item = g.lib.get_item(item_id)
|
||||
return flask.jsonify(_rep(item))
|
||||
@app.route('/item/<entity_ids>')
|
||||
@resource('items')
|
||||
def get_item(id):
|
||||
return g.lib.get_item(id)
|
||||
|
||||
|
||||
@app.route('/item/')
|
||||
@app.route('/item/query/')
|
||||
@resource_list('items')
|
||||
def all_items():
|
||||
return app.response_class(
|
||||
json_generator(g.lib.items(), root='items'),
|
||||
mimetype='application/json')
|
||||
return g.lib.items()
|
||||
|
||||
@app.route('/item/<int:item_id>/file')
|
||||
def item_file(item_id):
|
||||
|
|
@ -100,32 +158,28 @@ def item_file(item_id):
|
|||
return response
|
||||
|
||||
@app.route('/item/query/<path:query>')
|
||||
def item_query(query):
|
||||
parts = query.split('/')
|
||||
items = g.lib.items(parts)
|
||||
return flask.jsonify(results=[_rep(item) for item in items])
|
||||
@resource_query('items')
|
||||
def item_query(queries):
|
||||
return g.lib.items(queries)
|
||||
|
||||
|
||||
# Albums.
|
||||
|
||||
@app.route('/album/<int:album_id>')
|
||||
def single_album(album_id):
|
||||
album = g.lib.get_album(album_id)
|
||||
return flask.jsonify(_rep(album))
|
||||
@app.route('/album/<entity_ids>')
|
||||
@resource('albums')
|
||||
def get_album(id):
|
||||
return g.lib.get_album(id)
|
||||
|
||||
@app.route('/album/')
|
||||
@app.route('/album/query/')
|
||||
@resource_list('albums')
|
||||
def all_albums():
|
||||
return app.response_class(
|
||||
json_generator(g.lib.albums(), root='albums'),
|
||||
mimetype='application/json')
|
||||
|
||||
return g.lib.albums()
|
||||
|
||||
@app.route('/album/query/<path:query>')
|
||||
def album_query(query):
|
||||
parts = query.split('/')
|
||||
albums = g.lib.albums(parts)
|
||||
return flask.jsonify(results=[_rep(album) for album in albums])
|
||||
@resource_query('albums')
|
||||
def album_query(queries):
|
||||
return g.lib.album(queries)
|
||||
|
||||
@app.route('/album/<int:album_id>/art')
|
||||
def album_art(album_id):
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import _common
|
|||
import json
|
||||
import beets
|
||||
import beetsplug
|
||||
from beets.library import Item, Album
|
||||
beetsplug.__path__ = ['./beetsplug', '../beetsplug']
|
||||
from beetsplug import web
|
||||
|
||||
|
|
@ -15,23 +16,45 @@ class WebPluginTest(_common.LibTestCase):
|
|||
super(WebPluginTest, self).setUp()
|
||||
|
||||
# Add fixtures
|
||||
self.lib.add(beets.library.Item(
|
||||
title = u'another title',
|
||||
path = 'somepath' + str(_common._item_ident)))
|
||||
self.lib.add(beets.library.Album())
|
||||
self.lib.add(beets.library.Album())
|
||||
for track in self.lib.items():
|
||||
track.remove()
|
||||
self.lib.add(Item(title='title', path='', id=1))
|
||||
self.lib.add(Item(title='another title', path='', id=2))
|
||||
self.lib.add(Album(album='album', id=1))
|
||||
self.lib.add(Album(album='another album', id=2))
|
||||
|
||||
web.app.config['TESTING'] = True
|
||||
web.app.config['lib'] = self.lib
|
||||
self.client = web.app.test_client()
|
||||
|
||||
def test_get_item(self):
|
||||
def test_get_all_items(self):
|
||||
response = self.client.get('/item/')
|
||||
response.json = json.loads(response.data)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(response.json['items']), 2)
|
||||
|
||||
def test_get_single_item_by_id(self):
|
||||
response = self.client.get('/item/1')
|
||||
response.json = json.loads(response.data)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.json['id'], 1)
|
||||
self.assertEqual(response.json['title'], 'title')
|
||||
|
||||
def test_get_multiple_items_by_id(self):
|
||||
response = self.client.get('/item/1,2')
|
||||
response.json = json.loads(response.data)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(response.json['items']), 2)
|
||||
response_titles = [item['title'] for item in response.json['items']]
|
||||
self.assertItemsEqual(response_titles, ['title', 'another title'])
|
||||
|
||||
def test_get_single_item_not_found(self):
|
||||
response = self.client.get('/item/3')
|
||||
self.assertEqual(response.status_code, 404)
|
||||
|
||||
def test_get_item_empty_query(self):
|
||||
response = self.client.get('/item/query/')
|
||||
response.json = json.loads(response.data)
|
||||
|
|
@ -39,13 +62,29 @@ class WebPluginTest(_common.LibTestCase):
|
|||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(response.json['items']), 2)
|
||||
|
||||
def test_get_album(self):
|
||||
def test_get_all_albums(self):
|
||||
response = self.client.get('/album/')
|
||||
response.json = json.loads(response.data)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(response.json['albums']), 2)
|
||||
|
||||
def test_get_single_album_by_id(self):
|
||||
response = self.client.get('/album/2')
|
||||
response.json = json.loads(response.data)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.json['id'], 2)
|
||||
self.assertEqual(response.json['album'], 'another album')
|
||||
|
||||
def test_get_multiple_items_by_id(self):
|
||||
response = self.client.get('/album/1,2')
|
||||
response.json = json.loads(response.data)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
response_albums = [album['album'] for album in response.json['albums']]
|
||||
self.assertItemsEqual(response_albums, ['album', 'another album'])
|
||||
|
||||
def test_get_album_empty_query(self):
|
||||
response = self.client.get('/album/query/')
|
||||
response.json = json.loads(response.data)
|
||||
|
|
|
|||
Loading…
Reference in a new issue