Пример #1
0
def test_create_bucket_permissions(client, json_headers, location, testdata,
                                   users):
    """Test create bucket permissions."""
    url = url_for("invenio_app_ils_files.eitmid_bucket", pid_value="eitemid-1")
    _test_response(client, "post", url, json_headers, None, 401)

    test_data = [
        ("admin", "eitemid-1", 201),
        ("librarian", "eitemid-2", 201),
        ("patron1", "eitemid-2", 403),
    ]
    for user, pid, status_code in test_data:
        user_login(client, user, users)
        url = url_for("invenio_app_ils_files.eitmid_bucket", pid_value=pid)
        _test_response(client, "post", url, json_headers, None, status_code)
Пример #2
0
def test_delete_internal_location(client, users, json_headers, testdata):
    """Test DELETE existing internal_location."""
    user_login(client, "admin", users)

    internal_location_pid = 'ilocid-1'
    url = url_for('invenio_records_rest.ilocid_item',
                  pid_value=internal_location_pid)
    res = client.delete(url, headers=json_headers)
    assert res.status_code == 400

    internal_location_pid = 'ilocid-3'
    url = url_for('invenio_records_rest.ilocid_item',
                  pid_value=internal_location_pid)
    res = client.delete(url, headers=json_headers)
    assert res.status_code == 204
def test_patrons_can_search_their_own_loans(client, json_headers, users,
                                            testdata):
    """Test that patrons can search their own loans."""
    def _validate_only_patron_loans(res, user, state):
        """Assert that result loans belong to the given user only."""
        patron_loans = [
            l for l in testdata["loans"]
            if l["patron_pid"] == str(user.id) and l["state"] == state
        ]

        assert res.status_code == 200
        hits = json.loads(res.data.decode("utf-8"))
        assert len(hits["hits"]["hits"]) == len(patron_loans)
        for hit in hits["hits"]["hits"]:
            assert hit["metadata"]["patron_pid"] == str(user.id)

    state = "PENDING"
    for username in ["patron1", "patron2"]:
        user = user_login(client, username, users)
        # search with no params
        res = _search_loans(client, json_headers, state=state)
        _validate_only_patron_loans(res, user, state)

        # search with params
        res = _search_loans(
            client,
            json_headers,
            state=state,  # test extra query
            q="patron_pid:{}".format(str(user.id)),
        )
        _validate_only_patron_loans(res, user, state)
Пример #4
0
def test_create_bucket_endpoint(client, json_headers, location, testdata,
                                users):
    """Test GET permissions."""
    user_login(client, "admin", users)

    url_with_bucket_id = url_for("invenio_app_ils_files.eitmid_bucket",
                                 pid_value="eitemid-3")
    url_without_bucket_id = url_for("invenio_app_ils_files.eitmid_bucket",
                                    pid_value="eitemid-4")

    res1 = _test_response(client, "post", url_with_bucket_id, json_headers,
                          None, 200)
    _test_data_exists("bucket_id", res1)
    res2 = _test_response(client, "post", url_without_bucket_id, json_headers,
                          None, 201)
    _test_data_exists("bucket_id", res2)
def test_patron_cannot_update_loans(client, json_headers, users, testdata):
    """Test that patrons cannot update loans."""
    loanid = "loanid-1"
    user = user_login(client, "patron1", users)
    _test_post_new_loan(client, json_headers, user.id, 403)
    _test_replace_existing_loan(client, json_headers, user.id, loanid, 403)
    _test_delete_existing_loan(client, json_headers, loanid, 403)
