diff --git a/emails/base.spt b/emails/base.spt
index 076880092..cf1149d71 100644
--- a/emails/base.spt
+++ b/emails/base.spt
@@ -10,7 +10,7 @@ $body
_("Something wrong? This email was sent automatically, but you can contact us by replying to it.")
}}
-
{{
_("Change your email settings")
}}.
@@ -29,4 +29,4 @@ $body
{{ _("Something wrong? This email was sent automatically, but you can contact us by replying to it.") }}
-{{ _("Change your email settings") }}: https://liberapay.com/about/me/emails/
+{{ _("Change your email settings") }}: {{ participant.url('emails/') }}
diff --git a/liberapay/models/account_elsewhere.py b/liberapay/models/account_elsewhere.py
index e7ab12e12..da530d109 100644
--- a/liberapay/models/account_elsewhere.py
+++ b/liberapay/models/account_elsewhere.py
@@ -193,9 +193,6 @@ def update():
raise
# Return account after propagating avatar_url to participant
- avatar_url = account.avatar_url
- if avatar_url and avatar_url.startswith('https://pbs.twimg.com/'):
- avatar_url = 'https://nitter.net/pic/' + avatar_url[22:].replace('/', '%2F')
account.participant.update_avatar(check=False)
return account
diff --git a/liberapay/models/participant.py b/liberapay/models/participant.py
index 6066201f6..fc645de72 100644
--- a/liberapay/models/participant.py
+++ b/liberapay/models/participant.py
@@ -1794,7 +1794,7 @@ def url(self, path='', query='', log_in='auto'):
extra_query = []
if log_in == 'required' or log_in == 'auto' and not self.has_password:
primary_email = self.get_email_address()
- if email_row.address.lower() == primary_email.lower():
+ if primary_email and email_row.address.lower() == primary_email.lower():
# Only send login links to the primary email address
session = self._email_session
if not session:
@@ -1810,13 +1810,8 @@ def url(self, path='', query='', log_in='auto'):
extra_query.append(('log-in.token', session.secret))
if log_in != 'required':
extra_query.append(('log-in.required', 'no'))
- else:
- try:
- raise AssertionError('%r != %r' % (email_row.address, primary_email))
- except AssertionError as e:
- website.tell_sentry(e)
- if log_in == 'required':
- raise
+ elif log_in == 'required':
+ raise AssertionError('%r != %r' % (email_row.address, primary_email))
if not email_row.verified:
if not email_row.nonce:
email_row = self._rendering_email_to = self.db.one("""
diff --git a/sql/branch.sql b/sql/branch.sql
new file mode 100644
index 000000000..910f9b6fe
--- /dev/null
+++ b/sql/branch.sql
@@ -0,0 +1,3 @@
+UPDATE participants
+ SET avatar_url = 'https://pbs.twimg.com/' || regexp_replace(substr(avatar_url, 24), '%2F', '/', 'g')
+ WHERE avatar_url LIKE 'https://nitter.net/pic/%';
diff --git a/tests/py/test_sessions.py b/tests/py/test_sessions.py
index 1cedab8a6..3bec81f2c 100644
--- a/tests/py/test_sessions.py
+++ b/tests/py/test_sessions.py
@@ -155,6 +155,7 @@ def test_email_login(self):
alice = self.make_participant('alice', email=None)
alice.add_email(email)
alice.close()
+ self.db.run("DELETE FROM user_secrets")
# Sanity checks
email_row = alice.get_email(email)
@@ -248,6 +249,7 @@ def test_email_login_with_old_unverified_address(self):
alice = self.make_participant('alice', email=None)
alice.add_email(email)
Participant.dequeue_emails()
+ self.db.run("DELETE FROM user_secrets")
self.db.run("UPDATE emails SET nonce = null")
# Initiate email log-in
diff --git a/www/admin/payments.spt b/www/admin/payments.spt
index 52e116170..6b54c7235 100644
--- a/www/admin/payments.spt
+++ b/www/admin/payments.spt
@@ -81,9 +81,11 @@ title = "Payments Admin"
% extends "templates/layouts/admin.html"
-% macro render_payin_transfer(pt, pi)
+% macro render_payin_transfer(pt, pi, show_amount=True)
+ % if show_amount
{{ locale.format_money(pt.amount) }}
+ % endif
to {{ pt.recipient_name }}
% if pt.period
({{ locale.format_money(pt.unit_amount) }}/{{ pt.period[:-2] }} × {{ pt.n_units }})
@@ -167,8 +169,9 @@ title = "Payments Admin"
{{ locale.format_money_basket(item['sum']) }}
through team {{ item['team_name'] }}
+ % set show_amount = len(item['transfers']) > 1
% for pt in item['transfers']
- {{ render_payin_transfer(pt, pi) }}
+ {{ render_payin_transfer(pt, pi, show_amount=show_amount) }}
% endfor
diff --git a/www/callbacks/stripe.spt b/www/callbacks/stripe.spt
index 976ebdaf2..54af17d2d 100644
--- a/www/callbacks/stripe.spt
+++ b/www/callbacks/stripe.spt
@@ -87,6 +87,10 @@ elif event_object_type == 'charge.dispute':
# Notify the person who initiated the payment
payer = Participant.from_id(payin.payer)
if dispute.status in ('needs_response', 'lost'):
+ try:
+ due_by = dispute.evidence_details.due_by
+ except AttributeError:
+ due_by = 0
try:
payer.notify(
'payin_disputed',
@@ -97,7 +101,10 @@ elif event_object_type == 'charge.dispute':
payin_amount=payin.amount,
payin_ctime=payin.ctime,
dispute_reason=dispute.reason,
- dispute_can_be_withdrawn=dispute.status == 'needs_response',
+ dispute_can_be_withdrawn=(
+ dispute.status == 'needs_response' and
+ due_by > utcnow().timestamp()
+ ),
mandate_url=route.get_mandate_url(),
)
except DuplicateNotification: