Merge pull request #190 from SibrenVasse/sender_format

Add more From: sender formatting options
This commit is contained in:
Son Nguyen Kim 2020-05-16 20:38:13 +02:00 committed by GitHub
commit 78ff15912e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 122 additions and 43 deletions

View File

@ -206,31 +206,30 @@
<div class="card-body"> <div class="card-body">
<div class="card-title">Sender address format</div> <div class="card-title">Sender address format</div>
<div class="mt-1 mb-3"> <div class="mt-1 mb-3">
When your alias receives an email, says from <b>John Wick &lt;john@wick.com&gt;</b>, When your alias receives an email, it says from: <b>John Wick &lt;john@wick.com&gt;</b>,
SimpleLogin forwards it to your mailbox. <br> SimpleLogin forwards it to your mailbox. <br>
Due to some email constraints, SimpleLogin cannot keep the sender email address Due to some email constraints, SimpleLogin cannot keep the sender email address
in the original form and needs to <b>transform</b> it to one of the 2 below formats. in the original form and needs to <b>transform</b> it to one of the formats below.
</div> </div>
<form method="post" action="#sender-format"> <form method="post" action="#sender-format">
<input type="hidden" name="form-name" value="change-sender-format"> <input type="hidden" name="form-name" value="change-sender-format">
<div class="form-check"> <select class="form-control mr-sm-2" name="sender-format">
<input class="form-check-input" type="radio" name="sender-format" id="exampleRadios1" value="1" <option value="{{ SenderFormatEnum.VIA.value }}"
{% if current_user.use_via_format_for_sender %} checked {% endif %}> {% if current_user.sender_format == SenderFormatEnum.VIA.value %} selected {% endif %}>
<label class="form-check-label" for="exampleRadios1"> john@wick.com via SimpleLogin</option>
<b>john@wick.com via SimpleLogin</b> <option value="{{ SenderFormatEnum.AT.value }}"
</label> {% if current_user.sender_format == SenderFormatEnum.AT.value %} selected {% endif %}>
</div> John Wick - john at wick.com</option>
<option value="{{ SenderFormatEnum.A.value }}"
<div class="form-check"> {% if current_user.sender_format == SenderFormatEnum.A.value %} selected {% endif %}>
<input class="form-check-input" type="radio" name="sender-format" id="exampleRadios2" value="0" John Wick - john(a)wick.com</option>
{% if not current_user.use_via_format_for_sender %} checked {% endif %}> <option value="{{ SenderFormatEnum.FULL.value }}"
<label class="form-check-label" for="exampleRadios2"> {% if current_user.sender_format == SenderFormatEnum.FULL.value %} selected {% endif %}>
<b>John Wick - john at wick.com</b> John Wick - john@wick.com</option>
</label> </select>
</div>
<button class="btn btn-outline-primary mt-3">Update</button> <button class="btn btn-outline-primary mt-3">Update</button>
</form> </form>

View File

@ -30,6 +30,7 @@ from app.models import (
Client, Client,
AliasGeneratorEnum, AliasGeneratorEnum,
ManualSubscription, ManualSubscription,
SenderFormatEnum,
) )
from app.utils import random_string from app.utils import random_string
@ -161,12 +162,11 @@ def setting():
return redirect(url_for("dashboard.setting")) return redirect(url_for("dashboard.setting"))
elif request.form.get("form-name") == "change-sender-format": elif request.form.get("form-name") == "change-sender-format":
sender_format = int(request.form.get("sender-format")) sender_format = int(request.form.get("sender-format"))
if sender_format == 0: if SenderFormatEnum.has_value(sender_format):
current_user.use_via_format_for_sender = False current_user.sender_format = sender_format
else: db.session.commit()
current_user.use_via_format_for_sender = True flash("Your sender format preference has been updated", "success")
db.session.commit() db.session.commit()
flash("Your sender format preference has been updated", "success")
return redirect(url_for("dashboard.setting")) return redirect(url_for("dashboard.setting"))
elif request.form.get("form-name") == "export-data": elif request.form.get("form-name") == "export-data":
@ -200,6 +200,7 @@ def setting():
"dashboard/setting.html", "dashboard/setting.html",
form=form, form=form,
PlanEnum=PlanEnum, PlanEnum=PlanEnum,
SenderFormatEnum=SenderFormatEnum,
promo_form=promo_form, promo_form=promo_form,
change_email_form=change_email_form, change_email_form=change_email_form,
pending_email=pending_email, pending_email=pending_email,

View File