Пример #6
0
def test_series_edit_permissions(client, testdata, json_headers, users):
    """Test series endpoints permissions."""
    dummy_series = dict(
        title="The Gulf: The Making of An American Sea",
        authors=["Einstein, Albert", "Stachel, John J et al."],
        mode_of_issuance="MULTIPART_MONOGRAPH",
    )
    tests = [
        ("admin", _HTTP_OK, dummy_series),
        ("librarian", _HTTP_OK, dummy_series),
        ("patron1", [403], dummy_series),
        ("anonymous", [401], dummy_series),
    ]

    def _test_create(expected_status, data):
        """Test record creation."""
        url = url_for(LIST_ENDPOINT)
        res = client.post(url, headers=json_headers, data=json.dumps(data))
        assert res.status_code in expected_status

        if res.status_code < 400:
            record = res.get_json()["metadata"]
            assert record
            return record["pid"]

    def _test_update(expected_status, data, pid):
        """Test record update."""
        pid_value = pid or SERIES_PID
        url = url_for(ITEM_ENDPOINT, pid_value=pid_value)
        res = client.put(url, headers=json_headers, data=json.dumps(data))
        assert res.status_code in expected_status
        if res.status_code < 400:
            record = res.get_json()["metadata"]
            assert record

    def _test_delete(expected_status, pid):
        """Test record delete."""
        pid_value = pid or SERIES_PID
        url = url_for(ITEM_ENDPOINT, pid_value=pid_value)
        res = client.delete(url, headers=json_headers)
        assert res.status_code in expected_status

    for username, expected_status, data in tests:
        user_login(client, username, users)
        pid = _test_create(expected_status, data)
        _test_update(expected_status, data, pid)
        _test_delete(expected_status, pid)
Пример #7
0
def test_create_document_request(client, testdata, json_headers, users):
    """Test creating document requests."""
    tests = [
        ("admin", 201,
         dict(title="Test title",
              request_type="LOAN",
              medium="Paper",
              patron_pid="1")),
        ("librarian", 400, dict(patron_pid="1")),
        (
            "admin",
            201,
            dict(patron_pid="1",
                 title="Test",
                 invalid_param="Test",
                 request_type="LOAN",
                 medium="Paper"),
        ),
        ("librarian", 201,
         dict(title="Test title",
              patron_pid="1",
              request_type="BUY",
              medium="Paper")),
        ("patron1", 201,
         dict(title="Test title",
              patron_pid="1",
              request_type="BUY",
              medium="Paper")),
        ("patron2", 400,
         dict(title="Test title",
              patron_pid="1",
              request_type="LOAN",
              medium="Paper")),
        ("patron2", 201,
         dict(title="Test title",
              patron_pid="2",
              request_type="LOAN",
              medium="Paper")),
    ]
    for username, expected_status, data in tests:
        user_login(client, username, users)
        url = url_for("invenio_records_rest.dreqid_list")
        res = client.post(url, headers=json_headers, data=json.dumps(data))
        assert res.status_code == expected_status
        if res.status_code == 201:
            assert "invalid_param" not in json.loads(res.data)["metadata"]
Пример #8
0
def test_patron_can_request_loan_with_or_without_end_date(
    app, client, json_headers, users, testdata
):
    """Test that a patron can request a loan [with/without] end date."""
    url = url_for("invenio_app_ils_circulation.loan_request")
    user = user_login(client, "patron1", users)

    now = arrow.utcnow()
    start_date = (now + timedelta(days=3)).date().isoformat()
    end_date = (now + timedelta(days=15)).date().isoformat()

    # it should succeed when start/end dates provided
    params = deepcopy(NEW_LOAN)
    params["document_pid"] = "docid-2"
    params["request_start_date"] = start_date
    params["request_expire_date"] = end_date
    params["transaction_user_pid"] = str(user.id)
    res = client.post(url, headers=json_headers, data=json.dumps(params))
    assert res.status_code == 202
    loan = res.get_json()["metadata"]
    assert loan["state"] == "PENDING"
    assert loan["document_pid"] == params["document_pid"]
    assert loan["request_start_date"] == start_date
    assert loan["request_expire_date"] == end_date
    assert loan["transaction_date"]

    # it should fail when wrong date provided
    params = deepcopy(NEW_LOAN)
    past_end_date = now - timedelta(days=30)
    params["request_expire_date"] = past_end_date.date().isoformat()
    params["transaction_user_pid"] = str(user.id)
    res = client.post(url, headers=json_headers, data=json.dumps(params))
    assert res.status_code == 400

    # it should fail when request duration over max
    params = deepcopy(NEW_LOAN)
    days = app.config["ILS_CIRCULATION_LOAN_REQUEST_DURATION_DAYS"]
    past_end_date = now + timedelta(days=days + 1)
    params["request_expire_date"] = past_end_date.date().isoformat()
    params["transaction_user_pid"] = str(user.id)
    res = client.post(url, headers=json_headers, data=json.dumps(params))
    assert res.status_code == 400

    # it should fail when request start/end date not provided
    params = deepcopy(NEW_LOAN)
    params["document_pid"] = "docid-4"
    params["transaction_user_pid"] = str(user.id)
    del params["request_start_date"]
    del params["request_expire_date"]
    res = client.post(url, headers=json_headers, data=json.dumps(params))
    assert res.status_code == 202
    loan = res.get_json()["metadata"]
    now = arrow.utcnow()
    start_date = now.date().isoformat()
    days = app.config["ILS_CIRCULATION_LOAN_REQUEST_DURATION_DAYS"]
    end_date = (now + timedelta(days=days)).date().isoformat()
    assert loan["request_start_date"] == start_date
    assert loan["request_expire_date"] == end_date
