Example #1
0
def test_it_lists_profiles_in_slices():
    profiles = SQLAlchemyProfiles(db)
    profiles.add(Profile('11111111', Name('Name 1')))
    profiles.add(Profile('11111112', Name('Name 2')))
    profiles.add(Profile('11111113', Name('Name 3')))

    profiles_list = profiles.list(limit=1)

    assert len(profiles_list) == 1
    assert str(profiles_list[0].name) == 'Name 3'

    profiles_list = profiles.list(offset=1)

    assert len(profiles_list) == 2
    assert str(profiles_list[0].name) == 'Name 2'
    assert str(profiles_list[1].name) == 'Name 1'

    profiles_list = profiles.list(limit=1, offset=1)

    assert len(profiles_list) == 1
    assert str(profiles_list[0].name) == 'Name 2'

    profiles_list = profiles.list(offset=10)

    assert len(profiles_list) == 0
Example #2
0
def test_it_gets_profiles_by_their_email_address():
    profiles = SQLAlchemyProfiles(db)

    profile1 = Profile('12345678', Name('name1'))
    profile1.add_email_address('*****@*****.**')
    profile1.add_email_address('*****@*****.**')
    profile2 = Profile('12345679', Name('name2'))
    profile2.add_email_address('*****@*****.**')

    profiles.add(profile1)
    profiles.add(profile2)

    assert profiles.get_by_email_address('*****@*****.**') == profile1
    assert profiles.get_by_email_address('*****@*****.**') == profile1
    assert profiles.get_by_email_address('*****@*****.**',
                                         '*****@*****.**') == profile1
    assert profiles.get_by_email_address('*****@*****.**',
                                         '*****@*****.**') == profile1
    assert profiles.get_by_email_address('*****@*****.**') == profile2

    with pytest.raises(ProfileNotFound):
        profiles.get_by_email_address()
    with pytest.raises(ProfileNotFound):
        profiles.get_by_email_address('*****@*****.**')
    with pytest.raises(ProfileNotFound):
        profiles.get_by_email_address('*****@*****.**', '*****@*****.**')
Example #3
0
def test_it_does_not_updates_the_name_if_its_missing(name):
    profile = Profile('12345678', Name('Old Name'))
    orcid_record = {'person': {'name': name}}

    update_profile_from_orcid_record(profile, orcid_record)

    assert profile.name == Name('Old Name')
Example #4
0
def test_it_can_be_compared():
    name = Name('Foo Bar')
    name1 = Name('Foo Bar', 'Bar, Foo')
    name2 = Name('Foo Bar', 'Bar, Foo')
    name3 = Name('Bar Foo')

    assert name == name1
    assert name == name2
    assert name != name3
Example #5
0
def test_it_avoids_orcid_conflicts():
    profiles = SQLAlchemyProfiles(db)

    profile1 = Profile('12345678', Name('name1'), '0000-0002-1825-0097')
    profile2 = Profile('12345679', Name('name2'), '0000-0002-1825-0097')

    profile1 = profiles.add(profile1)
    profile2 = profiles.add(profile2)

    assert profile1 == profile2

    with pytest.raises(ProfileNotFound):
        profiles.get('12345679')
Example #6
0
def test_it_gets_profiles_by_their_orcid():
    profiles = SQLAlchemyProfiles(db)

    profile1 = Profile('12345678', Name('name1'), '0000-0002-1825-0097')
    profile2 = Profile('12345679', Name('name2'))

    profiles.add(profile1)
    profiles.add(profile2)

    assert profiles.get_by_orcid('0000-0002-1825-0097') == profile1

    with pytest.raises(ProfileNotFound):
        profiles.get_by_orcid('0000-0002-1825-0098')
Example #7
0
def _update_name_from_orcid_record(profile: Profile,
                                   orcid_record: dict) -> None:
    given_name = jmespath.search('person.name."given-names".value',
                                 orcid_record)
    family_name = jmespath.search('person.name."family-name".value',
                                  orcid_record)

    if given_name and family_name:
        profile.name = Name('{} {}'.format(given_name, family_name),
                            '{}, {}'.format(family_name, given_name))
    elif given_name:
        profile.name = Name(given_name, given_name)
    elif family_name:
        profile.name = Name(family_name, family_name)
Example #8
0
def test_it_contains_profiles():
    profiles = SQLAlchemyProfiles(db)

    profile1 = Profile('12345678', Name('name1'), '0000-0002-1825-0097')
    profile2 = Profile('12345679', Name('name2'))

    profile1 = profiles.add(profile1)
    profile2 = profiles.add(profile2)

    assert profiles.get('12345678') == profile1
    assert profiles.get('12345679') == profile2

    with pytest.raises(ProfileNotFound):
        profiles.get('12345670')
