예제 #1
0
def cdb_run(ctx, rd, which, version):
    try:
        m = module_for_cmd(which)
    except ImportError:
        raise HTTPNotFound('No module named: {}'.format(which))
    if not getattr(m, 'readonly', False):
        ctx.check_for_write_access(rd)
    if getattr(m, 'version', 0) != int(version):
        raise HTTPNotFound(
            ('The module {} is not available in version: {}.'
             'Make sure the version of calibre used for the'
             ' server and calibredb match').format(which, version))
    db = get_library_data(ctx, rd, strict_library_id=True)[0]
    if ctx.restriction_for(rd, db):
        raise HTTPForbidden(
            'Cannot use the command-line db interface with a user who has per library restrictions'
        )
    raw = rd.read()
    ct = rd.inheaders.get('Content-Type', all=True)
    ct = {x.lower().partition(';')[0] for x in ct}
    try:
        if MSGPACK_MIME in ct:
            args = msgpack_loads(raw)
        elif 'application/json' in ct:
            args = json_loads(raw)
        else:
            raise HTTPBadRequest('Only JSON or msgpack requests are supported')
    except Exception:
        raise HTTPBadRequest('args are not valid encoded data')
    if getattr(m, 'needs_srv_ctx', False):
        args = [ctx] + list(args)
    try:
        result = m.implementation(
            db, partial(ctx.notify_changes, db.backend.library_path), *args)
    except Exception as err:
        import traceback
        return {'err': as_unicode(err), 'tb': traceback.format_exc()}
    return {'result': result}
예제 #2
0
def conversion_status(ctx, rd, job_id):
    with cache_lock:
        job_status = conversion_jobs.get(job_id)
        if job_status is None:
            raise HTTPNotFound(f'No job with id: {job_id}')
        job_status.last_check_at = monotonic()
        if job_status.running:
            percent, msg = job_status.current_status
            if rd.query.get('abort_job'):
                ctx.abort_job(job_id)
            return {'running': True, 'percent': percent, 'msg': msg}

        del conversion_jobs[job_id]

    try:
        ans = {
            'running': False,
            'ok': job_status.ok,
            'was_aborted': job_status.was_aborted,
            'traceback': job_status.traceback,
            'log': job_status.log
        }
        if job_status.ok:
            db, library_id = get_library_data(ctx, rd)[:2]
            if library_id != job_status.library_id:
                raise HTTPNotFound('job library_id does not match')
            fmt = job_status.output_path.rpartition('.')[-1]
            try:
                db.add_format(job_status.book_id, fmt, job_status.output_path)
            except NoSuchBook:
                raise HTTPNotFound(
                    f'book_id {job_status.book_id} not found in library')
            formats_added({job_status.book_id: (fmt, )})
            ans['size'] = os.path.getsize(job_status.output_path)
            ans['fmt'] = fmt
        return ans
    finally:
        job_status.cleanup()
예제 #3
0
파일: books.py 프로젝트: vrdev/calibre
def set_last_read_position(ctx, rd, library_id, book_id, fmt):
    db = get_db(ctx, rd, library_id)
    user = rd.username or None
    if not ctx.has_id(rd, db, book_id):
        raise BookNotFound(book_id, db)
    try:
        data = jsonlib.load(rd.request_body_file)
        device, cfi, pos_frac = data['device'], data['cfi'], data['pos_frac']
    except Exception:
        raise HTTPNotFound('Invalid data')
    db.set_last_read_position(
        book_id, fmt, user=user, device=device, cfi=cfi or None, pos_frac=pos_frac)
    rd.outheaders['Content-type'] = 'text/plain'
    return b''
예제 #4
0
 def find_route(self, path):
     size = len(path)
     # routes for which min_size <= size <= max_size
     routes = self.max_size_map.get(size, set()) & self.min_size_map.get(size, set())
     for route in sorted(routes, key=attrgetter('max_size'), reverse=True):
         args = route.matches(path)
         if args is not False:
             return route.endpoint, args
     for route in self.soak_routes:
         if route.min_size <= size:
             args = route.matches(path)
             if args is not False:
                 return route.endpoint, args
     raise HTTPNotFound()