Пример #9
0
def test_patrons_permissions(client, testdata, json_headers, users):
    """Test patron endpoints permissions."""
    tests = [
        ("admin", [200]),
        ("librarian", [200]),
        ("patron1", [403]),
        ("anonymous", [401]),
    ]

    def _test_list(expected_status):
        """Test get list."""
        url = url_for(_LIST_ENDPOINT)
        res = client.get(url, headers=json_headers)
        assert res.status_code in expected_status

    for username, expected_status in tests:
        user_login(client, username, users)
        _test_list(expected_status)
Пример #10
0
def test_document_request_reject(client, json_headers, testdata, users):
    """Test Document Request permissions to reject request."""

    tests = [
        ("patron1", "dreq-1", 202),
        ("librarian", "dreq-5", 202),
        ("admin", "dreq-6", 202),
        ("anonymous", "dreq-1", 401),
        ("admin", "dreq-2", 400),
    ]

    for user, res_id, expected_resp_code in tests:
        user_login(client, user, users)
        url = url_for("invenio_app_ils_document_requests.dreqid_reject",
                      pid_value=res_id)
        data = {"reject_reason": "USER_CANCEL"}
        validate_response(client, "post", url, json_headers, data,
                          expected_resp_code)
Пример #11
0
def test_brwreq_create_loan_fails_on_wrong_status(
    db, client, testdata, json_headers, users
):
    """Test borrowing requests create loan action fails on wrong status."""
    user_login(client, "librarian", users)

    def _create_new_brwreq(data=None):
        brwreq = data or dict(
            document_pid="docid-3",
            provider_pid="ill-provid-2",
            patron_pid="1",
            status="PENDING",
            type="PHYSICAL_COPY",
        )
        url = url_for(LIST_ENDPOINT)
        res = client.post(url, headers=json_headers, data=json.dumps(brwreq))
        assert res.status_code in _HTTP_OK
        brw_req = res.get_json()["metadata"]
        return brw_req["pid"]

    def _update_brwreq_with_new_status(pid, status):
        rec = BorrowingRequest.get_record_by_pid(pid)
        rec["status"] = status
        if status == "CANCELLED":
            rec["cancel_reason"] = "OTHER"
        rec.commit()
        db.session.commit()

    def _assert_fail_when_status(pid, status):
        _update_brwreq_with_new_status(pid, status)

        now = arrow.utcnow()
        future = now + timedelta(days=15)
        data = dict(
            loan_start_date=now.isoformat(), loan_end_date=future.isoformat()
        )
        _assert_create_loan_action_fails(pid, data, client, json_headers)

    pid = _create_new_brwreq()

    _assert_fail_when_status(pid, "PENDING")
    _assert_fail_when_status(pid, "ON_LOAN")
    _assert_fail_when_status(pid, "RETURNED")
    _assert_fail_when_status(pid, "CANCELLED")
Пример #12
0
def test_document_request_add_document(client, json_headers, testdata, users):
    """Test add document to Document Request permissions."""

    tests = [
        ("patron1", "dreq-1", 403),
        ("librarian", "dreq-1", 202),
        ("admin", "dreq-1", 202),
        ("anonymous", "dreq-1", 401),
    ]

    for user, res_id, expected_resp_code in tests:
        user_login(client, user, users)
        url = url_for(
            "invenio_app_ils_document_requests.dreqid_document",
            pid_value=res_id,
        )
        data = {"document_pid": "docid-1"}
        validate_response(client, "post", url, json_headers, data,
                          expected_resp_code)
