示例#1
0
    def render(self, page=1, sort='desc', list=None):
        if not self.user:
            return render.notfound("User %s" % self.username, create=False)
        logged_in_user = accounts.get_current_user()
        is_logged_in_user = (logged_in_user
                             and logged_in_user.key.split('/')[-1]
                             == self.username)
        is_public = self.user.preferences().get('public_readlog',
                                                'no') == 'yes'

        data = None

        if is_logged_in_user and self.key in self.ALL_KEYS:
            self.counts.update(PatronBooknotes.get_counts(self.username))
            sponsorships = get_sponsored_editions(self.user)
            self.counts['sponsorships'] = len(sponsorships)

            if self.key == 'sponsorships':
                data = add_availability(
                    web.ctx.site.get_many([
                        '/books/%s' % doc['openlibrary_edition']
                        for doc in sponsorships
                    ])) if sponsorships else None
            elif self.key in self.READING_LOG_KEYS:
                data = add_availability(
                    self.readlog.get_works(self.key,
                                           page=page,
                                           sort='created',
                                           sort_order=sort),
                    mode="openlibrary_work",
                )
            elif self.key == 'list':
                data = list

            else:
                data = self._prepare_data(logged_in_user)
        elif self.key in self.READING_LOG_KEYS and is_public:
            data = add_availability(
                self.readlog.get_works(self.key,
                                       page=page,
                                       sort='created',
                                       sort_order=sort),
                mode="openlibrary_work",
            )

        if data is not None:
            return render['account/books'](
                data,
                self.key,
                self.counts,
                logged_in_user=logged_in_user,
                user=self.user,
                lists=self.lists,
                public=is_public,
                owners_page=is_logged_in_user,
            )

        raise web.seeother(self.user.key)
示例#2
0
def work_search(query, sort=None, page=1, offset=0, limit=100):
    """
    params:
    query: dict
    sort: str editions|old|new|scans
    """
    sorts = {
        'editions': 'edition_count desc',
        'old': 'first_publish_year asc',
        'new': 'first_publish_year desc',
        'scans': 'ia_count desc'
    }
    query['wt'] = 'json'

    try:
        (reply, solr_select, q_list) = run_solr_query(query,
                                                      rows=limit,
                                                      page=page,
                                                      sort=sorts.get(sort),
                                                      offset=offset,
                                                      fields="*")
        response = json.loads(reply)['response'] or ''
    except (ValueError, IOError) as e:
        logger.error("Error in processing search API.")
        response = dict(start=0, numFound=0, docs=[], error=str(e))

    # backward compatibility
    response['num_found'] = response['numFound']
    response['docs'] = add_availability(response['docs'])
    return response
示例#3
0
def inject_availability(subject_results):
    works = add_availability(subject_results.works)
    for work in works:
        ocaid = work.ia if work.ia else None
        availability = work.get('availability', {}).get('status')
    subject_results.works = works
    return subject_results
示例#4
0
 def GET(self):
     i = web.input(q='',
                   page=1,
                   limit=100,
                   subject='',
                   work_id='',
                   _type='',
                   sorts='')
     sorts = i.sorts.split(',')
     page = int(i.page)
     limit = int(i.limit)
     url = lending.compose_ia_url(query=i.q,
                                  limit=limit,
                                  page=page,
                                  subject=i.subject,
                                  work_id=i.work_id,
                                  _type=i._type,
                                  sorts=sorts)
     result = {
         'query':
         url,
         'works': [
             work.dict() for work in lending.add_availability(
                 lending.get_available(url=url))
         ]
     }
     return delegate.RawText(simplejson.dumps(result),
                             content_type="application/json")
示例#5
0
def inject_availability(subject_results):
    works = add_availability(subject_results.works)
    for work in works:
        ocaid = work.ia if work.ia else None
        availability = work.get('availability', {}).get('status')
    subject_results.works = works
    return subject_results
示例#6
0
def work_search(query, sort=None, page=1, offset=0, limit=100, fields='*', facet=True,
                spellcheck_count=None):
    """
    params:
    query: dict
    sort: str editions|old|new|scans
    """
    query['wt'] = 'json'
    if sort:
        sort = process_sort(sort)
    try:
        (reply, solr_select, q_list) = run_solr_query(query,
                                                      rows=limit,
                                                      page=page,
                                                      sort=sort,
                                                      offset=offset,
                                                      fields=fields,
                                                      facet=facet,
                                                      spellcheck_count=spellcheck_count)
        response = json.loads(reply)['response'] or ''
    except (ValueError, IOError) as e:
        logger.error("Error in processing search API.")
        response = dict(start=0, numFound=0, docs=[], error=str(e))

    # backward compatibility
    response['num_found'] = response['numFound']
    if fields == '*' or 'availability' in fields:
        response['docs'] = add_availability(response['docs'])
    return response
