-
Notifications
You must be signed in to change notification settings - Fork 308
Email - Part 1 #2752
Email - Part 1 #2752
Changes from all commits
aebe84b
3c589fa
c12554c
301e94f
cdd872f
2db3f30
803f25b
f61197c
fc0ffbe
f406e37
5ed0e38
06cec4e
21a561c
6e2acec
5d0088e
135e99c
1a4528c
baea124
c9112f1
abdf353
bc8a77c
e7cec73
ee8af15
a07f027
81710eb
69bef23
9288749
3af999f
50fa80e
1c6aad2
195088e
99b65e4
bd93c02
a34edaa
e4e4276
904d31b
0214e51
ee6b490
208c766
a826986
37300cc
d881efa
890ecd8
88a0787
5fe231f
03bfd20
c8c71e2
12453f1
c36a918
0b35719
71be243
43448ca
fad8bf2
645f5ce
cdbbc42
75b9910
0c8c43c
74b573c
30bf017
21198b7
4e454d9
ee3c871
c4d91c8
8538edc
8274597
3aa0e36
11ace50
d7fe2e0
ed30791
6290606
eab4f81
f65199c
7ae4095
f1610f3
a8dec44
2bc84bd
f07a1db
468239f
a969f77
2e60c4c
365e182
3110318
6793871
3afd352
5286d52
aea5b43
8a1a80a
7931824
3a69204
1beb434
b72d4bb
f475cec
8328a18
7b14196
df5a49b
14be73e
87ef00a
66f8f64
c8d0c16
114b39b
f01be44
a79ed2f
42bbdc0
dd61c5b
ee65f9a
2ab4145
835de34
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
""" | ||
This is a one-off script to populate the new `emails` table using the addresses | ||
we have in `participants`. | ||
""" | ||
from __future__ import division, print_function, unicode_literals | ||
|
||
from urllib import quote | ||
import uuid | ||
|
||
import gratipay | ||
from aspen.utils import utcnow | ||
from postgres.orm import Model | ||
|
||
import gratipay.wireup | ||
|
||
env = gratipay.wireup.env() | ||
tell_sentry = gratipay.wireup.make_sentry_teller(env) | ||
db = gratipay.wireup.db(env) | ||
gratipay.wireup.mail(env) | ||
gratipay.wireup.load_i18n('.', tell_sentry) | ||
gratipay.wireup.canonical(env) | ||
|
||
|
||
class EmailAddressWithConfirmation(Model): | ||
typname = "email_address_with_confirmation" | ||
|
||
db.register_model(EmailAddressWithConfirmation) | ||
|
||
|
||
def add_email(self, email): | ||
nonce = str(uuid.uuid4()) | ||
verification_start = utcnow() | ||
|
||
scheme = gratipay.canonical_scheme | ||
host = gratipay.canonical_host | ||
username = self.username_lower | ||
quoted_email = quote(email) | ||
link = "{scheme}://{host}/{username}/emails/verify.html?email={quoted_email}&nonce={nonce}" | ||
self.send_email('initial', | ||
email=email, | ||
link=link.format(**locals()), | ||
username=self.username, | ||
include_unsubscribe=False) | ||
|
||
db.run(""" | ||
INSERT INTO emails | ||
(address, nonce, verification_start, participant) | ||
VALUES (%s, %s, %s, %s) | ||
""", (email, nonce, verification_start, self.username)) | ||
|
||
|
||
participants = db.all(""" | ||
SELECT p.*::participants | ||
FROM participants p | ||
WHERE email IS NOT NULL | ||
AND NOT is_closed | ||
AND is_suspicious IS NOT true | ||
AND claimed_time IS NOT NULL; | ||
""") | ||
total = len(participants) | ||
for i, p in enumerate(participants, 1): | ||
print('sending email to %s (%i/%i)' % (p.username, i, total)) | ||
add_email(p, p.email.address) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
BEGIN; | ||
CREATE TABLE emails | ||
( id serial PRIMARY KEY | ||
, address text NOT NULL | ||
, verified boolean DEFAULT NULL | ||
CONSTRAINT verified_cant_be_false | ||
-- Only use TRUE and NULL, so that the | ||
-- unique constraint below functions | ||
-- properly. | ||
CHECK (verified IS NOT FALSE) | ||
, nonce text | ||
, verification_start timestamp with time zone NOT NULL | ||
DEFAULT CURRENT_TIMESTAMP | ||
, verification_end timestamp with time zone | ||
, participant text NOT NULL | ||
REFERENCES participants | ||
ON UPDATE CASCADE | ||
ON DELETE RESTRICT | ||
|
||
, UNIQUE (address, verified) -- A verified email address can't be linked to multiple | ||
-- participants. However, an *un*verified address *can* | ||
-- be linked to multiple participants. We implement this | ||
-- by using NULL instead of FALSE for the unverified | ||
-- state, hence the check constraint on verified. | ||
, UNIQUE (participant, address) | ||
); | ||
|
||
-- The participants table currently has an `email` attribute of type | ||
-- email_address_with confirmation. This should be deleted in the future, | ||
-- once the emails are migrated. The column we're going to replace it with | ||
-- is named `email_address`. This is only for **verified** emails. All | ||
-- unverified email stuff happens in the emails table and won't touch this | ||
-- attribute. | ||
|
||
ALTER TABLE participants ADD COLUMN email_address text UNIQUE, | ||
ADD COLUMN email_lang text; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because for now we only use it for emails, and because it seems to me like a good idea to be able to choose the language of emails independently from the rest. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Really? I'm mono-lingual, so not really qualified to say, but I'm surprised that you'd want the website in one language but emails in another. |
||
|
||
UPDATE events | ||
SET payload = replace(replace( payload::text, '"set"', '"add"') | ||
, '"current_email"' | ||
, '"email"' | ||
)::json | ||
WHERE payload->>'action' = 'set' | ||
AND (payload->'values'->'current_email') IS NOT NULL; | ||
|
||
END; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,6 +71,6 @@ ASPEN_WWW_ROOT=www/ | |
# https://github.com/benoitc/gunicorn/issues/186 | ||
GUNICORN_OPTS="--workers=1 --timeout=99999999" | ||
|
||
MANDRILL_KEY= | ||
MANDRILL_KEY=Phh_Lm3RdPT5blqOPY4dVQ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Whose key is this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gratipay's test key. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should update the README to talk about this. Iinm you won't be able to use this to actually send email. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in ee65f9a. |
||
|
||
RAISE_CARD_EXPIRATION=no |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
[---] text/html | ||
<div style="text-align: center; padding: 20px 0; margin: 0;"> | ||
<img src="https://downloads.gratipay.com/email/gratipay.png" alt="Gratipay"> | ||
</div> | ||
|
||
<div style="text-align: center; font: normal 14px/21px Arial, sans-serif; color: #333; padding: 0 20%;"> | ||
$body | ||
</div> | ||
|
||
<div style="text-align: center; color: #999; padding: 21px 0 0;"> | ||
<div style="font: normal 14px/21px Arial, sans-serif;"> | ||
{{ _("Something not right? Reply to this email for help.") }} | ||
</div> | ||
<div style="font: normal 10px/21px Arial, sans-serif;"> | ||
Sent by <a href="https://gratipay.com/" style="color: #999; text-decoration: underline;">Gratipay, LLC</a> | 716 Park Road, Ambridge, PA, 15003, USA | ||
</div> | ||
</div> | ||
|
||
[---] text/plain | ||
{{ _("Greetings, program!") }} | ||
|
||
$body | ||
|
||
{{ _("Something not right? Reply to this email for help.") }} | ||
|
||
---- | ||
|
||
Sent by Gratipay, LLC, https://gratipay.com/ | ||
716 Park Road, Ambridge, PA, 15003, USA |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{{ _("Connect to {0} on Gratipay?", username) }} | ||
|
||
[---] text/html | ||
A while ago we received a request to connect <b>{{ escape(email) }}</b> to the | ||
{{ '<b><a href="https://gratipay.com/{0}/">{0}</a></b>'.format(username) }} | ||
account on Gratipay (<a | ||
href="https://medium.com/gratipay-blog/gratitude-gratipay-ef24ad5e41f9">formerly</a> | ||
Gittip). Now we're finally sending a verification email! Ring a bell? | ||
<br> | ||
<br> | ||
<a href="{{ link }}" style="color: #fff; text-decoration:none; display:inline-block; padding: 0 15px; background: #396; font: normal 14px/40px Arial, sans-serif; white-space: nowrap; border-radius: 3px">Yes, proceed!</a> | ||
|
||
[---] text/plain | ||
|
||
A while ago we received a request to connect `{{ email }}` | ||
to the `{{ username }}` account on Gratipay (formerly Gittip). | ||
Now we're finally sending a verification email! | ||
|
||
Ring a bell? Follow this link to finish connecting your email: | ||
|
||
{{ link }} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
{{ _("Connect to {0} on Gratipay?", username) }} | ||
|
||
[---] text/html | ||
{{ _("We've received a request to connect {0} to the {1} account on Gratipay. Sound familiar?", | ||
'<b>%s</b>' % escape(email), | ||
'<b><a href="https://gratipay.com/{0}">{0}</a></b>'.format(username)) }} | ||
<br> | ||
<br> | ||
<a href="{{ link }}" style="color: #fff; text-decoration:none; display:inline-block; padding: 0 15px; background: #396; font: normal 14px/40px Arial, sans-serif; white-space: nowrap; border-radius: 3px">{{ _("Yes, proceed!") }}</a> | ||
|
||
[---] text/plain | ||
{{ _("We've received a request to connect {0} to the {1} account on Gratipay. Sound familiar?", | ||
email, username) }} | ||
|
||
{{ _("Follow this link to finish connecting your email:") }} | ||
|
||
{{ link }} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
{{ _("Connecting {0} to {1} on Gratipay.", new_email, username) }} | ||
|
||
[---] text/html | ||
{{ _("We are connecting {0} to the {1} account on Gratipay. This is a notification " | ||
"sent to {2} because that is the primary email address we have on file.", | ||
'<b>%s</b>' % escape(new_email), | ||
'<b><a href="https://gratipay.com/{0}">{0}</a></b>'.format(username), | ||
'<b>%s</b>' % escape(email)) }} | ||
|
||
[---] text/plain | ||
{{ _("We are connecting {0} to the {1} account on Gratipay. This is a notification " | ||
"sent to {2} because that is the primary email address we have on file.", | ||
new_email, username, email) }} |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why
email_address
instead ofemail
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because
email
already exists, it's the one we're replacing.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does that mean we can't use the same name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because we want to migrate data between the two, is that it? So it'd be a little more complicated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.