Пример #13
0
def test_document_request_remove_provider(client, json_headers, testdata,
                                          users):
    """Test remove provider from Document Request permissions."""

    tests = [
        ("patron1", "dreq-1", 403),
        ("librarian", "dreq-1", 202),
        ("admin", "dreq-1", 202),
        ("anonymous", "dreq-1", 401),
    ]

    for user, res_id, expected_resp_code in tests:
        user_login(client, user, users)
        url = url_for(
            "invenio_app_ils_document_requests.dreqid_provider",
            pid_value=res_id,
        )
        validate_response(client, "delete", url, json_headers, None,
                          expected_resp_code)
Пример #14
0
def test_access_permissions(
    client, json_headers, testdata, users, with_access
):
    """Test GET documents with `_access` ignoring `restricted`."""
    # set the documents to have read access only by patron2. `_access` should
    # be taken into account and take precedence over `restricted`.
    indexer = RecordIndexer()
    doc1 = Document.get_record_by_pid("docid-open-access")
    doc2 = Document.get_record_by_pid("docid-closed-access")
    for doc in [doc1, doc2]:
        doc.update(dict(_access=dict(read=[users["patron2"].id])))
        doc.commit()
        db.session.commit()
        indexer.index(doc)
    current_search.flush_and_refresh(index="documents")

    test_data = [
        ("anonymous", "docid-open-access", 401, 0),
        ("patron1", "docid-open-access", 403, 0),
        ("patron2", "docid-open-access", 200, 1),  # should have access
        ("librarian", "docid-open-access", 200, 1),
        ("admin", "docid-open-access", 200, 1),
        ("anonymous", "docid-closed-access", 401, 0),
        ("patron1", "docid-closed-access", 403, 0),
        ("patron2", "docid-closed-access", 200, 1),  # should have access
        ("librarian", "docid-closed-access", 200, 1),
        ("admin", "docid-closed-access", 200, 1),
    ]
    for user, pid, status_code, n_hits in test_data:
        # item endpoint
        user_login(client, user, users)
        url = url_for("invenio_records_rest.docid_item", pid_value=pid)
        res = client.get(url, headers=json_headers)
        assert res.status_code == status_code

        # list endpoint
        user_login(client, user, users)
        url = url_for(
            "invenio_records_rest.docid_list", q="pid:{}".format(pid)
        )
        res = client.get(url, headers=json_headers)
        hits = json.loads(res.data.decode("utf-8"))
        assert hits["hits"]["total"] == n_hits
Пример #15
0
def test_email_db_table_and_endpoint(users, client, json_headers):
    """Test creation of email in db table and read emails from endpoint."""
    request = {"id": "test-id", "task": "test-task"}
    data = {
        "id": "test-id",
        "recipients": ["*****@*****.**"],
        "is_manually_triggered": True,
        "message_id": "1",
    }
    exc = "An error occured."
    log_successful_mail(None, data)

    log_error_mail(request=request, exc=exc, traceback=None, data=data)

    assert EmailLog.query.filter_by(id=1).one().send_log == "Success"
    assert (
        EmailLog.query.filter_by(id=2).one().send_log
        == "Error: 'An error occured.'"
    )

    ITEM_ENDPOINT = "invenio_app_ils_emails_item.get_email"
    LIST_ENDPOINT = "invenio_app_ils_emails_list.get_emails"

    user_login(client, "librarian", users)

    url = url_for(LIST_ENDPOINT)
    res = client.get(url, headers=json_headers)

    assert (
        res.get_json()["hits"][0]["send_log"] == "Error: 'An error occured.'"
    )
    assert res.get_json()["hits"][1]["send_log"] == "Success"

    url = url_for(ITEM_ENDPOINT, id=1)
    res = client.get(url, headers=json_headers)
    assert res.get_json()["send_log"] == "Success"
    assert res.get_json()["id"] == 1

    url = url_for(ITEM_ENDPOINT, id=2)
    res = client.get(url, headers=json_headers)
    assert res.get_json()["send_log"] == "Error: 'An error occured.'"
    assert res.get_json()["id"] == 2