예제 #5
0
파일: opds.py 프로젝트: zhanghb1994/calibre
def opds_category(ctx, rd, category, which):
    try:
        offset = int(rd.query.get('offset', 0))
    except Exception:
        raise HTTPNotFound('Not found')

    if not which or not category:
        raise HTTPNotFound('Not found')
    rc = RequestContext(ctx, rd)
    page_url = rc.url_for('/opds/category', which=which, category=category)
    up_url = rc.url_for('/opds/navcatalog', which=category)

    which, category = from_hex_unicode(which), from_hex_unicode(category)
    type_ = which[0]
    which = which[1:]
    if type_ == 'I':
        try:
            p = which.rindex(':')
            category = which[p + 1:]
            which = which[:p]
            # This line will toss an exception for composite columns
            which = int(which[:p])
        except Exception:
            # Might be a composite column, where we have the lookup key
            if not (category in rc.db.field_metadata and
                    rc.db.field_metadata[category]['datatype'] == 'composite'):
                raise HTTPNotFound('Tag %r not found' % which)

    categories = rc.get_categories()
    if category not in categories:
        raise HTTPNotFound('Category %r not found' % which)

    if category == 'search':
        try:
            ids = rc.search('search:"%s"' % which)
        except Exception:
            raise HTTPNotFound('Search: %r not understood' % which)
        return get_acquisition_feed(rc, ids, offset, page_url, up_url,
                                    'calibre-search:' + which)

    if type_ != 'I':
        raise HTTPNotFound('Non id categories not supported')

    q = category
    if q == 'news':
        q = 'tags'
    ids = rc.db.get_books_for_category(q, which) & rc.allowed_book_ids()
    sort_by = 'series' if category == 'series' else 'title'

    return get_acquisition_feed(rc,
                                ids,
                                offset,
                                page_url,
                                up_url,
                                'calibre-category:' + category + ':' +
                                unicode_type(which),
                                sort_by=sort_by)
예제 #6
0
def book_manifest(ctx, rd, book_id, fmt):
    db, library_id = get_library_data(ctx, rd)[:2]
    force_reload = rd.query.get('force_reload') == '1'
    if plugin_for_input_format(fmt) is None:
        raise HTTPNotFound('The format %s cannot be viewed' % fmt.upper())
    if not ctx.has_id(rd, db, book_id):
        raise BookNotFound(book_id, db)
    with db.safe_read_lock:
        fm = db.format_metadata(book_id, fmt, allow_cache=False)
        if not fm:
            raise HTTPNotFound(f'No {fmt} format for the book (id:{book_id}) in the library: {library_id}')
        size, mtime = map(int, (fm['size'], time.mktime(fm['mtime'].utctimetuple())*10))
        bhash = book_hash(db.library_id, book_id, fmt, size, mtime)
        with cache_lock:
            mpath = abspath(os.path.join(books_cache_dir(), 'f', bhash, 'calibre-book-manifest.json'))
            if force_reload:
                safe_remove(mpath, True)
            try:
                os.utime(mpath, None)
                with lopen(mpath, 'rb') as f:
                    ans = jsonlib.load(f)
                ans['metadata'] = book_as_json(db, book_id)
                user = rd.username or None
                ans['last_read_positions'] = db.get_last_read_positions(book_id, fmt, user) if user else []
                ans['annotations_map'] = db.annotations_map_for_book(book_id, fmt, user_type='web', user=user or '*')
                return ans
            except OSError as e:
                if e.errno != errno.ENOENT:
                    raise
            x = failed_jobs.pop(bhash, None)
            if x is not None:
                return {'aborted':x[0], 'traceback':x[1], 'job_status':'finished'}
            job_id = queued_jobs.get(bhash)
            if job_id is None:
                job_id = queue_job(ctx, partial(db.copy_format_to, book_id, fmt), bhash, fmt, book_id, size, mtime)
    status, result, tb, aborted = ctx.job_status(job_id)
    return {'aborted': aborted, 'traceback':tb, 'job_status':status, 'job_id':job_id}
예제 #7
0
def update_annotations(ctx, rd, library_id, book_id, fmt):
    db = get_db(ctx, rd, library_id)
    user = rd.username or '*'
    if not ctx.has_id(rd, db, book_id):
        raise BookNotFound(book_id, db)
    try:
        amap = jsonlib.load(rd.request_body_file)
    except Exception:
        raise HTTPNotFound('Invalid data')
    alist = []
    for val in itervalues(amap):
        if val:
            alist.extend(val)
    db.merge_annotations_for_book(book_id, fmt, alist, user_type='web', user=user)
    return b''
