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_scheduled_tasks(app, mocker): """Test scheduled tasks.""" org = app.data["org"] task = Task.create(org=org, task_type=TaskType.AFFILIATION) rq = app.extensions["rq2"] s = rq.get_scheduler() s.run(burst=True) task = Task.get(task.id) utils.process_tasks.queue() task = Task.get(task.id) assert task.expires_at is not None task.expires_at = utils.datetime(1988, 1, 1) task.save() utils.process_tasks.queue() assert Task.select().where(Task.id == task.id).count() == 0 Organisation.update(webhook_enabled=True, email_notifications_enabled=True).execute() User.update(orcid_updated_at=utils.date.today().replace(day=1) - utils.timedelta(days=1)).execute() send_email = mocker.patch("orcid_hub.utils.send_email") utils.send_orcid_update_summary.queue(org_id=org.id) send_email.assert_called()
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()