Пример #16
0
def test_force_checkout_specific_permissions(app, client, json_headers, users,
                                             testdata):
    """Test that only allowed users can perform a force checkout."""
    default_factory = app.config["ILS_VIEWS_PERMISSIONS_FACTORY"]
    librarian2 = users["librarian2"]

    # override default permission factory to require specific permission for
    # force-checkout action
    def custom_views_permissions_factory(action):
        if action == "circulation-loan-force-checkout":
            # fake permission for a specific user
            return Permission(UserNeed(librarian2.id))
        else:
            return default_factory(action)

    app.config[
        "ILS_VIEWS_PERMISSIONS_FACTORY"] = custom_views_permissions_factory

    # prepare request
    url = url_for("invenio_app_ils_circulation.loan_checkout")
    params = deepcopy(NEW_LOAN)
    params["force"] = True
    params["item_pid"] = dict(type="pitmid", value="itemid-MISSING")
    params["transaction_user_pid"] = str(librarian2.id)

    # force-checkout as librarian should fail
    user_login(client, "librarian", users)
    res = client.post(url, headers=json_headers, data=json.dumps(params))
    assert res.status_code == 403

    # force-checkout as librarian2 should succeed
    user_login(client, "librarian2", users)
    res = client.post(url, headers=json_headers, data=json.dumps(params))
    assert res.status_code == 202
    loan = res.get_json()["metadata"]
    assert loan["state"] == "ITEM_ON_LOAN"
    assert loan["item_pid"] == params["item_pid"]
    assert loan["document_pid"] == params["document_pid"]
    assert loan["patron_pid"] == params["patron_pid"]

    # restore default config
    app.config["ILS_VIEWS_PERMISSIONS_FACTORY"] = default_factory
Пример #17
0
def test_loan_extend_permissions(client, json_headers, users, testdata,
                                 loan_params):
    """Test loan can be extended."""
    def _checkout(loan_pid, params):
        """Perform checkout action before extension."""
        user_login(client, "librarian", users)
        checkout_url = url_for(
            "invenio_circulation_loan_actions.loanid_actions",
            pid_value=loan_pid,
            action="checkout",
        )
        resp = client.post(checkout_url,
                           headers=json_headers,
                           data=json.dumps(params))
        assert resp.status_code == 202
        return resp.get_json()

    loan_pid = "loanid-1"
    params = deepcopy(loan_params)
    del params["transaction_date"]
    params["document_pid"] = "docid-1"
    params["item_pid"]["value"] = "itemid-2"

    loan = _checkout(loan_pid, params)

    tests = [
        ("admin", 202),
        ("librarian", 202),
        ("patron1", 202),
        ("patron3", 403),
    ]

    for username, expected_resp_code in tests:
        extend_url = loan["links"]["actions"]["extend"]

        # test extension
        user_login(client, username, users)
        extend_res = client.post(extend_url,
                                 headers=json_headers,
                                 data=json.dumps(params))
        assert extend_res.status_code == expected_resp_code
def test_patron_can_get_only_his_loans(client, json_headers, users, testdata):
    """Test that patrons can get only their loans."""
    loan_patron1 = testdata["loans"][0]
    assert loan_patron1["patron_pid"] == "1"

    loan_patron2 = testdata["loans"][3]
    assert loan_patron2["patron_pid"] == "2"

    # Patron 1 GET his loans
    user_login(client, "patron1", users)
    _assert_get_loan_success(client, json_headers, loan_patron1)
    # Patron 1 GET loans of Patron 2
    res = _fetch_loan(client, json_headers, loan_patron2)
    assert res.status_code == 403

    # Patron 2 GET his loans
    user_login(client, "patron2", users)
    _assert_get_loan_success(client, json_headers, loan_patron2)
    # Patron 2 GET loans of Patron 1
    res = _fetch_loan(client, json_headers, loan_patron1)
    assert res.status_code == 403
Пример #19
0
def test_get_document_request_endpoint(client, json_headers, testdata, users):
    """Test GET permissions."""

    tests = [
        ("patron1", "dreq-1", 200),
        ("librarian", "dreq-1", 200),
        ("admin", "dreq-1", 200),
        ("patron2", "dreq-1", 403),
        ("anonymous", "dreq-1", 401),
        ("patron2", "dreq-2", 200),
        ("librarian", "dreq-2", 200),
        ("admin", "dreq-2", 200),
        ("patron1", "dreq-2", 403),
        ("anonymous", "dreq-2", 401),
    ]

    for user, res_id, expected_resp_code in tests:
        user_login(client, user, users)
        url = url_for("invenio_records_rest.dreqid_item", pid_value=res_id)
        validate_response(client, "get", url, json_headers, None,
                          expected_resp_code)