예제 #8
0
파일: code.py 프로젝트: exedre/calibre
def books(ctx, rd):
    '''
    Get data to create list of books

    Optional: ?num=50&sort=timestamp.desc&library_id=<default library>
              &search=''&extra_books=''&vl=''
    '''
    ans = {}
    try:
        num = int(rd.query.get('num', rd.opts.num_per_page))
    except Exception:
        raise HTTPNotFound('Invalid number of books: %r' % rd.query.get('num'))
    library_id, db, sorts, orders, vl = get_basic_query_data(ctx, rd)
    ans = get_library_init_data(ctx, rd, db, num, sorts, orders, vl)
    ans['library_id'] = library_id
    return ans
예제 #9
0
def books(ctx, rd, library_id):
    '''
    Return the metadata for the books as a JSON dictionary.

    Query parameters: ?ids=all&category_urls=true&id_is_uuid=false&device_for_template=None

    If category_urls is true the returned dictionary also contains a
    mapping of category (field) names to URLs that return the list of books in the
    given category.

    If id_is_uuid is true then the book_id is assumed to be a book uuid instead.
    '''
    db = get_db(ctx, rd, library_id)
    with db.safe_read_lock:
        id_is_uuid = rd.query.get('id_is_uuid', 'false')
        ids = rd.query.get('ids')
        if ids is None or ids == 'all':
            ids = db.all_book_ids()
        else:
            ids = ids.split(',')
            if id_is_uuid == 'true':
                ids = {db.lookup_by_uuid(x) for x in ids}
                ids.discard(None)
            else:
                try:
                    ids = {int(x) for x in ids}
                except Exception:
                    raise HTTPNotFound('ids must a comma separated list of integers')
        last_modified = None
        category_urls = rd.query.get('category_urls', 'true').lower() == 'true'
        device_compatible = rd.query.get('device_compatible', 'false').lower() == 'true'
        device_for_template = rd.query.get('device_for_template', None)
        ans = {}
        restricted_to = ctx.allowed_book_ids(rd, db)
        for book_id in ids:
            if book_id not in restricted_to:
                ans[book_id] = None
                continue
            data, lm = book_to_json(
                ctx, rd, db, book_id, get_category_urls=category_urls,
                device_compatible=device_compatible, device_for_template=device_for_template)
            last_modified = lm if last_modified is None else max(lm, last_modified)
            ans[book_id] = data
    if last_modified is not None:
        rd.outheaders['Last-Modified'] = http_date(timestampfromdt(last_modified))
    return ans
예제 #10
0
 def __init__(self, offset, delta, total):
     if offset < 0:
         offset = 0
     if offset >= total:
         raise HTTPNotFound('Invalid offset: %r' % offset)
     last_allowed_index = total - 1
     last_current_index = offset + delta - 1
     self.slice_upper_bound = offset + delta
     self.offset = offset
     self.next_offset = last_current_index + 1
     if self.next_offset > last_allowed_index:
         self.next_offset = -1
     self.previous_offset = self.offset - delta
     if self.previous_offset < 0:
         self.previous_offset = 0
     self.last_offset = last_allowed_index - delta
     if self.last_offset < 0:
         self.last_offset = 0
예제 #11
0
파일: opds.py 프로젝트: exedre/calibre
def get_navcatalog(request_context, which, page_url, up_url, offset=0):
    categories = request_context.get_categories()
    if which not in categories:
        raise HTTPNotFound('Category %r not found'%which)

    items = categories[which]
    updated = request_context.last_modified()
    category_meta = request_context.db.field_metadata
    meta = category_meta.get(which, {})
    category_name = meta.get('name', which)
    feed_title = default_feed_title + ' :: ' + _('By %s') % category_name

    id_ = 'calibre-category-feed:'+which

    MAX_ITEMS = request_context.opts.max_opds_ungrouped_items

    if MAX_ITEMS > 0 and len(items) <= MAX_ITEMS:
        max_items = request_context.opts.max_opds_items
        offsets = Offsets(offset, max_items, len(items))
        items = list(items)[offsets.offset:offsets.offset+max_items]
        ans = CategoryFeed(items, which, id_, updated, request_context, offsets,
            page_url, up_url, title=feed_title)
    else:
        Group = namedtuple('Group', 'text count')
        starts = set()
        for x in items:
            val = getattr(x, 'sort', x.name)
            if not val:
                val = 'A'
            starts.add(val[0].upper())
        category_groups = OrderedDict()
        for x in sorted(starts, key=sort_key):
            category_groups[x] = len([y for y in items if
                getattr(y, 'sort', y.name).upper().startswith(x)])
        items = [Group(x, y) for x, y in category_groups.items()]
        max_items = request_context.opts.max_opds_items
        offsets = Offsets(offset, max_items, len(items))
        items = items[offsets.offset:offsets.offset+max_items]
        ans = CategoryGroupFeed(items, which, id_, updated, request_context, offsets,
            page_url, up_url, title=feed_title)

    request_context.outheaders['Last-Modified'] = http_date(timestampfromdt(updated))

    return ans.root
