From 56c72d5fba72f3499773333b8e4b991ff788bcb9 Mon Sep 17 00:00:00 2001 From: Son Nguyen Kim Date: Mon, 20 Sep 2021 18:28:43 +0200 Subject: [PATCH] create auto create page, remove custom domain auto_create_regex part --- .../dashboard/domain_detail/auto-create.html | 140 +++++++++++++++++ .../dashboard/domain_detail/base.html | 6 + .../dashboard/domain_detail/info.html | 65 +------- app/dashboard/views/domain_detail.py | 148 +++++++++++++++--- app/models.py | 4 - static/style.css | 4 - 6 files changed, 282 insertions(+), 85 deletions(-) create mode 100644 app/dashboard/templates/dashboard/domain_detail/auto-create.html diff --git a/app/dashboard/templates/dashboard/domain_detail/auto-create.html b/app/dashboard/templates/dashboard/domain_detail/auto-create.html new file mode 100644 index 00000000..7c56fc30 --- /dev/null +++ b/app/dashboard/templates/dashboard/domain_detail/auto-create.html @@ -0,0 +1,140 @@ +{% extends 'dashboard/domain_detail/base.html' %} + +{% set domain_detail_page = "auto_create" %} + +{% block title %} + {{ custom_domain.domain }} Auto Create Rules +{% endblock %} + +{% block domain_detail_content %} +

{{ custom_domain.domain }} auto create alias rules

+
+ Advanced + Beta +
+ + + + {% if custom_domain.catch_all %} +
+ Rules are ineffective when catch-all is enabled. +
+ {% endif %} + +
+
+ For a greater control than a simple catch-all, you can define a set of rules to auto create aliases.
+ A rule is based on a regular expression (regex): if an alias matches the expression, it'll be automatically + created. +
+ +
+ Only the local part of the alias (i.e. @{{ custom_domain.domain }} is ignored) during the + regex test. +
+ +
+ When there are several rules, rules will be evaluated by their order. +
+ + {% if custom_domain.auto_create_rules | length > 0 %} +
+ {% for auto_create_rule in custom_domain.auto_create_rules %} +
+
+ Order: {{ auto_create_rule.order }}
+ + New alias will belong to + {% for mailbox in auto_create_rule.mailboxes %} + {{ mailbox.email }} + {% if not loop.last %},{% endif %} + {% endfor %} + +
+ + + +
+
+
+ {% endfor %} +
+ {% endif %} + +
+
+

New rule

