diff options
-rw-r--r-- | gn3/auth/authorisation/users/collections.py | 83 | ||||
-rw-r--r-- | gn3/auth/authorisation/users/views.py | 6 |
2 files changed, 67 insertions, 22 deletions
diff --git a/gn3/auth/authorisation/users/collections.py b/gn3/auth/authorisation/users/collections.py index 9ddc138..2e2672c 100644 --- a/gn3/auth/authorisation/users/collections.py +++ b/gn3/auth/authorisation/users/collections.py @@ -1,30 +1,77 @@ """Handle user collections.""" +import uuid import json from redis import Redis +from email_validator import validate_email, EmailNotValidError from .models import User +def __valid_email__(email:str) -> bool: + """Check for email validity.""" + try: + validate_email(email, check_deliverability=True) + except EmailNotValidError as _enve: + return False + return True + +def __toggle_boolean_field__( + rconn: Redis, email: str, field: str): + """Toggle the valuen of a boolean field""" + mig_dict = json.loads(rconn.hget("migratable-accounts", email) or "{}") + if bool(mig_dict): + rconn.hset("migratable-accounts", email, + {**mig_dict, field: not mig_dict.get(field, True)}) + +def __build_email_uuid_bridge__(rconn: Redis): + """ + Build a connection between new accounts and old user accounts. + + The only thing that is common between the two is the email address, + therefore, we use that to link the two items. + """ + old_accounts = { + account["email_address"]: { + "user_id": account["user_id"], + "collections-migrated": False, + "resources_migrated": False + } for account in ( + acct for acct in + (json.loads(usr) for usr in rconn.hgetall("users").values()) + if (bool(acct.get("email_address", False)) and + __valid_email__(acct["email_address"]))) + } + if bool(old_accounts): + rconn.hset("migratable-accounts", mapping={ + key: json.dumps(value) for key,value in old_accounts.items() + }) + return old_accounts + +def __retrieve_old_accounts__(rconn: Redis) -> dict: + accounts = rconn.hgetall("migratable-accounts") + if accounts: + return { + key: json.loads(value) for key, value in accounts.items() + } + return __build_email_uuid_bridge__(rconn) + +def __retrieve_old_user_collections__(rconn: Redis, old_user_id: uuid.UUID) -> tuple: + """Retrieve any old collections relating to the user.""" + return tuple(json.loads(rconn.hget("collections", old_user_id) or "[]")) + def user_collections(rconn: Redis, user: User) -> tuple: """Retrieve current user collections.""" - return tuple(json.loads( + collections = tuple(json.loads( rconn.hget("collections", str(user.user_id)) or "[]")) - -def old_user_collections(rconn: Redis, user: User) -> tuple: - """ - Retrieve any old user collections and migrate them to new account. - """ - collections = user_collections(rconn, user) - old_user_accounts = [ - acct for acct in - (json.loads(usr) for usr in rconn.hgetall("users").values()) - if acct.get("email_address", "") == user.email] - for account in old_user_accounts: - collections = collections + tuple(json.loads( - rconn.hget("collections", account["user_id"]) or "[]")) - rconn.hdel("collections", account["user_id"]) - - rconn.hset( - "collections", key=str(user.user_id), value=json.dumps(collections)) + old_accounts = __retrieve_old_accounts__(rconn) + if (user.email in old_accounts and + not old_accounts[user.email]["collections-migrated"]): + old_user_id = old_accounts[user.email]["user_id"] + collections = tuple(set(collections + __retrieve_old_user_collections__( + rconn, uuid.UUID(old_user_id)))) + rconn.hdel("collections", old_user_id) + __toggle_boolean_field__(rconn, user.email, "collections-migrated") + rconn.hset( + "collections", key=user.user_id, value=json.dumps(collections)) return collections diff --git a/gn3/auth/authorisation/users/views.py b/gn3/auth/authorisation/users/views.py index 0a82de3..2b4230e 100644 --- a/gn3/auth/authorisation/users/views.py +++ b/gn3/auth/authorisation/users/views.py @@ -13,7 +13,7 @@ from gn3.auth.dictify import dictify from gn3.auth.db_utils import with_db_connection from .models import list_users -from .collections import user_collections, old_user_collections +from .collections import user_collections from ..groups.models import user_group as _user_group from ..resources.models import user_resources as _user_resources @@ -180,6 +180,4 @@ def list_user_collections() -> Response: with (require_oauth.acquire("profile user") as the_token, Redis.from_url(current_app.config["REDIS_URI"], decode_responses=True) as redisconn): - return jsonify( - user_collections(redisconn, the_token.user) or - old_user_collections(redisconn, the_token.user)) + return jsonify(user_collections(redisconn, the_token.user)) |