diff --git a/app/api/views/alias.py b/app/api/views/alias.py index aa1ef7b8..25ac419f 100644 --- a/app/api/views/alias.py +++ b/app/api/views/alias.py @@ -220,7 +220,7 @@ def serialize_contact(fe: Contact) -> dict: def get_alias_contacts(alias, page_id: int) -> [dict]: q = ( - Contact.query.filter_by(gen_email_id=alias.id) + Contact.query.filter_by(alias_id=alias.id) .order_by(Contact.id.desc()) .limit(PAGE_LIMIT) .offset(page_id * PAGE_LIMIT) @@ -305,11 +305,11 @@ def create_contact_route(alias_id): _, website_email = parseaddr(contact_email) # already been added - if Contact.get_by(gen_email_id=alias.id, website_email=website_email): + if Contact.get_by(alias_id=alias.id, website_email=website_email): return jsonify(error="Contact already added"), 409 contact = Contact.create( - gen_email_id=alias.id, + alias_id=alias.id, website_email=website_email, website_from=contact_email, reply_email=reply_email, diff --git a/app/api/views/alias_options.py b/app/api/views/alias_options.py index 4cad82a8..3cf32e2d 100644 --- a/app/api/views/alias_options.py +++ b/app/api/views/alias_options.py @@ -41,7 +41,7 @@ def options(): q = ( db.session.query(AliasUsedOn, Alias, User) .filter( - AliasUsedOn.gen_email_id == Alias.id, + AliasUsedOn.alias_id == Alias.id, Alias.user_id == user.id, AliasUsedOn.hostname == hostname, ) @@ -124,7 +124,7 @@ def options_v2(): q = ( db.session.query(AliasUsedOn, Alias, User) .filter( - AliasUsedOn.gen_email_id == Alias.id, + AliasUsedOn.alias_id == Alias.id, Alias.user_id == user.id, AliasUsedOn.hostname == hostname, ) diff --git a/app/api/views/new_custom_alias.py b/app/api/views/new_custom_alias.py index a97a728a..6fb6bd66 100644 --- a/app/api/views/new_custom_alias.py +++ b/app/api/views/new_custom_alias.py @@ -72,7 +72,7 @@ def new_custom_alias(): db.session.commit() if hostname: - AliasUsedOn.create(gen_email_id=alias.id, hostname=hostname) + AliasUsedOn.create(alias_id=alias.id, hostname=hostname) db.session.commit() return jsonify(alias=full_alias), 201 diff --git a/app/api/views/new_random_alias.py b/app/api/views/new_random_alias.py index 6d773dae..b023b210 100644 --- a/app/api/views/new_random_alias.py +++ b/app/api/views/new_random_alias.py @@ -52,7 +52,7 @@ def new_random_alias(): hostname = request.args.get("hostname") if hostname: - AliasUsedOn.create(gen_email_id=alias.id, hostname=hostname) + AliasUsedOn.create(alias_id=alias.id, hostname=hostname) db.session.commit() return jsonify(alias=alias.email), 201 diff --git a/app/dashboard/views/alias_contact_manager.py b/app/dashboard/views/alias_contact_manager.py index 3557accb..2e0affd0 100644 --- a/app/dashboard/views/alias_contact_manager.py +++ b/app/dashboard/views/alias_contact_manager.py @@ -80,14 +80,14 @@ def alias_contact_manager(alias_id, contact_id=None): _, website_email = parseaddr(contact_email) # already been added - if Contact.get_by(gen_email_id=alias.id, website_email=website_email): + if Contact.get_by(alias_id=alias.id, website_email=website_email): flash(f"{website_email} is already added", "error") return redirect( url_for("dashboard.alias_contact_manager", alias_id=alias_id) ) contact = Contact.create( - gen_email_id=alias.id, + alias_id=alias.id, website_email=website_email, website_from=contact_email, reply_email=reply_email, @@ -113,7 +113,7 @@ def alias_contact_manager(alias_id, contact_id=None): return redirect( url_for("dashboard.alias_contact_manager", alias_id=alias_id) ) - elif contact.gen_email_id != alias.id: + elif contact.alias_id != alias.id: flash("You cannot delete reverse-alias", "warning") return redirect( url_for("dashboard.alias_contact_manager", alias_id=alias_id) diff --git a/app/dashboard/views/alias_log.py b/app/dashboard/views/alias_log.py index 2cc0af94..9fe37004 100644 --- a/app/dashboard/views/alias_log.py +++ b/app/dashboard/views/alias_log.py @@ -44,7 +44,7 @@ def alias_log(alias_id, page_id): base = ( db.session.query(Contact, EmailLog) .filter(Contact.id == EmailLog.contact_id) - .filter(Contact.gen_email_id == alias.id) + .filter(Contact.alias_id == alias.id) ) total = base.count() email_forwarded = ( @@ -68,7 +68,7 @@ def get_alias_log(alias: Alias, page_id=0): q = ( db.session.query(Contact, EmailLog) .filter(Contact.id == EmailLog.contact_id) - .filter(Contact.gen_email_id == alias.id) + .filter(Contact.alias_id == alias.id) .order_by(EmailLog.id.desc()) .limit(PAGE_LIMIT) .offset(page_id * PAGE_LIMIT) diff --git a/app/dashboard/views/index.py b/app/dashboard/views/index.py index 9c6981d1..46db83a3 100644 --- a/app/dashboard/views/index.py +++ b/app/dashboard/views/index.py @@ -194,7 +194,7 @@ def get_alias_info( q = ( db.session.query(Alias, Contact, EmailLog, Mailbox) - .join(Contact, Alias.id == Contact.gen_email_id, isouter=True) + .join(Contact, Alias.id == Contact.alias_id, isouter=True) .join(EmailLog, Contact.id == EmailLog.contact_id, isouter=True) .join(Mailbox, Alias.mailbox_id == Mailbox.id, isouter=True) .filter(Alias.user_id == user.id) diff --git a/app/models.py b/app/models.py index 3294677a..31346bb0 100644 --- a/app/models.py +++ b/app/models.py @@ -619,7 +619,7 @@ class ClientUser(db.Model, ModelMixin): client_id = db.Column(db.ForeignKey(Client.id, ondelete="cascade"), nullable=False) # Null means client has access to user original email - gen_email_id = db.Column(db.ForeignKey(Alias.id, ondelete="cascade"), nullable=True) + alias_id = db.Column(db.ForeignKey(Alias.id, ondelete="cascade"), nullable=True) # user can decide to send to client another name name = db.Column( @@ -637,7 +637,7 @@ class ClientUser(db.Model, ModelMixin): client = db.relationship(Client) def get_email(self): - return self.alias.email if self.gen_email_id else self.user.email + return self.alias.email if self.alias_id else self.user.email def get_user_name(self): if self.name: @@ -684,7 +684,7 @@ class ClientUser(db.Model, ModelMixin): res[Scope.AVATAR_URL.value] = None elif scope == Scope.EMAIL: # Use generated email - if self.gen_email_id: + if self.alias_id: LOG.debug( "Use gen email for user %s, client %s", self.user, self.client ) @@ -702,12 +702,10 @@ class Contact(db.Model, ModelMixin): """ __table_args__ = ( - db.UniqueConstraint("gen_email_id", "website_email", name="uq_forward_email"), + db.UniqueConstraint("alias_id", "website_email", name="uq_contact"), ) - gen_email_id = db.Column( - db.ForeignKey(Alias.id, ondelete="cascade"), nullable=False - ) + alias_id = db.Column(db.ForeignKey(Alias.id, ondelete="cascade"), nullable=False) # used to be envelope header, should be mail header from instead website_email = db.Column(db.String(512), nullable=False) @@ -848,12 +846,10 @@ class AliasUsedOn(db.Model, ModelMixin): """Used to know where an alias is created""" __table_args__ = ( - db.UniqueConstraint("gen_email_id", "hostname", name="uq_alias_used"), + db.UniqueConstraint("alias_id", "hostname", name="uq_alias_used"), ) - gen_email_id = db.Column( - db.ForeignKey(Alias.id, ondelete="cascade"), nullable=False - ) + alias_id = db.Column(db.ForeignKey(Alias.id, ondelete="cascade"), nullable=False) hostname = db.Column(db.String(1024), nullable=False) diff --git a/app/oauth/views/authorize.py b/app/oauth/views/authorize.py index b14e07ee..333b0f0d 100644 --- a/app/oauth/views/authorize.py +++ b/app/oauth/views/authorize.py @@ -224,7 +224,7 @@ def authorize(): client_id=client.id, user_id=current_user.id ) if alias: - client_user.gen_email_id = alias.id + client_user.alias_id = alias.id if custom_name: client_user.name = custom_name diff --git a/cron.py b/cron.py index 86e4d122..e245fe9f 100644 --- a/cron.py +++ b/cron.py @@ -121,7 +121,7 @@ def stats(): # nb mails forwarded q = db.session.query(EmailLog, Contact, Alias, User).filter( EmailLog.contact_id == Contact.id, - Contact.gen_email_id == Alias.id, + Contact.alias_id == Alias.id, Alias.user_id == User.id, ) for ie in IGNORED_EMAILS: diff --git a/email_handler.py b/email_handler.py index 6c76ff8e..43db2686 100644 --- a/email_handler.py +++ b/email_handler.py @@ -212,7 +212,7 @@ def get_or_create_contact(website_from_header: str, alias: Alias) -> Contact: website_from_header can be the full-form email, i.e. "First Last " """ _, website_email = parseaddr(website_from_header) - contact = Contact.get_by(gen_email_id=alias.id, website_email=website_email) + contact = Contact.get_by(alias_id=alias.id, website_email=website_email) if contact: # update the website_from if needed if contact.website_from != website_from_header: @@ -236,7 +236,7 @@ def get_or_create_contact(website_from_header: str, alias: Alias) -> Contact: reply_email = f"reply+{random_string(30)}@{EMAIL_DOMAIN}" contact = Contact.create( - gen_email_id=alias.id, + alias_id=alias.id, website_email=website_email, website_from=website_from_header, reply_email=reply_email, @@ -482,7 +482,7 @@ def handle_reply(envelope, smtp: SMTP, msg: Message, rcpt_to: str) -> str: add_or_replace_header(msg, "To", contact.website_email) # add List-Unsubscribe header - unsubscribe_link = f"{URL}/dashboard/unsubscribe/{contact.gen_email_id}" + unsubscribe_link = f"{URL}/dashboard/unsubscribe/{contact.alias_id}" add_or_replace_header(msg, "List-Unsubscribe", f"<{unsubscribe_link}>") add_or_replace_header(msg, "List-Unsubscribe-Post", "List-Unsubscribe=One-Click") diff --git a/migrations/versions/2020_031711_0809266d08ca_.py b/migrations/versions/2020_031711_0809266d08ca_.py new file mode 100644 index 00000000..2afac36f --- /dev/null +++ b/migrations/versions/2020_031711_0809266d08ca_.py @@ -0,0 +1,56 @@ +"""empty message + +Revision ID: 0809266d08ca +Revises: e9395fe234a4 +Create Date: 2020-03-17 11:56:05.392474 + +""" +import sqlalchemy_utils +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "0809266d08ca" +down_revision = "e9395fe234a4" +branch_labels = None +depends_on = None + + +def upgrade(): + # alias_used_on table + op.alter_column("alias_used_on", "gen_email_id", new_column_name="alias_id") + op.drop_constraint("uq_alias_used", "alias_used_on", type_="unique") + op.create_unique_constraint( + "uq_alias_used", "alias_used_on", ["alias_id", "hostname"] + ) + op.drop_constraint( + "alias_used_on_gen_email_id_fkey", "alias_used_on", type_="foreignkey" + ) + op.create_foreign_key( + None, "alias_used_on", "alias", ["alias_id"], ["id"], ondelete="cascade" + ) + + # client_user table + op.alter_column("client_user", "gen_email_id", new_column_name="alias_id") + op.drop_constraint( + "client_user_gen_email_id_fkey", "client_user", type_="foreignkey" + ) + op.create_foreign_key( + None, "client_user", "alias", ["alias_id"], ["id"], ondelete="cascade" + ) + + # contact table + op.alter_column("contact", "gen_email_id", new_column_name="alias_id") + op.create_unique_constraint("uq_contact", "contact", ["alias_id", "website_email"]) + op.drop_constraint("uq_forward_email", "contact", type_="unique") + op.drop_constraint("forward_email_gen_email_id_fkey", "contact", type_="foreignkey") + op.create_foreign_key( + None, "contact", "alias", ["alias_id"], ["id"], ondelete="cascade" + ) + + +def downgrade(): + # One-way only + # Too complex to downgrade + raise Exception("Cannot downgrade") diff --git a/tests/api/test_alias.py b/tests/api/test_alias.py index ebf51c29..aa145b89 100644 --- a/tests/api/test_alias.py +++ b/tests/api/test_alias.py @@ -131,7 +131,7 @@ def test_alias_activities(flask_client): contact = Contact.create( website_email="marketing@example.com", reply_email="reply@a.b", - gen_email_id=alias.id, + alias_id=alias.id, ) db.session.commit() @@ -203,7 +203,7 @@ def test_alias_contacts(flask_client): contact = Contact.create( website_email=f"marketing-{i}@example.com", reply_email=f"reply-{i}@a.b", - gen_email_id=alias.id, + alias_id=alias.id, ) db.session.commit() diff --git a/tests/api/test_alias_options.py b/tests/api/test_alias_options.py index e8d34f96..418380a7 100644 --- a/tests/api/test_alias_options.py +++ b/tests/api/test_alias_options.py @@ -42,7 +42,7 @@ def test_different_scenarios(flask_client): # <<< with recommendation >>> alias = Alias.create_new(user, prefix="test") db.session.commit() - AliasUsedOn.create(gen_email_id=alias.id, hostname="www.test.com") + AliasUsedOn.create(alias_id=alias.id, hostname="www.test.com") db.session.commit() r = flask_client.get( @@ -87,7 +87,7 @@ def test_different_scenarios_v2(flask_client): # <<< with recommendation >>> alias = Alias.create_new(user, prefix="test") db.session.commit() - AliasUsedOn.create(gen_email_id=alias.id, hostname="www.test.com") + AliasUsedOn.create(alias_id=alias.id, hostname="www.test.com") db.session.commit() r = flask_client.get(