예제 #12
0
파일: ajax.py 프로젝트: zengchunyun/calibre
def book(ctx, rd, book_id, library_id):
    '''
    Return the metadata of the book as a JSON dictionary.

    Query parameters: ?category_urls=true&id_is_uuid=false&device_for_template=None

    If category_urls is true the returned dictionary also contains a
    mapping of category (field) names to URLs that return the list of books in the
    given category.

    If id_is_uuid is true then the book_id is assumed to be a book uuid instead.
    '''
    db = get_db(ctx, rd, library_id)
    with db.safe_read_lock:
        id_is_uuid = rd.query.get('id_is_uuid', 'false')
        oid = book_id
        if id_is_uuid == 'true':
            book_id = db.lookup_by_uuid(book_id)
        else:
            try:
                book_id = int(book_id)
                if not db.has_id(book_id):
                    book_id = None
            except Exception:
                book_id = None
        if book_id is None or book_id not in ctx.allowed_book_ids(rd, db):
            raise HTTPNotFound('Book with id %r does not exist' % oid)
        category_urls = rd.query.get('category_urls', 'true').lower()
        device_compatible = rd.query.get('device_compatible', 'false').lower()
        device_for_template = rd.query.get('device_for_template', None)

        data, last_modified = book_to_json(
            ctx,
            rd,
            db,
            book_id,
            get_category_urls=category_urls == 'true',
            device_compatible=device_compatible == 'true',
            device_for_template=device_for_template)
    rd.outheaders['Last-Modified'] = http_date(timestampfromdt(last_modified))
    return data
예제 #13
0
파일: ajax.py 프로젝트: yangbinji/calibre
def search_result(ctx, rd, db, query, num, offset, sort, sort_order, vl=''):
    multisort = [(sanitize_sort_field_name(db.field_metadata, s), ensure_val(o, 'asc', 'desc') == 'asc')
                 for s, o in zip(sort.split(','), cycle(sort_order.split(',')))]
    skeys = db.field_metadata.sortable_field_keys()
    for sfield, sorder in multisort:
        if sfield not in skeys:
            raise HTTPNotFound('%s is not a valid sort field'%sort)

    ids = ctx.search(rd, db, query, vl=vl)
    ids = db.multisort(fields=multisort, ids_to_sort=ids)
    total_num = len(ids)
    ids = ids[offset:offset+num]
    return {
        'total_num': total_num, 'sort_order':sort_order,
        'offset':offset, 'num':len(ids), 'sort':sort,
        'base_url':ctx.url_for(search, library_id=db.server_library_id),
        'query': query,
        'library_id': db.server_library_id,
        'book_ids':ids,
        'vl': vl,
    }
예제 #14
0
파일: books.py 프로젝트: vrdev/calibre
def get_last_read_position(ctx, rd, library_id, which):
    '''
    Get last read position data for the specified books, where which is of the form:
    book_id1-fmt1_book_id2-fmt2,...
    '''
    db = get_db(ctx, rd, library_id)
    user = rd.username or None
    if not user:
        raise HTTPNotFound('login required for sync')
    ans = {}
    allowed_book_ids = ctx.allowed_book_ids(rd, db)
    for item in which.split('_'):
        book_id, fmt = item.partition('-')[::2]
        try:
            book_id = int(book_id)
        except Exception:
            continue
        if book_id not in allowed_book_ids:
            continue
        key = '{}:{}'.format(book_id, fmt)
        ans[key] = db.get_last_read_positions(book_id, fmt, user)
    return ans