Пример #20
0
def test_brwreq_create_loan_succeeds(
    db, client, testdata, json_headers, users
):
    """Test borrowing requests create loan action succeeds."""
    user = user_login(client, "librarian", users)

    # demo data "illbid-2" has the valid state `REQUESTED`
    pid = "illbid-2"

    now = arrow.utcnow()
    start = (now + timedelta(days=3)).date().isoformat()
    future = (now + timedelta(days=5)).date().isoformat()
    data = dict(loan_start_date=start, loan_end_date=future)
    res = _create_loan_action(pid, data, client, json_headers)
    assert res.status_code in _HTTP_OK
    brw_req = res.get_json()["metadata"]

    assert brw_req["status"] == "ON_LOAN"
    assert "patron_loan" in brw_req
    patron_loan = brw_req["patron_loan"]
    assert "pid" in patron_loan
    assert "loan" in patron_loan
    loan = patron_loan["loan"]
    assert patron_loan["pid"] == loan["pid"]
    assert loan["end_date"] == future
    loan_pid = loan["pid"]

    # fetch the loan
    url = url_for("invenio_records_rest.loanid_item", pid_value=loan_pid)
    res = client.get(url, headers=json_headers)
    assert res.status_code in _HTTP_OK
    loan = res.get_json()["metadata"]

    # make sure the loan is created with the data from the ILL
    assert loan["item_pid"] == dict(type=BORROWING_REQUEST_PID_TYPE, value=pid)
    assert loan["start_date"] == start
    assert loan["end_date"] == future
    assert loan["document_pid"] == brw_req["document_pid"]
    assert loan["patron_pid"] == brw_req["patron_pid"]
    assert loan["transaction_user_pid"] == str(user.id)

    # update notes (a random field)
    brw_req["notes"] = "This is a note"
    url = url_for(ITEM_ENDPOINT, pid_value=pid)
    res = client.put(url, headers=json_headers, data=json.dumps(brw_req))
    assert res.status_code in _HTTP_OK
    updated_brw_req = res.get_json()["metadata"]

    # make sure `patron_loan` system field is preserved
    assert updated_brw_req["notes"] == "This is a note"
    assert "patron_loan" in updated_brw_req
    assert "pid" in patron_loan
    assert "loan" in patron_loan
def test_ill_brwreqs_list_permissions(client, testdata, json_headers, users):
    """Test borrowing requests list permissions."""
    patron1_brwreq = dict(
        status="PENDING",
        document_pid="docid-1",
        patron_pid="1",
        provider_pid="ill-provid-1",
        type="PHYSICAL_COPY",
    )
    patron2_brwreq = dict(
        status="PENDING",
        document_pid="docid-1",
        patron_pid="2",
        provider_pid="ill-provid-1",
        type="PHYSICAL_COPY",
    )

    def _test_list(expected_status, pids):
        """Test get list for given pids."""
        q = " OR ".join(["pid:{}".format(pid) for pid in pids])
        list_url = url_for(LIST_ENDPOINT, q=q)
        res = client.get(list_url, headers=json_headers)
        assert res.status_code in expected_status
        return res.get_json()

    # create records
    list_url = url_for(LIST_ENDPOINT)
    user_login(client, "admin", users)
    res = client.post(list_url,
                      headers=json_headers,
                      data=json.dumps(patron1_brwreq))
    patron1_brwreq_pid = res.get_json()["metadata"]["pid"]

    res = client.post(list_url,
                      headers=json_headers,
                      data=json.dumps(patron2_brwreq))
    patron2_brwreq_pid = res.get_json()["metadata"]["pid"]
    all_pids = [patron1_brwreq_pid, patron2_brwreq_pid]
    # wait for ES
    current_search.flush_and_refresh(index="ill_borrowing_requests")

    # test results
    tests = [
        ("admin", _HTTP_OK, all_pids),
        ("librarian", _HTTP_OK, all_pids),
        ("patron1", _HTTP_OK, [patron1_brwreq_pid]),
        ("patron2", _HTTP_OK, [patron2_brwreq_pid]),
    ]
    for username, expected_status, expected_pids in tests:
        user_login(client, username, users)
        results = _test_list(expected_status, all_pids)
        assert results["hits"]["total"] == len(expected_pids)
        found_pids = [
            hit["metadata"]["pid"] for hit in results["hits"]["hits"]
        ]
        assert set(expected_pids) == set(found_pids)

    # anonymous
    user_login(client, "anonymous", users)
    _test_list([401], [])