Example #9
0
def test_it_avoids_email_address_conflicts():
    profiles = SQLAlchemyProfiles(db)

    profile1 = Profile('12345678', Name('name1'))
    profile1.add_email_address('*****@*****.**')
    profile2 = Profile('12345679', Name('name2'))
    profile2.add_email_address('*****@*****.**')

    profile1 = profiles.add(profile1)
    profile2 = profiles.add(profile2)

    assert profile1 == profile2

    with pytest.raises(ProfileNotFound):
        profiles.get('12345679')
Example #10
0
def test_it_can_get_all_affiliations_including_restricted(yesterday):
    address = Address(countries.get('gb'), 'City')

    affiliation = Affiliation('1',
                              address=address,
                              organisation='Org',
                              starts=yesterday)
    affiliation2 = Affiliation('2',
                               address=address,
                               organisation='Org',
                               starts=yesterday,
                               restricted=True)
    affiliation3 = Affiliation('3',
                               address=address,
                               organisation='Org',
                               starts=yesterday)

    profile = Profile('12345678', Name('foo'), '0000-0002-1825-0097')

    profile.add_affiliation(affiliation, position=1)
    profile.add_affiliation(affiliation2, position=0)
    profile.add_affiliation(affiliation3, position=2)

    affiliations = profile.get_affiliations(include_restricted=True)

    assert len(affiliations) == 3
Example #11
0
def test_it_does_not_return_null_values_in_response(
        test_client: FlaskClient, yesterday: Date,
        commit: Callable[[], None]) -> None:

    address = Address(country=countries.get('gb'), city='City',
                      region=None)  # produces null value when serialized
    affiliation = Affiliation(
        '2',
        address=address,
        organisation='Org',
        department=None,  # produces null value when serialized
        starts=yesterday,
        restricted=False)

    profile = Profile('a1b2c3d4', Name('Foo Bar'), '0000-0002-1825-0097')
    profile.add_email_address('*****@*****.**', restricted=False)
    profile.add_affiliation(affiliation)

    db.session.add(profile)
    commit()

    headers = Headers()
    headers.set('X-Consumer-Groups',
                'View-restricted-profiles, Something else')
    response = test_client.get('/profiles/a1b2c3d4', headers=headers)
    data = json.loads(response.data.decode('UTF-8'))

    assert response.status_code == 200, response.status_code
    assert response.headers.get(
        'Content-Type') == 'application/vnd.elife.profile+json;version=1'
    assert validate_json(data, schema_name='profile.v1') is True
    assert contains_none_values(data) is False
Example #12
0
def test_it_does_not_return_restricted_data_when_authenticated(
        test_client: FlaskClient, yesterday: Date,
        commit: Callable[[], None]) -> None:

    address = Address(country=countries.get('gb'),
                      city='City',
                      region='Region')
    affiliation = Affiliation('1',
                              address=address,
                              organisation='Org',
                              department='Dep',
                              starts=yesterday,
                              restricted=True)

    profile = Profile('a1b2c3d4', Name('Foo Bar'), '0000-0002-1825-0097')
    profile.add_email_address('*****@*****.**', restricted=True)
    profile.add_affiliation(affiliation)

    db.session.add(profile)
    commit()

    response = test_client.get('/profiles/a1b2c3d4')
    data = json.loads(response.data.decode('UTF-8'))

    assert response.status_code == 200
    assert response.headers.get(
        'Content-Type') == 'application/vnd.elife.profile+json;version=1'
    assert validate_json(data, schema_name='profile.v1') is True
    assert not data['affiliations']
    assert not data['emailAddresses']
Example #13
0
def test_get_profile_response_contains_affiliations(
        test_client: FlaskClient, yesterday, commit: Callable[[],
                                                              None]) -> None:
    address = Address(country=countries.get('gb'),
                      city='City',
                      region='Region')
    affiliation = Affiliation('1',
                              address=address,
                              organisation='Org',
                              department='Dep',
                              starts=yesterday)

    profile = Profile('a1b2c3d4', Name('Foo Bar'), '0000-0002-1825-0097')

    db.session.add(profile)
    profile.add_affiliation(affiliation)

    commit()

    response = test_client.get('/profiles/a1b2c3d4')
    data = json.loads(response.data.decode('UTF-8'))

    assert response.status_code == 200
    assert response.headers.get(
        'Content-Type') == 'application/vnd.elife.profile+json;version=1'
    assert validate_json(data, schema_name='profile.v1') is True
    assert len(data['affiliations']) == 1
