From 040c6d1f9ec8855f1025dbc1ea9544c11dd7f21d Mon Sep 17 00:00:00 2001
From: Son NK <>
Date: Thu, 25 Jun 2020 13:02:43 +0200
Subject: [PATCH 1/4] add User.default_random_alias_domain_id
---
app/models.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/app/models.py b/app/models.py
index ccb7bec1..1cfe1e59 100644
--- a/app/models.py
+++ b/app/models.py
@@ -166,6 +166,10 @@ class User(db.Model, ModelMixin, UserMixin):
# Fields for WebAuthn
fido_uuid = db.Column(db.String(), nullable=True, unique=True)
+ default_random_alias_domain_id = db.Column(
+ db.ForeignKey("custom_domain.id"), nullable=True, default=None
+ )
+
def fido_enabled(self) -> bool:
if self.fido_uuid is not None:
return True
From abe9768db4d9e4887594c179c195e44283b2cb88 Mon Sep 17 00:00:00 2001
From: Son NK <>
Date: Thu, 25 Jun 2020 13:04:27 +0200
Subject: [PATCH 2/4] user can update the random alias domain
---
.../templates/dashboard/setting.html | 26 +++++++++++++++---
app/dashboard/views/setting.py | 27 ++++++++++++++++++-
app/models.py | 6 +++++
3 files changed, 55 insertions(+), 4 deletions(-)
diff --git a/app/dashboard/templates/dashboard/setting.html b/app/dashboard/templates/dashboard/setting.html
index 6be24b01..da7023ca 100644
--- a/app/dashboard/templates/dashboard/setting.html
+++ b/app/dashboard/templates/dashboard/setting.html
@@ -132,11 +132,12 @@
-
+
Random Alias
-
Change the way random aliases are generated by default.
-
+
+ {% if current_user.has_custom_domain() %}
+
Select the domain for random aliases.
+
+ {% endif %}
diff --git a/app/dashboard/views/setting.py b/app/dashboard/views/setting.py
index 8b3b6442..d1407207 100644
--- a/app/dashboard/views/setting.py
+++ b/app/dashboard/views/setting.py
@@ -10,7 +10,7 @@ from wtforms import StringField, validators
from wtforms.fields.html5 import EmailField
from app import s3, email_utils
-from app.config import URL
+from app.config import URL, FIRST_ALIAS_DOMAIN
from app.dashboard.base import dashboard_bp
from app.email_utils import (
email_domain_can_be_used_as_mailbox,
@@ -159,6 +159,30 @@ def setting():
flash("Your preference has been updated", "success")
return redirect(url_for("dashboard.setting"))
+ elif request.form.get("form-name") == "change-random-alias-default-domain":
+ default_domain = request.form.get("random-alias-default-domain")
+ if default_domain:
+ default_domain_id = int(default_domain)
+ # sanity check
+ domain = CustomDomain.get(default_domain_id)
+ if (
+ not domain
+ or domain.user_id != current_user.id
+ or not domain.verified
+ ):
+ flash(
+ "Something went wrong, sorry for the inconvenience. Please retry. ",
+ "error",
+ )
+ return redirect(url_for("dashboard.setting"))
+ current_user.default_random_alias_domain_id = default_domain_id
+ else:
+ current_user.default_random_alias_domain_id = None
+
+ db.session.commit()
+ flash("Your preference has been updated", "success")
+ return redirect(url_for("dashboard.setting"))
+
elif request.form.get("form-name") == "change-sender-format":
sender_format = int(request.form.get("sender-format"))
if SenderFormatEnum.has_value(sender_format):
@@ -215,6 +239,7 @@ def setting():
pending_email=pending_email,
AliasGeneratorEnum=AliasGeneratorEnum,
manual_sub=manual_sub,
+ FIRST_ALIAS_DOMAIN=FIRST_ALIAS_DOMAIN,
)
diff --git a/app/models.py b/app/models.py
index 1cfe1e59..7f8c962b 100644
--- a/app/models.py
+++ b/app/models.py
@@ -434,6 +434,12 @@ class User(db.Model, ModelMixin, UserMixin):
def nb_directory(self):
return Directory.query.filter_by(user_id=self.id).count()
+ def has_custom_domain(self):
+ return CustomDomain.filter_by(user_id=self.id, verified=True).count() > 0
+
+ def custom_domains(self):
+ return CustomDomain.filter_by(user_id=self.id, verified=True).all()
+
def __repr__(self):
return f"
"
From b2f82ba4a821ebe5bd60da6bc29675f4a841ef59 Mon Sep 17 00:00:00 2001
From: Son NK <>
Date: Thu, 25 Jun 2020 13:05:25 +0200
Subject: [PATCH 3/4] use custom domain to generate a random alias if user
enables this option
---
app/models.py | 29 +++++++++++++++++++++++------
1 file changed, 23 insertions(+), 6 deletions(-)
diff --git a/app/models.py b/app/models.py
index 7f8c962b..bc9eb97c 100644
--- a/app/models.py
+++ b/app/models.py
@@ -656,17 +656,20 @@ class OauthToken(db.Model, ModelMixin):
def generate_email(
- scheme: int = AliasGeneratorEnum.word.value, in_hex: bool = False
+ scheme: int = AliasGeneratorEnum.word.value,
+ in_hex: bool = False,
+ alias_domain=FIRST_ALIAS_DOMAIN,
) -> str:
"""generate an email address that does not exist before
+ :param alias_domain: the domain used to generate the alias.
:param scheme: int, value of AliasGeneratorEnum, indicate how the email is generated
:type in_hex: bool, if the generate scheme is uuid, is hex favorable?
"""
if scheme == AliasGeneratorEnum.uuid.value:
name = uuid.uuid4().hex if in_hex else uuid.uuid4().__str__()
- random_email = name + "@" + FIRST_ALIAS_DOMAIN
+ random_email = name + "@" + alias_domain
else:
- random_email = random_words() + "@" + FIRST_ALIAS_DOMAIN
+ random_email = random_words() + "@" + alias_domain
random_email = random_email.lower().strip()
@@ -800,14 +803,28 @@ class Alias(db.Model, ModelMixin):
note: str = None,
):
"""create a new random alias"""
- random_email = generate_email(scheme=scheme, in_hex=in_hex)
- return Alias.create(
+ domain = None
+
+ if user.default_random_alias_domain_id:
+ domain = CustomDomain.get(user.default_random_alias_domain_id)
+ random_email = generate_email(
+ scheme=scheme, in_hex=in_hex, alias_domain=domain.domain
+ )
+ else:
+ random_email = generate_email(scheme=scheme, in_hex=in_hex)
+
+ alias = Alias.create(
user_id=user.id,
email=random_email,
mailbox_id=user.default_mailbox_id,
note=note,
)
+ if domain:
+ alias.custom_domain_id = domain.id
+
+ return alias
+
def mailbox_email(self):
if self.mailbox_id:
return self.mailbox.email
@@ -1257,7 +1274,7 @@ class CustomDomain(db.Model, ModelMixin):
# an alias is created automatically the first time it receives an email
catch_all = db.Column(db.Boolean, nullable=False, default=False, server_default="0")
- user = db.relationship(User)
+ user = db.relationship(User, foreign_keys=[user_id])
def nb_alias(self):
return Alias.filter_by(custom_domain_id=self.id).count()
From 1f7779ed7b017baa053537eb94c8a12bf04866f8 Mon Sep 17 00:00:00 2001
From: Son NK <>
Date: Thu, 25 Jun 2020 13:05:37 +0200
Subject: [PATCH 4/4] add sql migration
---
.../versions/2020_062513_a3c9a43e41f4_.py | 31 +++++++++++++++++++
1 file changed, 31 insertions(+)
create mode 100644 migrations/versions/2020_062513_a3c9a43e41f4_.py
diff --git a/migrations/versions/2020_062513_a3c9a43e41f4_.py b/migrations/versions/2020_062513_a3c9a43e41f4_.py
new file mode 100644
index 00000000..9abf5a85
--- /dev/null
+++ b/migrations/versions/2020_062513_a3c9a43e41f4_.py
@@ -0,0 +1,31 @@
+"""empty message
+
+Revision ID: a3c9a43e41f4
+Revises: a5b4dc311a89
+Create Date: 2020-06-25 13:02:21.128994
+
+"""
+import sqlalchemy_utils
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = 'a3c9a43e41f4'
+down_revision = 'a5b4dc311a89'
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.add_column('users', sa.Column('default_random_alias_domain_id', sa.Integer(), nullable=True))
+ op.create_foreign_key(None, 'users', 'custom_domain', ['default_random_alias_domain_id'], ['id'])
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_constraint(None, 'users', type_='foreignkey')
+ op.drop_column('users', 'default_random_alias_domain_id')
+ # ### end Alembic commands ###