def test_orcid_login_callback_researcher_flow(patch, patch2, request_ctx): """Test login from orcid callback function for researcher and display profile.""" org = Organisation.create(name="THE ORGANISATION", tuakiri_name="THE ORGANISATION", confirmed=True, orcid_client_id="CLIENT ID", orcid_secret="Client Secret", city="CITY", country="COUNTRY", disambiguated_id="ID", disambiguation_source="SOURCE", is_email_sent=True) u = User.create(email="*****@*****.**", name="TEST USER", roles=Role.RESEARCHER, orcid="123", confirmed=True, organisation=org) UserOrg.create(user=u, org=org, is_admin=False) token = utils.generate_confirmation_token(email=u.email, org=org.name) UserInvitation.create(email=u.email, token=token, affiliations=Affiliation.EMP) OrcidToken.create(user=u, org=org, scope='/read-limited,/activities/update') with request_ctx(): request.args = {"invitation_token": token, "state": "xyz"} session['oauth_state'] = "xyz" resp = authcontroller.orcid_login_callback(request) assert resp.status_code == 302 # display profile assert resp.location.startswith("/profile")
def test_profile(client): """Test an affilated user profile and ORCID data retrieval and a user profile that doesn't hava an ORCID.""" org = Organisation.get(name="THE ORGANISATION") test_user = User.create(email="*****@*****.**", organisation=org, orcid="ABC123", confirmed=True) OrcidToken.create(user=test_user, org=org, scope="/read-limited,/activities/update", access_token="ABC1234") resp = client.login(test_user, follow_redirects=True) resp = client.get("/profile", follow_redirects=True) assert resp.status_code == 200 assert b"ABC123" in resp.data client.logout() # Test a user profile that doesn't hava an ORCID. user = User.select().where(User.organisation == org, User.orcid.is_null()).first() resp = client.login(user, follow_redirects=True) resp = client.get("/profile") assert resp.status_code == 302 assert "/link" in resp.location
def test_link_orcid_auth_callback(name, request_ctx): """Test ORCID callback - the user authorized the organisation access to the ORCID profile.""" with request_ctx("/auth?state=xyz") as ctx: org = Organisation(name="THE ORGANISATION", confirmed=True) org.save() test_user = User.create( name=name, email="*****@*****.**", organisation=org, orcid="ABC123", confirmed=True) orcidtoken = OrcidToken.create( user=test_user, org=org, scope="/read-limited,/activities/update", access_token="ABC1234") login_user(test_user, remember=True) session['oauth_state'] = "xyz" rv = ctx.app.full_dispatch_request() assert rv.status_code == 302, "If the user is already affiliated, the user should be redirected ..." assert "profile" in rv.location, "redirection to 'profile' showing the ORCID" u = User.get(id=test_user.id) orcidtoken = OrcidToken.get(user=u) assert u.orcid == "ABC-123-456-789" assert orcidtoken.access_token == "ABC1234" if name: assert u.name == name, "The user name should be changed" else: assert u.name == "NEW TEST", "the user name should be set from record coming from ORCID"
def test_get_client_credentials_token(request_ctx): """Test retrieval of the webhook tokens.""" with request_ctx("/"), patch("orcid_hub.utils.requests.post") as mockpost: admin = User.get(email="*****@*****.**") org = admin.organisation login_user(admin) 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 OrcidToken.create( org=org, access_token="access_token", refresh_token="refresh_token", scopes="/webhook" ) token = utils.get_client_credentials_token(org, "/webhook") assert ( OrcidToken.select() .where(OrcidToken.org == org, OrcidToken.scopes == "/webhook") .count() == 1 ) assert token.access_token == "ACCESS-TOKEN-123" assert token.refresh_token == "REFRESH-TOKEN-123" assert token.expires_in == 99999 assert token.scopes == "/webhook"
def test_test_database(models): """Test of the consitency of the test database.""" assert Organisation.select().count() == 10 assert User.select().count() == 63 assert OrcidToken.select().count() == 60 assert AffiliationRecord.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 ResearcherUrlRecord.select().count() == 10 assert OtherNameRecord.select().count() == 10 assert KeywordRecord.select().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() == 1 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() == 10 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, scope="S1,S2,S3") assert len(ot.scopes) == 3 ot.scopes = ["A", "B", "C", "D"] assert ot.scope == "A,B,C,D"
def test_process_other_id_records(app, mocker): """Test create or update researcher other id.""" mocker.patch("orcid_hub.utils.send_email", send_mail_mock) mocker.patch( "orcid_api_v3.api.DevelopmentMemberAPIV30Api.create_external_identifierv3", create_or_update_fund_mock) mocker.patch("orcid_hub.orcid_client.MemberAPIV3.get_record", return_value=get_profile()) org = app.data["org"] u = User.create(email="*****@*****.**", name="TEST USER", roles=Role.RESEARCHER, orcid="12344", confirmed=True, organisation=org) UserOrg.create(user=u, org=org) t = Task.create(org=org, filename="xyz.json", created_by=u, updated_by=u, task_type=TaskType.OTHER_ID) OtherIdRecord.create(task=t, type="grant_number", value="xyz", url="https://xyz.com", relationship="SELF", is_active=True, status="email sent", first_name="Test", last_name="Test", email="*****@*****.**", visibility="PUBLIC", display_index=1) UserInvitation.create(invitee=u, inviter=u, org=org, task=t, email="*****@*****.**", token="xyztoken") OrcidToken.create(user=u, org=org, scopes="/read-limited,/person/update", access_token="Test_token") utils.process_other_id_records() record = OtherIdRecord.get(email="*****@*****.**") assert 12399 == record.put_code assert "12344" == record.orcid
def test_link_already_affiliated(request_ctx): """Test a user affiliation initialization if the uerer is already affilated.""" with request_ctx("/link") as ctx: org = Organisation.get(name="THE ORGANISATION") test_user = User( email="*****@*****.**", name="TEST USER", organisation=org, orcid="ABC123", confirmed=True) test_user.save() orcidtoken = OrcidToken( user=test_user, org=org, scopes="/read-limited", access_token="ABC1234") orcidtoken_write = OrcidToken( user=test_user, org=org, scopes="/read-limited,/activities/update", access_token="ABC234") orcidtoken.save() orcidtoken_write.save() login_user(test_user, remember=True) uo = UserOrg(user=test_user, org=org) uo.save() rv = ctx.app.full_dispatch_request() assert rv.status_code == 302, "If the user is already affiliated, the user should be redirected ..." assert "profile" in rv.location, "redirection to 'profile' showing the ORCID"
def test_sync_profile(app, mocker): """Test sync_profile.""" mocker.patch("orcid_api.MemberAPIV20Api.update_employment", return_value=Mock(status=201, headers={'Location': '12344/XYZ/54321'})) mocker.patch("orcid_api.MemberAPIV20Api.update_education", return_value=Mock(status=201, headers={'Location': '12344/XYZ/12345'})) org = Organisation.create( name="THE ORGANISATION:test_sync_profile", tuakiri_name="THE ORGANISATION:test_sync_profile", confirmed=True, orcid_client_id="APP-5ZVH4JRQ0C27RVH5", orcid_secret="Client Secret", city="CITY", country="COUNTRY", disambiguated_id="ID", disambiguation_source="SOURCE") u = User.create(email="*****@*****.**", name="TEST USER", roles=Role.RESEARCHER, orcid="12344", confirmed=True, organisation=org) UserOrg.create(user=u, org=org) access_token = "ACCESS-TOKEN" t = Task.create(org=org, task_type=TaskType.SYNC) api = MemberAPI(org=org) mocker.patch("orcid_hub.orcid_client.MemberAPI.get_record", lambda *args: None) api.sync_profile(task=t, user=u, access_token=access_token) OrcidToken.create(user=u, org=org, scope="/read-limited,/activities/update") mocker.patch("orcid_hub.orcid_client.MemberAPI.get_record", lambda *args: None) api.sync_profile(task=t, user=u, access_token=access_token) assert Log.select().count() > 0 mocker.patch("orcid_hub.orcid_client.MemberAPI.get_record", return_value=get_profile()) api.sync_profile(task=t, user=u, access_token=access_token) last_log = Log.select().order_by(Log.id.desc()).first() assert "Successfully update" in last_log.message
def test_link_orcid_auth_callback(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"], expires_in="1212", refresh_token="ABC1235")) 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.NONE) client.login(test_user) User.update(name=name).execute() resp = client.get("/link") state = session['oauth_state'] resp = client.get(f"/auth?state={state}") assert resp.status_code == 302, "If the user is already affiliated, the user should be redirected ..." assert "profile" in resp.location, "redirection to 'profile' showing the ORCID" u = User.get(id=test_user.id) orcidtoken = OrcidToken.get(user=u) assert u.orcid == "ABC-123-456-789" assert orcidtoken.access_token == "ABC123" if name: assert u.name == name, "The user name should be changed" else: assert u.name == "NEW TEST", "the user name should be set from record coming from ORCID"
def test_link_orcid_auth_callback_with_affiliation(name, request_ctx): """Test ORCID callback - the user authorized the organisation access to the ORCID profile.""" with patch("orcid_hub.orcid_client.MemberAPI") as m, patch( "orcid_hub.orcid_client.SourceClientId"), request_ctx("/auth?state=xyz") as ctx: org = Organisation.create( name="THE ORGANISATION", confirmed=True, orcid_client_id="CLIENT ID", city="CITY", country="COUNTRY", disambiguated_id="ID", disambiguation_source="SOURCE") 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) login_user(test_user, remember=True) session['oauth_state'] = "xyz" api_mock = m.return_value ctx.app.full_dispatch_request() 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), ])
def test_profile(request_ctx): """Test an affilated user profile and ORCID data retrieval.""" with request_ctx("/profile") as ctx: org = Organisation(name="THE ORGANISATION", confirmed=True) org.save() test_user = User( email="*****@*****.**", organisation=org, orcid="ABC123", confirmed=True) test_user.save() orcidtoken = OrcidToken( user=test_user, org=org, scope="/read-limited,/activities/update", access_token="ABC1234") orcidtoken.save() login_user(test_user, remember=True) rv = ctx.app.full_dispatch_request() assert rv.status_code == 200 assert b"ABC123" in rv.data
def test_link_orcid_auth_callback_with_affiliation(name, request_ctx): """Test ORCID callback - the user authorized the organisation access to the ORCID profile.""" with patch("orcid_hub.orcid_client.MemberAPI") as m, patch( "orcid_hub.orcid_client.SourceClientId"), request_ctx( "/auth?state=xyz") as ctx: 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) login_user(test_user, remember=True) session['oauth_state'] = "xyz" api_mock = m.return_value ctx.app.full_dispatch_request() 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() resp = ctx.app.full_dispatch_request() 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"
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_once_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_once() 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") 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)) 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)) api.get_record() app.logger.error.assert_called_with("ApiException Occurred: (401)\nReason: FAILURE\n") 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_create_or_update_funding(app, mocker): """Test create or update funding.""" mocker.patch("orcid_hub.utils.send_email", send_mail_mock) mocker.patch( "orcid_api_v3.api.DevelopmentMemberAPIV30Api.create_fundingv3", create_or_update_fund_mock) org = app.data["org"] mocker.patch("orcid_hub.orcid_client.MemberAPIV3.get_record", return_value=get_profile(org=org)) u = User.create(email="*****@*****.**", name="TEST USER", roles=Role.RESEARCHER, orcid="123", confirmed=True, organisation=org) UserOrg.create(user=u, org=org) t = Task.create(org=org, filename="xyz.json", created_by=u, updated_by=u, task_type=TaskType.FUNDING) fr = FundingRecord.create(task=t, title="Test titile", translated_title="Test title", translated_title_language_code="hi", type="GRANT", organization_defined_type="Test org", short_description="Test desc", amount="1000", currency="USD", org_name="Test_orgname", city="Test city", region="Test", url="url", start_date=PartialDate.create("2003-07-14"), end_date=PartialDate.create("2004-07-14"), country="NZ", disambiguated_id="Test_dis", disambiguation_source="Test_source", is_active=True) FundingInvitee.create(record=fr, first_name="Test", email="*****@*****.**", visibility="PUBLIC", orcid="123") ExternalId.create(record=fr, type="Test_type", value="Test_value", url="Test", relationship="SELF") FundingContributor.create(record=fr, orcid="1213", role="LEAD", name="Contributor", email="*****@*****.**") UserInvitation.create(invitee=u, inviter=u, org=org, task=t, email="*****@*****.**", token="xyztoken") OrcidToken.create(user=u, org=org, scopes="/read-limited,/activities/update", access_token="Test_token") utils.process_funding_records() funding_invitees = FundingInvitee.get(orcid="12344") assert 12399 == funding_invitees.put_code assert "12344" == funding_invitees.orcid
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.MemberAPI") 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(f"/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(f"/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_user_and_token_api(client, resource, version): """Test the echo endpoint.""" user = User.get(email="*****@*****.**") org2_user = User.get(email="*****@*****.**") resp = client.get(f"/api/{version}/{resource}/ABC123", headers=dict(authorization="Bearer TEST")) assert resp.status_code == 400 assert "error" in resp.json assert "incorrect identifier" in resp.json["error"].lower() resp = client.get(f"/api/{version}/{resource}/0000-0000-0000-0000", headers=dict(authorization="Bearer TEST")) assert resp.status_code == 400 assert "error" in resp.json assert "incorrect identifier" in resp.json["error"].lower() resp = client.get(f"/api/{version}/{resource}/[email protected]", headers=dict(authorization="Bearer TEST")) assert resp.status_code == 404 assert "error" in resp.json assert "not found" in resp.json["error"].lower() resp = client.get(f"/api/{version}/{resource}/0000-0000-0000-0001", headers=dict(authorization="Bearer TEST")) assert resp.status_code == 404 assert "error" in resp.json assert "not found" in resp.json["error"].lower() for identifier in [ user.email, user.orcid, ]: resp = client.get(f"/api/{version}/{resource}/{identifier}", headers=dict(authorization="Bearer TEST")) assert resp.status_code == 200 if resource == "users": assert resp.json["email"] == user.email assert resp.json["eppn"] == user.eppn assert resp.json["orcid"] == user.orcid else: token = OrcidToken.get(user_id=user.id) assert resp.json["access_token"] == token.access_token if resource == "users": # test user listing resp = client.get(f"/api/{version}/{resource}", headers=dict(authorization="Bearer TEST")) assert resp.status_code == 200 assert len(resp.json) == 11 resp = client.get( f"/api/{version}/{resource}?page=INVALID&page_size=INVALID", headers=dict(authorization="Bearer TEST")) assert resp.status_code == 200 assert len(resp.json) == 11 resp = client.get(f"/api/{version}/{resource}?page=2&page_size=3", headers=dict(authorization="Bearer TEST")) assert resp.status_code == 200 assert len(resp.json) == 3 resp = client.get(f"/api/{version}/{resource}?page_size=3", headers=dict(authorization="Bearer TEST")) assert resp.status_code == 200 assert len(resp.json) == 3 resp = client.get(f"/api/{version}/{resource}?page=42", headers=dict(authorization="Bearer TEST")) assert resp.status_code == 200 assert len(resp.json) == 0 resp = client.get(f"/api/{version}/{resource}?from_date=ABCD", headers=dict(authorization="Bearer TEST")) assert resp.status_code == 422 resp = client.get(f"/api/{version}/{resource}?from_date=2018-01-01", headers=dict(authorization="Bearer TEST")) assert resp.status_code == 200 assert len(resp.json) == 4 resp = client.get(f"/api/{version}/{resource}?to_date=2018-01-01", headers=dict(authorization="Bearer TEST")) assert resp.status_code == 200 assert len(resp.json) == 7 resp = client.get( f"/api/{version}/{resource}?from_date=2017-12-20&to_date=2017-12-21", headers=dict(authorization="Bearer TEST")) assert resp.status_code == 200 assert len(resp.json) == 2 if resource == "tokens": user2 = User.get(email="*****@*****.**") for identifier in [ user2.email, user2.orcid, ]: resp = client.get(f"/api/{version}/tokens/{identifier}", headers=dict(authorization="Bearer TEST")) assert resp.status_code == 404 assert "error" in resp.json resp = client.get(f"/api/{version}/{resource}/{org2_user.email}", headers=dict(authorization="Bearer TEST")) assert resp.status_code == 404 assert "error" in resp.json
def test_create_or_update_work(app, mocker): """Test create or update work.""" mocker.patch("orcid_hub.utils.send_email", send_mail_mock) mocker.patch("orcid_api_v3.api.DevelopmentMemberAPIV30Api.create_workv3", create_or_update_fund_mock) org = app.data["org"] mocker.patch("orcid_hub.orcid_client.MemberAPIV3.get_record", return_value=get_profile(org=org)) u = User.create(email="*****@*****.**", name="TEST USER", roles=Role.RESEARCHER, orcid="12344", confirmed=True, organisation=org) UserOrg.create(user=u, org=org) t = Task.create(org=org, filename="xyz.json", created_by=u, updated_by=u, task_type=TaskType.WORK) wr = WorkRecord.create(task=t, title="Test titile", subtitle="Test titile", translated_title="Test title", translated_title_language_code="hi", journal_title="Test titile", short_description="Test desc", citation_type="bibtex", citation_value="Test", type="BOOK_CHAPTER", publication_date=PartialDate.create("2003-07-14"), url="Test org", language_code="en", country="NZ", org_name="Test_orgname", city="Test city", region="Test", is_active=True) WorkInvitee.create(record=wr, first_name="Test", email="*****@*****.**", orcid="12344", visibility="PUBLIC") WorkExternalId.create(record=wr, type="Test_type", value="Test_value", url="Test", relationship="SELF") WorkContributor.create(record=wr, contributor_sequence="first", orcid="1213", role="author", name="xyz", email="*****@*****.**") UserInvitation.create(invitee=u, inviter=u, org=org, task=t, email="*****@*****.**", token="xyztoken") OrcidToken.create(user=u, org=org, scopes="/read-limited,/activities/update", access_token="Test_token") utils.process_work_records() invitee = WorkInvitee.get(orcid="12344") assert 12399 == invitee.put_code assert "12344" == invitee.orcid
def test_create_or_update_peer_review(email_patch, patch, test_db, request_ctx): """Test create or update peer review.""" org = Organisation.create(name="THE ORGANISATION", tuakiri_name="THE ORGANISATION", confirmed=True, orcid_client_id="APP-5ZVH4JRQ0C27RVH5", orcid_secret="Client Secret", city="CITY", country="COUNTRY", disambiguation_org_id="ID", disambiguation_org_source="SOURCE") u = User.create(email="*****@*****.**", name="TEST USER", username="******", roles=Role.RESEARCHER, orcid="12344", confirmed=True, organisation=org) UserOrg.create(user=u, org=org) t = Task.create(id=12, org=org, filename="xyz.json", created_by=u, updated_by=u, task_type=3) pr = PeerReviewRecord.create(task=t, review_group_id="issn:12131", reviewer_role="reviewer", review_url="xyz", review_type="REVIEW", subject_external_id_type="doi", subject_external_id_value="1212", subject_external_id_url="url/SELF", subject_external_id_relationship="SELF", subject_container_name="Journal title", subject_type="JOURNAL_ARTICLE", subject_name_title="name", subject_name_subtitle="subtitle", subject_name_translated_title_lang_code="en", subject_name_translated_title="sdsd", subject_url="url", convening_org_name="THE ORGANISATION", convening_org_city="auckland", convening_org_region="auckland", convening_org_country="nz", convening_org_disambiguated_identifier="123", convening_org_disambiguation_source="1212", is_active=True) PeerReviewInvitee.create(peer_review_record=pr, first_name="Test", email="*****@*****.**", orcid="12344", visibility="PUBLIC") PeerReviewExternalId.create(peer_review_record=pr, type="Test_type", value="122334_different", url="Test", relationship="SELF") UserInvitation.create(invitee=u, inviter=u, org=org, task=t, email="*****@*****.**", token="xyztoken") OrcidToken.create(user=u, org=org, scope="/read-limited,/activities/update", access_token="Test_token") utils.process_peer_review_records() peer_review_invitees = PeerReviewInvitee.get(orcid=12344) assert 12399 == peer_review_invitees.put_code assert "12344" == peer_review_invitees.orcid
def test_create_or_update_affiliation(patch, test_db, request_ctx): """Test create or update affiliation.""" org = Organisation.create(name="THE ORGANISATION", tuakiri_name="THE ORGANISATION", confirmed=True, orcid_client_id="APP-5ZVH4JRQ0C27RVH5", orcid_secret="Client Secret", city="CITY", country="COUNTRY", disambiguation_org_id="ID", disambiguation_org_source="SOURCE") u = User.create(email="*****@*****.**", name="TEST USER", username="******", roles=Role.RESEARCHER, orcid="123", confirmed=True, organisation=org) UserOrg.create(user=u, org=org) t = Task.create(org=org, filename="xyz.json", created_by=u, updated_by=u, task_type=0) AffiliationRecord.create(is_active=True, task=t, external_id="Test", first_name="Test", last_name="Test", email="*****@*****.**", orcid="123112311231", organisation="asdasd", affiliation_type="staff", role="Test", department="Test", city="Test", state="Test", country="Test", disambiguated_id="Test", disambiguation_source="Test") UserInvitation.create(invitee=u, inviter=u, org=org, task=t, email="*****@*****.**", token="xyztoken") OrcidToken.create(user=u, org=org, scope="/read-limited,/activities/update", access_token="Test_token") tasks = (Task.select( Task, AffiliationRecord, User, UserInvitation.id.alias("invitation_id"), OrcidToken ).where( AffiliationRecord.processed_at.is_null(), AffiliationRecord.is_active, ((User.id.is_null(False) & User.orcid.is_null(False) & OrcidToken.id.is_null(False)) | ((User.id.is_null() | User.orcid.is_null() | OrcidToken.id.is_null()) & UserInvitation.id.is_null() & (AffiliationRecord.status.is_null() | AffiliationRecord.status.contains("sent").__invert__())))).join( AffiliationRecord, on=(Task.id == AffiliationRecord.task_id)).join( User, JOIN.LEFT_OUTER, on=((User.email == AffiliationRecord.email) | (User.orcid == AffiliationRecord.orcid))).join( Organisation, JOIN.LEFT_OUTER, on=(Organisation.id == Task.org_id)). join(UserInvitation, JOIN.LEFT_OUTER, on=((UserInvitation.email == AffiliationRecord.email) & (UserInvitation.task_id == Task.id))).join( OrcidToken, JOIN.LEFT_OUTER, on=((OrcidToken.user_id == User.id) & (OrcidToken.org_id == Organisation.id) & (OrcidToken.scope.contains("/activities/update")) )).limit(20)) for (task_id, org_id, user), tasks_by_user in groupby( tasks, lambda t: ( t.id, t.org_id, t.affiliation_record.user, )): utils.create_or_update_affiliations(user=user, org_id=org_id, records=tasks_by_user) affiliation_record = AffiliationRecord.get(task=t) assert 12399 == affiliation_record.put_code assert "12344" == affiliation_record.orcid assert "Employment record was updated" in affiliation_record.status
def test_create_or_update_funding(email_patch, patch, test_db, request_ctx): """Test create or update funding.""" org = Organisation.create(name="THE ORGANISATION", tuakiri_name="THE ORGANISATION", confirmed=True, orcid_client_id="APP-5ZVH4JRQ0C27RVH5", orcid_secret="Client Secret", city="CITY", country="COUNTRY", disambiguation_org_id="ID", disambiguation_org_source="SOURCE") u = User.create(email="*****@*****.**", name="TEST USER", username="******", roles=Role.RESEARCHER, orcid="123", confirmed=True, organisation=org) UserOrg.create(user=u, org=org) t = Task.create(org=org, filename="xyz.json", created_by=u, updated_by=u, task_type=1) fr = FundingRecord.create(task=t, title="Test titile", translated_title="Test title", translated_title_language_code="Test", type="GRANT", organization_defined_type="Test org", short_description="Test desc", amount="1000", currency="USD", org_name="Test_orgname", city="Test city", region="Test", country="Test", disambiguated_org_identifier="Test_dis", disambiguation_source="Test_source", is_active=True) FundingInvitees.create(funding_record=fr, first_name="Test", email="*****@*****.**", visibility="PUBLIC", orcid="123") ExternalId.create(funding_record=fr, type="Test_type", value="Test_value", url="Test", relationship="SELF") FundingContributor.create(funding_record=fr, orcid="1213", role="LEAD", name="Contributor", email="*****@*****.**") UserInvitation.create(invitee=u, inviter=u, org=org, task=t, email="*****@*****.**", token="xyztoken") OrcidToken.create(user=u, org=org, scope="/read-limited,/activities/update", access_token="Test_token") utils.process_funding_records() funding_invitees = FundingInvitees.get(orcid=12344) assert 12399 == funding_invitees.put_code assert "12344" == funding_invitees.orcid
def test_create_or_update_work(email_patch, patch, test_db, request_ctx): """Test create or update work.""" org = Organisation.create(name="THE ORGANISATION", tuakiri_name="THE ORGANISATION", confirmed=True, orcid_client_id="APP-5ZVH4JRQ0C27RVH5", orcid_secret="Client Secret", city="CITY", country="COUNTRY", disambiguation_org_id="ID", disambiguation_org_source="SOURCE") u = User.create(email="*****@*****.**", name="TEST USER", username="******", roles=Role.RESEARCHER, orcid="12344", confirmed=True, organisation=org) UserOrg.create(user=u, org=org) t = Task.create(org=org, filename="xyz.json", created_by=u, updated_by=u, task_type=2) wr = WorkRecord.create(task=t, title="Test titile", sub_title="Test titile", translated_title="Test title", translated_title_language_code="Test", journal_title="Test titile", short_description="Test desc", citation_type="Test", citation_value="Test", type="BOOK_CHAPTER", url="Test org", language_code="en", country="Test", org_name="Test_orgname", city="Test city", region="Test", is_active=True) WorkInvitees.create(work_record=wr, first_name="Test", email="*****@*****.**", orcid="12344", visibility="PUBLIC") WorkExternalId.create(work_record=wr, type="Test_type", value="Test_value", url="Test", relationship="SELF") WorkContributor.create(work_record=wr, contributor_sequence="1", orcid="1213", role="LEAD", name="xyz", email="*****@*****.**") UserInvitation.create(invitee=u, inviter=u, org=org, task=t, email="*****@*****.**", token="xyztoken") OrcidToken.create(user=u, org=org, scope="/read-limited,/activities/update", access_token="Test_token") utils.process_work_records() work_invitees = WorkInvitees.get(orcid=12344) assert 12399 == work_invitees.put_code assert "12344" == work_invitees.orcid
def test_orcidtoken_count(test_models): assert OrcidToken.select().count() == 60
def test_create_or_update_peer_review(app, mocker): """Test create or update peer review.""" mocker.patch("orcid_hub.utils.send_email", send_mail_mock) mocker.patch( "orcid_api_v3.api.DevelopmentMemberAPIV30Api.create_peer_reviewv3", create_or_update_fund_mock) org = app.data["org"] mocker.patch("orcid_hub.orcid_client.MemberAPIV3.get_record", return_value=get_profile(org=org)) u = User.create(email="*****@*****.**", name="TEST USER", roles=Role.RESEARCHER, orcid="12344", confirmed=True, organisation=org) UserOrg.create(user=u, org=org) t = Task.create(id=12, org=org, filename="xyz.json", created_by=u, updated_by=u, task_type=TaskType.PEER_REVIEW) pr = PeerReviewRecord.create( task=t, review_group_id="issn:12131", reviewer_role="reviewer", review_url="xyz", review_type="REVIEW", subject_external_id_type="doi", subject_external_id_value="1212", subject_external_id_url="url/SELF", subject_external_id_relationship="SELF", subject_container_name="Journal title", subject_type="JOURNAL_ARTICLE", subject_name_title="name", subject_name_subtitle="subtitle", review_completion_date=PartialDate.create("2003-07-14"), subject_name_translated_title_lang_code="en", subject_name_translated_title="sdsd", subject_url="url", convening_org_name="THE ORGANISATION", convening_org_city="auckland", convening_org_region="auckland", convening_org_country="NZ", convening_org_disambiguated_identifier="123", convening_org_disambiguation_source="1212", is_active=True) PeerReviewInvitee.create(record=pr, first_name="Test", email="*****@*****.**", orcid="12344", visibility="PUBLIC") PeerReviewExternalId.create(record=pr, type="Test_type", value="122334_different", url="Test", relationship="SELF") UserInvitation.create(invitee=u, inviter=u, org=org, task=t, email="*****@*****.**", token="xyztoken") OrcidToken.create(user=u, org=org, scopes="/read-limited,/activities/update", access_token="Test_token") utils.process_peer_review_records() peer_review_invitees = PeerReviewInvitee.get(orcid=12344) assert 12399 == peer_review_invitees.put_code assert "12344" == peer_review_invitees.orcid
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", 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) client = Client.get(client_id="CLIENT_ID") token = Token.select().where(Token.user == user, Token._scopes == "/webhook").first() 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/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/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/{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/{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.scopes == "/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.scopes == "/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/{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/{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.scopes == "/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.scopes == "/webhook"
def test_create_or_update_property_record(app, mocker): """Test create or update researcher keyword, researcher url, other name and country""" mocker.patch("orcid_hub.utils.send_email", send_mail_mock) mocker.patch( "orcid_api_v3.api.DevelopmentMemberAPIV30Api.create_keywordv3", create_or_update_fund_mock) mocker.patch( "orcid_api_v3.api.DevelopmentMemberAPIV30Api.create_researcher_urlv3", create_or_update_fund_mock) mocker.patch( "orcid_api_v3.api.DevelopmentMemberAPIV30Api.create_other_namev3", create_or_update_fund_mock) mocker.patch( "orcid_api_v3.api.DevelopmentMemberAPIV30Api.create_addressv3", create_or_update_fund_mock) mocker.patch("orcid_hub.orcid_client.MemberAPIV3.get_record", return_value=get_profile()) org = app.data["org"] u = User.create(email="*****@*****.**", name="TEST USER", roles=Role.RESEARCHER, orcid="12344", confirmed=True, organisation=org) UserOrg.create(user=u, org=org) OrcidToken.create(user=u, org=org, scopes="/read-limited,/person/update", access_token="Test_token") t = Task.create(id=12, org=org, filename="xyz.json", created_by=u, updated_by=u, task_type=TaskType.PROPERTY) PropertyRecord.create(task=t, type="KEYWORD", is_active=True, status="email sent", first_name="Test", last_name="Test", email="*****@*****.**", visibility="PUBLIC", value="dummy name", display_index=1) PropertyRecord.create(task=t, type="COUNTRY", is_active=True, status="email sent", first_name="Test", last_name="Test", email="*****@*****.**", visibility="PUBLIC", value="IN", display_index=1) PropertyRecord.create(task=t, type="URL", is_active=True, status="email sent", first_name="Test", last_name="Test", email="*****@*****.**", visibility="PUBLIC", name="url name", value="https://www.xyz.com", display_index=1) PropertyRecord.create(task=t, type="NAME", is_active=True, status="email sent", first_name="Test", last_name="Test", email="*****@*****.**", visibility="PUBLIC", value="dummy name", display_index=1) UserInvitation.create(invitee=u, inviter=u, org=org, task=t, email="*****@*****.**", token="xyztoken") utils.process_property_records() keyword_record = PropertyRecord.get(email="*****@*****.**", type="KEYWORD") assert 12399 == keyword_record.put_code assert "12344" == keyword_record.orcid address_record = PropertyRecord.get(email="*****@*****.**", type="COUNTRY") assert 12399 == address_record.put_code assert "12344" == address_record.orcid url_record = PropertyRecord.get(email="*****@*****.**", type="URL") assert 12399 == url_record.put_code assert "12344" == url_record.orcid other_name_record = PropertyRecord.get(email="*****@*****.**", type="NAME") assert 12399 == other_name_record.put_code assert "12344" == other_name_record.orcid
def test_user_cv(client, mocker): """Test user CV.""" user0 = User.get(email="*****@*****.**") client.login(user0) resp = client.get("/user_cv") assert resp.status_code == 302 client.logout() user = User.get(email="*****@*****.**") client.login(user, follow_redirects=True) resp = client.get("/user_cv") assert resp.status_code == 302 url = urlparse(resp.location) assert url.path == '/link' OrcidToken.create(access_token="ABC12345678901", user=user, org=user.organisation, scope="/scope/read-limited") mocker.patch("orcid_hub.reports.MemberAPI.get_record", side_effect=Exception("ERROR!!!")) resp = client.get("/user_cv", follow_redirects=True) assert resp.status_code == 200 assert b"iframe" not in resp.data assert b"ERROR!!!" in resp.data get_record = mocker.patch( "orcid_hub.reports.MemberAPI.get_record", return_value=json.loads(json.dumps({ "orcid-identifier": { "uri": "http://sandbox.orcid.org/0000-0001-7027-8698", "path": "0000-0001-7027-8698", "host": "sandbox.orcid.org" }, "preferences": { "locale": "EN" }, "history": { "creation-method": "MEMBER_REFERRED", "completion-date": None, "submission-date": { "value": 1505964892638 }, "last-modified-date": { "value": 1505965202659 }, "claimed": True, "source": None, "deactivation-date": None, "verified-email": False, "verified-primary-email": False }, "person": { "last-modified-date": { "value": 1505964892861 }, "name": { "created-date": { "value": 1505964892638 }, "last-modified-date": { "value": 1505964892861 }, "given-names": { "value": "Sally" }, "family-name": { "value": "Simpsond" }, "credit-name": None, "source": None, "visibility": "PUBLIC", "path": "0000-0001-7027-8698" }, "other-names": { "last-modified-date": None, "other-name": [], "path": "/0000-0001-7027-8698/other-names" }, "biography": None, "researcher-urls": { "last-modified-date": None, "researcher-url": [], "path": "/0000-0001-7027-8698/researcher-urls" }, "emails": { "last-modified-date": { "value": 1505964892861 }, "email": [{ "created-date": { "value": 1505964892861 }, "last-modified-date": { "value": 1505964892861 }, "source": { "source-orcid": { "uri": "http://sandbox.orcid.org/0000-0001-7027-8698", "path": "0000-0001-7027-8698", "host": "sandbox.orcid.org" }, "source-client-id": None, "source-name": { "value": "Sally Simpson" } }, "email": "*****@*****.**", "path": None, "visibility": "LIMITED", "verified": False, "primary": True, "put-code": None }], "path": "/0000-0001-7027-8698/email" }, "addresses": { "last-modified-date": None, "address": [], "path": "/0000-0001-7027-8698/address" }, "keywords": { "last-modified-date": None, "keyword": [], "path": "/0000-0001-7027-8698/keywords" }, "external-identifiers": { "last-modified-date": None, "external-identifier": [], "path": "/0000-0001-7027-8698/external-identifiers" }, "path": "/0000-0001-7027-8698/person" }, "activities-summary": { "last-modified-date": None, "educations": { "last-modified-date": None, "education-summary": [], "path": "/0000-0001-7027-8698/educations" }, "employments": { "last-modified-date": None, "employment-summary": [], "path": "/0000-0001-7027-8698/employments" }, "fundings": { "last-modified-date": None, "group": [], "path": "/0000-0001-7027-8698/fundings" }, "peer-reviews": { "last-modified-date": None, "group": [], "path": "/0000-0001-7027-8698/peer-reviews" }, "works": { "last-modified-date": None, "group": [], "path": "/0000-0001-7027-8698/works" }, "path": "/0000-0001-7027-8698/activities" }, "path": "/0000-0001-7027-8698" }), object_pairs_hook=NestedDict)) resp = client.get("/user_cv") assert resp.status_code == 200 assert b"iframe" in resp.data assert user.first_name.encode() not in resp.data resp = client.get("/user_cv/show") assert resp.status_code == 200 assert user.name.encode() in resp.data get_record.assert_called_once_with() get_record.reset_mock() resp = client.get("/user_cv/download") assert resp.status_code == 200 assert user.name.replace(' ', '_') in resp.headers["Content-Disposition"] assert b"content.xml" in resp.data get_record.asser_not_called()
def test_orcid_login_callback_researcher_flow(client, mocker): """Test login from orcid callback function for researcher and display profile.""" fetch_token = mocker.patch("orcid_hub.OAuth2Session.fetch_token", side_effect=fetch_token_mock) mocker.patch( "orcid_hub.orcid_client.MemberAPI.create_or_update_affiliation", side_effect=affiliation_mock) org = Organisation.create( name="THE ORGANISATION:test_orcid_login_callback_researcher_flow", tuakiri_name= "THE ORGANISATION:test_orcid_login_callback_researcher_flow", confirmed=True, 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.RESEARCHER, orcid="123", confirmed=True, organisation=org) UserOrg.create(user=u, org=org, is_admin=False) token = utils.new_invitation_token() UserInvitation.create(email=u.email, token=token, affiliations=Affiliation.EMP, org=org, invitee=u) resp = client.get(f"/orcid/login/{token}") assert resp.status_code == 200 assert token.encode() in resp.data state = session['oauth_state'] resp = client.get(f"/auth/?state={state}&login=1") assert resp.status_code == 302 assert resp.location.endswith("/link") fetch_token.assert_called_once() resp = client.get(f"/auth/?invitation_token={token}&login=1") assert resp.status_code == 302 assert urlparse(resp.location).path == "/" fetch_token.assert_called_once() resp = client.get(f"/auth/?invitation_token={token}&login=1", follow_redirects=True) assert b"Danger" in resp.data assert b"Something went wrong, Please retry giving permissions " in resp.data fetch_token.reset_mock() resp = client.get(f"/auth/?invitation_token={token}&state={state}", follow_redirects=True) assert b"Warning" in resp.data assert b"The ORCID Hub was not able to automatically write an affiliation" in resp.data OrcidToken.delete().where(OrcidToken.user == u, OrcidToken.org == org).execute() fetch_token.reset_mock() resp = client.get(f"/auth/?invitation_token={token}&state={state}&login=1") assert resp.status_code == 302 assert resp.location.endswith("/profile") fetch_token.assert_called_once() assert OrcidToken.select().where(OrcidToken.user == u).count() == 1 resp = client.get(f"/orcid/login/{token}", follow_redirects=True) assert b"You have already given permission" in resp.data
def test_create_or_update_affiliation(app, mocker): """Test create or update affiliation.""" mocker.patch( "orcid_api_v3.api.DevelopmentMemberAPIV30Api.update_employmentv3", return_value=Mock(status=201, headers={'Location': '12344/XYZ/12399'})) mocker.patch( "orcid_api_v3.api.DevelopmentMemberAPIV30Api.create_employmentv3", return_value=Mock(status=201, headers={'Location': '12344/XYZ/12399'})) send_email = mocker.patch("orcid_hub.utils.send_email") capture_event = mocker.patch( "sentry_sdk.transport.HttpTransport.capture_event") org = app.data["org"] u = User.create(email="*****@*****.**", name="TEST USER", roles=Role.RESEARCHER, orcid="123", confirmed=True, organisation=org) UserOrg.create(user=u, org=org) t = Task.create(org=org, filename="xyz.json", created_by=u, updated_by=u, task_type=TaskType.AFFILIATION) OrcidToken.create(user=u, org=org, scopes="/read-limited,/activities/update", access_token="Test_token") UserInvitation.create(invitee=u, inviter=u, org=org, task=t, email="*****@*****.**", token="xyztoken") u = User.create(email="*****@*****.**", name="TEST USER 2", roles=Role.RESEARCHER, confirmed=True, organisation=org) UserOrg.create(user=u, org=org) AffiliationRecord.create(is_active=True, task=t, local_id="Test", first_name="Test", last_name="Test", email="*****@*****.**", orcid="123112311231", organisation="asdasd", affiliation_type="staff", role="Test", department="Test", city="Test", state="Test", country="NZ", disambiguated_id="Test", disambiguation_source="Test") AffiliationRecord.create(is_active=True, task=t, local_id="Test", first_name="Test", last_name="Test", email="*****@*****.**", orcid="123112311231", organisation=org.name, affiliation_type="staff", role="Test", department="Test", city="Test", state="Test", country="NZ") AffiliationRecord.create(is_active=True, task=t, local_id="Test", first_name="Test", last_name="Test", email="*****@*****.**", orcid="123112311231", organisation="ANOTHER ORG", affiliation_type="staff", role="Test", department="Test", city="Test", state="Test", country="NZ", visibility="PUBLIC") AffiliationRecord.create(is_active=True, task=t, local_id="Test#2", first_name="Test2", last_name="Test2", email="*****@*****.**", organisation=org.name, affiliation_type="staff") tasks = (Task.select( Task, AffiliationRecord, User, UserInvitation.id.alias("invitation_id"), OrcidToken).join( AffiliationRecord, on=(Task.id == AffiliationRecord.task_id).alias("record")).join( User, JOIN.LEFT_OUTER, on=((User.email == AffiliationRecord.email) | (User.orcid == AffiliationRecord.orcid))).join( Organisation, JOIN.LEFT_OUTER, on=(Organisation.id == Task.org_id)).join( UserInvitation, JOIN.LEFT_OUTER, on=((UserInvitation.email == AffiliationRecord.email) & (UserInvitation.task_id == Task.id))). join(OrcidToken, JOIN.LEFT_OUTER, on=((OrcidToken.user_id == User.id) & (OrcidToken.org_id == Organisation.id) & (OrcidToken.scopes.contains("/activities/update"))))) app.config["SERVER_NAME"] = "orcidhub" for (task_id, org_id, user), tasks_by_user in groupby( tasks, lambda t: ( t.id, t.org_id, t.record.user, )): with patch("orcid_hub.orcid_client.MemberAPIV3.get_record", return_value=get_profile() if user.orcid else None) as get_record: utils.create_or_update_affiliations(user=user, org_id=org_id, records=tasks_by_user) get_record.assert_any_call() affiliation_record = AffiliationRecord.select().order_by( AffiliationRecord.id).limit(1).first() assert 12399 == affiliation_record.put_code assert "12344" == affiliation_record.orcid assert ("Employment record was updated" in affiliation_record.status or "Employment record was created" in affiliation_record.status) capture_event.assert_called() send_email.assert_called_once()
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)))).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, external_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, state="Test_%d" % i, country="Test_%d" % i, disambiguated_id="Test_%d" % i, disambiguation_source="Test_%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_org_webhook_api(client, mocker): """Test Organisation webhooks.""" mocker.patch.object( utils.requests, "post", lambda *args, **kwargs: Mock( status_code=201, json=lambda: dict( access_token="ABC123", refresh_token="REFRESH_ME", expires_in=123456789 ), ), ) mockput = mocker.patch.object(utils.requests, "put") mockdelete = mocker.patch.object(utils.requests, "delete") org = client.data["org"] admin = org.tech_contact send_email = mocker.patch("orcid_hub.utils.send_email") api_client = Client.get(org=org) resp = client.post( "/oauth/token", data=dict( grant_type="client_credentials", client_id=api_client.client_id, client_secret=api_client.client_secret, scope="/webhook", ), ) assert resp.status_code == 200 data = json.loads(resp.data) api_client = Client.get(client_id="CLIENT_ID") token = Token.select().where(Token.user == admin, Token._scopes == "/webhook").first() assert data["access_token"] == token.access_token assert data["expires_in"] == client.application.config["OAUTH2_PROVIDER_TOKEN_EXPIRES_IN"] assert data["token_type"] == token.token_type client.access_token = token.access_token resp = client.put("/api/v1/webhook/INCORRECT-WEBHOOK-URL") assert resp.status_code == 415 assert json.loads(resp.data) == { "error": "Invalid call-back URL", "message": "Invalid call-back URL: INCORRECT-WEBHOOK-URL", } # 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 # 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 = client.put("/api/v1/webhook/http%3A%2F%2FCALL-BACK") assert resp.status_code == 200 resp = client.put( "/api/v1/webhook/http%3A%2F%2FCALL-BACK", data=dict(enabled=True, url="https://CALL-BACK.edu/callback"), ) assert resp.status_code == 201 server_name = client.application.config["SERVER_NAME"] mockput.assert_has_calls( [ call( "https://api.sandbox.orcid.org/1001-0001-0001-0001/webhook/" f"https%3A%2F%2F{server_name}%2Fservices%2F21%2Fupdated", headers={ "Accept": "application/json", "Authorization": "Bearer ABC123", "Content-Length": "0", }, ), call( "https://api.sandbox.orcid.org/0000-0000-0000-00X3/webhook/" f"https%3A%2F%2F{server_name}%2Fservices%2F22%2Fupdated", headers={ "Accept": "application/json", "Authorization": "Bearer ABC123", "Content-Length": "0", }, ), call( "https://api.sandbox.orcid.org/0000-0000-0000-11X2/webhook/" f"https%3A%2F%2F{server_name}%2Fservices%2F30%2Fupdated", headers={ "Accept": "application/json", "Authorization": "Bearer ABC123", "Content-Length": "0", }, ), ] ) q = OrcidToken.select().where(OrcidToken.org == org, OrcidToken.scopes == "/webhook") assert q.exists() assert q.count() == 1 orcid_token = q.first() assert orcid_token.access_token == "ABC123" assert orcid_token.refresh_token == "REFRESH_ME" assert orcid_token.expires_in == 123456789 assert orcid_token.scopes == "/webhook" # deactivate: resp = client.delete("/api/v1/webhook/http%3A%2F%2FCALL-BACK") assert resp.status_code == 200 assert "job-id" in resp.json # activate with all options: mockput.reset_mock() resp = client.put( "/api/v1/webhook", data={ "enabled": True, "append-orcid": True, "apikey": "APIKEY123", "email-notifications-enabled": True, "notification-email": "*****@*****.**", }, ) server_name = client.application.config["SERVER_NAME"] mockput.assert_has_calls( [ call( "https://api.sandbox.orcid.org/1001-0001-0001-0001/webhook/" f"https%3A%2F%2F{server_name}%2Fservices%2F21%2Fupdated", headers={ "Accept": "application/json", "Authorization": "Bearer ABC123", "Content-Length": "0", }, ), call( "https://api.sandbox.orcid.org/0000-0000-0000-00X3/webhook/" f"https%3A%2F%2F{server_name}%2Fservices%2F22%2Fupdated", headers={ "Accept": "application/json", "Authorization": "Bearer ABC123", "Content-Length": "0", }, ), call( "https://api.sandbox.orcid.org/0000-0000-0000-11X2/webhook/" f"https%3A%2F%2F{server_name}%2Fservices%2F30%2Fupdated", headers={ "Accept": "application/json", "Authorization": "Bearer ABC123", "Content-Length": "0", }, ), ] ) # Link other org to the users org2 = Organisation.select().where(Organisation.id != org.id).first() UserOrg.insert_many([dict(user_id=u.id, org_id=org2.id) for u in org.users]).execute() org2.webhook_enabled = True org2.save() resp = client.delete("/api/v1/webhook") mockput.reset_mock() resp = client.put( "/api/v1/webhook", data={ "enabled": False, "url": "https://CALL-BACK.edu/callback", "append-orcid": False, "email-notifications-enabled": True, "notification-email": "*****@*****.**", }, ) mockput.assert_not_called() # Test update summary: User.update( orcid_updated_at=datetime.date.today().replace(day=1) - datetime.timedelta(days=15) ).execute() send_email.reset_mock() utils.send_orcid_update_summary() send_email.assert_called_once() client.logout()