예제 #15
0
파일: ajax.py 프로젝트: smdx023/calibre
def search_result(ctx, rd, db, query, num, offset, sort, sort_order, vl=''):
    multisort = [
        (sanitize_sort_field_name(db.field_metadata,
                                  s), ensure_val(o, 'asc', 'desc') == 'asc')
        for s, o in zip(sort.split(','), cycle(sort_order.split(',')))
    ]
    skeys = db.field_metadata.sortable_field_keys()
    for sfield, sorder in multisort:
        if sfield not in skeys:
            raise HTTPNotFound('%s is not a valid sort field' % sort)

    ids, parse_error = ctx.search(rd,
                                  db,
                                  query,
                                  vl=vl,
                                  report_restriction_errors=True)
    ids = db.multisort(fields=multisort, ids_to_sort=ids)
    total_num = len(ids)
    ids = ids[offset:offset + num]
    num_books = db.number_of_books_in_virtual_library(
        vl) if query else total_num
    ans = {
        'total_num': total_num,
        'sort_order': sort_order,
        'num_books_without_search': num_books,
        'offset': offset,
        'num': len(ids),
        'sort': sort,
        'base_url': ctx.url_for(search, library_id=db.server_library_id),
        'query': query,
        'library_id': db.server_library_id,
        'book_ids': ids,
        'vl': vl,
    }
    if parse_error is not None:
        ans['bad_restriction'] = str(parse_error)
    return ans
예제 #16
0
def category(ctx, rd, encoded_name, library_id):
    '''
    Return a dictionary describing the category specified by name. The

    Optional: ?num=100&offset=0&sort=name&sort_order=asc

    The dictionary looks like::

        {
            'category_name': Category display name,
            'base_url': Base URL for this category,
            'total_num': Total numberof items in this category,
            'offset': The offset for the items returned in this result,
            'num': The number of items returned in this result,
            'sort': How the returned items are sorted,
            'sort_order': asc or desc
            'subcategories': List of sub categories of this category.
            'items': List of items in this category,
        }

    Each subcategory is a dictionary of the same form as those returned by
    /ajax/categories

    Each  item is a dictionary of the form::

        {
            'name': Display name,
            'average_rating': Average rating for books in this item,
            'count': Number of books in this item,
            'url': URL to get list of books in this item,
            'has_children': If True this item contains sub categories, look
            for an entry corresponding to this item in subcategories int he
            main dictionary,
        }

    :param sort: How to sort the returned items. Choices are: name, rating,
                    popularity
    :param sort_order: asc or desc

    To learn how to create subcategories see
    https://manual.calibre-ebook.com/sub_groups.html
    '''

    db = get_db(ctx, rd, library_id)
    with db.safe_read_lock:
        num, offset = get_pagination(rd.query)
        sort, sort_order = rd.query.get('sort'), rd.query.get('sort_order')
        sort = ensure_val(sort, 'name', 'rating', 'popularity')
        sort_order = ensure_val(sort_order, 'asc', 'desc')
        try:
            dname = decode_name(encoded_name)
        except:
            raise HTTPNotFound('Invalid encoding of category name %r'%encoded_name)
        base_url = ctx.url_for(globals()['category'], encoded_name=encoded_name, library_id=db.server_library_id)

        if dname in ('newest', 'allbooks'):
            sort, sort_order = 'timestamp', 'desc'
            rd.query['sort'], rd.query['sort_order'] = sort, sort_order
            return books_in(ctx, rd, encoded_name, encode_name('0'), library_id)

        fm = db.field_metadata
        categories = ctx.get_categories(rd, db)
        hierarchical_categories = db.pref('categories_using_hierarchy', ())

        subcategory = dname
        toplevel = subcategory.partition('.')[0]
        if toplevel == subcategory:
            subcategory = None
        if toplevel not in categories or toplevel not in fm:
            raise HTTPNotFound('Category %r not found'%toplevel)

        # Find items and sub categories
        subcategories = []
        meta = fm[toplevel]
        item_names = {}
        children = set()

        if meta['kind'] == 'user':
            fullname = ((toplevel + '.' + subcategory) if subcategory is not
                                None else toplevel)
            try:
                # User categories cannot be applied to books, so this is the
                # complete set of items, no need to consider sub categories
                items = categories[fullname]
            except:
                raise HTTPNotFound('User category %r not found'%fullname)

            parts = fullname.split('.')
            for candidate in categories:
                cparts = candidate.split('.')
                if len(cparts) == len(parts)+1 and cparts[:-1] == parts:
                    subcategories.append({'name':cparts[-1],
                        'url':candidate,
                        'icon':category_icon(toplevel, meta)})

            category_name = toplevel[1:].split('.')
            # When browsing by user categories we ignore hierarchical normal
            # columns, so children can be empty

        elif toplevel in hierarchical_categories:
            items = []

            category_names = [x.original_name.split('.') for x in categories[toplevel] if
                    '.' in x.original_name]

            if subcategory is None:
                children = set(x[0] for x in category_names)
                category_name = [meta['name']]
                items = [x for x in categories[toplevel] if '.' not in x.original_name]
            else:
                subcategory_parts = subcategory.split('.')[1:]
                category_name = [meta['name']] + subcategory_parts

                lsp = len(subcategory_parts)
                children = set('.'.join(x) for x in category_names if len(x) ==
                        lsp+1 and x[:lsp] == subcategory_parts)
                items = [x for x in categories[toplevel] if x.original_name in
                        children]
                item_names = {x:x.original_name.rpartition('.')[-1] for x in
                        items}
                # Only mark the subcategories that have children themselves as
                # subcategories
                children = set('.'.join(x[:lsp+1]) for x in category_names if len(x) >
                        lsp+1 and x[:lsp] == subcategory_parts)
            subcategories = [{'name':x.rpartition('.')[-1],
                'url':toplevel+'.'+x,
                'icon':category_icon(toplevel, meta)} for x in children]
        else:
            items = categories[toplevel]
            category_name = meta['name']

        for x in subcategories:
            x['url'] = ctx.url_for(globals()['category'], encoded_name=encode_name(x['url']), library_id=db.server_library_id)
            x['icon'] = ctx.url_for(get_icon, which=x['icon'])
            x['is_category'] = True

        sort_keygen = {
                'name': lambda x: sort_key(x.sort if x.sort else x.original_name),
                'popularity': lambda x: x.count,
                'rating': lambda x: x.avg_rating
        }
        items.sort(key=sort_keygen[sort], reverse=sort_order == 'desc')
        total_num = len(items)
        items = items[offset:offset+num]
        items = [{
            'name':item_names.get(x, x.original_name),
            'average_rating': x.avg_rating,
            'count': x.count,
            'url': ctx.url_for(books_in, encoded_category=encode_name(x.category if x.category else toplevel),
                               encoded_item=encode_name(x.original_name if x.id is None else unicode(x.id)),
                               library_id=db.server_library_id
                               ),
            'has_children': x.original_name in children,
            } for x in items]

        return {
                'category_name': category_name,
                'base_url': base_url,
                'total_num': total_num,
                'offset':offset, 'num':len(items), 'sort':sort,
                'sort_order':sort_order,
                'subcategories':subcategories,
                'items':items,
        }