+ +
+ + {{ new_auto_create_rule_form.csrf_token }} + + +
+ + + {{ new_auto_create_rule_form.regex(class="form-control", + placeholder="prefix\..*", + data_parsley_pattern="[0-9a-z-_.(\\\)(\*)(\|)]{1,}", + data_parsley_trigger="change", + data_parsley_error_message="Only lowercase letter, number, dot (.), dash (-), underscore (_), backslash (\), star (*) are currently supported.") }} + {{ render_field_errors(new_auto_create_rule_form.regex) }} + +
+ For example, if you want aliases that starts with prefix. to be automatically created, you can set + the + regex to prefix\..* +
+ + If you want aliases that ends with .suffix to be automatically created, you can use the regex + .*\.suffix +
+ To test out regex, we recommend using regex tester tool like + https://regex101.com↗ +
+
+ +
+ + {{ new_auto_create_rule_form.order(class="form-control", placeholder="10", min=1, value=1, type="number") }} + {{ render_field_errors(new_auto_create_rule_form.order) }} +
+ +
+
+ +
+
+ + +
+ +
+ +
+ + +{% endblock %} + +{% block script %} + +{% endblock %} + diff --git a/app/dashboard/templates/dashboard/domain_detail/base.html b/app/dashboard/templates/dashboard/domain_detail/base.html index 4e9112bd..21295a0a 100644 --- a/app/dashboard/templates/dashboard/domain_detail/base.html +++ b/app/dashboard/templates/dashboard/domain_detail/base.html @@ -20,6 +20,12 @@ class="list-group-item list-group-item-action {{ 'active' if domain_detail_page == 'trash' }}"> Deleted Alias + + + Auto Create + + diff --git a/app/dashboard/templates/dashboard/domain_detail/info.html b/app/dashboard/templates/dashboard/domain_detail/info.html index 8eb97aa9..5d860010 100644 --- a/app/dashboard/templates/dashboard/domain_detail/info.html +++ b/app/dashboard/templates/dashboard/domain_detail/info.html @@ -41,68 +41,19 @@ Simply use anything@{{ custom_domain.domain }} next time you need an alias: it'll be automatically created the first time it receives an email. - To have more fine-grained control, you can also use the - regular expression . + To have more fine-grained control, you can also define + auto create + rules + . -
- Advanced - Beta
- You can also set a regular expression (regex): if an alias matches the expression, it'll be automatically created. -
- Please note that only the local part of the alias (i.e. @{{ custom_domain.domain }} is ignored) during the - regex - test. -
- -
- -
- - {% if custom_domain.auto_create_regex %} - - {% endif %} -
- - For example, if you want aliases that starts with prefix. to be automatically created, you can set the - regex to prefix\..* -
- - If you want aliases that ends with .suffix to be automatically created, you can use the regex - .*\.suffix -
- - To test out regex, we recommend using regex tester tool like https://regex101.com↗ -
- -
- The new alias will belong to - {% for mailbox in custom_domain.mailboxes %} - {{ mailbox.email }} - {% if not loop.last %},{% endif %} - {% endfor %} -
-
-
Auto-created aliases are automatically owned by these mailboxes
+
+
Auto-created aliases are automatically owned by the following mailboxes + . +
{% set domain_mailboxes=custom_domain.mailboxes %}
diff --git a/app/dashboard/views/domain_detail.py b/app/dashboard/views/domain_detail.py index ca4b4957..10096e81 100644 --- a/app/dashboard/views/domain_detail.py +++ b/app/dashboard/views/domain_detail.py @@ -2,6 +2,8 @@ from threading import Thread from flask import render_template, request, redirect, url_for, flash from flask_login import login_required, current_user +from flask_wtf import FlaskForm +from wtforms import StringField, validators, IntegerField from app.config import EMAIL_SERVERS_WITH_PRIORITY, EMAIL_DOMAIN from app.dashboard.base import dashboard_bp @@ -14,7 +16,15 @@ from app.dns_utils import ( from app.email_utils import send_email from app.extensions import db from app.log import LOG -from app.models import CustomDomain, Alias, DomainDeletedAlias, Mailbox, DomainMailbox +from app.models import ( + CustomDomain, + Alias, + DomainDeletedAlias, + Mailbox, + DomainMailbox, + AutoCreateRule, + AutoCreateRuleMailbox, +) from app.utils import random_string @@ -261,25 +271,6 @@ def domain_detail(custom_domain_id): return redirect( url_for("dashboard.domain_detail", custom_domain_id=custom_domain.id) ) - elif request.form.get("form-name") == "set-auto_create_regex": - if request.form.get("action") == "save": - auto_create_regex = request.form.get("auto_create_regex") - if auto_create_regex: - custom_domain.auto_create_regex = auto_create_regex - db.session.commit() - flash("The auto create regex has been updated", "success") - else: - flash("The auto create regex cannot be empty", "error") - else: - custom_domain.auto_create_regex = None - db.session.commit() - flash( - f"The auto create regex has been has been removed", - "info", - ) - return redirect( - url_for("dashboard.domain_detail", custom_domain_id=custom_domain.id) - ) elif request.form.get("form-name") == "delete": name = custom_domain.domain @@ -378,3 +369,120 @@ def domain_detail_trash(custom_domain_id): domain_deleted_aliases=domain_deleted_aliases, custom_domain=custom_domain, ) + + +class AutoCreateRuleForm(FlaskForm): + regex = StringField( + "regex", validators=[validators.DataRequired(), validators.Length(max=128)] + ) + + order = IntegerField( + "order", + validators=[validators.DataRequired(), validators.NumberRange(min=0, max=100)], + ) + + +@dashboard_bp.route( + "/domains//auto-create", methods=["GET", "POST"] +) +@login_required +def domain_detail_auto_create(custom_domain_id): + custom_domain: CustomDomain = CustomDomain.get(custom_domain_id) + mailboxes = current_user.mailboxes() + new_auto_create_rule_form = AutoCreateRuleForm() + + if not custom_domain or custom_domain.user_id != current_user.id: + flash("You cannot see this page", "warning") + return redirect(url_for("dashboard.index")) + + if request.method == "POST": + if request.form.get("form-name") == "create-auto-create-rule": + if new_auto_create_rule_form.validate(): + # make sure order isn't used before + for auto_create_rule in custom_domain.auto_create_rules: + auto_create_rule: AutoCreateRule + if auto_create_rule.order == int( + new_auto_create_rule_form.order.data + ): + flash( + "Another rule with the same order already exists", "error" + ) + break + else: + 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.domain_detail_auto_create", + custom_domain_id=custom_domain.id, + ) + ) + mailboxes.append(mailbox) + + if not mailboxes: + flash("You must select at least 1 mailbox", "warning") + return redirect( + url_for( + "dashboard.domain_detail_auto_create", + custom_domain_id=custom_domain.id, + ) + ) + + rule = AutoCreateRule.create( + custom_domain_id=custom_domain.id, + order=int(new_auto_create_rule_form.order.data), + regex=new_auto_create_rule_form.regex.data, + flush=True, + ) + + for mailbox in mailboxes: + AutoCreateRuleMailbox.create( + auto_create_rule_id=rule.id, mailbox_id=mailbox.id + ) + + db.session.commit() + + flash("New auto create rule has been created", "success") + + return redirect( + url_for( + "dashboard.domain_detail_auto_create", + custom_domain_id=custom_domain.id, + ) + ) + elif request.form.get("form-name") == "delete-auto-create-rule": + rule_id = request.form.get("rule-id") + rule: AutoCreateRule = AutoCreateRule.get(int(rule_id)) + + if not rule or rule.custom_domain_id != custom_domain.id: + flash("Something wrong, please retry", "error") + return redirect( + url_for( + "dashboard.domain_detail_auto_create", + custom_domain_id=custom_domain.id, + ) + ) + + rule_order = rule.order + AutoCreateRule.delete(rule_id) + db.session.commit() + flash(f"Rule #{rule_order} has been deleted", "success") + + return redirect( + url_for( + "dashboard.domain_detail_auto_create", custom_domain_id=custom_domain.id + ) + ) + + nb_alias = Alias.filter_by(custom_domain_id=custom_domain.id).count() + + return render_template("dashboard/domain_detail/auto-create.html", **locals()) diff --git a/app/models.py b/app/models.py index 22ff95b7..7fc862dc 100644 --- a/app/models.py +++ b/app/models.py @@ -1844,10 +1844,6 @@ class CustomDomain(db.Model, ModelMixin): user = db.relationship(User, foreign_keys=[user_id]) - @property - def auto_create_alias_enabled(self) -> bool: - return self.catch_all or self.auto_create_regex is not None - @property def mailboxes(self): if self._mailboxes: diff --git a/static/style.css b/static/style.css index dd196eac..0996d792 100644 --- a/static/style.css +++ b/static/style.css @@ -170,7 +170,3 @@ textarea.parsley-error { .domain_detail_content { font-size: 15px; } - -.domain_detail_content .parsley-errors-list { - max-width: 20em; -} \ No newline at end of file