Example #14
0
def test_list_of_profiles_in_pages(test_client: FlaskClient,
                                   commit: Callable[[], None]) -> None:
    for number in range(1, 11):
        number = str(number).zfill(2)
        db.session.add(Profile(str(number), Name('Profile %s' % number)))
    commit()

    response = test_client.get('/profiles?page=1&per-page=5')

    assert response.status_code == 200
    assert response.headers.get(
        'Content-Type') == 'application/vnd.elife.profile-list+json;version=1'

    data = json.loads(response.data.decode('UTF-8'))

    assert validate_json(data, schema_name='profile-list.v1') is True
    assert data['total'] == 10
    assert len(data['items']) == 5
    for number in range(5, 0):
        assert data['items'][number - 1]['id'] == str(number).zfill(2)

    response = test_client.get('/profiles?page=2&per-page=5')

    assert response.status_code == 200
    assert response.headers.get(
        'Content-Type') == 'application/vnd.elife.profile-list+json;version=1'

    data = json.loads(response.data.decode('UTF-8'))

    assert validate_json(data, schema_name='profile-list.v1') is True
    assert data['total'] == 10
    assert len(data['items']) == 5
    for number in range(5, 0):
        assert data['items'][number - 1]['id'] == str(number + 5).zfill(2)
Example #15
0
def test_it_updates_and_returns_204_if_a_profile_is_found(
        test_client: FlaskClient, webhook_payload: str,
        commit: Callable[[], None]) -> None:
    profile = Profile('a1b2c3d4', Name('Foo Bar'), '0000-0002-1825-0097')
    orcid_token = OrcidToken('0000-0002-1825-0097', 'access-token',
                             expires_at(1234))

    db.session.add(profile)
    db.session.add(orcid_token)

    commit()

    with requests_mock.Mocker() as mocker:
        mocker.get(
            'http://www.example.com/api/v2.1/0000-0002-1825-0097/record',
            json={
                'person': {
                    'name': {
                        'family-name': {
                            'value': 'Family Name'
                        },
                        'given-names': {
                            'value': 'Given Names'
                        }
                    }
                }
            })

        response = test_client.post(
            '/orcid-webhook/{}'.format(webhook_payload))

    assert response.status_code == 204
    assert profile.name.preferred == 'Given Names Family Name'
Example #16
0
def test_it_updates_email_addresses():
    profile = Profile('12345678', Name('Name'))
    profile.add_email_address('*****@*****.**', True, True)

    orcid_record = {
        'person': {
            'emails': {
                'email': [
                    {
                        'email': '*****@*****.**',
                        'primary': True,
                        'verified': True,
                        'visibility': 'PUBLIC'
                    },
                ]
            },
        }
    }

    update_profile_from_orcid_record(profile, orcid_record)

    assert len(profile.email_addresses) == 1

    assert profile.email_addresses[0].email == '*****@*****.**'
    assert profile.email_addresses[0].restricted is False
    assert profile.email_addresses[0].position == 0
Example #17
0
    def _create_profile(token_data: dict) -> Profile:
        if not token_data['name']:
            raise InvalidRequest('No name visible')
        profile = Profile(profiles.next_id(), Name(token_data['name']),
                          token_data['orcid'])

        return profiles.add(profile)
Example #18
0
def test_it_clears_profiles():
    profiles = SQLAlchemyProfiles(db)
    profiles.add(Profile('11111111', Name('name')))
    profiles.clear()

    with pytest.raises(ProfileNotFound):
        profiles.get('11111111')
Example #19
0
def test_it_can_get_only_non_restricted_email_addresses():
    profile = Profile('12345678', Name('foo'), '0000-0002-1825-0097')

    profile.add_email_address('*****@*****.**', restricted=True)
    profile.add_email_address('*****@*****.**')
    profile.add_email_address('*****@*****.**')

    assert len(profile.get_email_addresses()) == 2
Example #20
0
def test_it_can_get_all_email_addresses_including_restricted():
    profile = Profile('12345678', Name('foo'), '0000-0002-1825-0097')

    profile.add_email_address('*****@*****.**', restricted=True)
    profile.add_email_address('*****@*****.**')
    profile.add_email_address('*****@*****.**')

    assert len(profile.get_email_addresses(include_restricted=True)) == 3
Example #21
0
def test_it_normalizes_profile_with_single_email_address(
        id_, preferred, index, orcid, email):
    profile = Profile(id_, Name(preferred, index), orcid)
    profile.add_email_address(email)

    normalized_profile = normalize(profile)

    assert len(normalized_profile['emailAddresses']) == 1
Example #22
0
def test_it_removes_email_addresses():
    profile = Profile('12345678', Name('Name'))
    profile.add_email_address('*****@*****.**')

    orcid_record = {'person': {}}

    update_profile_from_orcid_record(profile, orcid_record)

    assert len(profile.email_addresses) == 0
