diff --git a/app/api/helpers/user.py b/app/api/helpers/user.py new file mode 100644 index 0000000000..98946e29fe --- /dev/null +++ b/app/api/helpers/user.py @@ -0,0 +1,48 @@ +from sqlalchemy.orm.exc import NoResultFound +from app.api.helpers.exceptions import ForbiddenException +from app.models import db +from app.api.helpers.db import save_to_db +from app.models.user import User + + +def modify_email_for_user_to_be_deleted(user): + """ + Update the email ID of user which is to be deleted. + Adds '.deleted' substring to email of a user to be deleted. + :param order: User to be deleted. + :return: + """ + not_unique_email = True + user_email = user.email + while not_unique_email: + try: + db.session.query(User).filter_by(email=user_email).one() + except NoResultFound: + user.email = user_email + save_to_db(user) + not_unique_email = False + else: + user_email = user_email + '.deleted' + return user + + +def modify_email_for_user_to_be_restored(user): + """ + Update the email ID of user which is to be restored. + Removes '.deleted' substring from a user to be restored. + :param order: User to be restored. + :return: + """ + user_email = user.email + remove_str = '.deleted' + if user_email.endswith(remove_str): + user_email = user_email[:-len(remove_str)] + try: + db.session.query(User).filter_by(email=user_email).one() + except NoResultFound: + user.email = user_email + save_to_db(user) + else: + raise ForbiddenException({'pointer': '/data/attributes/email'}, + "This email is already registered! Manually edit and then try restoring") + return user diff --git a/app/api/users.py b/app/api/users.py index 7603df240e..ae6943aa6c 100644 --- a/app/api/users.py +++ b/app/api/users.py @@ -14,6 +14,7 @@ from app.api.helpers.mail import send_email_confirmation, send_email_change_user_email, send_email_with_action from app.api.helpers.permission_manager import has_access from app.api.helpers.permissions import is_user_itself +from app.api.helpers.user import modify_email_for_user_to_be_deleted, modify_email_for_user_to_be_restored from app.api.helpers.utilities import get_serializer, str_generator from app.api.schema.users import UserSchema, UserSchemaPublic from app.models import db @@ -207,21 +208,27 @@ def before_update_object(self, user, data, view_kwargs): # data['small_image_url'] = uploaded_images['thumbnail_image_url'] # data['thumbnail_image_url'] = uploaded_images['thumbnail_image_url'] # data['icon_image_url'] = uploaded_images['icon_image_url'] + + if data.get('deleted_at') != user.deleted_at: + if has_access('is_user_itself', user_id=user.id) or has_access('is_admin'): + if data.get('deleted_at'): + if len(user.events) != 0: + raise ForbiddenException({'source': ''}, "Users associated with events cannot be deleted") + elif len(user.orders) != 0: + raise ForbiddenException({'source': ''}, "Users associated with orders cannot be deleted") + else: + modify_email_for_user_to_be_deleted(user) + else: + modify_email_for_user_to_be_restored(user) + data['email'] = user.email + user.deleted_at = data.get('deleted_at') + else: + raise ForbiddenException({'source': ''}, "You are not authorized to update this information.") + users_email = data.get('email', None) if users_email is not None: users_email = users_email.strip() - if has_access('is_admin') and data.get('deleted_at') != user.deleted_at: - user.deleted_at = data.get('deleted_at') - - if has_access('is_user_itself', user_id=user.id) and data.get('deleted_at') != user.deleted_at: - if len(user.events) != 0: - raise ForbiddenException({'source': ''}, "Users associated with events cannot be deleted") - elif len(user.orders) != 0: - raise ForbiddenException({'source': ''}, "Users associated with orders cannot be deleted") - else: - user.deleted_at = data.get('deleted_at') - if users_email is not None and users_email != user.email: try: db.session.query(User).filter_by(email=users_email).one() diff --git a/migrations/versions/6f7b6fad3f56_refactor_deleted_users_email.py b/migrations/versions/6f7b6fad3f56_refactor_deleted_users_email.py new file mode 100644 index 0000000000..f879a70e27 --- /dev/null +++ b/migrations/versions/6f7b6fad3f56_refactor_deleted_users_email.py @@ -0,0 +1,20 @@ +"""Refactor deleted users email +Revision ID: 6f7b6fad3f56 +Revises: 0e80c49a6e28 +Create Date: 2019-05-24 03:26:25 +""" + +from alembic import op + +# revision identifiers, used by Alembic. +revision = '6f7b6fad3f56' +down_revision = '0e80c49a6e28' + + +def upgrade(): + op.execute("UPDATE users SET _email = concat(_email, '.deleted') where deleted_at IS NOT NULL;", + execution_options=None) + +def downgrade(): + op.execute("UPDATE users SET _email = left(_email, length(_email)-8) where right(_email, 8) = '.deleted' and deleted_at IS NOT NULL;", + execution_options=None)