@ -96,19 +96,29 @@ class File(db.Model, ModelMixin):
return s3.get_url(self.path, expires_in) return s3.get_url(self.path, expires_in)
class PlanEnum(enum.Enum): class EnumE(enum.Enum):
@classmethod
def has_value(cls, value: int) -> bool:
return value in set(item.value for item in cls)
class PlanEnum(EnumE):
monthly = 2 monthly = 2
yearly = 3 yearly = 3
class AliasGeneratorEnum(enum.Enum): # Specify the format for sender address
class SenderFormatEnum(EnumE):
AT = 0 # John Wick - john at wick.com
VIA = 1 # john@wick.com via SimpleLogin
A = 2 # John Wick - john(a)wick.com
FULL = 3 # John Wick - john@wick.com
class AliasGeneratorEnum(EnumE):
word = 1 # aliases are generated based on random words word = 1 # aliases are generated based on random words
uuid = 2 # aliases are generated based on uuid uuid = 2 # aliases are generated based on uuid
@classmethod
def has_value(cls, value: int) -> bool:
return value in set(item.value for item in cls)
class User(db.Model, ModelMixin, UserMixin): class User(db.Model, ModelMixin, UserMixin):
__tablename__ = "users" __tablename__ = "users"
@ -172,10 +182,13 @@ class User(db.Model, ModelMixin, UserMixin):
profile_picture = db.relationship(File, foreign_keys=[profile_picture_id]) profile_picture = db.relationship(File, foreign_keys=[profile_picture_id])
# Use the "via" format for sender address, i.e. "name@example.com via SimpleLogin" # Specify the format for sender address
# If False, use the format "Name - name at example.com" # John Wick - john at wick.com -> 0
use_via_format_for_sender = db.Column( # john@wick.com via SimpleLogin -> 1
db.Boolean, default=True, nullable=False, server_default="1" # John Wick - john@wick.com -> 2
# John Wick - john@wick.com -> 3
sender_format = db.Column(
db.Integer, default="1", nullable=False, server_default="1"
) )
referral_id = db.Column( referral_id = db.Column(
@ -868,21 +881,35 @@ class Contact(db.Model, ModelMixin):
def new_addr(self): def new_addr(self):
""" """
Replace original email by reply_email. 2 possible formats: Replace original email by reply_email. Possible formats:
- first@example.com by SimpleLogin <reply_email> OR - first@example.com via SimpleLogin <reply_email> OR
- First Last - first at example.com <reply_email> - First Last - first at example.com <reply_email> OR
- First Last - first(a)example.com <reply_email> OR
- First Last - first@example.com <reply_email> OR
And return new address with RFC 2047 format And return new address with RFC 2047 format
`new_email` is a special reply address `new_email` is a special reply address
""" """
user = self.user user = self.user
if user and user.use_via_format_for_sender: if (
not user
or not SenderFormatEnum.has_value(user.sender_format)
or user.sender_format == SenderFormatEnum.VIA.value
):
new_name = f"{self.website_email} via SimpleLogin" new_name = f"{self.website_email} via SimpleLogin"
else: elif user.sender_format == SenderFormatEnum.AT.value:
name = self.name or "" name = self.name or ""
new_name = ( new_name = (
name + (" - " if name else "") + self.website_email.replace("@", " at ") name + (" - " if name else "") + self.website_email.replace("@", " at ")
).strip() ).strip()
elif user.sender_format == SenderFormatEnum.A.value:
name = self.name or ""
new_name = (
name + (" - " if name else "") + self.website_email.replace("@", "(a)")
).strip()
elif user.sender_format == SenderFormatEnum.FULL.value:
name = self.name or ""
new_name = (name + (" - " if name else "") + self.website_email).strip()
new_addr = formataddr((new_name, self.reply_email)).strip() new_addr = formataddr((new_name, self.reply_email)).strip()
return new_addr.strip() return new_addr.strip()

View File

@ -0,0 +1,45 @@
"""empty message
Revision ID: 5cad8fa84386
Revises: a5e3c6693dc6
Create Date: 2020-05-15 15:10:00.096349
"""
import sqlalchemy_utils
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = "5cad8fa84386"
down_revision = "a5e3c6693dc6"
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column("users", "use_via_format_for_sender", server_default=None)
op.alter_column(
"users",
"use_via_format_for_sender",
new_column_name="sender_format",
type_=sa.Integer(),
postgresql_using="use_via_format_for_sender::integer",
)
op.alter_column("users", "sender_format", server_default="1")
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.alter_column("users", "sender_format", server_default=None)
op.alter_column(
"users",
"sender_format",
new_column_name="use_via_format_for_sender",
type_=sa.Boolean(),
postgresql_using="sender_format::boolean",
)
op.alter_column("users", "use_via_format_for_sender", server_default="1")
# ### end Alembic commands ###

View File

@ -1,11 +1,18 @@
from uuid import UUID
import pytest import pytest
from uuid import UUID
from app.config import EMAIL_DOMAIN, MAX_NB_EMAIL_FREE_PLAN from app.config import EMAIL_DOMAIN, MAX_NB_EMAIL_FREE_PLAN
from app.email_utils import parseaddr_unicode from app.email_utils import parseaddr_unicode
from app.extensions import db from app.extensions import db
from app.models import generate_email, User, Alias, Contact, Mailbox, AliasMailbox from app.models import (
generate_email,
User,
Alias,
Contact,
Mailbox,
AliasMailbox,
SenderFormatEnum,
)
def test_generate_email(flask_client): def test_generate_email(flask_client):
@ -104,7 +111,7 @@ def test_new_addr(flask_client):
alias = Alias.create_new_random(user) alias = Alias.create_new_random(user)
db.session.commit() db.session.commit()
# use_via_format_for_sender is by default # default sender_format is 'via'
c1 = Contact.create( c1 = Contact.create(
user_id=user.id, user_id=user.id,
alias_id=alias.id, alias_id=alias.id,
@ -115,8 +122,8 @@ def test_new_addr(flask_client):
db.session.commit() db.session.commit()
assert c1.new_addr() == '"abcd@example.com via SimpleLogin" <rep@SL>' assert c1.new_addr() == '"abcd@example.com via SimpleLogin" <rep@SL>'
# use_via_format_for_sender = False # set sender_format = AT
user.use_via_format_for_sender = False user.sender_format = SenderFormatEnum.AT.value
db.session.commit() db.session.commit()
assert c1.new_addr() == '"First Last - abcd at example.com" <rep@SL>' assert c1.new_addr() == '"First Last - abcd at example.com" <rep@SL>'