Merge pull request #222 from simple-login/directory-mailboxes

Directory mailboxes
This commit is contained in:
Son Nguyen Kim 2020-06-05 22:33:01 +02:00 committed by GitHub
commit 4eef620e3c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 141 additions and 3 deletions

View file

@ -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

View file

@ -66,6 +66,29 @@
<h6 class="card-subtitle mb-2 text-muted">
Created {{ dir.created_at | dt }} <br>
<span class="font-weight-bold">{{ dir.nb_alias() }}</span> aliases.
<br><br>
<b>Mailboxes:</b> <i class="fe fe-info" data-toggle="tooltip"
title="Aliases created with this directory are automatically owned by these mailboxes"></i>
<br>
{% set dir_mailboxes=dir.mailboxes %}
<form method="post" class="mt-2">
<input type="hidden" name="form-name" value="update">
<input type="hidden" name="dir-id" value="{{ dir.id }}">
<select data-width="100%" required
class="mailbox-select" multiple name="mailbox_ids">
{% for mailbox in mailboxes %}
<option value="{{ mailbox.id }}" {% if mailbox in dir_mailboxes %}
selected {% endif %}>
{{ mailbox.email }}
</option>
{% endfor %}
</select>
<button class="mt-2 btn btn-outline-primary btn-sm">Update</button>
</form>
</h6>
</div>
@ -105,7 +128,24 @@
Only lowercase letters, numbers, dashes (-) and underscores (_) are currently supported.
</div>
<button class="btn btn-lg btn-success mt-2">Create</button>
<div class="mt-3 small-text alert alert-info">
By default, aliases created with directory are "owned" by your default
mailbox <b>{{ current_user.default_mailbox.email }}</b>. <br>
You can however choose the mailbox(es) that new alias automatically belongs to by setting this below option.
</div>
<select data-width="100%"
class="mailbox-select" multiple name="mailbox_ids">
{% for mailbox in mailboxes %}
<option value="{{ mailbox.id }}" {% if mailbox.id == current_user.default_mailbox_id %}
selected {% endif %}>
{{ mailbox.email }}
</option>
{% endfor %}
</select>
<button id="btn-create-directory" class="btn btn-lg btn-success mt-2">Create</button>
</form>
</div>
@ -142,5 +182,8 @@
})
});
$('.mailbox-select').multipleSelect();
</script>
{% endblock %}

View file

@ -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,
)

View file

@ -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