Exemple #1
0
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
Exemple #3
0
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"
Exemple #5
0
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"
Exemple #10
0
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),
        ])
Exemple #11
0
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
Exemple #18
0
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
Exemple #19
0
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
Exemple #20
0
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
Exemple #21
0
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
Exemple #22
0
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()
Exemple #27
0
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()