diff --git a/README.md b/README.md index 601bbc91..1324843b 100644 --- a/README.md +++ b/README.md @@ -870,6 +870,7 @@ If success, 200 with the list of aliases. Each alias has the following fields: - id - email +- name - enabled - creation_timestamp - note @@ -896,6 +897,7 @@ Here's an example: "creation_date": "2020-04-06 17:57:14+00:00", "creation_timestamp": 1586195834, "email": "prefix1.cat@sl.local", + "name": "A Name", "enabled": true, "id": 3, "mailbox": { @@ -920,6 +922,7 @@ Here's an example: "creation_date": "2020-04-06 17:57:14+00:00", "creation_timestamp": 1586195834, "email": "prefix0.hey@sl.local", + "name": null, "enabled": true, "id": 2, "mailbox": { @@ -1046,6 +1049,7 @@ Input: - `alias_id` in url. - (optional) `note` in request body - (optional) `mailbox_id` in request body +- (optional) `name` in request body Output: If success, return 200 diff --git a/app/api/serializer.py b/app/api/serializer.py index edd0dfc2..58d44d5a 100644 --- a/app/api/serializer.py +++ b/app/api/serializer.py @@ -47,6 +47,7 @@ def serialize_alias_info_v2(alias_info: AliasInfo) -> dict: "creation_timestamp": alias_info.alias.created_at.timestamp, "enabled": alias_info.alias.enabled, "note": alias_info.alias.note, + "name": alias_info.alias.name, # activity "nb_forward": alias_info.nb_forward, "nb_block": alias_info.nb_blocked, diff --git a/app/api/views/alias.py b/app/api/views/alias.py index b407d57d..a75d8b38 100644 --- a/app/api/views/alias.py +++ b/app/api/views/alias.py @@ -253,6 +253,7 @@ def update_alias(alias_id): Input: alias_id: in url note: in body + name: in body Output: 200 """ @@ -281,6 +282,11 @@ def update_alias(alias_id): alias.mailbox_id = mailbox_id changed = True + if "name" in data: + new_name = data.get("name") + alias.name = new_name + changed = True + if changed: db.session.commit() diff --git a/app/dashboard/templates/dashboard/index.html b/app/dashboard/templates/dashboard/index.html index 0f9344c0..64b1db0a 100644 --- a/app/dashboard/templates/dashboard/index.html +++ b/app/dashboard/templates/dashboard/index.html @@ -212,10 +212,16 @@ -
+
+ + {% if alias_info.latest_email_log != None %} +
+ Alias created {{ alias.created_at | dt }} +
+ {% endif %} {% if mailboxes|length > 1 %} -
Current mailbox
+
Current mailbox
+ placeholder="e.g. where the alias is used or why is it created">{{ alias.note or "" }}
@@ -261,6 +268,29 @@
+
+ Alias name + +
+ +
+
+ +
+ + +
+ + save + +
+ + +
+
@@ -495,5 +525,31 @@ } }) + + $(".save-alias-name").on("click", async function () { + let aliasId = $(this).data("alias"); + let name = $(`#alias-name-${aliasId}`).val(); + + try { + let res = await fetch(`/api/aliases/${aliasId}`, { + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + name: name, + }), + }); + + if (res.ok) { + toastr.success(`Alias Name Saved`); + } else { + toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error"); + } + } catch (e) { + toastr.error("Sorry for the inconvenience! Could you refresh the page & retry please?", "Unknown Error"); + } + + }) {% endblock %} diff --git a/app/models.py b/app/models.py index 1258929d..c3013845 100644 --- a/app/models.py +++ b/app/models.py @@ -579,6 +579,9 @@ class Alias(db.Model, ModelMixin): user_id = db.Column(db.ForeignKey(User.id, ondelete="cascade"), nullable=False) email = db.Column(db.String(128), unique=True, nullable=False) + # the name to use when user replies/sends from alias + name = db.Column(db.String(128), nullable=True, default=None) + enabled = db.Column(db.Boolean(), default=True, nullable=False) custom_domain_id = db.Column( diff --git a/email_handler.py b/email_handler.py index a9201521..dd6f90c2 100644 --- a/email_handler.py +++ b/email_handler.py @@ -513,7 +513,12 @@ def handle_reply(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> (bool, str delete_header(msg, "Received") # make the email comes from alias - add_or_replace_header(msg, "From", alias.email) + if alias.name: + LOG.d("Put alias name in from header") + from_header = formataddr((alias.name, alias.email)) + else: + from_header = alias.email + add_or_replace_header(msg, "From", from_header) # some email providers like ProtonMail adds automatically the Reply-To field # make sure to delete it diff --git a/migrations/versions/2020_042610_b4146f7d5277_.py b/migrations/versions/2020_042610_b4146f7d5277_.py new file mode 100644 index 00000000..24a9ce37 --- /dev/null +++ b/migrations/versions/2020_042610_b4146f7d5277_.py @@ -0,0 +1,29 @@ +"""empty message + +Revision ID: b4146f7d5277 +Revises: bd05eac83f5f +Create Date: 2020-04-26 10:26:18.625088 + +""" +import sqlalchemy_utils +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'b4146f7d5277' +down_revision = 'bd05eac83f5f' +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column('alias', sa.Column('name', sa.String(length=128), nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column('alias', 'name') + # ### end Alembic commands ### diff --git a/tests/api/test_alias.py b/tests/api/test_alias.py index 7229f301..a1e32138 100644 --- a/tests/api/test_alias.py +++ b/tests/api/test_alias.py @@ -155,6 +155,7 @@ def test_get_aliases_v2(flask_client): # "email": "prefix1.yeah@sl.local", # "enabled": true, # "id": 3, + # "name": "Hey hey", # "latest_activity": { # "action": "forward", # "contact": { @@ -173,6 +174,7 @@ def test_get_aliases_v2(flask_client): # "nb_reply": 0, # "note": null # } + assert "name" in r0 assert r0["email"].startswith("prefix1") assert r0["latest_activity"]["action"] == "forward" assert "timestamp" in r0["latest_activity"] @@ -333,6 +335,30 @@ def test_update_alias_mailbox(flask_client): assert r.status_code == 400 +def test_update_alias_name(flask_client): + user = User.create( + email="a@b.c", password="password", name="Test User", activated=True + ) + db.session.commit() + + # create api_key + api_key = ApiKey.create(user.id, "for test") + db.session.commit() + + alias = Alias.create_new_random(user) + db.session.commit() + + r = flask_client.put( + url_for("api.update_alias", alias_id=alias.id), + headers={"Authentication": api_key.code}, + json={"name": "Test Name"}, + ) + + assert r.status_code == 200 + alias = Alias.get(alias.id) + assert alias.name == "Test Name" + + def test_alias_contacts(flask_client): user = User.create( email="a@b.c", password="password", name="Test User", activated=True