示例#7
0
def works_by_author(akey,
                    sort='editions',
                    page=1,
                    rows=100,
                    has_fulltext=False):
    # called by merge_author_works
    q = 'author_key:' + akey
    offset = rows * (page - 1)
    fields = [
        'key', 'author_name', 'author_key', 'title', 'subtitle',
        'edition_count', 'ia', 'cover_edition_key', 'has_fulltext',
        'first_publish_year', 'public_scan_b', 'lending_edition_s',
        'lending_identifier_s', 'ia_collection_s', 'cover_i'
    ]
    fl = ','.join(fields)
    fq = 'has_fulltext:true' if has_fulltext else ''  # ebooks_only
    solr_select = solr_select_url + "?fq=type:work&q.op=AND&q=%s&fq=%s&start=%d&rows=%d&fl=%s&wt=json" % (
        q, fq, offset, rows, fl)
    facet_fields = [
        "author_facet", "language", "publish_year", "publisher_facet",
        "subject_facet", "person_facet", "place_facet", "time_facet"
    ]
    if sort == 'editions':
        solr_select += '&sort=edition_count+desc'
    elif sort.startswith('old'):
        solr_select += '&sort=first_publish_year+asc'
    elif sort.startswith('new'):
        solr_select += '&sort=first_publish_year+desc'
    elif sort.startswith('title'):
        solr_select += '&sort=title+asc'
    solr_select += "&facet=true&facet.mincount=1&f.author_facet.facet.sort=count&f.publish_year.facet.limit=-1&facet.limit=25&" + '&'.join(
        "facet.field=" + f for f in facet_fields)
    reply = parse_json_from_solr_query(solr_select)
    if reply is None:
        return web.storage(
            num_found=0,
            works=[],
            years=[],
            get_facet=[],
            sort=sort,
        )
    # TODO: Deep JSON structure defense - for now, let it blow up so easier to detect
    facets = reply['facet_counts']['facet_fields']
    works = [work_object(w) for w in reply['response']['docs']]

    def get_facet(f, limit=None):
        return list(web.group(facets[f][:limit * 2] if limit else facets[f],
                              2))

    return web.storage(
        num_found=int(reply['response']['numFound']),
        works=add_availability(works),
        years=[(int(k), v) for k, v in get_facet('publish_year')],
        get_facet=get_facet,
        sort=sort,
    )
示例#8
0
def readonline_carousel():
    """Return template code for books pulled from search engine.
       TODO: If problems, use stock list.
    """
    try:
        data = random_ebooks()
        if len(data) > 30:
            data = lending.add_availability(random.sample(data, 30))
            data = [d for d in data if d['availability']['is_readable']]
        return storify(data)

    except Exception:
        logger.error("Failed to compute data for readonline_carousel", exc_info=True)
        return None
示例#9
0
def work_search(
    query,
    sort=None,
    page=1,
    offset=0,
    limit=100,
    fields='*',
    facet=True,
    spellcheck_count=None,
):
    """
    params:
    query: dict
    sort: str editions|old|new|scans
    """
    # Ensure we don't mutate the `query` passed in by reference
    query = copy.deepcopy(query)
    query['wt'] = 'json'
    if sort:
        sort = process_sort(sort)

    # deal with special /lists/ key queries
    query['q'], page, offset, limit = rewrite_list_editions_query(
        query['q'], page, offset, limit
    )
    try:
        (reply, solr_select, q_list) = run_solr_query(
            query,
            rows=limit,
            page=page,
            sort=sort,
            offset=offset,
            fields=fields,
            facet=facet,
            spellcheck_count=spellcheck_count,
        )
        response = json.loads(reply)['response'] or ''
    except (ValueError, OSError) as e:
        logger.error("Error in processing search API.")
        response = dict(start=0, numFound=0, docs=[], error=str(e))

    # backward compatibility
    response['num_found'] = response['numFound']
    if fields == '*' or 'availability' in fields:
        response['docs'] = add_availability(response['docs'])
    return response
