Repository: liberapay/liberapay.com

Issue:
Pledge locking is weird
It doesn't make much sense to prevent users from making pledges, they have the right to make a list of who they want to support and keep track of whether those people/projects have joined Liberapay. Pledges are only a problem when donors send awkward or confusing messages to their pledgees (e.g. #1863), so that's what we need to avoid.

In other words, pledgees should be able to state “we're aware of Liberapay but we currently can't or don't want to join”, not “we don't want Liberapay users to be able to pledge to us”.


Discussion:

Resolving patch:
diff --git a/liberapay/models/participant.py b/liberapay/models/participant.py
--- a/liberapay/models/participant.py
+++ b/liberapay/models/participant.py
@@ -57,7 +57,6 @@
     UnableToDistributeBalance,
     UnableToSendEmail,
     UnexpectedCurrency,
-    UserDoesntAcceptTips,
     UsernameAlreadyTaken,
     UsernameBeginsWithRestrictedCharacter,
     UsernameContainsInvalidCharacters,
@@ -2328,7 +2327,7 @@ def update_giving_and_tippees(self, cursor):
     def update_giving(self, cursor=None):
         # Update is_funded on tips
         tips = (cursor or self.db).all("""
-            SELECT t.*, p2.status AS tippee_status
+            SELECT t.*, p2.status AS tippee_status, p2.goal AS tippee_goal
               FROM current_tips t
               JOIN participants p2 ON p2.id = t.tippee
              WHERE t.tipper = %s
@@ -2354,10 +2353,9 @@ def update_giving(self, cursor=None):
         """, dict(p_id=self.id)) is not None
         updated = []
         for tip in tips:
-            if tip.tippee_status == 'stub':
-                is_funded = has_donated_recently
-            else:
-                is_funded = tip.amount <= (tip.paid_in_advance or 0)
+            is_funded = tip.amount <= (tip.paid_in_advance or 0)
+            if tip.tippee_status == 'stub' or tip.tippee_goal == -1:
+                is_funded |= has_donated_recently
             if tip.is_funded == is_funded:
                 continue
             updated.append((cursor or self.db).one("""
@@ -2447,8 +2445,6 @@ def set_tip_to(self, tippee, periodic_amount, period='weekly', renewal_mode=None
             limits = DONATION_LIMITS[periodic_amount.currency][period]
             if periodic_amount < limits[0] or periodic_amount > limits[1]:
                 raise BadAmount(periodic_amount, period, limits)
-            if not tippee.accepts_tips:
-                raise UserDoesntAcceptTips(tippee.username)
             if amount.currency not in tippee.accepted_currencies_set:
                 raise BadDonationCurrency(tippee, amount.currency)
 
diff --git a/liberapay/payin/common.py b/liberapay/payin/common.py
--- a/liberapay/payin/common.py
+++ b/liberapay/payin/common.py
@@ -9,7 +9,7 @@
 from ..constants import SEPA
 from ..exceptions import (
     AccountSuspended, MissingPaymentAccount, RecipientAccountSuspended,
-    NoSelfTipping,
+    NoSelfTipping, UserDoesntAcceptTips,
 )
 from ..i18n.currencies import Money, MoneyBasket
 from ..utils import group_by
@@ -315,6 +315,8 @@ def prepare_donation(
 
     if payer.is_suspended:
         raise AccountSuspended(payer)
+    if not tippee.accepts_tips:
+        raise UserDoesntAcceptTips(tippee.username)
     if tippee.is_suspended:
         raise RecipientAccountSuspended(tippee)
 


Test patch:
diff --git a/tests/py/test_participant.py b/tests/py/test_participant.py
--- a/tests/py/test_participant.py
+++ b/tests/py/test_participant.py
@@ -9,7 +9,6 @@
     NoSelfTipping,
     NoTippee,
     NonexistingElsewhere,
-    UserDoesntAcceptTips,
     UsernameAlreadyTaken,
     UsernameBeginsWithRestrictedCharacter,
     UsernameContainsInvalidCharacters,
@@ -462,12 +461,6 @@ def test_receiving_is_zero_for_patrons(self):
 
     # pledging
 
-    def test_cant_pledge_to_locked_accounts(self):
-        alice = self.make_participant('alice')
-        bob = self.make_stub(goal=EUR(-1))
-        with self.assertRaises(UserDoesntAcceptTips):
-            alice.set_tip_to(bob, EUR('3.00'))
-
     def test_pledging_isnt_giving(self):
         alice = self.make_participant('alice', balance=EUR(100))
         bob = self.make_elsewhere('github', 58946, 'bob').participant
diff --git a/tests/py/test_tip_json.py b/tests/py/test_tip_json.py
--- a/tests/py/test_tip_json.py
+++ b/tests/py/test_tip_json.py
@@ -70,8 +70,7 @@ def test_set_tip_to_patron(self):
         bob = self.make_participant("bob")
 
         response = self.tip(bob, "alice", "10.00", raise_immediately=False)
-        assert "doesn't accept donations" in response.text, response.text
-        assert response.code == 403
+        assert response.code == 200
 
     def test_tip_to_unclaimed(self):
         alice = self.make_elsewhere('twitter', 1, 'alice')