diff --git a/.github/workflows/pypi-publish.yml b/.github/workflows/pypi-publish.yml index d9167c1..01debc6 100644 --- a/.github/workflows/pypi-publish.yml +++ b/.github/workflows/pypi-publish.yml @@ -5,7 +5,6 @@ # Invenio-CERN-sync is free software; you can redistribute it and/or modify it # under the terms of the MIT License; see LICENSE file for more details. - name: Publish on: @@ -17,7 +16,7 @@ jobs: build-n-publish: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Set up Python 3.12 uses: actions/setup-python@v5 with: @@ -30,9 +29,8 @@ jobs: run: | python setup.py sdist bdist_wheel - name: pypi-publish - uses: pypa/gh-action-pypi-publish@v1.3.1 + uses: pypa/gh-action-pypi-publish@v1.13 with: user: __token__ password: ${{ secrets.pypi_token }} - diff --git a/invenio_cern_sync/users/sync.py b/invenio_cern_sync/users/sync.py index 7dcaa68..13e0469 100644 --- a/invenio_cern_sync/users/sync.py +++ b/invenio_cern_sync/users/sync.py @@ -21,6 +21,7 @@ from ..ldap.client import LdapClient from ..ldap.serializer import serialize_ldap_users from ..logging import log_info, log_warning +from ..sso import cern_remote_app_name from .api import create_user, update_existing_user @@ -131,16 +132,17 @@ def _update_existing(users, serializer_fn, log_uuid, log_name, persist_every=500 ) invenio_user["remote_account_extra_data"]["changes"] = ra_extra_data elif user and (not user_identity or user_identity.id_user != user.id): - # The `identity_id` changed. - # The `identity_id` of the UserIdentity associated to the User - # will have to be updated. + # The `identity_id` changed or it does not exist yet. try: user_identity = UserIdentity.query.filter_by(id_user=user.id).one() except NoResultFound: - current_app.logger.error( - f"UserIdentity not found for user.id={user.id}. Skipping this user..." + UserIdentity.create( + user, + cern_remote_app_name, + invenio_user["user_identity_id"], ) - continue + db.session.flush() + user_identity = UserIdentity.query.filter_by(id_user=user.id).one() _ra_extra_data = invenio_user["remote_account_extra_data"].get( "changes", [] @@ -211,7 +213,7 @@ def _insert_missing(invenio_users, log_uuid, log_name, persist_every=500): db.session.commit() except Exception as e: - current_app.logger.error( + current_app.logger.warning( f"Error creating user from CERN data: {e}. Skipping this user... User: {invenio_user}" ) continue diff --git a/tests/test_sync_users.py b/tests/test_sync_users.py index 13e5e35..610a5ab 100644 --- a/tests/test_sync_users.py +++ b/tests/test_sync_users.py @@ -259,7 +259,44 @@ def test_sync_person_id_change( "users-sync", dict(action="updating-existing-users", msg=expected_log_msg), log_uuid=mock.ANY, - ), + ) + + +@patch("invenio_cern_sync.users.sync.KeycloakService") +@patch("invenio_cern_sync.users.sync.AuthZService") +@patch("invenio_cern_sync.users.sync.log_warning") +def test_sync_identity_missing( + mock_log_warning, + MockAuthZService, + MockKeycloakService, + app, + cern_identities, + db, +): + """Test sync identity missing.""" + # prepare the db with the initial data + client_id = app.config["CERN_APP_CREDENTIALS"]["consumer_key"] + + MockAuthZService.return_value.get_identities.return_value = cern_identities + sync(method="AuthZ") + + # delete the first identity from the DB + first = cern_identities[0] + previous_person_id = first["personId"] + UserIdentity.query.filter_by(id=first["personId"]).delete() + db.session.commit() + MockAuthZService.return_value.get_identities.return_value = cern_identities + sync(method="AuthZ") + + # check that the user identity was updated, but the user was not duplicated + assert UserIdentity.query.filter_by(id=first["personId"]).one() + user = User.query.filter_by(email=first["primaryAccountEmail"]).one() + expected_log_msg = f"Identity Id changed for User `{user.username}` `{user.email}`. Previous UserIdentity.id in the local DB: `{previous_person_id}` - New Identity Id from CERN DB: `{first['personId']}`." + mock_log_warning.assert_any_call( + "users-sync", + dict(action="updating-existing-users", msg=expected_log_msg), + log_uuid=mock.ANY, + ) @patch("invenio_cern_sync.users.sync.KeycloakService") @@ -308,4 +345,4 @@ def test_sync_username_email_change( "users-sync", dict(action="updating-existing-users", msg=expected_log_msg), log_uuid=mock.ANY, - ), + )