예제 #1
0
def search_filter_record_permissions():
    """Filter list of results by `_access` and `open_access` fields."""
    if not has_request_context() or backoffice_permission().allows(g.identity):
        return Q()

    # A record is public if `open_access` field True or missing
    open_access_field_missing = ~Q("exists", field="open_access")
    is_open_access = open_access_field_missing | Q("term", open_access=True)

    combined_filter = is_open_access

    if current_app.config.get("ILS_RECORDS_EXPLICIT_PERMISSIONS_ENABLED"):
        # if `_access`, check `_access.read` against the user. It takes
        # precedence over `open_access`.
        # if not `_access`, check if open access as before.
        _access_field_exists = Q("exists", field="_access.read")
        provides = _get_user_provides()
        user_can_read = _access_field_exists & Q(
            "terms", **{"_access.read": provides}
        )
        combined_filter = user_can_read | (
            ~_access_field_exists & is_open_access
        )

    return Q("bool", filter=[combined_filter])
예제 #2
0
    def post(self, pid, record, **kwargs):
        """Send a signal to count record view for the record stats."""
        factory = RecordPermission(record, "read")
        if not factory.is_public() and not backoffice_permission().can():
            if not current_user.is_authenticated:
                abort(401)
            abort(403)

        data = request.get_json()
        event_name = data.get("event")
        if event_name == "record-view":
            record_viewed.send(
                current_app._get_current_object(),
                pid=pid,
                record=record,
            )
            return self.make_response(pid, record, 202)
        elif event_name == "file-download":
            if "key" not in data:
                abort(406, "File key is required")
            if "bucket_id" not in record:
                abort(406, "Record has no bucket")
            obj = ObjectVersion.get(record["bucket_id"], data["key"])
            file_downloaded.send(current_app._get_current_object(),
                                 obj=obj,
                                 record=record)
            return self.make_response(pid, record, 202)
        return StatsError(
            description="Invalid stats event request: {}".format(event_name))
예제 #3
0
def _filter_by_current_patron(search, query_string=None):
    """Filter search results by patron_pid."""
    # if the logged in user is not librarian or admin, validate the query
    if has_request_context() and not backoffice_permission().allows(
            g.identity):
        return _filter_by_patron(g.identity.id, search, query_string)
    return search, query_string
def validate_patron(patron_pid):
    """Validate patron PID."""
    if not backoffice_permission().allows(g.identity):
        if patron_pid != str(g.identity.id):
            raise ValidationError(
                "The authenticated user is not authorized to create or update "
                "a document request for another patron.")
예제 #5
0
def loan_permission_filter():
    """Filter loans by owner."""
    if backoffice_permission().allows(g.identity):
        return Q()

    # Filter loans where the user is owner
    return Q('match', **{'patron_pid': g.identity.id})
예제 #6
0
def views_permissions_factory(action):
    """Override ILS views permissions factory."""
    if action == "retrieve-patron-loans":
        return retrieve_patron_loans_permission()
    elif action == "document-importer":
        return backoffice_permission()
    return ils_views_permissions_factory(action)
예제 #7
0
def circulation_default_extension_max_count(loan):
    """Return a default extensions max count."""
    is_admin_or_librarian = has_request_context() and backoffice_permission(
    ).allows(g.identity)
    if is_admin_or_librarian:
        unlimited = loan.get("extension_count", 0) + 1
        return unlimited
    return 3
