Repository: liberapay/liberapay.com

Issue:
Ask users to donate to the Liberapay team
After a user gives or receives for the first time ask them to donate to the Liberapay team to keep the service running.



Discussion:
Experience has proven once again that if we don't ask users to donate to the Liberapay team then they won't.


Resolving patch:
diff --git a/liberapay/constants.py b/liberapay/constants.py
--- a/liberapay/constants.py
+++ b/liberapay/constants.py
@@ -39,6 +39,7 @@ def __str__(self):
 BIRTHDAY = date(2015, 5, 22)
 
 D_CENT = Decimal('0.01')
+D_INF = Decimal('inf')
 D_UNIT = Decimal('1.00')
 D_ZERO = Decimal('0.00')
 
diff --git a/liberapay/models/_mixin_team.py b/liberapay/models/_mixin_team.py
--- a/liberapay/models/_mixin_team.py
+++ b/liberapay/models/_mixin_team.py
@@ -6,7 +6,7 @@
 from decimal import Decimal, ROUND_UP
 from statistics import median
 
-from liberapay.constants import D_CENT, D_UNIT, D_ZERO
+from liberapay.constants import D_CENT, D_INF, D_UNIT, D_ZERO
 
 
 class MemberLimitReached(Exception): pass
@@ -94,7 +94,7 @@ def compute_max_this_week(self, member_id, last_week):
         initial_leftover = self.receiving - sum_last_week
         nonzero_last_week = [a for a in last_week.values() if a]
         member_last_week = last_week.get(member_id, 0)
-        leftover_share = member_last_week / (sum_last_week or Decimal('inf'))
+        leftover_share = member_last_week / (sum_last_week or D_INF)
         leftover_share = max(leftover_share, D_UNIT / self.nmembers)
         return max(
             member_last_week * 2,
diff --git a/liberapay/models/participant.py b/liberapay/models/participant.py
--- a/liberapay/models/participant.py
+++ b/liberapay/models/participant.py
@@ -21,7 +21,7 @@
 
 from liberapay.billing import mangoapi
 from liberapay.constants import (
-    ASCII_ALLOWED_IN_USERNAME, AVATAR_QUERY, EMAIL_RE,
+    ASCII_ALLOWED_IN_USERNAME, AVATAR_QUERY, D_CENT, D_ZERO, EMAIL_RE,
     EMAIL_VERIFICATION_TIMEOUT, MAX_TIP,
     MIN_TIP, PASSWORD_MAX_SIZE, PASSWORD_MIN_SIZE, SESSION, SESSION_REFRESH,
     SESSION_TIMEOUT, USERNAME_MAX_SIZE
@@ -334,18 +334,6 @@ def upsert_statement(self, lang, statement, type='profile'):
                 return self.upsert_statement(lang, statement)
 
 
-    # Pricing
-    # =======
-
-    @property
-    def usage(self):
-        return max(self.giving, self.receiving)
-
-    @property
-    def suggested_payment(self):
-        return (self.usage * Decimal('0.05')).quantize(Decimal('.01'))
-
-
     # Stubs
     # =====
 
@@ -407,11 +395,11 @@ def distribute_balance_as_final_gift(self, cursor):
 
         tips, total, _, _= self.get_giving_for_profile()
         transfers = []
-        distributed = Decimal('0.00')
+        distributed = D_ZERO
 
         for tip in tips:
             rate = tip.amount / total
-            pro_rated = (self.balance * rate).quantize(Decimal('0.01'), ROUND_DOWN)
+            pro_rated = (self.balance * rate).quantize(D_CENT, ROUND_DOWN)
             if pro_rated == 0:
                 continue
             distributed += pro_rated
@@ -887,8 +875,8 @@ def withdrawable_balance(self):
         """, (self.id, QUARANTINE))
 
 
-    # Random Stuff
-    # ============
+    # Events
+    # ======
 
     def add_event(self, c, type, payload, recorder=None):
         c.run("""
@@ -896,6 +884,20 @@ def add_event(self, c, type, payload, recorder=None):
             VALUES (%s, %s, %s, %s)
         """, (self.id, type, Json(payload), recorder))
 
+    def get_last_event_of_type(self, type):
+        return self.db.one("""
+            SELECT *
+              FROM events
+             WHERE participant = %s
+               AND type = %s
+          ORDER BY ts DESC
+             LIMIT 1
+        """, (self.id, type))
+
+
+    # Random Stuff
+    # ============
+
     def url(self, path='', query=''):
         scheme = website.canonical_scheme
         host = website.canonical_host
@@ -1242,7 +1244,7 @@ def set_tip_to(self, tippee, amount, update_self=True, update_tippee=True, curso
     def _zero_tip_dict(tippee):
         if isinstance(tippee, Participant):
             tippee = tippee.id
-        return dict(amount=Decimal('0.00'), is_funded=False, tippee=tippee)
+        return dict(amount=D_ZERO, is_funded=False, tippee=tippee)
 
 
     def get_tip_to(self, tippee):
@@ -1307,7 +1309,7 @@ def get_tip_distribution(self):
         tip_amounts = []
 
         npatrons = 0.0  # float to trigger float division
-        contributed = Decimal('0.00')
+        contributed = D_ZERO
         for rec in self.db.all(SQL, (self.id,)):
             tip_amounts.append([ rec.amount
                                , rec.ncontributing
@@ -1381,11 +1383,11 @@ def get_giving_for_profile(self):
         total = sum([t.amount for t in tips])
         if not total:
             # If tips is an empty list, total is int 0. We want a Decimal.
-            total = Decimal('0.00')
+            total = D_ZERO
 
         pledges_total = sum([t.amount for t in pledges])
         if not pledges_total:
-            pledges_total = Decimal('0.00')
+            pledges_total = D_ZERO
 
         return tips, total, pledges, pledges_total
 


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
@@ -421,12 +421,6 @@ def test_rs_returns_openstreetmap_url_for_stub_from_openstreetmap(self):
         actual = stub.resolve_stub()
         assert actual == "/on/openstreetmap/alice/"
 
-    # suggested_payment
-
-    def test_suggested_payment_is_zero_for_new_user(self):
-        alice = self.make_participant('alice')
-        assert alice.suggested_payment == 0
-
     # avatar
 
     def test_update_avatar(self):