Date: Wed, 11 Jan 2017 14:35:00 -0500
Subject: [PATCH 06/10] Trim whitespace
---
www/~/%username/settings/close.spt | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/www/~/%username/settings/close.spt b/www/~/%username/settings/close.spt
index f4d214f2e4..7714e78566 100644
--- a/www/~/%username/settings/close.spt
+++ b/www/~/%username/settings/close.spt
@@ -79,12 +79,12 @@ elif nteams == 1:
href="https://github.com/gratipay/gratipay.com/issues/397">data
retention policy).
- Things we clear immediately include your profile statement,
+
Things we clear immediately include your profile statement,
the payroll you're taking, and the payments you're giving.
- We specifically don't delete your past giving and
- taking history on the site, because that information also belongs
- equally to other users (the owners of the Teams you gave to and
+
We specifically don't delete your past giving and
+ taking history on the site, because that information also belongs
+ equally to other users (the owners of the Teams you gave to and
took from).
After you close your account, your profile page will say,
From 03b264f50230021031ef70f6d7202d52b95b6de8 Mon Sep 17 00:00:00 2001
From: Chad Whitacre
Date: Wed, 11 Jan 2017 14:43:06 -0500
Subject: [PATCH 07/10] Add projects notice to participant close page
---
www/~/%username/settings/close.spt | 21 ++++++++++-----------
1 file changed, 10 insertions(+), 11 deletions(-)
diff --git a/www/~/%username/settings/close.spt b/www/~/%username/settings/close.spt
index 7714e78566..ecbe299dc7 100644
--- a/www/~/%username/settings/close.spt
+++ b/www/~/%username/settings/close.spt
@@ -16,13 +16,9 @@ if request.method == 'POST':
else:
participant.close()
website.redirect('/~%s/' % participant.username)
-teams = participant.get_teams()
-nteams = len(teams)
-if nteams > 1:
- teams = ', '.join([t.name for t in teams[:-1]]) + ' and ' + teams[-1].name + ' teams'
-elif nteams == 1:
- teams = teams[0].name + ' team'
-
+teams = website.db.all( "SELECT teams.*::teams FROM teams WHERE owner=%s AND NOT is_closed"
+ , (participant.username,)
+ )
[---] text/html
{% extends "templates/base.html" %}
@@ -32,9 +28,12 @@ elif nteams == 1:
{% if teams %}
- You are the owner of the {{ teams }}. We don't yet support
- team owners closing their accounts.
+ Please close the following projects first:
+
{% endif %}
@@ -80,7 +79,7 @@ elif nteams == 1:
retention policy).
Things we clear immediately include your profile statement,
- the payroll you're taking, and the payments you're giving.
+ the payments you're taking, and the payments you're giving.
We specifically don't delete your past giving and
taking history on the site, because that information also belongs
From 73926df678ac2f197816568bf8157703a8132695 Mon Sep 17 00:00:00 2001
From: Chad Whitacre
Date: Wed, 11 Jan 2017 15:01:18 -0500
Subject: [PATCH 08/10] Bring participant close tests up to date
---
tests/py/test_close.py | 17 +----------------
1 file changed, 1 insertion(+), 16 deletions(-)
diff --git a/tests/py/test_close.py b/tests/py/test_close.py
index 971c7f294d..e70dcb3b7f 100644
--- a/tests/py/test_close.py
+++ b/tests/py/test_close.py
@@ -60,22 +60,7 @@ def test_close_page_shows_a_message_to_team_owners(self):
alice = self.make_participant('alice', claimed_time='now')
self.make_team('A', alice)
body = self.client.GET('/~alice/settings/close', auth_as='alice').body
- assert 'You are the owner of the A team.' in body
-
- def test_close_page_shows_a_message_to_owners_of_two_teams(self):
- alice = self.make_participant('alice', claimed_time='now')
- self.make_team('A', alice)
- self.make_team('B', alice)
- body = self.client.GET('/~alice/settings/close', auth_as='alice').body
- assert 'You are the owner of the A and B teams.' in body
-
- def test_close_page_shows_a_message_to_owners_of_three_teams(self):
- alice = self.make_participant('alice', claimed_time='now')
- self.make_team('A', alice)
- self.make_team('B', alice)
- self.make_team('C', alice)
- body = self.client.GET('/~alice/settings/close', auth_as='alice').body
- assert 'You are the owner of the A, B and C teams.' in body
+ assert 'Please close the following projects first:' in body
# cpi - clear_payment_instructions
From 6b191f091f52e2b6e5b10c75f35aeb4d8112c0c2 Mon Sep 17 00:00:00 2001
From: Matt
Date: Wed, 11 Jan 2017 21:40:33 -0600
Subject: [PATCH 09/10] Hide closed teams from ~user profile
---
gratipay/models/participant/__init__.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/gratipay/models/participant/__init__.py b/gratipay/models/participant/__init__.py
index 483ffacd85..2786ba53e6 100644
--- a/gratipay/models/participant/__init__.py
+++ b/gratipay/models/participant/__init__.py
@@ -1081,7 +1081,9 @@ def get_teams(self, only_approved=False, cursor=None):
"""Return a list of teams this user is an owner or member of.
"""
teams = (cursor or self.db).all("""
- SELECT teams.*::teams FROM teams WHERE owner=%s
+ SELECT teams.*::teams FROM teams WHERE
+ owner=%s AND
+ NOT is_closed
UNION
From 36948c045fb2eebab59ea4ae3e5d89bcbe01e317 Mon Sep 17 00:00:00 2001
From: Chad Whitacre
Date: Thu, 12 Jan 2017 12:10:20 -0500
Subject: [PATCH 10/10] Beef up implementation of closed filtering
Better match what we've already got.
---
gratipay/models/participant/__init__.py | 12 ++++----
gratipay/testing/harness.py | 6 ++--
templates/team-listing.html | 9 +++---
tests/py/test_pages.py | 39 +++++++++++++++++++++++++
tests/py/test_participant.py | 10 ++++++-
5 files changed, 63 insertions(+), 13 deletions(-)
diff --git a/gratipay/models/participant/__init__.py b/gratipay/models/participant/__init__.py
index 2786ba53e6..6158e000ef 100644
--- a/gratipay/models/participant/__init__.py
+++ b/gratipay/models/participant/__init__.py
@@ -1077,23 +1077,23 @@ def profile_url(self):
return '{base_url}/{username}/'.format(**locals())
- def get_teams(self, only_approved=False, cursor=None):
+ def get_teams(self, only_approved=False, only_open=False, cursor=None):
"""Return a list of teams this user is an owner or member of.
"""
teams = (cursor or self.db).all("""
- SELECT teams.*::teams FROM teams WHERE
- owner=%s AND
- NOT is_closed
+ SELECT teams.*::teams FROM teams WHERE owner=%s
UNION
SELECT teams.*::teams FROM teams WHERE id IN (
SELECT team_id FROM current_takes WHERE participant_id=%s
)
- """, (self.username, self.id)
- )
+ """, (self.username, self.id))
+
if only_approved:
teams = [t for t in teams if t.is_approved]
+ if only_open:
+ teams = [t for t in teams if not t.is_closed]
return teams
diff --git a/gratipay/testing/harness.py b/gratipay/testing/harness.py
index 0a5b0a56ea..2916d1c7d6 100644
--- a/gratipay/testing/harness.py
+++ b/gratipay/testing/harness.py
@@ -155,6 +155,8 @@ def make_team(self, *a, **kw):
_kw['slug_lower'] = _kw['slug'].lower()
if 'is_approved' not in _kw:
_kw['is_approved'] = False
+ if 'is_closed' not in _kw:
+ _kw['is_closed'] = False
if 'available' not in _kw:
_kw['available'] = 0
@@ -169,9 +171,9 @@ def make_team(self, *a, **kw):
team = self.db.one("""
INSERT INTO teams
(slug, slug_lower, name, homepage, product_or_service,
- onboarding_url, owner, is_approved, available)
+ onboarding_url, owner, is_approved, is_closed, available)
VALUES (%(slug)s, %(slug_lower)s, %(name)s, %(homepage)s, %(product_or_service)s,
- %(onboarding_url)s, %(owner)s, %(is_approved)s,
+ %(onboarding_url)s, %(owner)s, %(is_approved)s, %(is_closed)s,
%(available)s)
RETURNING teams.*::teams
""", _kw)
diff --git a/templates/team-listing.html b/templates/team-listing.html
index 51807d940e..f688395eff 100644
--- a/templates/team-listing.html
+++ b/templates/team-listing.html
@@ -1,16 +1,17 @@
-{% set approved_teams = participant.get_teams(only_approved=True) %}
+{% set unprivileged = not(participant == user.participant or user.ADMIN) %}
+{% set approved_open_teams = participant.get_teams(unprivileged, unprivileged) %}
-{% if (user.ADMIN or user.participant == participant) and approved_teams %}
+{% if (user.ADMIN or user.participant == participant) and approved_open_teams %}
{{ _("Projects") }}
-{% elif approved_teams %}
+{% elif approved_open_teams %}
{{ _("Projects") }}
- {% for team in approved_teams %}
+ {% for team in approved_open_teams %}
- {{ team.name }}
{% endfor %}
diff --git a/tests/py/test_pages.py b/tests/py/test_pages.py
index 30a3b6b4c0..58431dd9a1 100644
--- a/tests/py/test_pages.py
+++ b/tests/py/test_pages.py
@@ -266,3 +266,42 @@ def test_your_payment_template_basically_works(self):
self.make_team(is_approved=True)
self.make_participant('alice')
assert 'your-payment' in self.client.GET('/TheEnterprise/', auth_as='alice').body
+
+
+class TestTeamListingTemplate(Harness):
+
+ def setUp(self):
+ self.make_participant('Q', claimed_time='now', is_admin=True)
+ self.make_participant('Rambo', claimed_time='now')
+
+ def check(self, auth_as=None, expected=True):
+ body = self.client.GET('/~picard/', auth_as=auth_as).body.decode('utf8')
+ assert ('The Enterprise' in body) is expected
+
+ def test_includes_approved_open_team_for_everyone(self):
+ self.make_team(is_approved=True, is_closed=False)
+ self.check('picard')
+ self.check('Q')
+ self.check('Rambo')
+ self.check()
+
+ def test_includes_approved_closed_team_for_owner_and_admin(self):
+ self.make_team(is_approved=True, is_closed=True)
+ self.check('picard')
+ self.check('Q')
+ self.check('Rambo', False)
+ self.check(None, False)
+
+ def test_includes_unapproved_open_team_for_owner_and_admin(self):
+ self.make_team(is_approved=False, is_closed=True)
+ self.check('picard')
+ self.check('Q')
+ self.check('Rambo', False)
+ self.check(None, False)
+
+ def test_includes_unapproved_closed_team_for_owner_and_admin(self):
+ self.make_team(is_approved=False, is_closed=False)
+ self.check('picard')
+ self.check('Q')
+ self.check('Rambo', False)
+ self.check(None, False)
diff --git a/tests/py/test_participant.py b/tests/py/test_participant.py
index bf41ed86d2..07550c8c10 100644
--- a/tests/py/test_participant.py
+++ b/tests/py/test_participant.py
@@ -257,11 +257,19 @@ def test_get_teams_can_get_only_approved_teams(self):
self.make_team('The Stargazer', owner=picard, is_approved=False)
assert [t.slug for t in picard.get_teams(only_approved=True)] == ['TheEnterprise']
+ def test_get_teams_can_get_only_open_teams(self):
+ self.make_team()
+ picard = P('picard')
+ self.make_team('The Stargazer', owner=picard, is_closed=True)
+ assert [t.slug for t in picard.get_teams(only_open=True)] == ['TheEnterprise']
+
def test_get_teams_can_get_all_teams(self):
self.make_team(is_approved=True)
picard = P('picard')
self.make_team('The Stargazer', owner=picard, is_approved=False)
- assert [t.slug for t in picard.get_teams()] == ['TheEnterprise', 'TheStargazer']
+ self.make_team('The Trident', owner=picard, is_approved=False, is_closed=True)
+ assert [t.slug for t in picard.get_teams()] == \
+ ['TheEnterprise', 'TheStargazer', 'TheTrident']
# giving