Compare commits

...

2 Commits

Author SHA1 Message Date
5776128905 4.36.3 2023-11-08 12:00:06 +00:00
d661860f4c 4.35.6 2023-11-07 12:00:06 +00:00
11 changed files with 135 additions and 75 deletions

View File

@ -23,7 +23,7 @@ COPY poetry.lock pyproject.toml ./
# Install and setup poetry
RUN pip install -U pip \
&& apt-get update \
&& apt install -y curl netcat-traditional gcc python3-dev gnupg git libre2-dev \
&& apt install -y curl netcat-traditional gcc python3-dev gnupg git libre2-dev cmake ninja-build\
&& curl -sSL https://install.python-poetry.org | python3 - \
# Remove curl and netcat from the image
&& apt-get purge -y curl netcat-traditional \
@ -31,7 +31,7 @@ RUN pip install -U pip \
&& poetry config virtualenvs.create false \
&& poetry install --no-interaction --no-ansi --no-root \
# Clear apt cache \
&& apt-get purge -y libre2-dev \
&& apt-get purge -y libre2-dev cmake ninja-build\
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

View File

@ -5,10 +5,11 @@ from typing import Optional
from arrow import Arrow
from newrelic import agent
from sqlalchemy import or_
from app.db import Session
from app.email_utils import send_welcome_email
from app.utils import sanitize_email
from app.utils import sanitize_email, canonicalize_email
from app.errors import (
AccountAlreadyLinkedToAnotherPartnerException,
AccountIsUsingAliasAsEmail,
@ -131,8 +132,9 @@ class ClientMergeStrategy(ABC):
class NewUserStrategy(ClientMergeStrategy):
def process(self) -> LinkResult:
# Will create a new SL User with a random password
canonical_email = canonicalize_email(self.link_request.email)
new_user = User.create(
email=self.link_request.email,
email=canonical_email,
name=self.link_request.name,
password=random_string(20),
activated=True,
@ -213,11 +215,21 @@ def process_login_case(
partner_id=partner.id, external_user_id=link_request.external_user_id
)
if partner_user is None:
canonical_email = canonicalize_email(link_request.email)
# We didn't find any SimpleLogin user registered with that partner user id
# Make sure they aren't using an alias as their link email
check_alias(link_request.email)
check_alias(canonical_email)
# Try to find it using the partner's e-mail address
user = User.get_by(email=link_request.email)
users = User.filter(
or_(User.email == link_request.email, User.email == canonical_email)
).all()
if len(users) > 1:
user = [user for user in users if user.email == canonical_email][0]
elif len(users) == 1:
user = users[0]
else:
user = None
return get_login_strategy(link_request, user, partner).process()
else:
# We found the SL user registered with that partner user id

View File

@ -611,6 +611,26 @@ class NewsletterAdmin(SLModelView):
else:
flash(error_msg, "error")
@action(
"clone_newsletter",
"Clone this newsletter",
)
def clone_newsletter(self, newsletter_ids):
if len(newsletter_ids) != 1:
flash("you can only select 1 newsletter", "error")
return
newsletter_id = newsletter_ids[0]
newsletter: Newsletter = Newsletter.get(newsletter_id)
new_newsletter = Newsletter.create(
subject=newsletter.subject,
html=newsletter.html,
plain_text=newsletter.plain_text,
commit=True,
)
flash(f"Newsletter {new_newsletter.subject} has been cloned", "success")
class NewsletterUserAdmin(SLModelView):
column_searchable_list = ["id"]

View File

@ -3517,7 +3517,7 @@ class PartnerSubscription(Base, ModelMixin):
class Newsletter(Base, ModelMixin):
__tablename__ = "newsletter"
subject = sa.Column(sa.String(), nullable=False, unique=True, index=True)
subject = sa.Column(sa.String(), nullable=False, index=True)
html = sa.Column(sa.Text)
plain_text = sa.Column(sa.Text)

View File

@ -89,7 +89,6 @@ aghast
agile
agility
aging
agnostic
agonize
agonizing
agony
@ -375,8 +374,6 @@ augmented
august
authentic
author
autism
autistic
autograph
automaker
automated
@ -446,7 +443,6 @@ backyard
bacon
bacteria
bacterium
badass
badge
badland
badly
@ -1106,7 +1102,6 @@ clinic
clinking
clip
clique
cloak
clobber
clock
clone
@ -1776,7 +1771,6 @@ diagnosis
diagram
dial
diameter
diaper
diaphragm
diary
dice
@ -2032,9 +2026,6 @@ duffel
dugout
duh
duke
duller
dullness
duly
dumping
dumpling
dumpster
@ -2527,8 +2518,6 @@ feisty
feline
felt-tip
feminine
feminism
feminist
feminize
femur
fence
@ -2667,7 +2656,6 @@ fondness
fondue
font
food
fool
footage
football
footbath
@ -2777,7 +2765,6 @@ gag
gainfully
gaining
gains
gala
gallantly
galleria
gallery
@ -3164,8 +3151,6 @@ hardware
hardwired
hardwood
hardy
harmful
harmless
harmonica
harmonics
harmonize
@ -3340,7 +3325,6 @@ identical
identify
identity
ideology
idiocy
idiom
idly
igloo
@ -3357,7 +3341,6 @@ imaging
imbecile
imitate
imitation
immature
immerse
immersion
imminent
@ -3387,14 +3370,10 @@ implode
implosion
implosive
imply
impolite
important
importer
impose
imposing
impotence
impotency
impotent
impound
imprecise
imprint
@ -3424,8 +3403,6 @@ irritable
irritably
irritant
irritate
islamic
islamist
isolated
isolating
isolation
@ -3524,7 +3501,6 @@ june
junior
juniper
junkie
junkman
junkyard
jurist
juror
@ -3570,9 +3546,6 @@ king
kinship
kinsman
kinswoman
kissable
kisser
kissing
kitchen
kite
kitten
@ -3649,7 +3622,6 @@ laundry
laurel
lavender
lavish
laxative
lazily
laziness
lazy
@ -3690,7 +3662,6 @@ liable
liberty
librarian
library
licking
licorice
lid
life
@ -3741,8 +3712,6 @@ livestock
lividly
living
lizard
lubricant
lubricate
lucid
luckily
luckiness
@ -3878,7 +3847,6 @@ marshland
marshy
marsupial
marvelous
marxism
mascot
masculine
mashed
@ -3914,8 +3882,6 @@ maximum
maybe
mayday
mayflower
moaner
moaning
mobile
mobility
mobilize
@ -4124,7 +4090,6 @@ nemeses
nemesis
neon
nephew
nerd
nervous
nervy
nest
@ -4139,7 +4104,6 @@ never
next
nibble
nickname
nicotine
niece
nifty
nimble
@ -4167,14 +4131,10 @@ nuptials
nursery
nursing
nurture
nutcase
nutlike
nutmeg
nutrient
nutshell
nuttiness
nutty
nuzzle
nylon
oaf
oak
@ -4205,7 +4165,6 @@ obstinate
obstruct
obtain
obtrusive
obtuse
obvious
occultist
occupancy
@ -4446,7 +4405,6 @@ palpitate
paltry
pampered
pamperer
pampers
pamphlet
panama
pancake
@ -4651,7 +4609,6 @@ plated
platform
plating
platinum
platonic
platter
platypus
plausible
@ -4777,8 +4734,6 @@ prancing
pranker
prankish
prankster
prayer
praying
preacher
preaching
preachy
@ -4796,8 +4751,6 @@ prefix
preflight
preformed
pregame
pregnancy
pregnant
preheated
prelaunch
prelaw
@ -4937,7 +4890,6 @@ prudishly
prune
pruning
pry
psychic
public
publisher
pucker
@ -4957,8 +4909,7 @@ punctual
punctuate
punctured
pungent
punisher
punk
punishe
pupil
puppet
puppy
@ -5040,7 +4991,6 @@ quote
rabid
race
racing
racism
rack
racoon
radar
@ -5155,7 +5105,6 @@ recount
recoup
recovery
recreate
rectal
rectangle
rectified
rectify
@ -5622,7 +5571,6 @@ sarcastic
sardine
sash
sasquatch
sassy
satchel
satiable
satin
@ -5651,7 +5599,6 @@ scaling
scallion
scallop
scalping
scam
scandal
scanner
scanning
@ -5928,8 +5875,6 @@ silent
silica
silicon
silk
silliness
silly
silo
silt
silver
@ -6196,7 +6141,6 @@ splinter
splotchy
splurge
spoilage
spoiled
spoiler
spoiling
spoils
@ -7078,7 +7022,6 @@ undocked
undoing
undone
undrafted
undress
undrilled
undusted
undying

View File

@ -158677,16 +158677,6 @@ isis
isize
isl
islay
islam
islamic
islamism
islamist
islamistic
islamite
islamitic
islamitish
islamization
islamize
island
islanded
islander

View File

@ -0,0 +1,31 @@
"""empty message
Revision ID: 4bc54632d9aa
Revises: 46ecb648a47e
Create Date: 2023-11-07 14:02:17.610226
"""
import sqlalchemy_utils
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision = '4bc54632d9aa'
down_revision = '46ecb648a47e'
branch_labels = None
depends_on = None
def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index('ix_newsletter_subject', table_name='newsletter')
op.create_index(op.f('ix_newsletter_subject'), 'newsletter', ['subject'], unique=False)
# ### end Alembic commands ###
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_index(op.f('ix_newsletter_subject'), table_name='newsletter')
op.create_index('ix_newsletter_subject', 'newsletter', ['subject'], unique=True)
# ### end Alembic commands ###

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@ -86,6 +86,12 @@
</head>
<body>
<div class="page">
{% if current_user.is_authenticated and current_user.should_show_upgrade_button() %}
<div class="alert alert-success text-center mb-0" role="alert">
Black Friday: $20 for the first year instead of $30. Available until December 1st.
</div>
{% endif %}
{% block announcement %}{% endblock %}
<div class="container">
<!-- For flash messages -->

View File

@ -57,6 +57,19 @@
{% endblock %}
{% block default_content %}
<div class="alert alert-info">
Black Friday Deal: 33% off on the yearly plan for the <b>first</b> year ($20 instead of $30).
<br>
Please use this coupon code
<em data-toggle="tooltip"
title="Click to copy"
class="clipboard"
data-clipboard-text="BF2023">BF2023</em> during the checkout.
<br>
<img src="/static/images/coupon.png" class="m-2" style="max-width: 300px">
<br>
Available until December 1, 2023.
</div>
<div class="pb-8">
<div class="text-center mx-md-auto mb-8 mt-6">
<h1>Upgrade to unlock premium features</h1>

View File

@ -18,7 +18,7 @@ from app.db import Session
from app.errors import AccountAlreadyLinkedToAnotherPartnerException
from app.models import Partner, PartnerUser, User
from app.proton.utils import get_proton_partner
from app.utils import random_string
from app.utils import random_string, canonicalize_email
from tests.utils import random_email
@ -377,3 +377,48 @@ def test_link_account_with_uppercase(flask_client):
)
assert partner_user.partner_id == get_proton_partner().id
assert partner_user.external_user_id == partner_user_id
def test_login_to_account_with_canonical_email(flask_client):
email = "a.{rand}@gmail.com".format(rand=random_string(10))
canonical_email = canonicalize_email(email)
assert email != canonical_email
partner_user_id = random_string()
link_request = random_link_request(
external_user_id=partner_user_id, email=email.upper()
)
user = create_user(canonical_email)
assert user.email == canonical_email
res = process_login_case(link_request, get_proton_partner())
assert res.user.id == user.id
def test_login_to_account_with_canonical_email_if_there_is_also_non_canonical(
flask_client,
):
email = "a.{rand}@gmail.com".format(rand=random_string(10))
canonical_email = canonicalize_email(email)
assert email != canonical_email
partner_user_id = random_string()
link_request = random_link_request(
external_user_id=partner_user_id, email=email.upper()
)
user = create_user(canonical_email)
create_user(email)
assert user.email == canonical_email
res = process_login_case(link_request, get_proton_partner())
assert res.user.id == user.id
def test_login_creates_account_with_canonical_email(
flask_client,
):
email = "a.{rand}@gmail.com".format(rand=random_string(10))
canonical_email = canonicalize_email(email)
assert email != canonical_email
partner_user_id = random_string()
link_request = random_link_request(
external_user_id=partner_user_id, email=email.upper()
)
res = process_login_case(link_request, get_proton_partner())
assert res.user.email == canonical_email