예제 #17
0
def interface_data(ctx, rd):
    '''
    Return the data needed to create the server main UI

    Optional: ?num=50&sort=timestamp.desc&library_id=<default library>
              &search=''&extra_books=''
    '''
    ans = {
        'username':
        rd.username,
        'output_format':
        prefs['output_format'].upper(),
        'input_formats': {x.upper(): True
                          for x in available_input_formats()},
        'gui_pubdate_display_format':
        tweaks['gui_pubdate_display_format'],
        'gui_timestamp_display_format':
        tweaks['gui_timestamp_display_format'],
        'gui_last_modified_display_format':
        tweaks['gui_last_modified_display_format'],
        'use_roman_numerals_for_series_number':
        get_use_roman(),
        'translations':
        get_translations(),
    }
    ans['library_map'], ans['default_library'] = ctx.library_info(rd)
    ud = {}
    if rd.username:
        # Override session data with stored values for the authenticated user,
        # if any
        ud = ctx.user_manager.get_session_data(rd.username)
        lid = ud.get('library_id')
        if lid and lid in ans['library_map']:
            rd.query.set('library_id', lid)
        usort = ud.get('sort')
        if usort:
            rd.query.set('sort', usort)
    ans['library_id'], db, sorts, orders = get_basic_query_data(ctx, rd)
    ans['user_session_data'] = ud
    try:
        num = int(rd.query.get('num', DEFAULT_NUMBER_OF_BOOKS))
    except Exception:
        raise HTTPNotFound('Invalid number of books: %r' % rd.query.get('num'))
    with db.safe_read_lock:
        try:
            ans['search_result'] = search_result(ctx, rd, db,
                                                 rd.query.get('search', ''),
                                                 num, 0, ','.join(sorts),
                                                 ','.join(orders))
        except ParseException:
            ans['search_result'] = search_result(ctx, rd, db, '', num, 0,
                                                 ','.join(sorts),
                                                 ','.join(orders))
        sf = db.field_metadata.ui_sortable_field_keys()
        sf.pop('ondevice', None)
        ans['sortable_fields'] = sorted(
            ((sanitize_sort_field_name(db.field_metadata, k), v)
             for k, v in sf.iteritems()),
            key=lambda (field, name): sort_key(name))
        ans['field_metadata'] = db.field_metadata.all_metadata()
        ans['icon_map'] = icon_map()
        ans['icon_path'] = ctx.url_for('/icon', which='')
        mdata = ans['metadata'] = {}
        try:
            extra_books = set(
                int(x) for x in rd.query.get('extra_books', '').split(','))
        except Exception:
            extra_books = ()
        for coll in (ans['search_result']['book_ids'], extra_books):
            for book_id in coll:
                if book_id not in mdata:
                    data = book_as_json(db, book_id)
                    if data is not None:
                        mdata[book_id] = data

    return ans
