From 623cf37bab4b05eaf12afd795288ef1b254debf3 Mon Sep 17 00:00:00 2001 From: Shreyansh Dwivedi Date: Sat, 18 May 2019 17:22:50 +0530 Subject: [PATCH 1/2] fix: allows deleted users to signup with same email fixed hound issues updates the condition for restoring user Adds migration file to update email of all deleted users updates condition for modify_email_for_user_to_be_restored --- app/api/helpers/user.py | 48 +++++++++++++++++++ app/api/users.py | 29 ++++++----- ...7b6fad3f56_refactor_deleted_users_email.py | 20 ++++++++ 3 files changed, 86 insertions(+), 11 deletions(-) create mode 100644 app/api/helpers/user.py create mode 100644 migrations/versions/6f7b6fad3f56_refactor_deleted_users_email.py 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..03313251ce --- /dev/null +++ b/migrations/versions/6f7b6fad3f56_refactor_deleted_users_email.py @@ -0,0 +1,20 @@ +"""Refactor deleted users email +Revision ID: 6f7b6fad3f56 +Revises: 6f7b6fad3f55 +Create Date: 2019-05-24 03:26:25 +""" + +from alembic import op + +# revision identifiers, used by Alembic. +revision = '6f7b6fad3f56' +down_revision = '6f7b6fad3f55' + + +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) From 25c89d18fe2ee0ce0cd7929edd3388d3f1285bc4 Mon Sep 17 00:00:00 2001 From: Shreyansh Dwivedi Date: Mon, 3 Jun 2019 21:46:28 +0530 Subject: [PATCH 2/2] fixes multiple heads --- .../versions/6f7b6fad3f56_refactor_deleted_users_email.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/migrations/versions/6f7b6fad3f56_refactor_deleted_users_email.py b/migrations/versions/6f7b6fad3f56_refactor_deleted_users_email.py index 03313251ce..f879a70e27 100644 --- a/migrations/versions/6f7b6fad3f56_refactor_deleted_users_email.py +++ b/migrations/versions/6f7b6fad3f56_refactor_deleted_users_email.py @@ -1,6 +1,6 @@ """Refactor deleted users email Revision ID: 6f7b6fad3f56 -Revises: 6f7b6fad3f55 +Revises: 0e80c49a6e28 Create Date: 2019-05-24 03:26:25 """ @@ -8,7 +8,7 @@ # revision identifiers, used by Alembic. revision = '6f7b6fad3f56' -down_revision = '6f7b6fad3f55' +down_revision = '0e80c49a6e28' def upgrade():