Return mailbox activation on mailbox creation

This commit is contained in:
Adrià Casajús 2024-08-02 14:53:46 +02:00
parent ea138070fd
commit 4c035ca340
No known key found for this signature in database
GPG Key ID: F0033226A5AFC9B9
4 changed files with 60 additions and 33 deletions

View File

@ -41,7 +41,7 @@ def create_mailbox():
mailbox_email = sanitize_email(request.get_json().get("email")) mailbox_email = sanitize_email(request.get_json().get("email"))
try: try:
new_mailbox = mailbox_utils.create_mailbox(user, mailbox_email) new_mailbox = mailbox_utils.create_mailbox(user, mailbox_email).mailbox
except mailbox_utils.MailboxError as e: except mailbox_utils.MailboxError as e:
return jsonify(error=e.msg), 400 return jsonify(error=e.msg), 400

View File

@ -87,7 +87,9 @@ def mailbox_route():
return redirect(request.url) return redirect(request.url)
mailbox_email = new_mailbox_form.email.data.lower().strip().replace(" ", "") mailbox_email = new_mailbox_form.email.data.lower().strip().replace(" ", "")
try: try:
mailbox = mailbox_utils.create_mailbox(current_user, mailbox_email) mailbox = mailbox_utils.create_mailbox(
current_user, mailbox_email
).mailbox
except mailbox_utils.MailboxError as e: except mailbox_utils.MailboxError as e:
flash(e.msg, "warning") flash(e.msg, "warning")
return redirect(url_for("dashboard.mailbox_route")) return redirect(url_for("dashboard.mailbox_route"))

View File

