%PDF- %PDF-
| Direktori : /lib/calibre/calibre/srv/tests/ |
| Current File : //lib/calibre/calibre/srv/tests/ajax.py |
#!/usr/bin/env python3
__license__ = 'GPL v3'
__copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>'
import json
import os
import zlib
from functools import partial
from io import BytesIO
from calibre.ebooks.metadata.meta import get_metadata
from calibre.srv.tests.base import LibraryBaseTest
from polyglot.binary import as_base64_bytes
from polyglot.http_client import FORBIDDEN, NOT_FOUND, OK
from polyglot.urllib import quote, urlencode
def make_request(conn, url, headers={}, prefix='/ajax', username=None, password=None, method='GET', data=None):
if username and password:
headers[b'Authorization'] = b'Basic ' + as_base64_bytes(username + ':' + password)
conn.request(method, prefix + url, headers=headers, body=data)
r = conn.getresponse()
data = r.read()
if r.status == OK and data and data[0] in b'{[':
data = json.loads(data)
return r, data
class ContentTest(LibraryBaseTest):
def test_ajax_book(self): # {{{
'Test /ajax/book'
with self.create_server() as server:
db = server.handler.router.ctx.library_broker.get(None)
conn = server.connect()
request = partial(make_request, conn, prefix='/ajax/book')
r, data = request('/x')
self.ae(r.status, NOT_FOUND)
r, onedata = request('/1')
self.ae(r.status, OK)
self.ae(request('/1/' + db.server_library_id)[1], onedata)
self.ae(request('/%s?id_is_uuid=true' % db.field_for('uuid', 1))[1], onedata)
r, data = request('s')
self.ae(set(data), set(map(str, db.all_book_ids())))
r, zdata = request('s', headers={'Accept-Encoding':'gzip'})
self.ae(r.getheader('Content-Encoding'), 'gzip')
self.ae(json.loads(zlib.decompress(zdata, 16+zlib.MAX_WBITS)), data)
r, data = request('s?ids=1,2')
self.ae(set(data), {'1', '2'})
# }}}
def test_ajax_categories(self): # {{{
'Test /ajax/categories and /ajax/search'
with self.create_server() as server:
db = server.handler.router.ctx.library_broker.get(None)
db.set_pref('virtual_libraries', {'1':'title:"=Title One"'})
conn = server.connect()
request = partial(make_request, conn)
r, data = request('/categories')
self.ae(r.status, OK)
r, xdata = request('/categories/' + db.server_library_id)
self.ae(r.status, OK)
self.ae(data, xdata)
names = {x['name']:x['url'] for x in data}
for q in (_('Newest'), _('All books'), _('Tags'), _('Authors'), _('Enum'), _('Composite Tags')):
self.assertIn(q, names)
r, data = request(names[_('Tags')], prefix='')
self.ae(r.status, OK)
names = {x['name']:x['url'] for x in data['items']}
self.ae(set(names), set('Tag One,Tag Two,News'.split(',')))
r, data = request(names['Tag One'], prefix='')
self.ae(r.status, OK)
self.ae(set(data['book_ids']), {1, 2})
r, data = request('/search?' + urlencode({'query': 'tags:"=Tag One"'}))
self.ae(r.status, OK)
self.ae(set(data['book_ids']), {1, 2})
r, data = request('/search?' + urlencode({'query': 'tags:"=Tag One"', 'vl':'1'}))
self.ae(set(data['book_ids']), {2})
# }}}
def test_srv_restrictions(self): # {{{
' Test that virtual lib. + search restriction works on all end points'
with self.create_server(auth=True, auth_mode='basic') as server:
db = server.handler.router.ctx.library_broker.get(None)
db.set_pref('virtual_libraries', {'1':'id:1', '12':'id:1 or id:2'})
db.set_field('tags', {1: ['present'], 3: ['missing']})
self.assertTrue(db.has_id(3))
server.handler.ctx.user_manager.add_user('12', 'test', restriction={
'library_restrictions':{os.path.basename(db.backend.library_path): 'id:1 or id:2'}})
server.handler.ctx.user_manager.add_user('inv', 'test', restriction={
'library_restrictions':{os.path.basename(db.backend.library_path): '"1'}})
conn = server.connect()
def url_for(path, **kw):
p, q = path.partition('?')[::2]
ans = server.handler.router.url_for(p, **kw)
if q:
ans += '?' + q
return ans
ae = self.assertEqual
def r(path, status=OK, method='GET'):
r, data = make_request(conn, path, username='12', password='test', prefix='', method=method)
ae(status, r.status)
if status == NOT_FOUND:
p = data.partition(b':')[0]
ae(p, b'No book with id')
return data
ok = r
nf = partial(r, status=NOT_FOUND)
# ajax.py
ok(url_for('/ajax/book', book_id=1))
nf(url_for('/ajax/book', book_id=3))
data = ok(url_for('/ajax/books'))
self.assertIsNone(data['3'])
for i in '12':
self.assertIsNotNone(data[i])
ae(set(r(url_for('/ajax/search'))['book_ids']), {1,2})
ae(set(r(url_for('/ajax/search?query=id:2'))['book_ids']), {2})
ae(set(r(url_for('/ajax/search?vl=1'))['book_ids']), {1})
data = make_request(conn, '/ajax/search', username='inv', password='test', prefix='', method='GET')[1]
ae(data['bad_restriction'], _('Invalid syntax. Expected a lookup name or a word'))
# books.py
nf(url_for('/book-manifest', book_id=3, fmt='TXT'))
nf(url_for('/book-file', book_id=3, fmt='TXT', size=1, mtime=1, name='x'))
data = ok(url_for('/book-get-last-read-position', library_id=db.server_library_id, which='1-TXT_3-TXT'))
ae(set(data), {'1:TXT'})
nf(url_for('/book-set-last-read-position', book_id=3, library_id=db.server_library_id, fmt='TXT'), method='POST')
# cdb.py
r(url_for('/cdb/cmd', which='list'), status=FORBIDDEN)
r(url_for('/cdb/add-book', job_id=1, add_duplicates='n', filename='test.epub'), status=FORBIDDEN)
r(url_for('/cdb/delete-books', book_ids='1'), status=FORBIDDEN)
# code.py
def sr(path, **k):
return set(ok(url_for(path, **k))['search_result']['book_ids'])
for q in 'books-init init get-books'.split():
ae(sr('/interface-data/' + q), {1, 2})
ae(sr('/interface-data/get-books?vl=1'), {1})
ok(url_for('/interface-data/book-metadata', book_id=1))
nf(url_for('/interface-data/book-metadata', book_id=3))
# content.py
ok(url_for('/get', what='thumb', book_id=1))
nf(url_for('/get', what='thumb', book_id=3))
# Not going test legacy and opds as they are too painful
# }}}
def test_srv_add_book(self): # {{{
with self.create_server(auth=True, auth_mode='basic') as server:
server.handler.ctx.user_manager.add_user('12', 'test')
server.handler.ctx.user_manager.add_user('ro', 'test', readonly=True)
conn = server.connect()
ae = self.assertEqual
def a(filename, data=None, status=OK, method='POST', username='12', add_duplicates='n', job_id=1):
r, data = make_request(conn, '/cdb/add-book/{}/{}/{}'.format(job_id, add_duplicates, quote(filename.encode('utf-8'))),
username=username, password='test', prefix='', method=method, data=data)
ae(status, r.status)
return data
def d(book_ids, username='12', status=OK):
book_ids = ','.join(map(str, book_ids))
r, data = make_request(conn, f'/cdb/delete-books/{book_ids}',
username=username, password='test', prefix='', method='POST')
ae(status, r.status)
return data
a('test.epub', None, username='ro', status=FORBIDDEN)
content = b'content'
filename = 'test add - XXX.txt'
data = a(filename, content)
s = BytesIO(content)
s.name = filename
mi = get_metadata(s, stream_type='txt')
ae(data, {'title': mi.title, 'book_id': data['book_id'], 'authors': mi.authors, 'languages': mi.languages, 'id': '1', 'filename': filename})
r, q = make_request(conn, '/get/txt/{}'.format(data['book_id']), username='12', password='test', prefix='')
ae(r.status, OK)
ae(q, content)
d((1,), username='ro', status=FORBIDDEN)
d((1, data['book_id']))
# }}}