Repository: gratipay/gratipay.com

Issue:
preclude adding stub participants as team members
Reticketed from #2362.

preclude adding stub participants as team members
Reticketed from #2362.



Discussion:
I'll implement it.

I'll implement it.


Resolving patch:
diff --git a/gittip/models/_mixin_team.py b/gittip/models/_mixin_team.py
--- a/gittip/models/_mixin_team.py
+++ b/gittip/models/_mixin_team.py
@@ -7,6 +7,7 @@
 
 class MemberLimitReached(Exception): pass
 
+class StubParticipantAdded(Exception): pass
 
 class MixinTeam(object):
     """This class provides methods for working with a Participant as a Team.
@@ -39,6 +40,8 @@ def add_member(self, member):
         assert self.IS_PLURAL
         if len(self.get_takes()) == 149:
             raise MemberLimitReached
+        if not member.is_claimed:
+            raise StubParticipantAdded
         self.__set_take_for(member, Decimal('0.01'), self)
 
     def remove_member(self, member):


Test patch:
diff --git a/tests/py/test_lookup_json.py b/tests/py/test_lookup_json.py
--- a/tests/py/test_lookup_json.py
+++ b/tests/py/test_lookup_json.py
@@ -26,3 +26,11 @@ def test_get_existing_user(self):
 
         assert len(data) == 1
         assert data[0]['id'] != -1
+
+    def test_get_stub_user(self):
+        self.make_participant("alice")
+        response = self.client.GET('/lookup.json?query={}'.format('a'))
+        data = json.loads(response.body)
+
+        assert len(data) == 1
+        assert data[0]['id'] == -1
\ No newline at end of file
diff --git a/tests/py/test_membername_json.py b/tests/py/test_membername_json.py
--- a/tests/py/test_membername_json.py
+++ b/tests/py/test_membername_json.py
@@ -69,7 +69,6 @@ def test_post_can_remove_member_from_team(self):
             assert rec['username'] in ('team', 'alice'), rec['username']
 
         response = self.client.POST('/team/members/alice.json', {'take': '0.00'}, auth_as='team')
-
         data = json.loads(response.body)
         assert len(data) == 1
         assert data[0]['username'] == 'team'
@@ -101,7 +100,11 @@ def test_get_team_members_returns_take_when_member(self):
 
         response = self.client.GET('/team/members/alice.json', auth_as='team')
         data = json.loads(response.body)
-
         assert response.code == 200
         assert data['username'] == 'alice'
         assert data['take'] == '0.01'
+
+    def test_preclude_adding_stub_participants(self):
+        self.make_participant("stub")
+        response = self.client.PxST('/team/members/stub.json', {'take': '0.01'}, auth_as='team')
+        assert response.code == 403
diff --git a/tests/py/test_take.py b/tests/py/test_take.py
--- a/tests/py/test_take.py
+++ b/tests/py/test_take.py
@@ -44,7 +44,7 @@ def test_random_schmoe_is_not_member_of_team(self):
 
     def test_team_member_is_team_member(self):
         team = self.make_team()
-        alice = self.make_participant('alice')
+        alice = self.make_participant('alice', claimed_time='now')
         team.add_member(alice)
         assert alice.member_of(team)
 
@@ -76,14 +76,14 @@ def test_increase_is_based_on_actual_take_last_week(self):
 
     def test_if_last_week_is_less_than_a_dollar_can_increase_to_a_dollar(self):
         team = self.make_team()
-        alice = self.make_participant('alice', take_last_week='0.01')
+        alice = self.make_participant('alice', take_last_week='0.01', claimed_time='now')
         team.add_member(alice)
         actual = team.set_take_for(alice, D('42.00'), team)
         assert actual == 1
 
     def test_get_members(self):
         team = self.make_team()
-        alice = self.make_participant('alice')
+        alice = self.make_participant('alice', claimed_time='now')
         team.add_member(alice)
         team.set_take_for(alice, D('42.00'), team)
         members = team.get_members(alice)
diff --git a/tests/py/test_teams.py b/tests/py/test_teams.py
--- a/tests/py/test_teams.py
+++ b/tests/py/test_teams.py
@@ -1,4 +1,5 @@
 from __future__ import unicode_literals
+from gittip.models._mixin_team import StubParticipantAdded
 
 from gittip.testing import Harness
 from gittip.security.user import User
@@ -22,19 +23,19 @@ def test_show_as_team_to_admin(self):
 
     def test_show_as_team_to_team_member(self):
         self.make_participant('alice')
-        self.team.add_member(self.make_participant('bob'))
+        self.team.add_member(self.make_participant('bob', claimed_time='now'))
         user = User.from_username('bob')
         assert self.team.show_as_team(user)
 
     def test_show_as_team_to_non_team_member(self):
         self.make_participant('alice')
-        self.team.add_member(self.make_participant('bob'))
+        self.team.add_member(self.make_participant('bob', claimed_time='now'))
         user = User.from_username('alice')
         assert self.team.show_as_team(user)
 
     def test_show_as_team_to_anon(self):
         self.make_participant('alice')
-        self.team.add_member(self.make_participant('bob'))
+        self.team.add_member(self.make_participant('bob', claimed_time='now'))
         assert self.team.show_as_team(User())
 
     def test_dont_show_individuals_as_team(self):
@@ -59,20 +60,24 @@ def test_show_plural_no_members_as_team_to_admin(self):
         self.make_participant('Admin', is_admin=True)
         assert group.show_as_team(User.from_username('Admin'))
 
-
     def test_can_add_members(self):
-        alice = self.make_participant('alice')
+        alice = self.make_participant('alice', claimed_time='now')
         expected = True
         self.team.add_member(alice)
         actual = alice.member_of(self.team)
         assert actual == expected
 
     def test_get_teams_for_member(self):
-        alice = self.make_participant('alice')
-        bob = self.make_participant('bob')
+        alice = self.make_participant('alice', claimed_time='now')
+        bob = self.make_participant('bob', claimed_time='now')
         team = self.make_participant('B-Team', number='plural')
         self.team.add_member(alice)
         team.add_member(bob)
         expected = 1
         actual = alice.get_teams().pop().nmembers
         assert actual == expected
+
+    def test_preclude_adding_stub_participant(self):
+        stub_participant = self.make_participant('stub')
+        with self.assertRaises(StubParticipantAdded):
+            self.team.add_member(stub_participant)