Example #23
0
def test_it_finds_a_profile_by_email_address_when_exchanging(
        test_client: FlaskClient) -> None:
    original_profile = Profile('a1b2c3d4', Name('Foo', 'Bar'))
    original_profile.add_email_address('*****@*****.**')
    original_profile.add_email_address('*****@*****.**')

    db.session.add(original_profile)
    db.session.commit()

    with requests_mock.Mocker() as mocker:
        mocker.post('http://www.example.com/oauth/token',
                    json={
                        'access_token': '1/fFAGRNJru1FTz70BzhT3Zg',
                        'expires_in': 3920,
                        'foo': 'bar',
                        'token_type': 'Bearer',
                        'orcid': '0000-0002-1825-0097',
                        'name': 'Josiah Carberry'
                    })
        mocker.get(
            'http://www.example.com/api/v2.1/0000-0002-1825-0097/record',
            json={
                'person': {
                    'emails': {
                        'email': [
                            {
                                'email': '*****@*****.**',
                                'primary': True,
                                'verified': True,
                                'visibility': 'PUBLIC'
                            },
                            {
                                'email': '*****@*****.**',
                                'primary': False,
                                'verified': True,
                                'visibility': 'PUBLIC'
                            },
                        ]
                    },
                }
            })

        response = test_client.post(
            '/oauth2/token',
            data={
                'client_id': 'client_id',
                'client_secret': 'client_secret',
                'redirect_uri': 'http://www.example.com/client/redirect',
                'grant_type': 'authorization_code',
                'code': '1234'
            })

    assert Profile.query.count() == 1
    assert str(original_profile.name) == 'Josiah Carberry'
    assert [e.email for e in original_profile.email_addresses
            ] == ['*****@*****.**', '*****@*****.**']
    assert response.status_code == 200
Example #24
0
def test_it_removes_affiliations():
    profile = Profile('12345678', Name('Name'))
    profile.add_affiliation(
        Affiliation('1', Address(countries.get('gb'), 'City 1'),
                    'Organisation 1', Date(2017)))
    orcid_record = {}

    update_profile_from_orcid_record(profile, orcid_record)

    assert len(profile.affiliations) == 0
Example #25
0
def test_it_lists_profiles():
    profiles = SQLAlchemyProfiles(db)
    profiles.add(Profile('11111111', Name('Name 1')))
    profiles.add(Profile('11111112', Name('Name 2')))
    profiles.add(Profile('11111113', Name('Name 3')))

    profiles_list = profiles.list()

    assert len(profiles_list) == 3
    assert str(profiles_list[0].name) == 'Name 3'
    assert str(profiles_list[1].name) == 'Name 2'
    assert str(profiles_list[2].name) == 'Name 1'

    profiles_list = profiles.list(desc=False)

    assert len(profiles_list) == 3
    assert str(profiles_list[0].name) == 'Name 1'
    assert str(profiles_list[1].name) == 'Name 2'
    assert str(profiles_list[2].name) == 'Name 3'
Example #26
0
def test_it_limits_retrying_when_generating_the_next_profile_id():
    def id_generator():
        return '11111111'

    profiles = SQLAlchemyProfiles(db, id_generator)

    profiles.add(Profile('11111111', Name('name')))

    with pytest.raises(RuntimeError):
        assert profiles.next_id()
Example #27
0
def test_it_normalizes_profiles(id_, preferred, index):
    profile = Profile(id_, Name(preferred, index))

    assert normalize(profile) == {
        'id': id_,
        'name': {
            'preferred': preferred,
            'index': index
        },
        'emailAddresses': [],
        'affiliations': []
    }
Example #28
0
def test_it_normalizes_profile_snippets(id_, preferred, index, orcid):
    profile = Profile(id_, Name(preferred, index))

    assert normalize_snippet(profile) == {
        'id': id_,
        'name': {
            'preferred': preferred,
            'index': index
        },
    }

    profile = Profile(id_, Name(preferred, index), orcid)

    assert normalize_snippet(profile) == {
        'id': id_,
        'name': {
            'preferred': preferred,
            'index': index,
        },
        'orcid': orcid,
    }
Example #29
0
def test_it_retries_generating_the_next_profile_id():
    counter = 0

    def id_generator():
        nonlocal counter
        counter = counter + 1
        return str(11111110 + counter)

    profiles = SQLAlchemyProfiles(db, id_generator)

    profiles.add(Profile('11111111', Name('name')))

    assert profiles.next_id() == '11111112'
Example #30
0
def test_it_normalizes_profile_with_multiple_email_addresses_with_primary_address_first(
):
    primary_address = '*****@*****.**'

    profile = Profile('12345678', Name('Foo Bar', 'Bar, Foo'),
                      '0000-0002-1825-0097')
    profile.add_email_address('*****@*****.**')
    profile.add_email_address('*****@*****.**')
    profile.add_email_address(primary_address, primary=True)

    normalized_profile = normalize(profile)

    assert len(normalized_profile['emailAddresses']) == 3
    assert normalized_profile['emailAddresses'][0]['value'] == primary_address