示例#10
0
def work_search(
    query: dict,
    sort: str = None,
    page: int = 1,
    offset: int = 0,
    limit: int = 100,
    fields: str = '*',
    facet: bool = True,
    spellcheck_count: int = None,
) -> dict:
    """
    :param sort: key of SORTS dict at the top of this file
    """
    # Ensure we don't mutate the `query` passed in by reference
    query = copy.deepcopy(query)
    query['wt'] = 'json'
    if sort:
        sort = process_sort(sort)

    # deal with special /lists/ key queries
    query['q'], page, offset, limit = rewrite_list_query(
        query['q'], page, offset, limit)
    try:
        (reply, solr_select, q_list) = run_solr_query(
            query,
            rows=limit,
            page=page,
            sort=sort,
            offset=offset,
            fields=fields,
            facet=facet,
            spellcheck_count=spellcheck_count,
        )
        assert reply, "Received None response from run_solr_query"
        response = reply['response']
    except (ValueError, OSError, AssertionError) as e:
        logger.error("Error in processing search API.")
        response = dict(start=0, numFound=0, docs=[], error=str(e))

    # backward compatibility
    response['num_found'] = response['numFound']
    if fields == '*' or 'availability' in fields:
        response['docs'] = add_availability(response['docs'])
    return response
示例#11
0
    def GET(self, username, key='loans'):
        """check if user's reading log is public"""
        i = web.input(page=1, sort='desc')
        user = web.ctx.site.get('/people/%s' % username)
        if not user:
            return render.notfound("User %s" % username, create=False)
        is_public = user.preferences().get('public_readlog', 'no') == 'yes'
        logged_in_user = accounts.get_current_user()
        is_logged_in_user = (logged_in_user
                             and logged_in_user.key.split('/')[-1] == username)
        if is_public or is_logged_in_user:
            readlog = ReadingLog(user=user)
            sponsorships = get_sponsored_editions(user)
            if key == 'sponsorships':
                books = (web.ctx.site.get(
                    web.ctx.site.things({
                        'type': '/type/edition',
                        'isbn_%s' % len(s['isbn']): s['isbn']
                    })[0]) for s in sponsorships)
            elif key == 'notes' and is_logged_in_user:
                books = PatronBooknotes(user).get_notes(page=int(i.page))
            elif key == 'observations' and is_logged_in_user:
                books = PatronBooknotes(user).get_observations(
                    page=int(i.page))
            else:
                books = add_availability(readlog.get_works(key,
                                                           page=i.page,
                                                           sort='created',
                                                           sort_order=i.sort),
                                         mode="openlibrary_work")
            booknotes_counts = PatronBooknotes.get_counts(username)

            return render['account/books'](
                books,
                key,
                sponsorship_count=len(sponsorships),
                reading_log_counts=readlog.reading_log_counts,
                lists=readlog.lists,
                user=user,
                logged_in_user=logged_in_user,
                public=is_public,
                sort_order=str(i.sort),
                booknotes_counts=booknotes_counts)
        raise web.seeother(user.key)
示例#12
0
 def GET(self):
     i = web.input(q='', page=1, limit=100, subject='',
                   work_id='', _type='', sorts='')
     sorts = i.sorts.split(',')
     page = int(i.page)
     limit = int(i.limit)
     url = lending.compose_ia_url(
         query=i.q, limit=limit, page=page, subject=i.subject,
         work_id=i.work_id, _type=i._type, sorts=sorts)
     result = {
         'query': url,
         'works': [
             work.dict() for work in lending.add_availability(
                 lending.get_available(url=url)
             )
         ]
     }
     return delegate.RawText(
         simplejson.dumps(result),
         content_type="application/json")