@ -1,3 +1,4 @@
import dataclasses
import secrets import secrets
import random import random
from typing import Optional from typing import Optional
@ -17,6 +18,12 @@ from app.log import LOG
from app.models import User, Mailbox, Job, MailboxActivation from app.models import User, Mailbox, Job, MailboxActivation
@dataclasses.dataclass
class CreateMailboxOutput:
mailbox: Mailbox
activation: Optional[MailboxActivation]
class MailboxError(Exception): class MailboxError(Exception):
def __init__(self, msg: str): def __init__(self, msg: str):
self.msg = msg self.msg = msg
@ -42,7 +49,7 @@ def create_mailbox(
send_email: bool = True, send_email: bool = True,
use_digit_codes: bool = False, use_digit_codes: bool = False,
send_link: bool = True, send_link: bool = True,
) -> Mailbox: ) -> CreateMailboxOutput:
if not user.is_premium(): if not user.is_premium():
LOG.i( LOG.i(
f"User {user} has tried to create mailbox with {email} but is not premium" f"User {user} has tried to create mailbox with {email} but is not premium"
@ -69,14 +76,15 @@ def create_mailbox(
if verified: if verified:
LOG.i(f"User {user} as created a pre-verified mailbox with {email}") LOG.i(f"User {user} as created a pre-verified mailbox with {email}")
return new_mailbox return CreateMailboxOutput(mailbox=new_mailbox, activation=None)
LOG.i(f"User {user} has created mailbox with {email}") LOG.i(f"User {user} has created mailbox with {email}")
activation = generate_activation_code(new_mailbox, use_digit_code=use_digit_codes) activation = generate_activation_code(new_mailbox, use_digit_code=use_digit_codes)
output = CreateMailboxOutput(mailbox=new_mailbox, activation=activation)
if not send_email: if not send_email:
LOG.i(f"Skipping sending validation email for mailbox {new_mailbox}") LOG.i(f"Skipping sending validation email for mailbox {new_mailbox}")
return new_mailbox return output
send_verification_email( send_verification_email(
user, user,
@ -84,7 +92,7 @@ def create_mailbox(
activation=activation, activation=activation,
send_link=send_link, send_link=send_link,
) )
return new_mailbox return output
def delete_mailbox( def delete_mailbox(

View File

@ -71,7 +71,10 @@ def test_create_mailbox():
@mail_sender.store_emails_test_decorator @mail_sender.store_emails_test_decorator
def test_create_mailbox_verified(): def test_create_mailbox_verified():
email = random_email() email = random_email()
mailbox_utils.create_mailbox(user, email, verified=True) output = mailbox_utils.create_mailbox(user, email, verified=True)
assert output.mailbox is not None
assert output.mailbox.verified
assert output.activation is None
mailbox = Mailbox.get_by(email=email) mailbox = Mailbox.get_by(email=email)
assert mailbox is not None assert mailbox is not None
assert mailbox.verified assert mailbox.verified
@ -84,19 +87,26 @@ def test_create_mailbox_verified():
@mail_sender.store_emails_test_decorator @mail_sender.store_emails_test_decorator
def test_create_mailbox_with_digits(): def test_create_mailbox_with_digits():
email = random_email() email = random_email()
mailbox_utils.create_mailbox(user, email, use_digit_codes=True, send_link=False) output = mailbox_utils.create_mailbox(
user, email, use_digit_codes=True, send_link=False
)
assert output.activation is not None
assert output.activation.tries == 0
assert len(output.activation.code) == 6
mailbox = Mailbox.get_by(email=email) mailbox = Mailbox.get_by(email=email)
assert mailbox is not None assert mailbox is not None
assert not mailbox.verified assert not mailbox.verified
assert output.mailbox.id == mailbox.id
activation = MailboxActivation.get_by(mailbox_id=mailbox.id) activation = MailboxActivation.get_by(mailbox_id=mailbox.id)
assert activation is not None assert activation is not None
assert activation.tries == 0 assert output.activation.mailbox_id == activation.mailbox_id
assert len(activation.code) == 6
assert 1 == len(mail_sender.get_stored_emails()) assert 1 == len(mail_sender.get_stored_emails())
mail_sent = mail_sender.get_stored_emails()[0] mail_sent = mail_sender.get_stored_emails()[0]
mail_contents = str(mail_sent.msg) mail_contents = str(mail_sent.msg)
assert mail_contents.find(activation.code) > 0 assert mail_contents.find(output.activation.code) > 0
assert mail_contents.find(config.URL) == -1 assert mail_contents.find(config.URL) == -1
assert mail_sent.envelope_to == email assert mail_sent.envelope_to == email
@ -104,14 +114,18 @@ def test_create_mailbox_with_digits():
@mail_sender.store_emails_test_decorator @mail_sender.store_emails_test_decorator
def test_create_mailbox_without_verification_email(): def test_create_mailbox_without_verification_email():
email = random_email() email = random_email()
mailbox_utils.create_mailbox(user, email, use_digit_codes=True, send_email=False) output = mailbox_utils.create_mailbox(
user, email, use_digit_codes=True, send_email=False
)
mailbox = Mailbox.get_by(email=email) mailbox = Mailbox.get_by(email=email)
assert mailbox is not None assert mailbox is not None
assert not mailbox.verified assert not mailbox.verified
assert mailbox.id == output.mailbox.id
activation = MailboxActivation.get_by(mailbox_id=mailbox.id) activation = MailboxActivation.get_by(mailbox_id=mailbox.id)
assert activation is not None assert activation is not None
assert activation.tries == 0 assert activation.tries == 0
assert len(activation.code) == 6 assert len(activation.code) == 6
assert activation.code == output.activation.code
assert 0 == len(mail_sender.get_stored_emails()) assert 0 == len(mail_sender.get_stored_emails())
@ -168,7 +182,7 @@ def test_transfer_to_same_mailbox():
email = random_email() email = random_email()
mailbox = mailbox_utils.create_mailbox( mailbox = mailbox_utils.create_mailbox(
user, email, use_digit_codes=True, send_link=False user, email, use_digit_codes=True, send_link=False
) ).mailbox
with pytest.raises(mailbox_utils.MailboxError): with pytest.raises(mailbox_utils.MailboxError):
mailbox_utils.delete_mailbox(user, mailbox.id, transfer_mailbox_id=mailbox.id) mailbox_utils.delete_mailbox(user, mailbox.id, transfer_mailbox_id=mailbox.id)
@ -177,7 +191,7 @@ def test_transfer_to_other_users_mailbox():
email = random_email() email = random_email()
mailbox = mailbox_utils.create_mailbox( mailbox = mailbox_utils.create_mailbox(
user, email, use_digit_codes=True, send_link=False user, email, use_digit_codes=True, send_link=False
) ).mailbox
other = create_new_user() other = create_new_user()
other_mailbox = Mailbox.create(user_id=other.id, email=random_email(), commit=True) other_mailbox = Mailbox.create(user_id=other.id, email=random_email(), commit=True)
with pytest.raises(mailbox_utils.MailboxError): with pytest.raises(mailbox_utils.MailboxError):
@ -190,7 +204,7 @@ def test_delete_with_no_transfer():
email = random_email() email = random_email()
mailbox = mailbox_utils.create_mailbox( mailbox = mailbox_utils.create_mailbox(
user, email, use_digit_codes=True, send_link=False user, email, use_digit_codes=True, send_link=False
) ).mailbox
mailbox_utils.delete_mailbox(user, mailbox.id, transfer_mailbox_id=None) mailbox_utils.delete_mailbox(user, mailbox.id, transfer_mailbox_id=None)
job = Session.query(Job).order_by(Job.id.desc()).first() job = Session.query(Job).order_by(Job.id.desc()).first()
assert job is not None assert job is not None
@ -202,10 +216,10 @@ def test_delete_with_no_transfer():
def test_delete_with_transfer(): def test_delete_with_transfer():
mailbox = mailbox_utils.create_mailbox( mailbox = mailbox_utils.create_mailbox(
user, random_email(), use_digit_codes=True, send_link=False user, random_email(), use_digit_codes=True, send_link=False
) ).mailbox
transfer_mailbox = mailbox_utils.create_mailbox( transfer_mailbox = mailbox_utils.create_mailbox(
user, random_email(), use_digit_codes=True, send_link=False user, random_email(), use_digit_codes=True, send_link=False
) ).mailbox
mailbox_utils.delete_mailbox( mailbox_utils.delete_mailbox(
user, mailbox.id, transfer_mailbox_id=transfer_mailbox.id user, mailbox.id, transfer_mailbox_id=transfer_mailbox.id
) )
@ -246,42 +260,45 @@ def test_verify_other_users_mailbox():
@mail_sender.store_emails_test_decorator @mail_sender.store_emails_test_decorator
def test_verify_fail(): def test_verify_fail():
mailbox = mailbox_utils.create_mailbox(user, random_email()) output = mailbox_utils.create_mailbox(user, random_email())
for i in range(mailbox_utils.MAX_ACTIVATION_TRIES - 1): for i in range(mailbox_utils.MAX_ACTIVATION_TRIES - 1):
try: try:
mailbox_utils.verify_mailbox_code(user, mailbox.id, "9999999") mailbox_utils.verify_mailbox_code(
user, output.mailbox.id, output.activation.code + "nop"
)
assert False, f"test {i}" assert False, f"test {i}"
except mailbox_utils.CannotVerifyError: except mailbox_utils.CannotVerifyError:
activation = MailboxActivation.get_by(mailbox_id=mailbox.id) activation = MailboxActivation.get_by(mailbox_id=output.mailbox.id)
assert activation.tries == i + 1 assert activation.tries == i + 1
@mail_sender.store_emails_test_decorator @mail_sender.store_emails_test_decorator
def test_verify_too_may(): def test_verify_too_may():
mailbox = mailbox_utils.create_mailbox(user, random_email()) output = mailbox_utils.create_mailbox(user, random_email())
activation = MailboxActivation.get_by(mailbox_id=mailbox.id) output.activation.tries = mailbox_utils.MAX_ACTIVATION_TRIES
activation.tries = mailbox_utils.MAX_ACTIVATION_TRIES
Session.commit() Session.commit()
with pytest.raises(mailbox_utils.CannotVerifyError): with pytest.raises(mailbox_utils.CannotVerifyError):
mailbox_utils.verify_mailbox_code(user, mailbox.id, activation.code) mailbox_utils.verify_mailbox_code(
user, output.mailbox.id, output.activation.code
)
@mail_sender.store_emails_test_decorator @mail_sender.store_emails_test_decorator
def test_verify_too_old_code(): def test_verify_too_old_code():
mailbox = mailbox_utils.create_mailbox(user, random_email()) output = mailbox_utils.create_mailbox(user, random_email())
activation = MailboxActivation.get_by(mailbox_id=mailbox.id) output.activation.created_at = arrow.now().shift(minutes=-30)
activation.created_at = arrow.now().shift(minutes=-30)
Session.commit() Session.commit()
with pytest.raises(mailbox_utils.CannotVerifyError): with pytest.raises(mailbox_utils.CannotVerifyError):
mailbox_utils.verify_mailbox_code(user, mailbox.id, activation.code) mailbox_utils.verify_mailbox_code(
user, output.mailbox.id, output.activation.code
)
@mail_sender.store_emails_test_decorator @mail_sender.store_emails_test_decorator
def test_verify_ok(): def test_verify_ok():
mailbox = mailbox_utils.create_mailbox(user, random_email()) output = mailbox_utils.create_mailbox(user, random_email())
activation = MailboxActivation.get_by(mailbox_id=mailbox.id) mailbox_utils.verify_mailbox_code(user, output.mailbox.id, output.activation.code)
mailbox_utils.verify_mailbox_code(user, mailbox.id, activation.code) activation = MailboxActivation.get_by(mailbox_id=output.mailbox.id)
activation = MailboxActivation.get_by(mailbox_id=mailbox.id)
assert activation is None assert activation is None
mailbox = Mailbox.get(id=mailbox.id) mailbox = Mailbox.get(id=output.mailbox.id)
assert mailbox.verified assert mailbox.verified