예제 #8
0
def circulation_search_factory(self, search, query_parser=None):
    """Parse query using elasticsearch DSL query.

    :param self: REST view.
    :param search: Elastic search DSL search instance.
    :returns: Tuple with search instance and URL arguments.
    """
    def _default_parser(qstr=None):
        """Return default parser that uses the Q() from elasticsearch_dsl."""
        if qstr:
            return Q('query_string', query=qstr)
        return Q()

    from invenio_records_rest.facets import default_facets_factory
    from invenio_records_rest.sorter import default_sorter_factory

    query_string = request.values.get('q', '')
    query = _default_parser(qstr=query_string)

    # if the logged in user in not librarian or admin, validate the query
    if not backoffice_permission().allows(g.identity):
        # patron can find only his loans
        try:
            if not query_string:
                # force query to be patron_pid:<logged in user>
                only_patron_loans = 'patron_pid:{}'.format(g.identity.id)
                query = _default_parser(qstr=only_patron_loans)
            else:
                # check for patron_pid query value
                match = re.match(r"patron_pid:(?P<pid>\d)", query_string)
                if match and match.group('pid') != str(g.identity.id):
                    raise UnauthorizedSearch()
        except UnauthorizedSearch:
            current_app.logger.debug(
                "Search for `{0}` not allowed by `patron_pid:{1}`".format(
                    query_string, str(g.identity.id))
            )
            abort(403)

    try:
        search = search.query(query)
    except SyntaxError:
        current_app.logger.debug(
            "Failed parsing query: {0}".format(query_string), exc_info=True)
        raise InvalidQueryRESTError()

    search_index = search._index[0]
    search, urlkwargs = default_facets_factory(search, search_index)
    search, sortkwargs = default_sorter_factory(search, search_index)
    for key, value in sortkwargs.items():
        urlkwargs.add(key, value)

    urlkwargs.add('q', query_string)
    return search, urlkwargs
예제 #9
0
def filter_by_patron_search_factory(self, search, query_parser=None):
    """Filter search queries to only show records for the logged in patron.

    If the logged in  user has backoffice permissions do not filter by patron.

    :param self: REST view.
    :param search: Elastic search DSL search instance.
    :returns: Tuple with search instance and URL arguments.
    """
    def _default_parser(qstr=None):
        """Return default parser that uses the Q() from elasticsearch_dsl."""
        if qstr:
            return Q('query_string', query=qstr)
        return Q()

    from invenio_records_rest.facets import default_facets_factory
    from invenio_records_rest.sorter import default_sorter_factory

    query_string = request.values.get('q', '')

    if not current_user.is_authenticated:
        raise UnauthorizedSearchError(query_string)

    parser = query_parser or _default_parser
    query = parser(qstr=query_string)

    # if the logged in user in not librarian or admin, validate the query
    if has_request_context() and not backoffice_permission().allows(g.identity):
        # patron can find only his document requests
        if not query_string:
            # force query to be patron_pid:<logged in user>
            patron_pid_filter = 'patron_pid:{}'.format(g.identity.id)
            query = _default_parser(qstr=patron_pid_filter)
        else:
            # check for patron_pid query value
            match = re.match(r"patron_pid:(?P<pid>\d)", query_string)
            if match and match.group('pid') != str(g.identity.id):
                raise UnauthorizedSearchError(query_string, g.identity.id)
    try:
        search = search.query(query)
    except SyntaxError:
        raise SearchQueryError(query_string)

    search_index = search._index[0]
    search, urlkwargs = default_facets_factory(search, search_index)
    search, sortkwargs = default_sorter_factory(search, search_index)
    for key, value in sortkwargs.items():
        urlkwargs.add(key, value)

    urlkwargs.add('q', query_string)
    return search, urlkwargs
예제 #10
0
    def filter_by_patron(query_string):
        """Filter search results by patron_pid."""
        if not current_user.is_authenticated:
            raise UnauthorizedSearchError(query_string)

        # if the logged in user is not librarian or admin, validate the query
        if has_request_context() and not backoffice_permission().allows(
                g.identity):
            # patron can find only his records
            if not query_string:
                # force query to be patron_pid:<logged in user>
                query_string = "patron_pid:{}".format(g.identity.id)
            else:
                # check for patron_pid query value
                match = re.match(r"patron_pid:(?P<pid>\d+)", query_string)
                if match and match.group("pid") != str(g.identity.id):
                    raise UnauthorizedSearchError(query_string, g.identity.id)
        return query_string
예제 #11
0
def circulation_default_extension_max_count(loan):
    """Return a default extensions max count."""
    # NOTE: If user is admin or librarian always have 1 extra extension count.
    if has_request_context() and backoffice_permission().allows(g.identity):
        return loan.get("extension_count", 0) + 1
    return 3