diff --git a/app/alias_utils.py b/app/alias_utils.py index 4c7dd500..3fe21748 100644 --- a/app/alias_utils.py +++ b/app/alias_utils.py @@ -18,6 +18,7 @@ from app.models import ( User, DeletedAlias, DomainDeletedAlias, + AliasMailbox, ) @@ -65,12 +66,19 @@ def try_auto_create_directory(address: str) -> Optional[Alias]: try: LOG.d("create alias %s for directory %s", address, directory) + mailboxes = directory.mailboxes + alias = Alias.create( email=address, user_id=directory.user_id, directory_id=directory.id, - mailbox_id=dir_user.default_mailbox_id, + mailbox_id=mailboxes[0].id, ) + db.session.flush() + for i in range(1, len(mailboxes)): + AliasMailbox.create( + alias_id=alias.id, mailbox_id=mailboxes[i].id, + ) db.session.commit() return alias diff --git a/app/dashboard/templates/dashboard/directory.html b/app/dashboard/templates/dashboard/directory.html index 9036063d..33881bc4 100644 --- a/app/dashboard/templates/dashboard/directory.html +++ b/app/dashboard/templates/dashboard/directory.html @@ -66,6 +66,29 @@
Created {{ dir.created_at | dt }}
{{ dir.nb_alias() }} aliases. + +

+ + Mailboxes: +
+ + {% set dir_mailboxes=dir.mailboxes %} +
+ + + + + +
@@ -105,7 +128,24 @@ Only lowercase letters, numbers, dashes (-) and underscores (_) are currently supported. - +
+ By default, aliases created with directory are "owned" by your default + mailbox {{ current_user.default_mailbox.email }}.
+ You can however choose the mailbox(es) that new alias automatically belongs to by setting this below option. + +
+ + + + @@ -142,5 +182,8 @@ }) }); + + $('.mailbox-select').multipleSelect(); + {% endblock %} diff --git a/app/dashboard/views/directory.py b/app/dashboard/views/directory.py index 9c992cd5..bcad92f9 100644 --- a/app/dashboard/views/directory.py +++ b/app/dashboard/views/directory.py @@ -6,7 +6,7 @@ from wtforms import StringField, validators from app.config import EMAIL_DOMAIN, ALIAS_DOMAINS, MAX_NB_DIRECTORY from app.dashboard.base import dashboard_bp from app.extensions import db -from app.models import Directory +from app.models import Directory, Mailbox, DirectoryMailbox class NewDirForm(FlaskForm): @@ -24,6 +24,8 @@ def directory(): .all() ) + mailboxes = current_user.mailboxes() + new_dir_form = NewDirForm() if request.method == "POST": @@ -44,7 +46,46 @@ def directory(): flash(f"Directory {name} has been deleted", "success") return redirect(url_for("dashboard.directory")) + elif request.form.get("form-name") == "update": + dir_id = request.form.get("dir-id") + dir = Directory.get(dir_id) + if not dir: + flash("Unknown error. Refresh the page", "warning") + return redirect(url_for("dashboard.directory")) + elif dir.user_id != current_user.id: + flash("You cannot delete this directory", "warning") + return redirect(url_for("dashboard.directory")) + + mailbox_ids = request.form.getlist("mailbox_ids") + # check if mailbox is not tempered with + mailboxes = [] + for mailbox_id in mailbox_ids: + mailbox = Mailbox.get(mailbox_id) + if ( + not mailbox + or mailbox.user_id != current_user.id + or not mailbox.verified + ): + flash("Something went wrong, please retry", "warning") + return redirect(url_for("dashboard.directory")) + mailboxes.append(mailbox) + + if not mailboxes: + flash("You must select at least 1 mailbox", "warning") + return redirect(url_for("dashboard.directory")) + + # first remove all existing alias-mailboxes links + DirectoryMailbox.query.filter_by(directory_id=dir.id).delete() + db.session.flush() + + for mailbox in mailboxes: + DirectoryMailbox.create(directory_id=dir.id, mailbox_id=mailbox.id) + + db.session.commit() + flash(f"Directory {dir.name} has been updated", "success") + + return redirect(url_for("dashboard.directory")) elif request.form.get("form-name") == "create": if not current_user.is_premium(): flash("Only premium plan can add directory", "warning") @@ -72,6 +113,27 @@ def directory(): name=new_dir_name, user_id=current_user.id ) db.session.commit() + mailbox_ids = request.form.getlist("mailbox_ids") + if mailbox_ids: + # check if mailbox is not tempered with + mailboxes = [] + for mailbox_id in mailbox_ids: + mailbox = Mailbox.get(mailbox_id) + if ( + not mailbox + or mailbox.user_id != current_user.id + or not mailbox.verified + ): + flash("Something went wrong, please retry", "warning") + return redirect(url_for("dashboard.custom_alias")) + mailboxes.append(mailbox) + + for mailbox in mailboxes: + DirectoryMailbox.create( + directory_id=new_dir.id, mailbox_id=mailbox.id + ) + + db.session.commit() flash(f"Directory {new_dir.name} is created", "success") @@ -81,6 +143,7 @@ def directory(): "dashboard/directory.html", dirs=dirs, new_dir_form=new_dir_form, + mailboxes=mailboxes, EMAIL_DOMAIN=EMAIL_DOMAIN, ALIAS_DOMAINS=ALIAS_DOMAINS, ) diff --git a/app/models.py b/app/models.py index a5b23f04..0bc40075 100644 --- a/app/models.py +++ b/app/models.py @@ -1272,6 +1272,17 @@ class Directory(db.Model, ModelMixin): user = db.relationship(User) + _mailboxes = db.relationship( + "Mailbox", secondary="directory_mailbox", lazy="joined" + ) + + @property + def mailboxes(self): + if self._mailboxes: + return self._mailboxes + else: + return [self.user.default_mailbox] + def nb_alias(self): return Alias.filter_by(directory_id=self.id).count() @@ -1446,6 +1457,19 @@ class AliasMailbox(db.Model, ModelMixin): ) +class DirectoryMailbox(db.Model, ModelMixin): + __table_args__ = ( + db.UniqueConstraint("directory_id", "mailbox_id", name="uq_directory_mailbox"), + ) + + directory_id = db.Column( + db.ForeignKey(Directory.id, ondelete="cascade"), nullable=False + ) + mailbox_id = db.Column( + db.ForeignKey(Mailbox.id, ondelete="cascade"), nullable=False + ) + + _NB_RECOVERY_CODE = 8 _RECOVERY_CODE_LENGTH = 8