Merge pull request #233 from simple-login/random-alias-custom-domain

Random alias custom domain
This commit is contained in:
Son Nguyen Kim 2020-06-25 13:07:35 +02:00 committed by GitHub
commit 0e3aa42326
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 113 additions and 10 deletions

View File

@ -132,11 +132,12 @@
</div>
</div>
<div class="card">
<div id="random-alias" class="card">
<div class="card-body">
<div class="card-title">Random Alias</div>
<div class="mb-3">Change the way random aliases are generated by default.</div>
<form method="post" class="form-inline">
<div class="mt-3 mb-1">Change the way random aliases are generated by default.</div>
<form method="post" action="#random-alias" class="form-inline">
<input type="hidden" name="form-name" value="change-alias-generator">
<select class="form-control mr-sm-2" name="alias-generator-scheme">
<option value="{{ AliasGeneratorEnum.word.value }}"
@ -148,6 +149,25 @@
</select>
<button class="btn btn-outline-primary">Update</button>
</form>
{% if current_user.has_custom_domain() %}
<div class="mt-3 mb-1">Select the domain for random aliases.</div>
<form method="post" action="#random-alias" class="form-inline">
<input type="hidden" name="form-name" value="change-random-alias-default-domain">
<select class="form-control mr-sm-2" name="random-alias-default-domain">
<option value="" {% if not current_user.default_random_alias_domain_id %} selected {% endif %}>
{{ FIRST_ALIAS_DOMAIN }} (SimpleLogin domain)
</option>
{% for domain in current_user.custom_domains() %}
<option value="{{ domain.id }}"
{% if current_user.default_random_alias_domain_id == domain.id %} selected {% endif %} >
{{ domain.domain }} (your domain)
</option>
{% endfor %}
</select>
<button class="btn btn-outline-primary">Update</button>
</form>
{% endif %}
</div>
</div>

View File

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

View File

@ -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
@ -430,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"<User {self.id} {self.name} {self.email}>"
@ -646,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()
@ -790,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
@ -1247,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()

View File

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