示例#13
0
def works_by_author(akey,
                    sort='editions',
                    page=1,
                    rows=100,
                    has_fulltext=False,
                    query=None):
    # called by merge_author_works
    q = 'author_key:' + akey
    if query:
        q = query

    offset = rows * (page - 1)
    params = [
        ('fq', 'author_key:' + akey),
        ('fq', 'type:work'),
        ('q', q),
        ('start', offset),
        ('rows', rows),
        (
            'fl',
            ','.join([
                'key',
                'author_name',
                'author_key',
                'title',
                'subtitle',
                'edition_count',
                'ia',
                'cover_edition_key',
                'has_fulltext',
                'language',
                'first_publish_year',
                'public_scan_b',
                'lending_edition_s',
                'lending_identifier_s',
                'ia_collection_s',
                'id_project_gutenberg',
                'id_librivox',
                'id_standard_ebooks',
                'id_openstax',
                'cover_i',
            ]),
        ),
        ('wt', 'json'),
        ('q.op', 'AND'),
        ('facet', 'true'),
        ('facet.mincount', 1),
        ('f.author_facet.facet.sort', 'count'),
        ('f.publish_year.facet.limit', -1),
        ('facet.limit', 25),
    ]

    if has_fulltext:
        params.append(('fq', 'has_fulltext:true'))

    if sort == "editions":
        params.append(('sort', 'edition_count desc'))
    elif sort.startswith('old'):
        params.append(('sort', 'first_publish_year asc'))
    elif sort.startswith('new'):
        params.append(('sort', 'first_publish_year desc'))
    elif sort.startswith('title'):
        params.append(('sort', 'title asc'))

    facet_fields = [
        "author_facet",
        "language",
        "publish_year",
        "publisher_facet",
        "subject_facet",
        "person_facet",
        "place_facet",
        "time_facet",
    ]
    for f in facet_fields:
        params.append(("facet.field", f))

    reply = parse_json_from_solr_query(solr_select_url, params)
    if reply is None:
        return web.storage(
            num_found=0,
            works=[],
            years=[],
            get_facet=[],
            sort=sort,
        )
    # TODO: Deep JSON structure defense - for now, let it blow up so easier to detect
    facets = reply['facet_counts']['facet_fields']
    works = [work_object(w) for w in reply['response']['docs']]

    def get_facet(f, limit=None):
        return list(web.group(facets[f][:limit * 2] if limit else facets[f],
                              2))

    return web.storage(
        num_found=int(reply['response']['numFound']),
        works=add_availability(works),
        years=[(int(k), v) for k, v in get_facet('publish_year')],
        get_facet=get_facet,
        sort=sort,
    )
示例#14
0
    def get_subject(self,
                    key,
                    details=False,
                    offset=0,
                    limit=DEFAULT_RESULTS,
                    sort='first_publish_year desc',
                    **filters):
        meta = self.get_meta(key)

        q = self.make_query(key, filters)
        subject_type = meta.name
        name = meta.path.replace("_", " ")

        if details:
            kw = self.query_optons_for_details()
        else:
            kw = {}

        from search import work_search
        result = work_search(q, offset=offset, limit=limit, sort=sort, **kw)
        if not result:
            return None

        for w in result.docs:
            w.ia = w.ia and w.ia[0] or None
            w['checked_out'] = False
            if not w.get('public_scan') and w.ia and w.get(
                    'lending_identifier'):
                doc = web.ctx.site.store.get("ebooks/" +
                                             w['lending_identifier']) or {}
                w['checked_out'] = doc.get("borrowed") == "true"

            # XXX-Anand: Oct 2013
            # Somewhere something is broken, work keys are coming as OL1234W/works/
            # Quick fix it solve that issue.
            if w.key.endswith("/works/"):
                w.key = "/works/" + w.key.replace("/works/", "")

        subject = Subject(key=key,
                          name=name,
                          subject_type=subject_type,
                          work_count=result['num_found'],
                          works=add_availability(result['docs']))

        if details:
            subject.ebook_count = dict(result.facets["has_fulltext"]).get(
                "true", 0)
            #subject.ebook_count = self.get_ebook_count(meta.name, q[meta.facet_key], q.get('publish_year'))

            subject.subjects = result.facets["subject_facet"]
            subject.places = result.facets["place_facet"]
            subject.people = result.facets["person_facet"]
            subject.times = result.facets["time_facet"]

            subject.authors = result.facets["author_facet"]
            subject.publishers = result.facets["publisher_facet"]
            subject.languages = result.facets['language']

            # Ignore bad dates when computing publishing_history
            # year < 1000 or year > current_year+1 are considered bad dates
            current_year = datetime.datetime.utcnow().year
            subject.publishing_history = [[
                year, count
            ] for year, count in result.facets["publish_year"]
                                          if 1000 < year <= current_year + 1]

            # strip self from subjects and use that to find exact name
            for i, s in enumerate(subject[meta.key]):
                if "key" in s and s.key.lower() == key.lower():
                    subject.name = s.name
                    subject[meta.key].pop(i)
                    break

        return subject