def test_me(app_req_ctx): """Test the echo endpoint.""" user = User.get(email="*****@*****.**") token = Token.get(user=user) with app_req_ctx( "/api/me", headers=dict(authorization=f"Bearer {token.access_token}")) as ctx: rv = ctx.app.full_dispatch_request() assert rv.status_code == 200 data = json.loads(rv.data) assert data["email"] == user.email assert data["name"] == user.name # Test invalid token: with app_req_ctx("/api/me", headers=dict(authorization="Bearer INVALID")) as ctx: user = User.get(email="*****@*****.**") rv = ctx.app.full_dispatch_request() assert rv.status_code == 401 # Test expired token: from datetime import datetime token.expires = datetime(1971, 1, 1) token.save() with app_req_ctx( "/api/me", headers=dict(authorization=f"Bearer {token.access_token}")) as ctx: rv = ctx.app.full_dispatch_request() assert rv.status_code == 401
def test_org_switch(client): """Test organisation switching.""" user = User.get(orcid=User.select(fn.COUNT(User.orcid).alias("id_count"), User.orcid).group_by( User.orcid).having(fn.COUNT(User.orcid) > 1).naive().first().orcid) user_orgs = UserOrg.select().join(User).where(User.orcid == user.orcid) new_org = Organisation.select().where(Organisation.id.not_in([uo.org_id for uo in user_orgs])).first() UserOrg.create(user=user, org=new_org, affiliations=0) resp = client.login(user, follow_redirects=True) assert user.email.encode() in resp.data assert len(user.org_links) > 1 assert current_user == user # Nothing changes if it is the same organisation uo = user.userorg_set.where(UserOrg.org_id == user.organisation_id).first() resp = client.get(f"/select/user_org/{uo.id}", follow_redirects=True) assert User.get(user.id).organisation_id == user.organisation_id assert user.email.encode() in resp.data # The current org changes if it's a dirrerent org on the list uo = user.userorg_set.where(UserOrg.org_id != user.organisation_id).first() resp = client.get(f"/select/user_org/{uo.id}", follow_redirects=True) assert User.get(user.id).organisation_id != user.organisation_id assert User.get(user.id).organisation_id == uo.org_id for ol in user.org_links: assert ol.org.name.encode() in resp.data if UserOrg.get(ol.id).user.id != user.id: next_ol = ol # Shoud be a totally different user account: resp = client.get(f"/select/user_org/{next_ol.id}", follow_redirects=True) next_user = UserOrg.get(next_ol.id).user assert next_user.id != user.id
def test_invite_tech_contact(send_email, client): """Test on-boarding of an org.""" client.login_root() email = "*****@*****.**" client.post("/invite/organisation", data={ "org_name": "A NEW ORGANISATION", "org_email": email, "tech_contact": "y", }) u = User.get(email=email) oi = OrgInvitation.get(invitee=u) assert not u.confirmed assert oi.org.name == "A NEW ORGANISATION" assert oi.org.tech_contact == u send_email.assert_called_once() client.logout() # Test invited user login: client.login( u, **{ "Sn": "Surname", "Givenname": "Givenname", "Displayname": "Test User" }) u = User.get(email=email) assert u.confirmed assert u.organisation.tech_contact == u
def test_tuakiri_login_with_orcid(client): """ Test logging attempt via Shibboleth. After getting logged in a new user entry shoulg be created. """ data = { "Auedupersonsharedtoken": "ABC123", "Sn": "LAST NAME/SURNAME/FAMILY NAME", 'Givenname': "FIRST NAME/GIVEN NAME", "Mail": "*****@*****.**", "O": "ORGANISATION 123", "Displayname": "TEST USER FROM 123", "Unscoped-Affiliation": "staff", "Eppn": "*****@*****.**", "Orcid-Id": "http://orcid.org/ERROR-ERROR-ERROR", } # Incorrect ORCID iD resp = client.get("/sso/login", headers=data) assert resp.status_code == 302 u = User.get(email="*****@*****.**") assert u.name == "TEST USER FROM 123", "Expected to have the user in the DB" assert u.first_name == "FIRST NAME/GIVEN NAME" assert u.last_name == "LAST NAME/SURNAME/FAMILY NAME" assert u.orcid is None # Correct ORCID iD, existing user: client.logout() data["Orcid-Id"] = "http://orcid.org/1893-2893-3893-00X3" resp = client.get("/sso/login", headers=data) assert resp.status_code == 302 u = User.get(email="*****@*****.**") assert u.name == "TEST USER FROM 123", "Expected to have the user in the DB" assert u.first_name == "FIRST NAME/GIVEN NAME" assert u.last_name == "LAST NAME/SURNAME/FAMILY NAME" assert u.orcid == "1893-2893-3893-00X3" # A new user with ORCID iD: client.logout() data = { "Auedupersonsharedtoken": "ABC123ABC123", "Sn": "LAST NAME/SURNAME/FAMILY NAME", 'Givenname': "FIRST NAME/GIVEN NAME", "Mail": "*****@*****.**", "O": "ORGANISATION 123", "Displayname": "TEST USER FROM 123", "Unscoped-Affiliation": "staff", "Eppn": "*****@*****.**", "Orcid-Id": "1965-2965-3965-00X3", } resp = client.get("/sso/login", headers=data) assert resp.status_code == 302 u = User.get(email="*****@*****.**") assert u.name == "TEST USER FROM 123", "Expected to have the user in the DB" assert u.first_name == "FIRST NAME/GIVEN NAME" assert u.last_name == "LAST NAME/SURNAME/FAMILY NAME" assert u.orcid == "1965-2965-3965-00X3"
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_user_summary(request_ctx): """Test user summary.""" user = User.get(email="*****@*****.**") with request_ctx( "/user_summary?from_date=2017-01-01&to_date=2018-02-28") as ctx: login_user(user, remember=True) resp = ctx.app.full_dispatch_request() assert resp.status_code == 200 assert b"<!DOCTYPE html>" in resp.data, "Expected HTML content" assert b"TEST0" in resp.data assert b"*****@*****.**" in resp.data assert b"4 / 9 (44%)" in resp.data with request_ctx( "/user_summary?from_date=2017-01-01&to_date=2017-12-31") as ctx: login_user(user, remember=True) resp = ctx.app.full_dispatch_request() assert resp.status_code == 200 assert b"<!DOCTYPE html>" in resp.data, "Expected HTML content" assert b"TEST0" in resp.data assert b"*****@*****.**" in resp.data assert b"0 / 9 (0%)" in resp.data for (sort, desc) in [(0, 0), (0, 1), (1, 0), (1, 1)]: with request_ctx( f"/user_summary?from_date=2017-01-01&to_date=2018-12-31&sort={sort}&desc={desc}" ) as ctx: login_user(user, remember=True) resp = ctx.app.full_dispatch_request() assert resp.status_code == 200 data = resp.data.decode() assert f"&sort={0 if sort else 1}&desc=0" in data assert f"&sort={sort}&desc={0 if desc else 1}" in data with request_ctx("/user_summary") as ctx: login_user(user, remember=True) resp = ctx.app.full_dispatch_request() assert resp.status_code == 302
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("/index") assert b"https://exernal.ac.nz/SP" in resp.data get = mocker.patch( "requests.get", return_value=Mock(text=base64.b64encode(zlib.compress(pickle.dumps(data))))) 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"
def test_tuakiri_login_with_org(client): """ Test logging attempt via Shibboleth. If a user logs in from an organisation that isn't onboared, the user should be informed about that and redirected to the login page. """ org = Organisation(tuakiri_name="THE ORGANISATION", confirmed=True) org.save() rv = client.get("/Tuakiri/login", headers={ "Auedupersonsharedtoken": "ABC111", "Sn": "LAST NAME/SURNAME/FAMILY NAME", 'Givenname': "FIRST NAME/GIVEN NAME", "Mail": "*****@*****.**", "O": "THE ORGANISATION", "Displayname": "TEST USER FROM THE ORGANISATION", "Unscoped-Affiliation": "staff", "Eppn": "*****@*****.**" }, follow_redirects=True) u = User.get(email="*****@*****.**") assert u.organisation == org assert org in u.organisations assert b"Your organisation (THE ORGANISATION) is not onboarded" not in rv.data uo = UserOrg.get(user=u, org=org) assert not uo.is_admin
def test_upload_affiliation_with_wrong_country(request_ctx, mocker): """Test task loading and processing with failures.""" org = Organisation.get(name="TEST0") super_user = User.get(email="*****@*****.**") with request_ctx("/") as ctx: exception = mocker.patch.object(ctx.app.logger, "exception") login_user(super_user) # flake8: noqa with pytest.raises(ModelException): task = Task.load_from_csv( """First name\tLast name\temail address\tOrganisation\tCampus/Department\tCity\tCourse or Job title\tStart date\tEnd date\tStudent/Staff\tCountry FNA\tLBA\[email protected]\tTEST1\tResearch Funding\tWellington\tProgramme Manager - ORCID\t2016-09 19:00:00 PM\t\tStaff\tNO COUNTRY """, filename="TEST.tsv", org=org) # this should work: task = Task.load_from_csv( """First name\tLast name\temail address\tOrganisation\tCampus/Department\tCity\tCourse or Job title\tStart date\tEnd date\tStudent/Staff\tCountry FNA\tLBA\[email protected]\tTEST1\tResearch Funding\tWellington\tProgramme Manager - ORCID\t2016-09 19:00:00 PM\t\tStaff\t """, filename="TEST-2.tsv", org=org) rec = task.records.first() assert rec.country is None exception.assert_called_once()
def test_tuakiri_login_wo_org(client): """ Test logging attempt via Shibboleth. If a user logs in from an organisation that isn't onboared, the user should be informed about that and redirected to the login page. """ rv = client.get("/Tuakiri/login", headers={ "Auedupersonsharedtoken": "ABC999", "Sn": "LAST NAME/SURNAME/FAMILY NAME", 'Givenname': "FIRST NAME/GIVEN NAME", "Mail": "*****@*****.**", "O": "INCOGNITO", "Displayname": "TEST USER FROM UNKNOWN", "Unscoped-Affiliation": "staff", "Eppn": "*****@*****.**" }, follow_redirects=True) u = User.get(email="*****@*****.**") assert u is not None assert u.eppn == "*****@*****.**" assert b"Your organisation (INCOGNITO) is not yet using the Hub, " \ b"see your Technical Contact for a timeline" in rv.data
def test_tuakiri_login_usgin_eppn(client): """Test logging attempt via Shibboleth using differt values to identify the user.""" org = Organisation(tuakiri_name="ORGANISATION 123ABC") org.save() user = User.create(email="*****@*****.**", eppn="*****@*****.**", roles=Role.RESEARCHER) user.save() rv = client.get("/Tuakiri/login", headers={ "Auedupersonsharedtoken": "ABC123", "Sn": "LAST NAME/SURNAME/FAMILY NAME", 'Givenname': "FIRST NAME/GIVEN NAME", "Mail": "*****@*****.**", "O": "ORGANISATION 123ABC", "Displayname": "TEST USER FROM 123", "Unscoped-Affiliation": "staff", "Eppn": "*****@*****.**" }) assert rv.status_code == 302 u = User.get(eppn="*****@*****.**") assert u.email == "*****@*****.**" assert u.name == "TEST USER FROM 123", "Expected to have the user in the DB" assert u.first_name == "FIRST NAME/GIVEN NAME" assert u.last_name == "LAST NAME/SURNAME/FAMILY NAME"
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_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_admin_view_access(request_ctx): """Test if SUPERUSER can run reports.""" user = User.get(email="*****@*****.**") with request_ctx("/org_invitatin_summary") as ctx: login_user(user, remember=True) resp = ctx.app.full_dispatch_request() assert resp.status_code == 200 assert b"<!DOCTYPE html>" in resp.data, "Expected HTML content" assert b"Organisation Invitation Summary" in resp.data assert b"*****@*****.**" in resp.data
def test_user_invitation_summary(request_ctx): """Test user invitation summary.""" user = User.get(email="*****@*****.**") with request_ctx("/user_invitatin_summary") as ctx: login_user(user, remember=True) resp = ctx.app.full_dispatch_request() assert resp.status_code == 200 assert b"<!DOCTYPE html>" in resp.data, "Expected HTML content" assert b"User Invitation Summary" in resp.data assert b"*****@*****.**" in resp.data
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_upload_affiliation_with_wrong_country(request_ctx): """Test task loading and processing with failures.""" org = Organisation.get(name="TEST0") super_user = User.get(email="*****@*****.**") with patch("emails.html") as mock_msg, request_ctx("/") as ctx: login_user(super_user) # flake8: noqa with pytest.raises(ModelException): task = Task.load_from_csv( """First name\tLast name\temail address\tOrganisation\tCampus/Department\tCity\tCourse or Job title\tStart date\tEnd date\tStudent/Staff\tCountry FNA\tLBA\[email protected]\tTEST1\tResearch Funding\tWellington\tProgramme Manager - ORCID\t2016-09 19:00:00 PM\t\tStaff\tNO COUNTRY """, filename="TEST.tsv", org=org)
def test_create_hub_administrator(app): """Test creation of the Hub administrators.""" org = app.data["org"] runner = CliRunner() runner.invoke(create_hub_administrator, ["*****@*****.**"]) assert User.select().where(User.email == "*****@*****.**").exists() assert Organisation.select().where( Organisation.name == "ORCID Hub").exists() runner.invoke(create_hub_administrator, ["*****@*****.**", "-O", "NEW ORGANISATION #0"]) assert Organisation.select().where( Organisation.name == "NEW ORGANISATION #0").exists() assert User.get( email="*****@*****.**").organisation.name == "NEW ORGANISATION #0" runner.invoke(create_hub_administrator, ["*****@*****.**", "-O", "NEW ORG"]) assert Organisation.select().where(Organisation.name == "NEW ORG").exists() assert User.get(email="*****@*****.**").organisation.name == "NEW ORG" org_count = Organisation.select().count() runner.invoke(create_hub_administrator, ["*****@*****.**", "-O", org.name]) assert Organisation.select().count() == org_count assert User.get(email="*****@*****.**").organisation.name == org.name runner.invoke(create_hub_administrator, ["*****@*****.**", "-I", "INTERNAL NAME 111"]) assert User.select().where(User.email == "*****@*****.**").exists() assert Organisation.select().where( Organisation.name == "ORCID Hub", Organisation.tuakiri_name == "INTERNAL NAME 111").exists() assert User.get(email="*****@*****.**" ).organisation.tuakiri_name == "INTERNAL NAME 111" runner.invoke( create_hub_administrator, ["*****@*****.**", "-O", "NEW ORG", "-I", "INTERNAL NAME 222"]) assert Organisation.select().where( Organisation.name == "NEW ORG", Organisation.tuakiri_name == "INTERNAL NAME 222").exists() assert User.get(email="*****@*****.**" ).organisation.tuakiri_name == "INTERNAL NAME 222" org_count = Organisation.select().count() runner.invoke( create_hub_administrator, ["*****@*****.**", "-O", org.name, "-I", "INTERNAL NAME 333"]) assert Organisation.select().count() == org_count assert User.get(email="*****@*****.**" ).organisation.tuakiri_name == "INTERNAL NAME 333"
def test_user_org_link(test_models): 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 len( User.get(email="*****@*****.**").linked_accounts) == 3 user = User.get(email="*****@*****.**") available_organisations = user.available_organisations assert available_organisations.count() == 10
def test_me(client): """Test the echo endpoint.""" user = User.get(email="*****@*****.**") token = Token.get(user=user) resp = client.get( "/api/me", headers=dict(authorization=f"Bearer {token.access_token}")) assert resp.status_code == 200 assert resp.json["email"] == user.email assert resp.json["name"] == user.name # Test invalid token: resp = client.get("/api/me", headers=dict(authorization="Bearer INVALID")) assert resp.status_code == 401 # Test expired token: token.expires = datetime(1971, 1, 1) token.save() resp = client.get( "/api/me", headers=dict(authorization=f"Bearer {token.access_token}")) assert resp.status_code == 401
def test_process_task_from_csv_with_failures(request_ctx): """Test task loading and processing with failures.""" org = Organisation.get(name="TEST0") super_user = User.get(email="*****@*****.**") with patch("emails.html") as mock_msg, 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 Start date End date Student/Staff FNA LBA [email protected] TEST1 Research Funding Wellington Programme Manager - ORCID 2016-09 Staff """, filename="TEST.tsv", org=org) AffiliationRecord.update(is_active=True).where( AffiliationRecord.task_id == task.id).execute() mock_msg().send = Mock(side_effect=Exception("FAILED TO SEND EMAIL")) utils.process_affiliation_records(10000) rec = AffiliationRecord.select().where(AffiliationRecord.task_id == task.id).first() assert "FAILED TO SEND EMAIL" in rec.status assert rec.processed_at is not None
def test_tuakiri_login(client): """ Test logging attempt via Shibboleth. After getting logged in a new user entry shoulg be created. """ rv = client.get("/Tuakiri/login", headers={ "Auedupersonsharedtoken": "ABC123", "Sn": "LAST NAME/SURNAME/FAMILY NAME", 'Givenname': "FIRST NAME/GIVEN NAME", "Mail": "*****@*****.**", "O": "ORGANISATION 123", "Displayname": "TEST USER FROM 123", "Unscoped-Affiliation": "staff", "Eppn": "*****@*****.**" }) assert rv.status_code == 302 u = User.get(email="*****@*****.**") assert u.name == "TEST USER FROM 123", "Expected to have the user in the DB" assert u.first_name == "FIRST NAME/GIVEN NAME" assert u.last_name == "LAST NAME/SURNAME/FAMILY NAME"
def test_user_org_link_org_constraint(test_models): user = User.get(id=1) uo = UserOrg(user=user, org_id=999999) with pytest.raises(Organisation.DoesNotExist): uo.save()
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_proxy_get_profile(client): """Test the echo endpoint.""" user = User.get(email="*****@*****.**") token = Token.get(user=user) orcid_id = "0000-0000-0000-00X3" with 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 = client.get( f"/orcid/api/v2.23/{orcid_id}", headers=dict(authorization=f"Bearer {token.access_token}")) assert resp.status_code == 200 args, kwargs = mocksend.call_args assert kwargs["stream"] assert args[0].url == f"https://api.sandbox.orcid.org/v2.23/{orcid_id}" assert args[0].headers[ "Authorization"] == "Bearer ORCID-TEST-ACCESS-TOKEN" assert resp.json == {"data": "TEST"} with 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", "Loction": "TEST-LOCATION", "Expires": "0", } mocksend.return_value = mockresp resp = client.post( f"/orcid/api/v2.23/{orcid_id}/SOMETHING-MORE", headers=dict(authorization=f"Bearer {token.access_token}"), data=b"""{"data": "REQUEST"}""") assert resp.status_code == 201 args, kwargs = mocksend.call_args assert kwargs["stream"] assert args[ 0].url == f"https://api.sandbox.orcid.org/v2.23/{orcid_id}/SOMETHING-MORE" assert args[0].headers[ "Authorization"] == "Bearer ORCID-TEST-ACCESS-TOKEN" assert resp.json == {"data": "TEST"} # malformatted ORCID ID: resp = client.get( "/orcid/api/v2.23/NOT-ORCID-ID/PATH", headers=dict(authorization=f"Bearer {token.access_token}")) assert resp.status_code == 415 # wrong version number: resp = client.get( f"/orcid/api/v1.23_ERROR/{orcid_id}/PATH", headers=dict(authorization=f"Bearer {token.access_token}")) assert resp.status_code == 404 assert resp.json == { "error": "Resource not found", "message": "Incorrect version: v1.23_ERROR" } # no ORCID access token resp = client.get( "/orcid/api/v2.23/0000-0000-0000-11X2/PATH", headers=dict(authorization=f"Bearer {token.access_token}")) assert resp.status_code == 403
def test_affiliation_api(client, mocker): """Test affiliation API in various formats.""" exception = mocker.patch.object(client.application.logger, "exception") capture_event = mocker.patch( "sentry_sdk.transport.HttpTransport.capture_event") 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 resp = client.get("/api/v1.0/tasks?type=AFFILIATION", headers=dict(authorization=f"Bearer {access_token}")) tasks = json.loads(resp.data) assert tasks[0]["id"] == task_id resp = client.get("/api/v1.0/tasks?type=AFFILIATION&page=1&page_size=20", 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(resp.json["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)) assert len(resp.json["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)) assert resp.status_code == 422 assert resp.json["error"] == "Validation error." resp = client.get(f"/api/v1.0/affiliations/{task_id}", headers=dict(authorization=f"Bearer {access_token}")) incorrect_data = copy.deepcopy(resp.json) 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)) assert resp.status_code == 422 assert resp.json["error"] == "Validation error." resp = client.get(f"/api/v1.0/affiliations/{task_id}", headers=dict(authorization=f"Bearer {access_token}")) new_data = copy.deepcopy(resp.json) 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(resp.json["records"]) == 3 resp = client.get(f"/api/v1.0/affiliations/{task_id}", headers=dict(authorization=f"Bearer {access_token}")) new_data = copy.deepcopy(resp.json) 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)) assert resp.status_code == 200 assert len(resp.json["records"]) == 3 assert all(r["is-active"] for r in resp.json["records"]) assert all(r["city"] == "TEST000" for r in resp.json["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 with patch.object(Task, "get", side_effect=Exception("ERROR")): resp = client.delete( f"/api/v1.0/affiliations/{task_id}", headers=dict(authorization=f"Bearer {access_token}")) assert resp.status_code == 400 assert resp.json == { "error": "Unhandled exception occurred.", "exception": "ERROR" } 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 """) assert resp.json["filename"] == "TEST42.yml" assert resp.json["task-type"] == "AFFILIATION" assert len(resp.json["records"]) == 3 task_id = resp.json["id"] task = Task.get(id=task_id) assert task.affiliation_records.count() == 3 resp = client.put(f"/api/v1.0/affiliations/{task_id}", 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 id: 9999999999 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 """) assert resp.status_code == 400 assert resp.json["error"] == "Unhandled exception occurred." assert "Instance matching query does not exist" in resp.json["exception"] with patch.object(AffiliationRecord, "get", side_effect=Exception("ERROR")): resp = client.put(f"/api/v1.0/affiliations/{task_id}", 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 id: 9999999999 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 """) assert resp.status_code == 400 assert resp.json == { "error": "Unhandled exception occurred.", "exception": "ERROR" } resp = client.post(f"/api/v1.0/affiliations/?filename=TEST42.csv", headers=dict(authorization=f"Bearer {access_token}", accept="text/yaml"), content_type="text/yaml", data="""task-type: INCORRECT filename: TEST42.yml records: - affiliation-type: student id: 9999999999 """) assert resp.status_code == 422 assert resp.json["error"] == "Validation error." assert "INCORRECT" in resp.json["message"] resp = client.post("/api/v1.0/affiliations/?filename=TEST_ERROR.csv", headers=dict(authorization=f"Bearer {access_token}", accept="text/yaml"), content_type="text/yaml", data="""task-type: AFFILIATION filename: TEST_ERROR.yml records: - affiliation-type: student something fishy is going here... """) assert resp.status_code == 415 assert resp.json[ "error"] == "Invalid request format. Only JSON, CSV, or TSV are acceptable." assert "something fishy is going here..." in resp.json["message"] exception.assert_called() capture_event.assert_called()
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_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 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_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"] == ( f"https://{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"] == ( f"https://{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