diff --git a/app/email_utils.py b/app/email_utils.py index 0ab5626c..070d2910 100644 --- a/app/email_utils.py +++ b/app/email_utils.py @@ -33,6 +33,7 @@ from flanker.addresslib import address from flanker.addresslib.address import EmailAddress from jinja2 import Environment, FileSystemLoader from sqlalchemy import func +from flask_login import current_user from app import config from app.db import Session @@ -74,11 +75,16 @@ def render(template_name, **kwargs) -> str: template = env.get_template(template_name) + use_partner_template = False + if current_user and current_user.is_authenticated: + use_partner_template = current_user.has_used_alias_from_partner() + return template.render( MAX_NB_EMAIL_FREE_PLAN=config.MAX_NB_EMAIL_FREE_PLAN, URL=config.URL, LANDING_PAGE_URL=config.LANDING_PAGE_URL, YEAR=arrow.now().year, + USE_PARTNER_TEMPLATE=use_partner_template, **kwargs, ) diff --git a/app/models.py b/app/models.py index c7c8f700..3f9952bd 100644 --- a/app/models.py +++ b/app/models.py @@ -330,6 +330,7 @@ class User(Base, ModelMixin, UserMixin, PasswordOracle): FLAG_FREE_DISABLE_CREATE_ALIAS = 1 << 0 FLAG_CREATED_FROM_PARTNER = 1 << 1 FLAG_FREE_OLD_ALIAS_LIMIT = 1 << 2 + FLAG_CREATED_ALIAS_FROM_PARTNER = 1 << 3 email = sa.Column(sa.String(256), unique=True, nullable=False) @@ -1153,6 +1154,13 @@ class User(Base, ModelMixin, UserMixin, PasswordOracle): return True return not config.DISABLE_CREATE_CONTACTS_FOR_FREE_USERS + def has_used_alias_from_partner(self) -> bool: + return ( + self.flags + & (User.FLAG_CREATED_ALIAS_FROM_PARTNER | User.FLAG_CREATED_FROM_PARTNER) + > 0 + ) + def __repr__(self): return f"" @@ -1646,6 +1654,12 @@ class Alias(Base, ModelMixin): ) EventDispatcher.send_event(user, EventContent(alias_created=event)) + if ( + new_alias.flags & cls.FLAG_PARTNER_CREATED > 0 + and new_alias.user.flags & User.FLAG_CREATED_ALIAS_FROM_PARTNER == 0 + ): + user.flags = user.flags | User.FLAG_CREATED_ALIAS_FROM_PARTNER + if commit: Session.commit() diff --git a/oneshot/recalculate_user_flag_alias_create_from_partner.py b/oneshot/recalculate_user_flag_alias_create_from_partner.py new file mode 100644 index 00000000..9f71f3e1 --- /dev/null +++ b/oneshot/recalculate_user_flag_alias_create_from_partner.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +import argparse +import time + +from sqlalchemy import func +from app.models import Alias, User +from app.db import Session + +parser = argparse.ArgumentParser( + prog="Backfill alias", description="Backfill user flags for partner alias created" +) +parser.add_argument( + "-s", "--start_user_id", default=0, type=int, help="Initial user_id" +) +parser.add_argument("-e", "--end_user_id", default=0, type=int, help="Last user_id") + +args = parser.parse_args() +user_id_start = args.start_user_id +max_user_id = args.end_user_id +if max_user_id == 0: + max_user_id = Session.query(func.max(User.id)).scalar() + +print(f"Checking user {user_id_start} to {max_user_id}") +step = 1000 +el_query = "SELECT user_id, count(id) from alias where user_id>=:start AND user_id < :end AND flags & :alias_flag > 0 GROUP BY user_id" +user_update_query = "UPDATE users set flags = flags | :user_flag where id = :user_id" +updated = 0 +start_time = time.time() +for batch_start in range(user_id_start, max_user_id, step): + rows = Session.execute( + el_query, + { + "start": batch_start, + "end": batch_start + step, + "alias_flag": Alias.FLAG_PARTNER_CREATED, + }, + ) + for row in rows: + if row[1] > 0: + Session.execute( + user_update_query, + {"user_id": row[0], "user_flag": User.FLAG_CREATED_ALIAS_FROM_PARTNER}, + ) + Session.commit() + updated += 1 + elapsed = time.time() - start_time + time_per_alias = elapsed / (updated + 1) + last_batch_id = batch_start + step + remaining = max_user_id - last_batch_id + time_remaining = (max_user_id - last_batch_id) * time_per_alias + hours_remaining = time_remaining / 3600.0 + print( + f"\rUser {batch_start}/{max_user_id} {updated} {hours_remaining:.2f}hrs remaining" + ) +print("") diff --git a/static/logo-proton.png b/static/logo-proton.png new file mode 100644 index 00000000..a213f55f Binary files /dev/null and b/static/logo-proton.png differ diff --git a/templates/emails/base.html b/templates/emails/base.html index 5ae5af94..aacac3b4 100644 --- a/templates/emails/base.html +++ b/templates/emails/base.html @@ -1,623 +1,8 @@ -{% from "_emailhelpers.html" import render_text, text, render_button, raw_url, grey_section, section %} - - - - - - - - - - - - {{ pre_header }} - - - - - - - +{% endif %} diff --git a/templates/emails/base_partner.html b/templates/emails/base_partner.html new file mode 100644 index 00000000..d22a3b06 --- /dev/null +++ b/templates/emails/base_partner.html @@ -0,0 +1,646 @@ +{% from "_emailhelpers.html" import render_text, text, render_button, raw_url, grey_section, section %} + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + + + + +
+ + + + + + +
+ + + + + + +
+ + Proton + +
+
+
+ {% block greeting %}{% endblock %} + {% block content %}{% endblock %} + + {% block sub_copy %}{% endblock %} +
+ + +
+
+ + diff --git a/templates/emails/base_sl.html b/templates/emails/base_sl.html new file mode 100644 index 00000000..5ae5af94 --- /dev/null +++ b/templates/emails/base_sl.html @@ -0,0 +1,623 @@ +{% from "_emailhelpers.html" import render_text, text, render_button, raw_url, grey_section, section %} + + + + + + + + + + + + {{ pre_header }} + + + + + + + diff --git a/tests/models/test_alias.py b/tests/models/test_alias.py index 3354b8bc..c11b596e 100644 --- a/tests/models/test_alias.py +++ b/tests/models/test_alias.py @@ -1,5 +1,5 @@ from app.db import Session -from app.models import Alias, Mailbox, AliasMailbox +from app.models import Alias, Mailbox, AliasMailbox, User from tests.utils import create_new_user, random_email @@ -15,3 +15,17 @@ def test_duplicated_mailbox_is_returned_only_once(): alias_mailbox_id = [mailbox.id for mailbox in alias_mailboxes] assert user.default_mailbox_id in alias_mailbox_id assert other_mailbox.id in alias_mailbox_id + + +def test_alias_create_from_partner_flags_also_the_user(): + user = create_new_user() + Session.flush() + email = random_email() + alias = Alias.create( + user_id=user.id, + email=email, + mailbox_id=user.default_mailbox_id, + flags=Alias.FLAG_PARTNER_CREATED, + flush=True, + ) + assert alias.user.flags & User.FLAG_CREATED_ALIAS_FROM_PARTNER > 0