def test_brwreq_decline_extension_success(client, testdata, json_headers,
                                          users):
    """Test declone extension success."""
    user_login(client, "librarian", users)

    # create request
    brwreq, brwreq_pid = _create_on_loan_brwreq_with_pending_extension(
        "1", client, json_headers)
    end_date = brwreq["patron_loan"]["loan"]["end_date"]

    user_login(client, "librarian", users)
    # decline extension
    res = _decline_extension_action(brwreq_pid, dict(), client, json_headers)
    assert res.status_code == 200

    patron_loan = res.get_json()["metadata"]["patron_loan"]
    assert patron_loan["loan"]["state"] == "ITEM_ON_LOAN"
    assert "extension_count" not in patron_loan["loan"]
    assert patron_loan["loan"]["end_date"] == end_date
    assert patron_loan["extension"]["status"] == "DECLINED"

    # request again should now fail because it has been declined
    user_login(client, "patron1", users)
    res = _request_extension_action(brwreq_pid, client, json_headers)
    assert res.status_code == 400
def test_brwreq_accept_decline_extension_only_librarian(
        client, testdata, json_headers, users):
    """Test that only librarian can accept or decline an extension."""

    tests = [_accept_extension_action, _decline_extension_action]
    for action in tests:
        user_login(client, "librarian", users)

        # create request
        brwreq, brwreq_pid = _create_on_loan_brwreq_with_pending_extension(
            "1", client, json_headers)

        loan_end_date = arrow.utcnow() + timedelta(days=15)
        data = dict(loan_end_date=loan_end_date.date().isoformat())

        # accept/decline

        # anonymous, forbidden
        user_logout(client)
        res = action(brwreq_pid, data, client, json_headers)
        assert res.status_code == 401

        # patron, forbidden
        user_login(client, "patron1", users)
        res = action(brwreq_pid, data, client, json_headers)
        assert res.status_code == 403

        # librarian, success
        user_login(client, "librarian", users)
        res = action(brwreq_pid, data, client, json_headers)
        assert res.status_code == 200
Пример #24
0
def test_patron_can_request_loan(client, json_headers, users, testdata):
    """Test that a patron can request a loan."""
    url = url_for("invenio_app_ils_circulation.loan_request")
    user = user_login(client, "patron1", users)
    params = deepcopy(NEW_LOAN)
    params["document_pid"] = "docid-3"
    params["transaction_user_pid"] = str(user.id)
    res = client.post(url, headers=json_headers, data=json.dumps(params))
    assert res.status_code == 202
    loan = res.get_json()["metadata"]
    assert loan["state"] == "PENDING"
    assert loan["document_pid"] == params["document_pid"]
    assert loan["transaction_date"]
def test_brwreq_create_loan_fails_on_loan_pid_already_attached(
        db, client, testdata, json_headers, users):
    """Test borrowing requests create loan action fails on loan_pid already."""
    user_login(client, "librarian", users)

    # demo data "illbid-2" has the valid state `REQUESTED`
    pid = "illbid-2"

    rec = BorrowingRequest.get_record_by_pid(pid)
    rec.setdefault("patron_loan", {})
    rec["patron_loan"]["pid"] = "loanid-3"
    rec.commit()
    db.session.commit()

    # already with a loan pid for some reasons
    now = arrow.utcnow()
    future = now + timedelta(days=5)
    data = dict(
        loan_start_date=now.date().isoformat(),
        loan_end_date=future.date().isoformat(),
    )
    _assert_create_loan_action_fails(pid, data, client, json_headers)
Пример #26
0
def test_patron_can_cancel_loan(
    client, json_headers, users, testdata, app_config
):
    """Test that a patron can cancel its own loan."""
    url = url_for("invenio_app_ils_circulation.loan_request")
    user = user_login(client, "patron3", users)
    params = deepcopy(NEW_LOAN)
    params["document_pid"] = "docid-3"
    params["transaction_user_pid"] = str(user.id)

    # Create a Loan
    res = client.post(url, headers=json_headers, data=json.dumps(params))
    loan = res.get_json()

    cancel_url = loan["links"]["actions"]["cancel"]
    meta = loan["metadata"]
    payload = {
        "document_pid": meta["document_pid"],
        "patron_pid": meta["patron_pid"],
        "transaction_location_pid": meta["transaction_location_pid"],
        "transaction_user_pid": meta["transaction_user_pid"],
        "cancel_reason": "USER_CANCEL",
    }
    assert res.status_code == 202

    # Try to cancel a loan that belongs to patron3 as patron1
    user_login(client, "patron1", users)
    cancel_res = client.post(
        cancel_url, headers=json_headers, data=json.dumps(payload)
    )
    assert cancel_res.status_code == 403

    # Try to cancel a loan that belongs to patron3 as patron3
    user_login(client, "patron3", users)
    cancel_res = client.post(
        cancel_url, headers=json_headers, data=json.dumps(payload)
    )
    assert cancel_res.status_code == 202
Пример #27
0
def test_loan_access_permission(client, json_headers, users, testdata):
    """
    Test that a patron should not be able to update their loan;
    and a fortiori, other people's.
    """
    loan = testdata["loans"][0]
    user = user_login(client, "patron1", users)
    url = _url_loan(loan["pid"])
    res = client.get(url, headers=json_headers)
    assert res.status_code == 200  # Can access their own loan
    metadata = _load_result(res)["metadata"]
    metadata["transaction_user_pid"] = str(user.id)
    res = client.put(url, headers=json_headers, data=json.dumps(metadata))
    assert res.status_code == 403  # Cannot modify the loan
Пример #28
0
 def login_and_test(username):
     user = user_login(client, username, users)
     # Create record
     id = uuid.uuid4()
     record = Record.create(access, id_=id)
     factory = RecordPermission(record, action)
     if user.has_role("admin"):
         # super user can do EVERYTHING
         assert factory.can()
     elif user.has_role("librarian") and action != "delete":
         # librarian should be able to update, create, and read everything
         assert factory.can()
     else:
         assert factory.can() if is_allowed else not factory.can()
def test_brwreq_accept_extension_success(client, testdata, json_headers,
                                         users):
    """Test accept extension success."""
    user_login(client, "librarian", users)

    # create request
    brwreq, brwreq_pid = _create_on_loan_brwreq_with_pending_extension(
        "1", client, json_headers)

    loan_end_date = arrow.utcnow() + timedelta(days=15)
    end_date = loan_end_date.date().isoformat()
    data = dict(loan_end_date=end_date)

    user_login(client, "librarian", users)
    # accept extension
    res = _accept_extension_action(brwreq_pid, data, client, json_headers)
    assert res.status_code == 200

    patron_loan = res.get_json()["metadata"]["patron_loan"]
    assert patron_loan["loan"]["state"] == "ITEM_ON_LOAN"
    assert patron_loan["loan"]["extension_count"] == 1
    assert patron_loan["loan"]["end_date"] == end_date
    assert "status" not in patron_loan["extension"]
def test_brwreq_accept_decline_extension_should_fail_when_loan_not_active(
        client, testdata, json_headers, users):
    """Test that accept or decline an extension fails on loan not active."""

    tests = [_accept_extension_action, _decline_extension_action]
    for action in tests:
        user_login(client, "librarian", users)

        # create request
        brwreq, brwreq_pid = _create_on_loan_brwreq_with_pending_extension(
            "1", client, json_headers)

        # check-in loan
        loan_pid = brwreq["patron_loan"]["pid"]
        url = url_for(
            "invenio_circulation_loan_actions.loanid_actions",
            pid_value=loan_pid,
            action="checkin",
        )
        item_pid = dict(type=BORROWING_REQUEST_PID_TYPE, value=brwreq["pid"])
        params = dict(
            document_pid=brwreq["document_pid"],
            item_pid=item_pid,
            patron_pid=brwreq["patron_pid"],
            transaction_location_pid="locid-1",
            transaction_user_pid="1",
        )
        res = client.post(url, headers=json_headers, data=json.dumps(params))
        assert res.status_code == 202

        # accept extension
        loan_end_date = arrow.utcnow() + timedelta(days=15)
        data = dict(loan_end_date=loan_end_date.date().isoformat())

        res = action(brwreq_pid, data, client, json_headers)
        assert res.status_code == 400