Exemple #1
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
Exemple #2
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
Exemple #3
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']
Exemple #4
0
def _update_email_addresses_from_orcid_record(profile: Profile,
                                              orcid_record: dict) -> None:
    orcid_email_dicts = extract_email_addresses(orcid_record)
    profiles = SQLAlchemyProfiles(db)

    for index, email_dict in enumerate(orcid_email_dicts):
        email = email_dict.get('email')
        try:
            email_profile = profiles.get_by_email_address(email)
        except ProfileNotFound:
            continue

        if email_profile.id != profile.id:
            message = ('Profile %s is trying to add email address %s but this '
                       'email is associated with profile %s which violates '
                       'unique constraint for email addresses' %
                       (profile.id, email, email_profile.id))
            LOGGER.error(message)
            del orcid_email_dicts[index]

    for email in profile.email_addresses:
        found = False
        for orcid_email in orcid_email_dicts:
            if orcid_email['email'] == email.email:
                found = True
                break
        if not found:
            profile.remove_email_address(email.email)

    for orcid_email in orcid_email_dicts:
        profile.add_email_address(
            orcid_email['email'], orcid_email['primary'],
            orcid_email['visibility'] != VISIBILITY_PUBLIC)
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('*****@*****.**', '*****@*****.**')
Exemple #6
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
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
Exemple #8
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
Exemple #9
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
Exemple #10
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
Exemple #11
0
def test_it_will_send_event_if_email_address_is_updated(mock_publisher: MagicMock, profile: Profile,
                                                        session: scoped_session,
                                                        commit: Callable[[], None]):
    event_publisher = send_update_events(publisher=mock_publisher)
    models_committed.connect(receiver=event_publisher)

    profile.add_email_address('*****@*****.**')
    session.add(profile)

    commit()

    assert mock_publisher.publish.call_count == 1
    assert mock_publisher.publish.call_args[0][0] == {'id': '12345678', 'type': 'profile'}
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
Exemple #13
0
def test_list_of_profiles_only_contains_snippets(
        test_client: FlaskClient, commit: Callable[[], None]) -> None:
    profile = Profile('a1b2c3d4', Name('Foo Bar'), '0000-0002-1825-0097')
    profile.add_email_address('*****@*****.**')

    db.session.add(profile)
    commit()

    response = test_client.get('/profiles')

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

    assert validate_json(data, schema_name='profile-list.v1') is True
    assert 'emailAddresses' not in data['items'][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')
Exemple #15
0
def test_does_not_contain_restricted_email_addresses(
        test_client: FlaskClient, commit: Callable[[], None]) -> None:
    profile = Profile('a1b2c3d4', Name('Foo Bar'), '0000-0002-1825-0097')
    profile.add_email_address('*****@*****.**')
    profile.add_email_address('*****@*****.**', restricted=True)

    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 [e['value'] for e in data['emailAddresses']] == ['*****@*****.**']
def test_it_sets_a_webhook_when_a_profile_is_updated(profile: Profile,
                                                     orcid_config: Dict[str, str],
                                                     mock_orcid_client: MagicMock,
                                                     session: scoped_session,
                                                     url_safe_serializer: URLSafeSerializer,
                                                     commit: Callable[[], None]):
    session.add(profile)
    commit()

    webhook_maintainer = maintain_orcid_webhook(orcid_config, mock_orcid_client,
                                                url_safe_serializer)
    models_committed.connect(receiver=webhook_maintainer)

    profile.add_email_address('*****@*****.**')
    session.add(profile)
    commit()

    assert mock_orcid_client.set_webhook.call_count == 1
    assert mock_orcid_client.set_webhook.call_args[0][0] == '0000-0002-1825-0097'
    assert mock_orcid_client.set_webhook.call_args[0][1] == 'http://localhost/orcid-webhook/{}' \
        .format(url_safe_serializer.dumps('0000-0002-1825-0097'))
def test_it_prevents_unique_constraint_error_when_inserting_existing_email_address(
        test_client: FlaskClient, webhook_payload: str) -> None:
    """
    This test was added as a result of this issue:
    https://github.com/elifesciences/issues/issues/4633
    """

    profile_1 = Profile('a1b2c3d4', Name('Foo Bar'))
    profile_1.add_email_address('*****@*****.**', restricted=False)

    profile_2 = Profile('b2c3d4e5', Name('Old Name'), '0000-0002-1825-0097')

    db.session.add(profile_1)
    db.session.add(profile_2)
    db.session.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': 'Name'
                        },
                        'given-names': {
                            'value': 'New'
                        }
                    },
                    'emails': {
                        'email': [{
                            'email': '*****@*****.**',
                            'primary': True,
                            'verified': True,
                            'visibility': 'PUBLIC'
                        }]
                    }
                }
            })

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

    response = test_client.get('/profiles/a1b2c3d4')
    assert response.status_code == 200

    data = json.loads(response.data)
    assert data['id'] == 'a1b2c3d4'
    assert data.get('orcid') is None
    assert data['emailAddresses'][0]['value'] == '*****@*****.**'
    assert data['name']['preferred'] == 'Foo Bar'

    response = test_client.get('/profiles/b2c3d4e5')
    assert response.status_code == 200

    data = json.loads(response.data)
    assert data['id'] == 'b2c3d4e5'
    assert data['orcid'] == '0000-0002-1825-0097'
    assert data['emailAddresses'] == []
    assert data['name']['preferred'] == 'New Name'