def test_link_orcid_auth_callback_with_affiliation(name, mocker, client): """Test ORCID callback - the user authorized the organisation access to the ORCID profile.""" mocker.patch( "requests_oauthlib.OAuth2Session.fetch_token", lambda self, *args, ** kwargs: dict(name="NEW TEST", access_token="ABC123", orcid="ABC-123-456-789", scope=['/read-limited,/activities/update'], expires_in="1212", refresh_token="ABC1235")) m = mocker.patch("orcid_hub.orcid_client.MemberAPIV3") mocker.patch("orcid_hub.orcid_client.SourceClientId") org = Organisation.get(name="THE ORGANISATION") test_user = User.create(name=name, email="*****@*****.**", organisation=org, orcid="ABC123", confirmed=True) UserOrg.create(user=test_user, org=org, affiliations=(Affiliation.EMP | Affiliation.EDU)) client.login(test_user) resp = client.get("/link") state = session['oauth_state'] resp = client.get(f"/auth?state={state}") api_mock = m.return_value test_user = User.get(test_user.id) assert test_user.orcid == "ABC-123-456-789" orcid_token = OrcidToken.get(user=test_user, org=org) assert orcid_token.access_token == "ABC123" api_mock.create_or_update_affiliation.assert_has_calls([ call(affiliation=Affiliation.EDU, initial=True), call(affiliation=Affiliation.EMP, initial=True), ]) # User with no Affiliation, should get flash warning. user_org = UserOrg.get(user=test_user, org=org) user_org.affiliations = Affiliation.NONE user_org.save() orcid_token.delete_instance() assert OrcidToken.select().where(OrcidToken.user == test_user, OrcidToken.org == org).count() == 0 resp = client.get(f"/auth?state={state}") assert resp.status_code == 302 assert b"<!DOCTYPE HTML" in resp.data, "Expected HTML content" assert "profile" in resp.location, "redirection to 'profile' showing the ORCID" assert OrcidToken.select().where(OrcidToken.user == test_user, OrcidToken.org == org).count() == 1 get_person = mocker.patch("requests_oauthlib.OAuth2Session.get", return_value=Mock(status_code=200)) resp = client.get("/profile", follow_redirects=True) assert b"can create and update research activities" in resp.data get_person.assert_called_once() get_person = mocker.patch("requests_oauthlib.OAuth2Session.get", return_value=Mock(status_code=401)) resp = client.get("/profile", follow_redirects=True) assert b"you'll be taken to ORCID to create or sign into your ORCID record" in resp.data get_person.assert_called_once()
def test_member_api_v3(app, mocker): """Test MemberAPI extension and wrapper of ORCID API.""" mocker.patch.multiple("orcid_hub.app.logger", error=DEFAULT, exception=DEFAULT, info=DEFAULT) org = Organisation.get(name="THE ORGANISATION") user = User.create(orcid="1001-0001-0001-0001", name="TEST USER 123", email="*****@*****.**", organisation=org, confirmed=True) UserOrg.create(user=user, org=org, affiliation=Affiliation.EDU) api = MemberAPIV3(user=user) assert api.api_client.configuration.access_token is None or api.api_client.configuration.access_token == '' api = MemberAPIV3(user=user, org=org) assert api.api_client.configuration.access_token is None or api.api_client.configuration.access_token == '' api = MemberAPIV3(user=user, org=org, access_token="ACCESS000") assert api.api_client.configuration.access_token == 'ACCESS000' OrcidToken.create(access_token="ACCESS123", user=user, org=org, scopes="/read-limited,/activities/update", expires_in='121') api = MemberAPIV3(user=user, org=org) assert api.api_client.configuration.access_token == "ACCESS123" # Test API call auditing: request_mock = mocker.patch.object( api.api_client.rest_client.pool_manager, "request", MagicMock(return_value=Mock(data=b"""{"mock": "data"}""", status=200))) api.get_record() request_mock.assert_called_with( "GET", "https://api.sandbox.orcid.org/v3.0/1001-0001-0001-0001", fields=None, preload_content=False, timeout=None, headers={ "Accept": "application/json", "Content-Type": "application/json", "User-Agent": "Swagger-Codegen/1.0.0/python", "Authorization": "Bearer ACCESS123" }) api_call = OrcidApiCall.select().first() assert api_call.response == '{"mock": "data"}' assert api_call.url == "https://api.sandbox.orcid.org/v3.0/1001-0001-0001-0001" create = mocker.patch.object(OrcidApiCall, "create", side_effect=Exception("FAILURE")) api.get_record() create.assert_called() app.logger.exception.assert_called_with( "Failed to create API call log entry.") # Handling of get_record call_api = mocker.patch.object(api.api_client, "call_api", side_effect=v3.rest.ApiException( reason="FAILURE", status=401)) delete = mocker.patch.object(OrcidToken, "delete") with pytest.raises(v3.rest.ApiException): api.get_record() call_api.assert_called_once() delete.assert_called_once() call_api = mocker.patch.object(api.api_client, "call_api", side_effect=v3.rest.ApiException( reason="FAILURE 999", status=999)) with pytest.raises(v3.rest.ApiException): api.get_record() app.logger.error.assert_called_with( "ApiException Occurred: (999)\nReason: FAILURE 999\n") call_api = mocker.patch.object(api.api_client, "call_api", side_effect=v3.rest.ApiException( reason="FAILURE", status=401)) with pytest.raises(v3.rest.ApiException): api.get_record() app.logger.error.assert_called() call_api.assert_called_once() call_api = mocker.patch.object(api.api_client, "call_api", return_value=( Mock(data=b"""{"mock": "data"}"""), 200, [], )) api.get_record() call_api.assert_called_with(f"/v3.0/{user.orcid}", "GET", _preload_content=False, auth_settings=["orcid_auth"], header_params={"Accept": "application/json"}, response_type=None) # Failed logging: request_mock = mocker.patch("orcid_api_v3.rest.RESTClientObject.request", return_value=Mock(data=None, status_code=200))
def test_proxy_get_profile(app_req_ctx): """Test the echo endpoint.""" user = User.get(email="*****@*****.**") token = Token.get(user=user) orcid_id = "0000-0000-0000-00X3" with app_req_ctx( f"/orcid/api/v1.23/{orcid_id}", headers=dict(authorization=f"Bearer {token.access_token}") ) as ctx, patch("orcid_hub.apis.requests.Session.send") as mocksend: mockresp = MagicMock(status_code=200) mockresp.raw.stream = lambda *args, **kwargs: iter( [b"""{"data": "TEST"}"""]) mockresp.raw.headers = { "Server": "TEST123", "Content-Type": "application/json;charset=UTF-8", "Transfer-Encoding": "chunked", "Connection": "keep-alive", "Access-Control-Allow-Origin": "*", "Cache-Control": "no -cache, no-store, max-age=0, must-revalidate", "Pragma": "no-cache", "Expires": "0", } mocksend.return_value = mockresp resp = ctx.app.full_dispatch_request() assert resp.status_code == 200 args, kwargs = mocksend.call_args assert kwargs["stream"] assert args[0].url == f"https://api.sandbox.orcid.org/v1.23/{orcid_id}" assert args[0].headers[ "Authorization"] == "Bearer ORCID-TEST-ACCESS-TOKEN" data = json.loads(resp.data) assert data == {"data": "TEST"} with app_req_ctx( f"/orcid/api/v1.23/{orcid_id}", headers=dict(authorization=f"Bearer {token.access_token}"), method="POST", data=b"""{"data": "REQUEST"}""") as ctx, patch( "orcid_hub.apis.requests.Session.send") as mocksend: mockresp = MagicMock(status_code=201) mockresp.raw.stream = lambda *args, **kwargs: iter( [b"""{"data": "TEST"}"""]) mockresp.raw.headers = { "Server": "TEST123", "Content-Type": "application/json;charset=UTF-8", "Transfer-Encoding": "chunked", "Connection": "keep-alive", "Access-Control-Allow-Origin": "*", "Cache-Control": "no -cache, no-store, max-age=0, must-revalidate", "Pragma": "no-cache", "Expires": "0", } mocksend.return_value = mockresp resp = ctx.app.full_dispatch_request() assert resp.status_code == 201 args, kwargs = mocksend.call_args assert kwargs["stream"] assert args[0].url == f"https://api.sandbox.orcid.org/v1.23/{orcid_id}" assert args[0].headers[ "Authorization"] == "Bearer ORCID-TEST-ACCESS-TOKEN" data = json.loads(resp.data) assert data == {"data": "TEST"} # malformatted ORCID ID: with app_req_ctx( "/orcid/api/v1.23/NOT-ORCID-ID/PATH", headers=dict(authorization=f"Bearer {token.access_token}")) as ctx: resp = ctx.app.full_dispatch_request() assert resp.status_code == 415 # no ORCID access token with app_req_ctx( "/orcid/api/v1.23/0000-0000-0000-11X2/PATH", headers=dict(authorization=f"Bearer {token.access_token}")) as ctx: resp = ctx.app.full_dispatch_request() assert resp.status_code == 403
def test_is_emp_or_edu_record_present(app, mocker): """Test 'is_emp_or_edu_record_present' method.""" mocker.patch.multiple("orcid_hub.app.logger", error=DEFAULT, exception=DEFAULT, info=DEFAULT) org = Organisation.get(name="THE ORGANISATION") user = User.create(orcid="1001-0001-0001-0001", name="TEST USER 123", email="*****@*****.**", organisation=org, confirmed=True) UserOrg.create(user=user, org=org, affiliation=Affiliation.EDU) api = MemberAPIV3(user=user, org=org) test_responses = [ None, """{"mock": "data"}""", """{ "employment-summary": [{"source": {"source-client-id": {"path": "CLIENT000"}}, "put-code": 123}], "education-summary": [{"source": {"source-client-id": {"path": "CLIENT000"}}, "put-code": 456}] }""", """{"employment-summary": [], "education-summary": []}""" ] for data in test_responses: with patch.object(v3.api_client.ApiClient, "call_api", return_value=Mock(data=data)) as call_api: api.is_emp_or_edu_record_present(Affiliation.EDU) call_api.assert_called_with("/v3.0/{orcid}/educations", "GET", {"orcid": "1001-0001-0001-0001"}, [], {"Accept": "application/json"}, _preload_content=False, _request_timeout=None, _return_http_data_only=True, async_req=None, auth_settings=["orcid_auth"], body=None, collection_formats={}, files={}, post_params=[], response_type="EducationsSummaryV30") api.is_emp_or_edu_record_present(Affiliation.EMP) call_api.assert_called_with("/v3.0/{orcid}/employments", "GET", {"orcid": "1001-0001-0001-0001"}, [], {"Accept": "application/json"}, _preload_content=False, _request_timeout=None, _return_http_data_only=True, async_req=None, auth_settings=["orcid_auth"], body=None, collection_formats={}, files={}, post_params=[], response_type="EmploymentsSummaryV30") with patch.object(v3.api_client.ApiClient, "call_api", side_effect=ApiException(reason="FAILURE", status=401)) as call_api: api.is_emp_or_edu_record_present(Affiliation.EDU) app.logger.error.assert_called_with( "For TEST USER 123 ([email protected]) while checking for employment " "and education records, Encountered Exception: (401)\nReason: FAILURE\n" ) with patch.object(v3.api_client.ApiClient, "call_api", side_effect=Exception("EXCEPTION")) as call_api: api.is_emp_or_edu_record_present(Affiliation.EDU) app.logger.exception.assert_called_with( "Failed to verify presence of employment or education record.")
def test_orcid_login_callback_admin_flow(patch, patch2, request_ctx): """Test login from orcid callback function for Organisation Technical contact.""" org = Organisation.create( name="THE ORGANISATION:test_orcid_login_callback_admin_flow", tuakiri_name="THE ORGANISATION:test_orcid_login_callback_admin_flow", confirmed=False, orcid_client_id="CLIENT ID", orcid_secret="Client Secret", city="CITY", country="COUNTRY", disambiguated_id="ID", disambiguation_source="RINGGOLD", is_email_sent=True) u = User.create( email="*****@*****.**", roles=Role.TECHNICAL, orcid="123", confirmed=False, organisation=org) UserOrg.create(user=u, org=org, is_admin=True) token = utils.generate_confirmation_token(email=u.email, org=org.name) with request_ctx() as resp: request.args = {"invitation_token": token, "state": "xyz"} session['oauth_state'] = "xyz" resp = authcontroller.orcid_login_callback(request) assert resp.status_code == 302 assert resp.location.startswith("/") with request_ctx() as respx: request.args = {"invitation_token": token, "state": "xyzabc"} session['oauth_state'] = "xyz" respx = authcontroller.orcid_login_callback(request) assert respx.status_code == 302 assert respx.location.startswith("/") with request_ctx() as resp: request.args = {"invitation_token": token, "state": "xyz", "error": "access_denied"} session['oauth_state'] = "xyz" resp = authcontroller.orcid_login_callback(request) assert resp.status_code == 302 assert resp.location.startswith("/") with request_ctx() as ct: token = utils.generate_confirmation_token(email=u.email, org=None) request.args = {"invitation_token": token, "state": "xyz"} session['oauth_state'] = "xyz" ctxx = authcontroller.orcid_login_callback(request) assert ctxx.status_code == 302 assert ctxx.location.startswith("/") with request_ctx() as ctxxx: request.args = {"invitation_token": token, "state": "xyzabc"} session['oauth_state'] = "xyz" ctxxx = authcontroller.orcid_login_callback(request) assert ctxxx.status_code == 302 assert ctxxx.location.startswith("/") with request_ctx() as cttxx: request.args = {"invitation_token": token, "state": "xyz", "error": "access_denied"} session['oauth_state'] = "xyz" cttxx = authcontroller.orcid_login_callback(request) assert cttxx.status_code == 302 assert cttxx.location.startswith("/") with request_ctx() as ct: token = utils.generate_confirmation_token(email=u.email, org=None) request.args = {"invitation_token": token, "state": "xyz"} session['oauth_state'] = "xyz" ct = authcontroller.orcid_login_callback(request) assert ct.status_code == 302 assert ct.location.startswith("/") with request_ctx(): request.args = {"invitation_token": None, "state": "xyz"} session['oauth_state'] = "xyz" ct = authcontroller.orcid_login_callback(request) assert ct.status_code == 302 assert ct.location.startswith("/") with request_ctx(): # Test case for catching general exception: invitation token here is integer, so an exception will be thrown. request.args = {"invitation_token": 123, "state": "xyz"} session['oauth_state'] = "xyz" ct = authcontroller.orcid_login_callback(request) assert ct.status_code == 302 assert ct.location.startswith("/") with request_ctx(): # User login via orcid, where organisation is not confirmed. u.orcid = "123" u.save() request.args = {"invitation_token": None, "state": "xyz-about"} session['oauth_state'] = "xyz-about" resp = authcontroller.orcid_login_callback(request) assert resp.status_code == 302 assert resp.location.startswith("/about") with request_ctx(): # User login via orcid, where organisation is confirmed, so showing viewmembers page. org.tech_contact = u org.confirmed = True org.save() request.args = {"invitation_token": None, "state": "xyz"} session['oauth_state'] = "xyz" resp = authcontroller.orcid_login_callback(request) assert resp.status_code == 302 assert resp.location.startswith("/admin/viewmembers/") with request_ctx(): # User login via orcid, where organisation is not confirmed and user is tech, so showing confirm org page. org.confirmed = False org.save() request.args = {"invitation_token": None, "state": "xyz"} session['oauth_state'] = "xyz" resp = authcontroller.orcid_login_callback(request) assert resp.status_code == 302 assert resp.location.startswith("/confirm/organisation")
def test_affiliation_api(client): """Test affiliation API in various formats.""" resp = client.post( "/oauth/token", content_type="application/x-www-form-urlencoded", data= b"grant_type=client_credentials&client_id=TEST0-ID&client_secret=TEST0-SECRET" ) data = json.loads(resp.data) access_token = data["access_token"] resp = client.post( "/api/v1.0/affiliations/?filename=TEST42.csv", headers=dict(authorization=f"Bearer {access_token}"), content_type="text/csv", data= b"First Name,Last Name,email,Organisation,Affiliation Type,Role,Department,Start Date," b"End Date,City,State,Country,Disambiguated Id,Disambiguated Source\n" b"Researcher,Par,[email protected],Royal Org1,Staff,Programme Guide - " b"ORCID,Research Funding,2016-09,,Wellington,SATE,NZ,,\n" b"Roshan,Pawar,[email protected],Royal Org1,Staff,AAA,Research " b"Funding,2016-09,,Wellington,SATE,NZ,,\n" b"Roshan,Pawar,[email protected],Royal Org1,Student,BBB,Research " b"Funding,2016-09,,Wellington,SATE,New Zealand,,") data = json.loads(resp.data) assert data["filename"] == "TEST42.csv" assert data["task-type"] == "AFFILIATION" assert len(data["records"]) == 3 task_id = data["id"] resp = client.get("/api/v1.0/tasks", headers=dict(authorization=f"Bearer {access_token}")) tasks = json.loads(resp.data) assert tasks[0]["id"] == task_id task_copy = copy.deepcopy(data) del (task_copy["id"]) task_copy["filename"] = "TASK-COPY.csv" resp = client.post("/api/v1.0/affiliations/", headers=dict(authorization=f"Bearer {access_token}"), content_type="application/json", data=json.dumps(task_copy)) assert Task.select().count() == 2 for r in data["records"]: del (r["id"]) r["city"] = "TEST000" resp = client.post(f"/api/v1.0/affiliations/{task_id}", headers=dict(authorization=f"Bearer {access_token}"), content_type="application/json", data=json.dumps(data)) data = json.loads(resp.data) assert len(data["records"]) == 3 # should get a new set of records del (data["records"][2]) resp = client.post(f"/api/v1.0/affiliations/{task_id}", headers=dict(authorization=f"Bearer {access_token}"), content_type="application/json", data=json.dumps(data)) new_data = json.loads(resp.data) assert len(new_data["records"]) == 2 incorrect_data = copy.deepcopy(data) incorrect_data["records"].insert(0, { "first-name": "TEST000 FN", "last-name": "TEST000 LN", }) resp = client.post(f"/api/v1.0/affiliations/{task_id}", headers=dict(authorization=f"Bearer {access_token}"), content_type="application/json", data=json.dumps(incorrect_data)) data = json.loads(resp.data) assert resp.status_code == 422 assert data["error"] == "Validation error." resp = client.get(f"/api/v1.0/affiliations/{task_id}", headers=dict(authorization=f"Bearer {access_token}")) data = json.loads(resp.data) incorrect_data = copy.deepcopy(data) incorrect_data["records"].insert( 0, { "email": "*****@*****.**", "first-name": "TEST000 FN", "last-name": "TEST000 LN", }) resp = client.post(f"/api/v1.0/affiliations/{task_id}", headers=dict(authorization=f"Bearer {access_token}"), content_type="application/json", data=json.dumps(incorrect_data)) data = json.loads(resp.data) assert resp.status_code == 422 assert data["error"] == "Validation error." resp = client.get(f"/api/v1.0/affiliations/{task_id}", headers=dict(authorization=f"Bearer {access_token}")) data = json.loads(resp.data) new_data = copy.deepcopy(data) new_data["records"].insert( 0, { "email": "*****@*****.**", "first-name": "TEST000 FN", "last-name": "TEST000 LN", "affiliation-type": "staff", "city": "TEST000" }) resp = client.post(f"/api/v1.0/affiliations/{task_id}", headers=dict(authorization=f"Bearer {access_token}"), content_type="application/json", data=json.dumps(new_data)) data = json.loads(resp.data) assert resp.status_code == 200 assert len(data["records"]) == 3 resp = client.put(f"/api/v1.0/affiliations/{task_id}", headers=dict(authorization=f"Bearer {access_token}"), content_type="application/json", data=json.dumps(data)) data = json.loads(resp.data) assert resp.status_code == 200 assert len(data["records"]) == 3 resp = client.get(f"/api/v1.0/affiliations/{task_id}", headers=dict(authorization=f"Bearer {access_token}")) data = json.loads(resp.data) new_data = copy.deepcopy(data) for i, r in enumerate(new_data["records"]): new_data["records"][i] = {"id": r["id"], "is-active": True} resp = client.patch(f"/api/v1.0/affiliations/{task_id}", headers=dict(authorization=f"Bearer {access_token}"), content_type="application/json", data=json.dumps(new_data)) data = json.loads(resp.data) assert resp.status_code == 200 assert len(data["records"]) == 3 assert all(r["is-active"] for r in data["records"]) assert all(r["city"] == "TEST000" for r in data["records"]) resp = client.head(f"/api/v1.0/affiliations/{task_id}", headers=dict(authorization=f"Bearer {access_token}")) assert "Last-Modified" in resp.headers resp = client.head("/api/v1.0/affiliations/999999999", headers=dict(authorization=f"Bearer {access_token}")) assert resp.status_code == 404 resp = client.get("/api/v1.0/affiliations/999999999", headers=dict(authorization=f"Bearer {access_token}")) assert resp.status_code == 404 resp = client.patch("/api/v1.0/affiliations/999999999", headers=dict(authorization=f"Bearer {access_token}"), content_type="application/json", data=json.dumps(new_data)) assert resp.status_code == 404 resp = client.delete(f"/api/v1.0/affiliations/{task_id}", headers=dict(authorization=f"Bearer {access_token}")) assert Task.select().count() == 1 resp = client.delete(f"/api/v1.0/affiliations/{task_id}", headers=dict(authorization=f"Bearer {access_token}")) assert resp.status_code == 404 other_user = User.get(email="*****@*****.**") other_task = Task.create(created_by=other_user, org=other_user.organisation, filename="OTHER.csv", task_type=TaskType.AFFILIATION) resp = client.head(f"/api/v1.0/affiliations/{other_task.id}", headers=dict(authorization=f"Bearer {access_token}")) assert resp.status_code == 403 resp = client.get(f"/api/v1.0/affiliations/{other_task.id}", headers=dict(authorization=f"Bearer {access_token}")) assert resp.status_code == 403 resp = client.patch(f"/api/v1.0/affiliations/{other_task.id}", headers=dict(authorization=f"Bearer {access_token}"), content_type="application/json", data=json.dumps(new_data)) assert resp.status_code == 403 resp = client.delete(f"/api/v1.0/affiliations/{other_task.id}", headers=dict(authorization=f"Bearer {access_token}")) assert resp.status_code == 403 resp = client.patch(f"/api/v1.0/affiliations/{task_id}", headers=dict(authorization=f"Bearer {access_token}"), content_type="application/json", data=b'') assert resp.status_code == 400 resp = client.post("/api/v1.0/affiliations/?filename=TEST42.csv", headers=dict(authorization=f"Bearer {access_token}", accept="text/yaml"), content_type="text/yaml", data="""task-type: AFFILIATION filename: TEST42.yml records: - affiliation-type: student city: Wellington country: NZ department: Research Funding email: [email protected] first-name: Roshan last-name: Pawar organisation: Royal Org1 role: BBB start-date: 2016-09 - affiliation-type: staff city: Wellington country: NZ department: Research Funding email: [email protected] first-name: Roshan last-name: Pawar organisation: Royal Org1 role: AAA start-date: 2016-09 - affiliation-type: staff city: Wellington country: NZ department: Research Funding email: [email protected] first-name: Researcher is-active: false last-name: Par organisation: Royal Org1 role: Programme Guide - ORCID start-date: 2016-09 """) data = json.loads(resp.data) assert data["filename"] == "TEST42.yml" assert data["task-type"] == "AFFILIATION" assert len(data["records"]) == 3 task_id = data["id"] task = Task.get(id=task_id) assert task.affiliation_records.count() == 3
def test_drop_tables(models): drop_tables() assert not User.table_exists() # assert not Organisation.table_exists() assert not UserOrg.table_exists()
def test_sso_loging_with_external_sp(client, mocker): """Test with EXTERNAL_SP.""" data = { "Auedupersonsharedtoken": "ABC123", "Sn": "LAST NAME/SURNAME/FAMILY NAME", 'Givenname': "FIRST NAME/GIVEN NAME", "Mail": "[email protected];[email protected]", "O": client.data["org"].name, "Displayname": "TEST USER #42", "Unscoped-Affiliation": "staff", "Eppn": "*****@*****.**" } client.application.config["EXTERNAL_SP"] = "https://exernal.ac.nz/SP" resp = client.get("/sso/login") assert resp.status_code == 302 assert urlparse(resp.location).path == '/' resp = client.get("/index") assert b"https://exernal.ac.nz/SP" in resp.data get = mocker.patch( "requests.get", return_value=Mock(content=zlib.compress(b"""{"GARBAGE": 123}"""))) resp = client.get("/sso/login", follow_redirects=True) assert b"500" in resp.data get.assert_called_once() get = mocker.patch( "requests.get", return_value=Mock(content=zlib.compress(json.dumps(data).encode()))) resp = client.get("/sso/login", follow_redirects=True) get.assert_called_once() assert b"TEST USER #42" in resp.data assert b"*****@*****.**" in resp.data u = User.get(email="*****@*****.**") assert u.name == "TEST USER #42" resp = client.logout(follow_redirects=False) data["Unscoped-Affiliation"] = "NONSENSE" data["Mail"] = "*****@*****.**" data["Eppn"] = "*****@*****.**" get = mocker.patch( "requests.get", return_value=Mock(content=zlib.compress(json.dumps(data).encode()))) resp = client.get("/index") resp = client.get("/sso/login", follow_redirects=True) assert b"NONSENSE" in resp.data resp = client.logout(follow_redirects=False) data["O"] = "A BRAND NEW ORGANISATION" get = mocker.patch( "requests.get", return_value=Mock(content=zlib.compress(json.dumps(data).encode()))) resp = client.get("/index") resp = client.get("/sso/login", follow_redirects=True) assert b"Your organisation (A BRAND NEW ORGANISATION) is not yet using the Hub" in resp.data resp = client.logout(follow_redirects=False) data["O"] = "A COMPLETELY BRAND NEW ORGANISATION" get = mocker.patch( "requests.get", return_value=Mock(content=zlib.compress(json.dumps(data).encode()))) mocker.patch("orcid_hub.models.Organisation.save", side_effect=Exception("FAILURE")) resp = client.get("/index") resp = client.get("/sso/login", follow_redirects=True) assert b"FAILURE" in resp.data
def test_test_database(models): """Test of the consitency of the test database.""" assert Organisation.select().count() == 14 assert User.select().count() == 95 assert OrcidToken.select().count() == 76 assert AffiliationRecord.select().count() == 10 assert AffiliationExternalId.select().count() == 10 assert FundingRecord.select().count() == 10 assert FundingContributor.select().count() == 10 assert FundingInvitee.select().count() == 10 assert ExternalId.select().count() == 10 assert WorkRecord.select().count() == 10 assert WorkContributor.select().count() == 10 assert WorkExternalId.select().count() == 10 assert WorkInvitee.select().count() == 10 assert PeerReviewRecord.select().count() == 10 assert PeerReviewExternalId.select().count() == 10 assert PeerReviewInvitee.select().count() == 10 assert PropertyRecord.select().where( PropertyRecord.type == "URL").count() == 10 assert PropertyRecord.select().where( PropertyRecord.type == "NAME").count() == 10 assert PropertyRecord.select().where( PropertyRecord.type == "KEYWORD").count() == 10 assert Task.select().count() == 30 assert UserOrgAffiliation.select().count() == 30 assert User.get(id=43).admin_for.count() == 10 assert User.get(id=1).admin_for.count() == 0 assert User.get(id=42).admin_for.count() > 0 assert User.get(id=2).organisations.count() > 0 assert Organisation.get(id=1).admins.count() == 2 assert Organisation.get(id=5).users.count() > 0 assert Organisation.get(id=5).admins.count() > 0 assert User.select().where(User.orcid == User.get( email="*****@*****.**").orcid).count() == 3 assert len(User.get(email="*****@*****.**").org_links) == 3 user = User.get(email="*****@*****.**") available_organisations = user.available_organisations assert available_organisations.count() == 14 admin = User.create(email="*****@*****.**", organisation=user.organisation, confirmed=True, first_name="TEST", last_name="ADMIN", roles=Role.ADMIN) ui = UserInvitation.create(email=user.email, invitee=user, inviter=admin, token="TOKEN-123") admin.delete_instance() ui = UserInvitation.get(ui.id) assert ui.inviter_id is None user.delete_instance() assert not UserInvitation.select().where( UserInvitation.id == ui.id).exists() org = Organisation.select().limit(1).first() user = User.select().limit(1).first() ot = OrcidToken.create(user=user, org=org, scopes="S1,S2,S3")
def test_user_roles(models): user = User(name="Test User ABC123", first_name="ABC", last_name="123", email="*****@*****.**", confirmed=True, roles=Role.ADMIN | Role.RESEARCHER) assert user.has_role(Role.ADMIN) assert user.has_role("ADMIN") assert user.has_role(Role.RESEARCHER) assert user.has_role("RESEARCHER") assert user.has_role(Role.RESEARCHER | Role.ADMIN) assert user.has_role(4) assert user.has_role(2) assert not user.has_role(Role.SUPERUSER) assert not user.has_role("SUPERUSER") assert not user.has_role(1) assert not user.has_role("NOT A ROLE") assert not user.has_role(~(1 | 2 | 4 | 8 | 16)) assert not user.has_role(1.1234)
def test_user_org_link_org_constraint(models): user = User.select().limit(1).first() from peewee import IntegrityError with pytest.raises(IntegrityError): UserOrg.create(user=user, org_id=999999)
def test_user_uuid(): u = User(email="*****@*****.**") assert str(u.uuid) == "8428e5f6-38c6-530f-8339-9aeffb99e022"
def models(testdb): Organisation.insert_many((dict(name="Organisation #%d" % i, tuakiri_name="Organisation #%d" % i, orcid_client_id="client-%d" % i, orcid_secret="secret-%d" % i, confirmed=(i % 2 == 0)) for i in range(10))).execute() User.insert_many( (dict(name="Test User #%d" % i, first_name="Test_%d" % i, last_name="User_%d" % i, email="user%d@org%d.org.nz" % (i, i * 4 % 10), confirmed=(i % 3 != 0), roles=Role.SUPERUSER if i % 42 == 0 else Role.ADMIN if i % 13 == 0 else Role.RESEARCHER) for i in range(60))).execute() User.insert_many((dict(name="Test User with ORCID ID 'ABC-123' #%d" % i, orcid="ABC-123", first_name="Test_%d" % i, last_name="User_%d" % i, email="user_the_same_id_%d@org%d.org.nz" % (i, i), confirmed=True, organisation=(i + 1), roles=Role.RESEARCHER) for i in range(3))).execute() UserOrg.insert_many( dict(user=u.id, org=u.organisation_id) for u in User.select().where(User.orcid == "ABC-123")).execute() UserOrg.insert_many( dict(is_admin=((u + o) % 23 == 0), user=u, org=o) for (u, o) in product(range(2, 60, 4), range(2, 10)) if not UserOrg.select().where(UserOrg.user == u, UserOrg.org == o).exists()).execute() UserOrg.insert_many( (dict(is_admin=True, user=43, org=o) for o in range(1, 11))).execute() OrcidToken.insert_many((dict(user=User.get(id=1), org=Organisation.get(id=1), scopes="/read-limited", access_token="Test_%d" % i) for i in range(60))).execute() UserOrgAffiliation.insert_many((dict(user=User.get(id=1), organisation=Organisation.get(id=1), department_name="Test_%d" % i, department_city="Test_%d" % i, role_title="Test_%d" % i, path="Test_%d" % i, put_code="%d" % i) for i in range(30))).execute() Task.insert_many((dict(org=Organisation.get(id=1), created_by=User.get(id=1), updated_by=User.get(id=1), filename="Test_%d" % i, task_type=0) for i in range(30))).execute() AffiliationRecord.insert_many((dict(is_active=False, task=Task.get(id=1), put_code=90, local_id="Test_%d" % i, status="Test_%d" % i, first_name="Test_%d" % i, last_name="Test_%d" % i, email="Test_%d" % i, orcid="123112311231%d" % i, organisation="Test_%d" % i, affiliation_type="Test_%d" % i, role="Test_%d" % i, department="Test_%d" % i, city="Test_%d" % i, region="Test_%d" % i, country="Test_%d" % i, disambiguated_id="Test_%d" % i, disambiguation_source="Test_%d" % i) for i in range(10))).execute() record = AffiliationRecord.get() AffiliationExternalId.insert_many((dict(record=record, type="Test1_%d" % i, value="Test1_%d" % i, url="Test1_%d" % i, relationship="Test1_%d" % i) for i in range(10))).execute() PropertyRecord.insert_many((dict(type="URL", is_active=False, task=Task.get(id=1), put_code=90, status="Test_%d" % i, first_name="Test_%d" % i, last_name="Test_%d" % i, email="Test_%d" % i, orcid="123112311231%d" % i, name="Test_%d" % i, value="Test_%d" % i, visibility="Test_%d" % i, display_index=i) for i in range(10))).execute() PropertyRecord.insert_many((dict(type="NAME", is_active=False, task=Task.get(id=1), put_code=90, status="Test_%d" % i, first_name="Test_%d" % i, last_name="Test_%d" % i, email="Test_%d" % i, orcid="123112311231%d" % i, value="Test_%d" % i, visibility="Test_%d" % i, display_index=i) for i in range(10))).execute() PropertyRecord.insert_many((dict(type="KEYWORD", is_active=False, task=Task.get(id=1), put_code=90, status="Test_%d" % i, first_name="Test_%d" % i, last_name="Test_%d" % i, email="Test_%d" % i, orcid="123112311231%d" % i, value="Test_%d" % i, visibility="Test_%d" % i, display_index=i) for i in range(10))).execute() FundingRecord.insert_many( (dict(task=Task.get(id=1), title="Test_%d" % i, translated_title="Test_%d" % i, translated_title_language_code="Test_%d" % i, type="Test_%d" % i, organization_defined_type="Test_%d" % i, short_description="Test_%d" % i, amount="Test_%d" % i, currency="Test_%d" % i, org_name="Test_%d" % i, city="Test_%d" % i, region="Test_%d" % i, country="Test_%d" % i, disambiguated_id="Test_%d" % i, disambiguation_source="Test_%d" % i, is_active=False, status="Test_%d" % i) for i in range(10))).execute() record = FundingRecord.get() FundingContributor.insert_many((dict(record=record, orcid="123112311231%d" % i, name="Test_%d" % i, role="Test_%d" % i) for i in range(10))).execute() FundingInvitee.insert_many((dict(record=record, orcid="123112311231%d" % i, first_name="Test_%d" % i, last_name="Test_%d" % i, put_code=i, status="Test_%d" % i, identifier="%d" % i, visibility="Test_%d" % i, email="Test_%d" % i) for i in range(10))).execute() ExternalId.insert_many((dict(record=record, type="Test_%d" % i, value="Test_%d" % i, url="Test_%d" % i, relationship="Test_%d" % i) for i in range(10))).execute() task = Task.get() PeerReviewRecord.insert_many( (dict(task=task, review_group_id="issn:1212_%d" % i, reviewer_role="reviewer_%d" % i, review_url="xyz_%d" % i, review_type="REVIEW_%d" % i, subject_external_id_type="doi_%d" % i, subject_external_id_value="1212_%d" % i, subject_external_id_url="url/SELF_%d" % i, subject_external_id_relationship="SELF_%d" % i, subject_container_name="Journal title_%d" % i, subject_type="JOURNAL_ARTICLE_%d" % i, subject_name_title="name_%d" % i, subject_name_subtitle="subtitle_%d" % i, subject_name_translated_title_lang_code="en", subject_name_translated_title="sdsd_%d" % i, subject_url="url_%d" % i, convening_org_name="THE ORGANISATION_%d" % i, convening_org_city="auckland_%d" % i, convening_org_region="auckland_%d" % i, convening_org_country="nz_%d" % i, convening_org_disambiguated_identifier="123_%d" % i, convening_org_disambiguation_source="1212_%d" % i, is_active=False) for i in range(10))).execute() record = PeerReviewRecord.get() PeerReviewExternalId.insert_many((dict(record=record, type="Test1_%d" % i, value="Test1_%d" % i, url="Test1_%d" % i, relationship="Test1_%d" % i) for i in range(10))).execute() PeerReviewInvitee.insert_many((dict(record=record, orcid="1231123112311%d" % i, first_name="Test1_%d" % i, last_name="Test1_%d" % i, put_code=i, status="Test1_%d" % i, identifier="1%d" % i, visibility="PUBLIC", email="Test1_%d" % i) for i in range(10))).execute() WorkRecord.insert_many((dict(task=task, title="Test_%d" % i, subtitle="Test_%d" % i, translated_title="Test_%d" % i, translated_title_language_code="Test_%d" % i, journal_title="Test_%d" % i, short_description="Test_%d" % i, citation_type="Test_%d" % i, citation_value="Test_%d" % i, type="Test_%d" % i, url="Test_%d" % i, language_code="Test_%d" % i, country="Test_%d" % i, is_active=False, status="Test_%d" % i) for i in range(10))).execute() record = WorkRecord.get() WorkContributor.insert_many((dict(record=record, orcid="123112311231%d" % i, name="Test_%d" % i, contributor_sequence="%d" % i, role="Test_%d" % i) for i in range(10))).execute() WorkExternalId.insert_many((dict(record=record, type="Test_%d" % i, value="Test_%d" % i, url="Test_%d" % i, relationship="Test_%d" % i) for i in range(10))).execute() WorkInvitee.insert_many((dict(record=record, orcid="123112311231%d" % i, first_name="Test_%d" % i, last_name="Test_%d" % i, put_code=i, status="Test_%d" % i, identifier="%d" % i, visibility="Test_%d" % i, email="Test_%d" % i) for i in range(10))).execute() yield testdb
def test_create_or_update_resource(app, mocker): """Test research resources.""" mocker.patch.multiple("orcid_hub.app.logger", error=DEFAULT, exception=DEFAULT, info=DEFAULT) org = Organisation.get(name="THE ORGANISATION") user = User.create(orcid="1001-0001-0001-0001", name="TEST USER 123", email="*****@*****.**", organisation=org, confirmed=True) UserOrg.create(user=user, org=org, affiliation=Affiliation.EDU) api = MemberAPIV3(user=user, org=org, access_token="ACCESS000") assert api.api_client.configuration.access_token == 'ACCESS000' OrcidToken.create(access_token="ACCESS123", user=user, org=org, scopes="/read-limited,/activities/update", expires_in='121') api = MemberAPIV3(user=user, org=org) assert api.api_client.configuration.access_token == "ACCESS123" # Test API call auditing: request_mock = mocker.patch.object( api.api_client.rest_client.pool_manager, "request", MagicMock(return_value=Mock(headers=HTTPHeaderDict({ 'Server': 'nginx/1.10.0', 'Date': 'Wed, 26 Jun 2019 05:26:32 GMT', 'Content-Type': 'application/json;charset=UTF-8', 'Content-Length': '0', 'Connection': 'keep-alive', 'Access-Control-Allow-Origin': '*', 'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'X-XSS-Protection': '1; mode=block', 'X-Frame-Options': 'DENY', 'X-Content-Type-Options': 'nosniff', 'Location': f'http://api.sandbox.orcid.org/v3.0/{user.orcid}/research-resource/2052' }), data=b'', status=201))) hosts = [ dict( name="TEST HOST", city="Auckland", country="NZ", disambiguated_id="3232", disambiguation_source="RINGGOLD", ) ] external_ids = [dict(value="ABC123", type="agr", relationship="self")] put_code, orcid, created, _ = api.create_or_update_resource( title="TEST", hosts=hosts, external_ids=external_ids, items=[{ "name": "TEST", "type": "equipment", "hosts": hosts, "external_ids": external_ids, }], display_index=999, visibility="public", ) request_mock.assert_called_once() assert put_code == 2052 assert orcid == user.orcid
def test_create_tables(models): drop_tables() create_tables() assert User.table_exists() assert Organisation.table_exists() assert UserOrg.table_exists()
def test_webhook_registration(client): """Test webhook registration.""" test_client = client user = User.get(email="*****@*****.**") test_client.login(user) org = user.organisation orcid_id = "0000-0000-0000-00X3" client = Client.get(org=org) resp = test_client.post("/oauth/token", method="POST", data=dict(grant_type="client_credentials", client_id=client.client_id, client_secret=client.client_secret, scope="/webhook")) assert resp.status_code == 200 data = json.loads(resp.data) token = Token.get(user=user, _scopes="/webhook") client = Client.get(client_id="CLIENT_ID") token = Token.get(client=client) assert data["access_token"] == token.access_token assert data["expires_in"] == test_client.application.config[ "OAUTH2_PROVIDER_TOKEN_EXPIRES_IN"] assert data["token_type"] == token.token_type # prevously created access token should be removed resp = test_client.put( "/api/v1.0/INCORRECT/webhook/http%3A%2F%2FCALL-BACK", headers=dict(authorization=f"Bearer {token.access_token}")) assert resp.status_code == 415 assert json.loads(resp.data)["error"] == "Missing or invalid ORCID iD." resp = test_client.put( "/api/v1.0/0000-0001-8228-7153/webhook/http%3A%2F%2FCALL-BACK", headers=dict(authorization=f"Bearer {token.access_token}")) assert resp.status_code == 404 assert json.loads(resp.data)["error"] == "Invalid ORCID iD." resp = test_client.put( f"/api/v1.0/{orcid_id}/webhook/INCORRECT-WEBHOOK-URL", headers=dict(authorization=f"Bearer {token.access_token}")) assert resp.status_code == 415 assert json.loads(resp.data) == { "error": "Invalid call-back URL", "message": "Invalid call-back URL: INCORRECT-WEBHOOK-URL" } with patch("orcid_hub.utils.requests.post") as mockpost, patch( "orcid_hub.utils.requests.put") as mockput: # Access toke request resp: mockresp = MagicMock(status_code=201) mockresp.json.return_value = { "access_token": "ACCESS-TOKEN-123", "token_type": "bearer", "refresh_token": "REFRESH-TOKEN-123", "expires_in": 99999, "scope": "/webhook", "orcid": None } mockpost.return_value = mockresp # Webhook registration response: mockresp = MagicMock(status_code=201, data=b'') mockresp.headers = { "Server": "TEST123", "Connection": "keep-alive", "Pragma": "no-cache", "Expires": "0", } mockput.return_value = mockresp resp = test_client.put( f"/api/v1.0/{orcid_id}/webhook/http%3A%2F%2FCALL-BACK", headers=dict(authorization=f"Bearer {token.access_token}")) assert resp.status_code == 201 args, kwargs = mockpost.call_args assert args[0] == "https://sandbox.orcid.org/oauth/token" assert kwargs["data"] == { "client_id": "APP-12345678", "client_secret": "CLIENT-SECRET", "scope": "/webhook", "grant_type": "client_credentials" } assert kwargs["headers"] == {"Accept": "application/json"} args, kwargs = mockput.call_args assert args[ 0] == "https://api.sandbox.orcid.org/0000-0000-0000-00X3/webhook/http%3A%2F%2FCALL-BACK" assert kwargs["headers"] == { "Accept": "application/json", "Authorization": "Bearer ACCESS-TOKEN-123", "Content-Length": "0" } q = OrcidToken.select().where(OrcidToken.org == org, OrcidToken.scope == "/webhook") assert q.count() == 1 orcid_token = q.first() assert orcid_token.access_token == "ACCESS-TOKEN-123" assert orcid_token.refresh_token == "REFRESH-TOKEN-123" assert orcid_token.expires_in == 99999 assert orcid_token.scope == "/webhook" with patch("orcid_hub.utils.requests.delete") as mockdelete: # Webhook deletion response: mockresp = MagicMock(status_code=204, data=b'') mockresp.headers = { "Seresper": "TEST123", "Connection": "keep-alive", "Location": "TEST-LOCATION", "Pragma": "no-cache", "Expires": "0", } mockdelete.return_value = mockresp resp = test_client.delete( f"/api/v1.0/{orcid_id}/webhook/http%3A%2F%2FCALL-BACK", headers=dict(authorization=f"Bearer {token.access_token}")) assert resp.status_code == 204 assert urlparse( resp.location ).path == f"/api/v1.0/{orcid_id}/webhook/http://TEST-LOCATION" args, kwargs = mockput.call_args assert args[ 0] == "https://api.sandbox.orcid.org/0000-0000-0000-00X3/webhook/http%3A%2F%2FCALL-BACK" assert kwargs["headers"] == { "Accept": "application/json", "Authorization": "Bearer ACCESS-TOKEN-123", "Content-Length": "0" } q = OrcidToken.select().where(OrcidToken.org == org, OrcidToken.scope == "/webhook") assert q.count() == 1 token = q.first() assert token.access_token == "ACCESS-TOKEN-123" assert token.refresh_token == "REFRESH-TOKEN-123" assert token.expires_in == 99999 assert token.scope == "/webhook"
def test_user_and_token_api(app_req_ctx, resource, version): """Test the echo endpoint.""" user = User.get(email="*****@*****.**") org2_user = User.get(email="*****@*****.**") with app_req_ctx(f"/api/{version}/{resource}/ABC123", headers=dict(authorization="Bearer TEST")) as ctx: resp = ctx.app.full_dispatch_request() assert resp.status_code == 400 data = json.loads(resp.data) assert "error" in data assert "incorrect identifier" in data["error"].lower() with app_req_ctx(f"/api/{version}/{resource}/0000-0000-0000-0000", headers=dict(authorization="Bearer TEST")) as ctx: resp = ctx.app.full_dispatch_request() assert resp.status_code == 400 data = json.loads(resp.data) assert "error" in data assert "incorrect identifier" in data["error"].lower() with app_req_ctx(f"/api/{version}/{resource}/[email protected]", headers=dict(authorization="Bearer TEST")) as ctx: resp = ctx.app.full_dispatch_request() assert resp.status_code == 404 data = json.loads(resp.data) assert "error" in data assert "not found" in data["error"].lower() with app_req_ctx(f"/api/{version}/{resource}/0000-0000-0000-0001", headers=dict(authorization="Bearer TEST")) as ctx: resp = ctx.app.full_dispatch_request() assert resp.status_code == 404 data = json.loads(resp.data) assert "error" in data assert "not found" in data["error"].lower() for identifier in [ user.email, user.orcid, ]: with app_req_ctx(f"/api/{version}/{resource}/{identifier}", headers=dict(authorization="Bearer TEST")) as ctx: resp = ctx.app.full_dispatch_request() data = json.loads(resp.data) assert resp.status_code == 200 data = json.loads(resp.data) if resource == "users": assert data["email"] == user.email assert data["eppn"] == user.eppn assert data["orcid"] == user.orcid else: token = OrcidToken.get(user_id=user.id) assert data["access_token"] == token.access_token if resource == "users": # test user listing with app_req_ctx(f"/api/{version}/{resource}", headers=dict(authorization="Bearer TEST")) as ctx: resp = ctx.app.full_dispatch_request() data = json.loads(resp.data) assert resp.status_code == 200 data = json.loads(resp.data) assert len(data) == 11 with app_req_ctx(f"/api/{version}/{resource}?page=2&page_size=3", headers=dict(authorization="Bearer TEST")) as ctx: resp = ctx.app.full_dispatch_request() data = json.loads(resp.data) assert resp.status_code == 200 data = json.loads(resp.data) assert len(data) == 3 with app_req_ctx(f"/api/{version}/{resource}?page_size=3", headers=dict(authorization="Bearer TEST")) as ctx: resp = ctx.app.full_dispatch_request() data = json.loads(resp.data) assert resp.status_code == 200 data = json.loads(resp.data) assert len(data) == 3 with app_req_ctx(f"/api/{version}/{resource}?page=42", headers=dict(authorization="Bearer TEST")) as ctx: resp = ctx.app.full_dispatch_request() data = json.loads(resp.data) assert resp.status_code == 200 data = json.loads(resp.data) assert len(data) == 0 with app_req_ctx(f"/api/{version}/{resource}?from_date=ABCD", headers=dict(authorization="Bearer TEST")) as ctx: resp = ctx.app.full_dispatch_request() data = json.loads(resp.data) assert resp.status_code == 422 with app_req_ctx(f"/api/{version}/{resource}?from_date=2018-01-01", headers=dict(authorization="Bearer TEST")) as ctx: resp = ctx.app.full_dispatch_request() data = json.loads(resp.data) assert resp.status_code == 200 data = json.loads(resp.data) assert len(data) == 4 with app_req_ctx(f"/api/{version}/{resource}?to_date=2018-01-01", headers=dict(authorization="Bearer TEST")) as ctx: resp = ctx.app.full_dispatch_request() data = json.loads(resp.data) assert resp.status_code == 200 data = json.loads(resp.data) assert len(data) == 7 with app_req_ctx( f"/api/{version}/{resource}?from_date=2017-12-20&to_date=2017-12-21", headers=dict(authorization="Bearer TEST")) as ctx: resp = ctx.app.full_dispatch_request() data = json.loads(resp.data) assert resp.status_code == 200 data = json.loads(resp.data) assert len(data) == 2 if resource == "tokens": user2 = User.get(email="*****@*****.**") for identifier in [ user2.email, user2.orcid, ]: with app_req_ctx(f"/api/{version}/tokens/{identifier}", headers=dict(authorization="Bearer TEST")) as ctx: resp = ctx.app.full_dispatch_request() assert resp.status_code == 404 data = json.loads(resp.data) assert "error" in data with app_req_ctx(f"/api/{version}/{resource}/{org2_user.email}", headers=dict(authorization="Bearer TEST")) as ctx: resp = ctx.app.full_dispatch_request() assert resp.status_code == 404 data = json.loads(resp.data) assert "error" in data
def test_onboard_org(client): """Test to organisation onboarding.""" org = Organisation.create(name="THE ORGANISATION:test_onboard_org", tuakiri_name="THE ORGANISATION:test_onboard_org", confirmed=False, orcid_client_id="CLIENT ID", orcid_secret="Client Secret", city="CITY", country="COUNTRY", disambiguated_id="ID", disambiguation_source="RINGGOLD", is_email_sent=True) u = User.create(email="*****@*****.**", name="TEST USER", roles=Role.TECHNICAL, orcid="123", confirmed=True, organisation=org) second_user = User.create(email="*****@*****.**", name="TEST USER", roles=Role.ADMIN, orcid="1243", confirmed=True, organisation=org) UserOrg.create(user=second_user, org=org, is_admin=True) org_info = OrgInfo.create(name="A NEW ORGANISATION", tuakiri_name="A NEW ORGANISATION") org.tech_contact = u org_info.save() org.save() client.login_root() with patch("orcid_hub.utils.send_email"): resp = client.post("/invite/organisation", data=dict(org_name="A NEW ORGANISATION", org_email="*****@*****.**"), follow_redirects=True) assert User.select().where( User.email == "*****@*****.**").exists() resp = client.post("/invite/organisation", data=dict(org_name="A NEW ORGANISATION", org_email="*****@*****.**", tech_contact='y'), follow_redirects=True) assert User.select().where( User.email == "*****@*****.**").exists() org = Organisation.get(name="A NEW ORGANISATION") user = User.get(email="*****@*****.**") assert user.name is None assert org.tech_contact == user client.logout() resp = client.login(user, **{ "Sn": "TECHNICAL", "Givenname": "CONTACT", "Displayname": "Test User", "shib_O": "NEW ORGANISATION" }, follow_redirects=True) user = User.get(email="*****@*****.**") org = user.organisation assert user.is_tech_contact_of(org) resp = client.get("/confirm/organisation") assert resp.status_code == 200 org = Organisation.get(org.id) assert b"<!DOCTYPE html>" in resp.data, "Expected HTML content" assert b"Take me to ORCID to obtain my Client ID and Client Secret" in resp.data with patch("orcid_hub.authcontroller.requests") as requests: requests.post.return_value = Mock(data=b'XXXX', status_code=200) resp = client.post("/confirm/organisation", data={ "orcid_client_id": "APP-1234567890ABCDEF", "orcid_secret": "12345678-1234-1234-1234-1234567890ab", "country": "NZ", "city": "Auckland", "disambiguated_id": "XYZ123", "disambiguation_source": "RINGGOLD", "name": org.name, "email": user.email, }) assert resp.status_code == 302 url = urlparse(resp.location).path assert url == "/link" resp = client.get(url) client.logout() org = Organisation.get(org.id) assert org.disambiguated_id == "XYZ123" assert org.disambiguation_source == "RINGGOLD" assert org.orcid_client_id == "APP-1234567890ABCDEF" assert org.orcid_secret == "12345678-1234-1234-1234-1234567890ab" user = User.get(email="*****@*****.**") resp = client.login(user, **{ "Sn": "NEW ORGANISATION", "Givenname": "ADMINISTRATOR", "Displayname": "Admin User", "shib_O": "NEW ORGANISATION" }, follow_redirects=True) assert b"Take me to ORCID to allow A NEW ORGANISATION permission to access my ORCID record" in resp.data resp = client.get("/confirm/organisation") assert resp.status_code == 302 assert urlparse(resp.location).path == "/admin/viewmembers/" resp = client.get("/admin/viewmembers/") assert b"*****@*****.**" in resp.data resp = client.get("/admin/viewmembers/export/csv/") assert resp.headers["Content-Type"] == "text/csv; charset=utf-8" assert b"*****@*****.**" in resp.data assert b"*****@*****.**" in resp.data
def test_process_tasks(request_ctx): """Test expiration data setting and deletion of the exprired tasks.""" org = Organisation.get(name="TEST0") super_user = User.get(email="*****@*****.**") with patch("orcid_hub.utils.send_email") as send_email, request_ctx( "/") as ctx: login_user(super_user) # flake8: noqa task = Task.load_from_csv( """First name Last name email address Organisation Campus/Department City Course or Job title\tStart date End date Student/Staff\tCountry FNA LBA [email protected] TEST1 Research Funding Wellington Programme Manager - ORCID 2016-09 Staff\tNew Zealand """, filename="TEST_TASK.tsv", org=org) Task.update(created_at=datetime(1999, 1, 1), updated_at=datetime(1999, 1, 1)).execute() utils.process_tasks() assert Task.select().count() == 1 assert not Task.select().where(Task.expires_at.is_null()).exists() send_email.assert_called_once() task = Task.select().first() args, kwargs = send_email.call_args assert "email/task_expiration.html" in args assert kwargs["error_count"] == 0 hostname = ctx.request.host assert kwargs["export_url"].endswith( f"//{hostname}/admin/affiliationrecord/export/csv/?task_id={task.id}" ) assert kwargs["recipient"] == ( super_user.name, super_user.email, ) assert kwargs["subject"] == "Batch process task is about to expire" assert kwargs["task"] == task # After the second go everything should be deleted utils.process_tasks() assert Task.select().count() == 0 # Funding processing task: task = Task.create(created_at=datetime(1999, 1, 1), org=org, filename="FUNDING.json", created_by=super_user, updated_by=super_user, task_type=TaskType.FUNDING.value) Task.update(updated_at=datetime(1999, 1, 1)).execute() assert Task.select().where(Task.expires_at.is_null()).count() == 1 utils.process_tasks() assert Task.select().count() == 1 assert Task.select().where(Task.expires_at.is_null()).count() == 0 utils.process_tasks() assert Task.select().count() == 0 args, kwargs = send_email.call_args assert "email/task_expiration.html" in args assert kwargs["error_count"] == 0 hostname = ctx.request.host assert kwargs["export_url"].endswith( f"//{hostname}/admin/fundingrecord/export/csv/?task_id={task.id}") assert kwargs["recipient"] == ( super_user.name, super_user.email, ) assert kwargs["subject"] == "Batch process task is about to expire" assert kwargs["task"] == task # Incorrect task type: task = Task.create(created_at=datetime(1999, 1, 1), org=org, filename="ERROR.err", created_by=super_user, updated_by=super_user, task_type=-12345) Task.update(updated_at=datetime(1999, 1, 1)).execute() with pytest.raises(Exception, message="Unexpeced task type: -12345 (ERROR.err)."): utils.process_tasks() task.delete().execute() # Cover case with an exterenal SP: with patch("orcid_hub.utils.EXTERNAL_SP", "SOME.EXTERNAL.SP"): Task.create(created_at=datetime(1999, 1, 1), org=org, filename="FILE.file", created_by=super_user, updated_by=super_user) Task.update(updated_at=datetime(1999, 1, 1)).execute() assert Task.select().count() == 1 utils.process_tasks() utils.process_tasks() assert Task.select().count() == 0