From 6646f977238e3c008e55783631cf7499b2150905 Mon Sep 17 00:00:00 2001
From: evcheng1
Date: Mon, 19 Apr 2021 16:33:00 -0400
Subject: [PATCH 1/3] added pause donations option in goals
---
emails/donations_paused.spt | 16 ++++++++++++++
liberapay/models/participant.py | 14 +++++++++++-
tests/py/test_goal.py | 34 ++++++++++++++++++++++++++++-
www/%username/edit/goal.spt | 19 +++++++++++-----
www/%username/giving/index.html.spt | 4 ++++
5 files changed, 80 insertions(+), 7 deletions(-)
create mode 100644 emails/donations_paused.spt
diff --git a/emails/donations_paused.spt b/emails/donations_paused.spt
new file mode 100644
index 0000000000..cc3e18b60f
--- /dev/null
+++ b/emails/donations_paused.spt
@@ -0,0 +1,16 @@
+% if donations_paused
+{{ _("Liberapay donation paused") }}
+% else
+{{ _("Liberapay donation resumed") }}
+% endif
+
+[---] text/html
+% if donations_paused
+{{ _("Due to changes recently made by {0}, your donations for {0} have been temporarily paused.", recipient) }}
+% else
+{{ _("Due to changes recently made by {0}, your donations for {0} are set to resume.", recipient) }}
+% endif
+
+{{ _("View your updated donations page at the following link:") }}
+
+{{ _("View Donations Page") }}
diff --git a/liberapay/models/participant.py b/liberapay/models/participant.py
index 220e82d506..edca671a75 100644
--- a/liberapay/models/participant.py
+++ b/liberapay/models/participant.py
@@ -2235,16 +2235,19 @@ def update_goal(self, goal, cursor=None):
raise UnexpectedCurrency(goal, self.main_currency)
with self.db.get_cursor(cursor) as c:
json = None if goal is None else str(goal)
+ donations_paused = goal == -2 and self.goal != -1
+ donations_resumed = goal != -1 and self.goal == -2
self.add_event(c, 'set_goal', json)
c.run("UPDATE participants SET goal=%s WHERE id=%s", (goal, self.id))
self.set_attributes(goal=goal)
- if not self.accepts_tips:
+ if not self.accepts_tips or donations_resumed:
tippers = c.all("""
SELECT p
FROM current_tips t
JOIN participants p ON p.id = t.tipper
WHERE t.tippee = %s
""", (self.id,))
+ if not self.accepts_tips:
for tipper in tippers:
tipper.update_giving(cursor=c)
r = c.one("""
@@ -2255,6 +2258,15 @@ def update_goal(self, goal, cursor=None):
RETURNING receiving, npatrons
""", (self.id,))
self.set_attributes(**r._asdict())
+ if donations_paused or donations_resumed:
+ for tipper in tippers:
+ tipper.send_email(
+ 'donations_paused',
+ tipper.get_email(tipper.get_email_address()),
+ recipient=self.username,
+ donations_paused=donations_paused,
+ donations_url=tipper.url('giving/')
+ )
def update_status(self, status, cursor=None):
with self.db.get_cursor(cursor) as c:
diff --git a/tests/py/test_goal.py b/tests/py/test_goal.py
index 2f5f886fd1..edf8b2f61f 100644
--- a/tests/py/test_goal.py
+++ b/tests/py/test_goal.py
@@ -1,5 +1,5 @@
from liberapay.testing import EUR, Harness
-
+from liberapay.testing.emails import EmailHarness
class Tests(Harness):
@@ -70,3 +70,35 @@ def test_team_member_can_change_team_goal(self):
)
assert r.code == 302
assert team.refetch().goal == EUR('99.99')
+
+class TestPauseDonations(EmailHarness):
+ def setUp(self):
+ EmailHarness.setUp(self)
+ self.alice = self.make_participant('alice', email='alice@example.com')
+
+ def change_goal(self, goal, goal_custom="", auth_as="alice", expect_success=False):
+ r = self.client.PxST(
+ "/alice/edit/goal",
+ {'goal': goal, 'goal_custom': goal_custom},
+ auth_as=self.alice if auth_as == 'alice' else auth_as
+ )
+ if expect_success and r.code >= 400:
+ raise r
+ return r
+
+ def test_pause(self):
+ bob = self.make_participant('bob', email='bob@example.com')
+ bob.set_tip_to(self.alice, EUR('0.99'), renewal_mode=2)
+ self.change_goal("-2", expect_success=True)
+
+ assert self.mailer.call_count == 1
+ last_email = self.get_last_email()
+ assert last_email['to'][0] == 'bob '
+ assert "paused" in last_email['text']
+
+ self.change_goal("null", "", expect_success=True)
+
+ assert self.mailer.call_count == 2
+ last_email = self.get_last_email()
+ assert last_email['to'][0] == 'bob '
+ assert "resume" in last_email['text']
diff --git a/www/%username/edit/goal.spt b/www/%username/edit/goal.spt
index 4f19edb4e9..e36d56b5bf 100644
--- a/www/%username/edit/goal.spt
+++ b/www/%username/edit/goal.spt
@@ -11,22 +11,25 @@ if request.method == "POST":
goal = request.body["goal_custom"]
goal_currency = request.body.get_currency('currency', participant.main_currency)
goal = locale.parse_money_amount(goal, goal_currency)
- if not (goal > 0 or participant.is_person and goal.amount in (0, -1)):
+ if not (goal > 0 or participant.is_person and goal.amount in (0, -1, -2)):
raise response.invalid_input(goal, 'goal_custom', 'body')
else:
- goal = Money(request.body.get_int("goal", minimum=-1), participant.main_currency).round_down()
- if not (goal > 0 or participant.is_person and goal.amount in (0, -1)):
+ goal = Money(request.body.get_int("goal", minimum=-2), participant.main_currency).round_down()
+ if not (goal > 0 or participant.is_person and goal.amount in (0, -1, -2)):
raise response.invalid_input(goal, 'goal', 'body')
- participant.update_goal(goal)
+ if goal != participant.goal:
+ participant.update_goal(goal)
form_post_success(state)
if participant.kind == 'individual':
GRATEFUL = _("I'm grateful for gifts, but don't have a specific funding goal.")
+ GRATEFUL_PAUSED_GIFTS = _("I'm grateful for gifts, but they are currently paused.")
PATRON = _("I'm here as a patron.")
PATRON_NO_GIFTS = _("I'm here as a patron, and politely decline to receive gifts.")
GOAL_RAW = _("My goal is to receive {0}")
else:
GRATEFUL = _("We're grateful for gifts, but don't have a specific funding goal.")
+ GRATEFUL_PAUSED_GIFTS = _("We're grateful for gifts, but they are currently paused.")
PATRON = _("We're here as a patron.")
PATRON_NO_GIFTS = _("We're here as a patron, and politely decline to receive gifts.")
GOAL_RAW = _("Our goal is to receive {0}")
@@ -69,6 +72,12 @@ subhead = _("Goal")
% if participant.kind != 'group'
+
+
-
{{ PATRON_NO_GIFTS }}
diff --git a/www/%username/giving/index.html.spt b/www/%username/giving/index.html.spt
index 05ca8f0cc4..62d5c32cf3 100644
--- a/www/%username/giving/index.html.spt
+++ b/www/%username/giving/index.html.spt
@@ -358,8 +358,8 @@ next_payday = compute_next_payday_date()
"Inactive because the account of the recipient is closed."
) }}
% elif tippee.goal == -2
- {{ glyphicon('warning-sign') }} {{ _(
- "Inactive because the recipient's donations are temporarily paused."
+
{{ glyphicon('pause') }} {{ _(
+ "This donation has been paused by the recipient."
) }}
% elif not tippee.accepts_tips
{{ glyphicon('warning-sign') }} {{ _(
From e467f17fe261f26d3debf11dd1d217798d744c5e Mon Sep 17 00:00:00 2001
From: evcheng1
Date: Sat, 24 Apr 2021 03:35:30 -0400
Subject: [PATCH 3/3] added seperate donations_paused and donations_resumed
events in the update_goal method
---
liberapay/models/participant.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/liberapay/models/participant.py b/liberapay/models/participant.py
index edca671a75..803c847ea8 100644
--- a/liberapay/models/participant.py
+++ b/liberapay/models/participant.py
@@ -2260,8 +2260,9 @@ def update_goal(self, goal, cursor=None):
self.set_attributes(**r._asdict())
if donations_paused or donations_resumed:
for tipper in tippers:
+ event = 'donations_paused' if donations_paused else 'donations_resumed'
tipper.send_email(
- 'donations_paused',
+ event,
tipper.get_email(tipper.get_email_address()),
recipient=self.username,
donations_paused=donations_paused,