diff --git a/mo/web/acct.py b/mo/web/acct.py
index e54311a2d0ef6bc6440d8685f1fa3182a46ebfb1..24f34bc2a38ac17937c03e88e57dd99a186e9365 100644
--- a/mo/web/acct.py
+++ b/mo/web/acct.py
@@ -193,19 +193,23 @@ def user_settings_personal():
sess.commit()
flash('Heslo změněno.', 'success')
if form.email.data != user.email:
- rr = mo.users.new_reg_request(db.RegReqType.change_email, request.remote_addr)
- if rr:
- rr.user_id = user.user_id
- rr.email = form.email.data
- sess.add(rr)
- sess.commit()
- app.logger.info(f'Settings: Požadavek na změnu e-mailu uživatele #{user.user_id}')
- flash('Odeslán e-mail s odkazem na potvrzení nové adresy.', 'success')
- mo.email.send_confirm_change_email(user, rr.email_token)
- else:
- app.logger.info('Settings: Rate limit')
- flash('Příliš mnoho požadavků na změny e-mailu. Počkejte prosím chvíli a zkuste to znovu.', 'danger')
+ if mo.users.user_by_email(form.email.data) is not None:
+ flash('Tuto e-mailovou adresu už používá jiný uživatel.', 'danger')
ok = False
+ else:
+ rr = mo.users.new_reg_request(db.RegReqType.change_email, request.remote_addr)
+ if rr:
+ rr.user_id = user.user_id
+ rr.email = form.email.data
+ sess.add(rr)
+ sess.commit()
+ app.logger.info(f'Settings: Požadavek na změnu e-mailu uživatele #{user.user_id}')
+ flash('Odeslán e-mail s odkazem na potvrzení nové adresy.', 'success')
+ mo.email.send_confirm_change_email(user, rr.email_token)
+ else:
+ app.logger.info('Settings: Rate limit')
+ flash('Příliš mnoho požadavků na změny e-mailu. Počkejte prosím chvíli a zkuste to znovu.', 'danger')
+ ok = False
if ok:
return redirect(url_for('user_settings'))
@@ -436,6 +440,7 @@ class Reg2:
RegStatus.new: 'Chybný potvrzovací kód. Zkontrolujte, že jste odkaz z e-mailu zkopírovali správně.',
RegStatus.expired: 'Vypršela platnost potvrzovacího kódu, požádejte prosím o změnu e-mailu znovu.',
RegStatus.already_spent: 'Tento odkaz na potvrzení změny e-mailu byl již využit.',
+ RegStatus.already_exists: 'Tuto adresu už použivá jiný účet.',
},
db.RegReqType.reset_passwd: {
RegStatus.new: 'Chybný kód pro obnovení hesla. Zkontrolujte, že jste odkaz z e-mailu zkopírovali správně.',
@@ -519,9 +524,16 @@ class Reg2:
self.user = user
return True
- def change_email(self):
+ def change_email(self) -> bool:
sess = db.get_session()
user = self.rr.user
+
+ if mo.users.user_by_email(self.rr.email) is not None:
+ app.logger.info(f'Reg2: Uživatel #{user.user_id} si chce změnit email na <{user.email}>, ale už je použitý jiným účtem.')
+ self.status = RegStatus.already_exists
+ return False
+
+ # Tady je krátké okénko, kdy může nastat race condition. Chytí ji integritní omezení v DB a vznikne výjimka.
user.email = self.rr.email
app.logger.info(f'Reg2: Uživatel #{user.user_id} si změnil email na <{user.email}>')
@@ -536,6 +548,7 @@ class Reg2:
self.rr.used_at = mo.now
sess.commit()
+ return True
def change_passwd(self, new_passwd: str):
sess = db.get_session()
@@ -610,13 +623,15 @@ def confirm_email():
form = ConfirmEmailForm()
if form.validate_on_submit():
if form.submit.data:
- reg2.change_email()
- flash('E-mail změněn.', 'success')
+ if reg2.change_email():
+ flash('E-mail změněn.', 'success')
+ return redirect(url_for('user_settings'))
elif form.cancel.data:
reg2.spend_request()
flash('Požadavek na změnu e-mailu zrušen.', 'success')
- return redirect(url_for('user_settings'))
+ return redirect(url_for('user_settings'))
+ reg2.flash_message()
form.orig_email.data = reg2.rr.user.email
form.new_email.data = reg2.rr.email