예제 #18
0
 def notfound():
     raise HTTPNotFound(_('No book with id: %d in library') % book_id)
예제 #19
0
 def handler(data):
     raise HTTPNotFound(body)
예제 #20
0
파일: ajax.py 프로젝트: smdx023/calibre
def books_in(ctx, rd, encoded_category, encoded_item, library_id):
    '''
    Return the books (as list of ids) present in the specified category.

    Optional: ?num=100&offset=0&sort=title&sort_order=asc&get_additional_fields=
    '''
    db = get_db(ctx, rd, library_id)
    with db.safe_read_lock:
        try:
            dname, ditem = map(decode_name, (encoded_category, encoded_item))
        except:
            raise HTTPNotFound('Invalid encoded param: %r (%r)' %
                               (encoded_category, encoded_item))
        num, offset = get_pagination(rd.query)
        sort, sort_order = rd.query.get('sort',
                                        'title'), rd.query.get('sort_order')
        sort_order = ensure_val(sort_order, 'asc', 'desc')
        sfield = sanitize_sort_field_name(db.field_metadata, sort)
        if sfield not in db.field_metadata.sortable_field_keys():
            raise HTTPNotFound('%s is not a valid sort field' % sort)

        if dname in ('allbooks', 'newest'):
            ids = ctx.allowed_book_ids(rd, db)
        elif dname == 'search':
            try:
                ids = ctx.search(rd, db, 'search:"%s"' % ditem)
            except Exception:
                raise HTTPNotFound('Search: %r not understood' % ditem)
        else:
            try:
                cid = int(ditem)
            except Exception:
                raise HTTPNotFound('Category id %r not an integer' % ditem)

            if dname == 'news':
                dname = 'tags'
            ids = db.get_books_for_category(dname, cid) & ctx.allowed_book_ids(
                rd, db)

        ids = db.multisort(fields=[(sfield, sort_order == 'asc')],
                           ids_to_sort=ids)
        total_num = len(ids)
        ids = ids[offset:offset + num]

        result = {
            'total_num':
            total_num,
            'sort_order':
            sort_order,
            'offset':
            offset,
            'num':
            len(ids),
            'sort':
            sort,
            'base_url':
            ctx.url_for(books_in,
                        encoded_category=encoded_category,
                        encoded_item=encoded_item,
                        library_id=db.server_library_id),
            'book_ids':
            ids
        }

        get_additional_fields = rd.query.get('get_additional_fields')
        if get_additional_fields:
            additional_fields = {}
            for field in get_additional_fields.split(','):
                field = field.strip()
                if field:
                    flist = additional_fields[field] = []
                    for id_ in ids:
                        flist.append(
                            db.field_for(field, id_, default_value=None))
            if additional_fields:
                result['additional_fields'] = additional_fields
        return result
예제 #21
0
def get_db(ctx, rd, library_id):
    db = ctx.get_library(rd, library_id)
    if db is None:
        raise HTTPNotFound('Library %r not found' % library_id)
    return db
예제 #22
0
 def check(tc, val):
     try:
         return tc(val)
     except Exception:
         raise HTTPNotFound('Argument of incorrect type')
예제 #23
0
파일: code.py 프로젝트: rakyi/calibre
def console_print(ctx, rd):
    if not getattr(rd.opts, 'allow_console_print', False):
        raise HTTPNotFound('console printing is not allowed')
    shutil.copyfileobj(rd.request_body_file, sys.stdout)
    return ''