Merge pull request #222 from simple-login/directory-mailboxes
Directory mailboxes
This commit is contained in:
commit
4eef620e3c
|
@ -18,6 +18,7 @@ from app.models import (
|
||||||
User,
|
User,
|
||||||
DeletedAlias,
|
DeletedAlias,
|
||||||
DomainDeletedAlias,
|
DomainDeletedAlias,
|
||||||
|
AliasMailbox,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,11 +66,18 @@ def try_auto_create_directory(address: str) -> Optional[Alias]:
|
||||||
try:
|
try:
|
||||||
LOG.d("create alias %s for directory %s", address, directory)
|
LOG.d("create alias %s for directory %s", address, directory)
|
||||||
|
|
||||||
|
mailboxes = directory.mailboxes
|
||||||
|
|
||||||
alias = Alias.create(
|
alias = Alias.create(
|
||||||
email=address,
|
email=address,
|
||||||
user_id=directory.user_id,
|
user_id=directory.user_id,
|
||||||
directory_id=directory.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()
|
db.session.commit()
|
||||||
|
|
|
@ -66,6 +66,29 @@
|
||||||
<h6 class="card-subtitle mb-2 text-muted">
|
<h6 class="card-subtitle mb-2 text-muted">
|
||||||
Created {{ dir.created_at | dt }} <br>
|
Created {{ dir.created_at | dt }} <br>
|
||||||
<span class="font-weight-bold">{{ dir.nb_alias() }}</span> aliases.
|
<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>
|
</h6>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -105,7 +128,24 @@
|
||||||
Only lowercase letters, numbers, dashes (-) and underscores (_) are currently supported.
|
Only lowercase letters, numbers, dashes (-) and underscores (_) are currently supported.
|
||||||
</div>
|
</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>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -142,5 +182,8 @@
|
||||||
})
|
})
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('.mailbox-select').multipleSelect();
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -6,7 +6,7 @@ from wtforms import StringField, validators
|
||||||
from app.config import EMAIL_DOMAIN, ALIAS_DOMAINS, MAX_NB_DIRECTORY
|
from app.config import EMAIL_DOMAIN, ALIAS_DOMAINS, MAX_NB_DIRECTORY
|
||||||
from app.dashboard.base import dashboard_bp
|
from app.dashboard.base import dashboard_bp
|
||||||
from app.extensions import db
|
from app.extensions import db
|
||||||
from app.models import Directory
|
from app.models import Directory, Mailbox, DirectoryMailbox
|
||||||
|
|
||||||
|
|
||||||
class NewDirForm(FlaskForm):
|
class NewDirForm(FlaskForm):
|
||||||
|
@ -24,6 +24,8 @@ def directory():
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
mailboxes = current_user.mailboxes()
|
||||||
|
|
||||||
new_dir_form = NewDirForm()
|
new_dir_form = NewDirForm()
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
|
@ -44,7 +46,46 @@ def directory():
|
||||||
flash(f"Directory {name} has been deleted", "success")
|
flash(f"Directory {name} has been deleted", "success")
|
||||||
|
|
||||||
return redirect(url_for("dashboard.directory"))
|
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":
|
elif request.form.get("form-name") == "create":
|
||||||
if not current_user.is_premium():
|
if not current_user.is_premium():
|
||||||
flash("Only premium plan can add directory", "warning")
|
flash("Only premium plan can add directory", "warning")
|
||||||
|
@ -72,6 +113,27 @@ def directory():
|
||||||
name=new_dir_name, user_id=current_user.id
|
name=new_dir_name, user_id=current_user.id
|
||||||
)
|
)
|
||||||
db.session.commit()
|
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")
|
flash(f"Directory {new_dir.name} is created", "success")
|
||||||
|
|
||||||
|
@ -81,6 +143,7 @@ def directory():
|
||||||
"dashboard/directory.html",
|
"dashboard/directory.html",
|
||||||
dirs=dirs,
|
dirs=dirs,
|
||||||
new_dir_form=new_dir_form,
|
new_dir_form=new_dir_form,
|
||||||
|
mailboxes=mailboxes,
|
||||||
EMAIL_DOMAIN=EMAIL_DOMAIN,
|
EMAIL_DOMAIN=EMAIL_DOMAIN,
|
||||||
ALIAS_DOMAINS=ALIAS_DOMAINS,
|
ALIAS_DOMAINS=ALIAS_DOMAINS,
|
||||||
)
|
)
|
||||||
|
|
|
@ -1272,6 +1272,17 @@ class Directory(db.Model, ModelMixin):
|
||||||
|
|
||||||
user = db.relationship(User)
|
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):
|
def nb_alias(self):
|
||||||
return Alias.filter_by(directory_id=self.id).count()
|
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
|
_NB_RECOVERY_CODE = 8
|
||||||
_RECOVERY_CODE_LENGTH = 8
|
_RECOVERY_CODE_LENGTH = 8
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue