From 0de47a317371e6aafb514b8b4136cd9c4bcf722f Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Fri, 24 Jun 2016 13:46:24 -0400 Subject: [PATCH 01/10] Factor tip migration out into a mixin This works around a bug in Sphinx where the print function under Python 2.7 prevents class attributes from showing up in documentation. I want to be able to document some attributes on the Team class. --- gratipay/models/team/__init__.py | 94 +---------------- gratipay/models/team/mixins/__init__.py | 3 + gratipay/models/team/mixins/tip_migration.py | 101 +++++++++++++++++++ tests/py/test_tip_migration.py | 2 +- 4 files changed, 107 insertions(+), 93 deletions(-) create mode 100644 gratipay/models/team/mixins/__init__.py create mode 100644 gratipay/models/team/mixins/tip_migration.py diff --git a/gratipay/models/team/__init__.py b/gratipay/models/team/__init__.py index 22cb3a93c0..3805701a4f 100644 --- a/gratipay/models/team/__init__.py +++ b/gratipay/models/team/__init__.py @@ -12,6 +12,7 @@ from postgres.orm import Model from gratipay.billing.exchanges import MINIMUM_CHARGE +from gratipay.models.team.mixins import TipMigration # Should have at least one letter. TEAM_NAME_PATTERN = re.compile(r'^(?=.*[A-Za-z])([A-Za-z0-9.,-_ ]+)$') @@ -32,7 +33,7 @@ def slugize(name): return slug -class Team(Model): +class Team(Model, TipMigration): """Represent a Gratipay team. """ @@ -303,50 +304,6 @@ def to_dict(self): 'todo_url': self.todo_url } - def migrate_tips(self): - """Migrate the Team owner's Gratipay 1.0 tips into 2.0 payment instructions to the Team. - - :return: ``None`` - :raises: :py:exc:`~gratipay.models.team.AlreadyMigrated` if payment - instructions already exist for this Team - - This method gets called under :py:func:`migrate_all_tips` during payday. - - """ - payment_instructions = self.db.all(""" - SELECT pi.* - FROM payment_instructions pi - JOIN teams t ON t.id = pi.team_id - WHERE t.owner = %s - AND pi.ctime < t.ctime - """, (self.owner, )) - - # Make sure the migration hasn't been done already - if payment_instructions: - raise AlreadyMigrated - - return self.db.one(""" - WITH rows AS ( - - INSERT INTO payment_instructions - (ctime, mtime, participant_id, team_id, amount, is_funded) - SELECT ct.ctime - , ct.mtime - , (SELECT id FROM participants WHERE username=ct.tipper) - , %(team_id)s - , ct.amount - , ct.is_funded - FROM current_tips ct - JOIN participants p ON p.username = tipper - WHERE ct.tippee=%(owner)s - AND p.claimed_time IS NOT NULL - AND p.is_suspicious IS NOT TRUE - AND p.is_closed IS NOT TRUE - RETURNING 1 - - ) SELECT count(*) FROM rows; - """, {'team_id': self.id, 'owner': self.owner}) - # Images # ====== @@ -389,50 +346,3 @@ def load_image(self, size): with self.db.get_connection() as c: image = c.lobject(oid, mode='rb').read() return image - - -def migrate_all_tips(db, print=print): - """Migrate tips for all teams. - - :param GratipayDB db: a database object - :param func print: a function that takes lines of log output - :returns: ``None`` - - This function loads :py:class:`~gratipay.models.team.Team` objects for all - Teams where the owner had tips under Gratipay 1.0 but those tips have not - yet been migrated into payment instructions under Gratipay 2.0. It then - migrates the tips using :py:meth:`~gratipay.models.team.Team.migrate_tips`. - - This function is wrapped in a script, ``bin/migrate-tips.py``, which is - `used during payday`_. - - .. _used during payday: http://inside.gratipay.com/howto/run-payday - - """ - teams = db.all(""" - SELECT distinct ON (t.id) t.*::teams - FROM teams t - JOIN tips ON t.owner = tips.tippee -- Only fetch teams whose owners had tips under Gratipay 1.0 - WHERE t.is_approved IS TRUE -- Only fetch approved teams - AND NOT EXISTS ( -- Make sure tips haven't been migrated for any teams with same owner - SELECT 1 - FROM payment_instructions pi - JOIN teams t2 ON t2.id = pi.team_id - WHERE t2.owner = t.owner - AND pi.ctime < t2.ctime - ) - """) - - for team in teams: - try: - ntips = team.migrate_tips() - print("Migrated {} tip(s) for '{}'".format(ntips, team.slug)) - except AlreadyMigrated: - print("'%s' already migrated." % team.slug) - - print("Done.") - - -class AlreadyMigrated(Exception): - """Raised by :py:meth:`~gratipay.models.team.migrate_tips`. - """ diff --git a/gratipay/models/team/mixins/__init__.py b/gratipay/models/team/mixins/__init__.py new file mode 100644 index 0000000000..5be5769fb5 --- /dev/null +++ b/gratipay/models/team/mixins/__init__.py @@ -0,0 +1,3 @@ +from .tip_migration import TipMigrationMixin as TipMigration + +__all__ = ['TipMigration'] diff --git a/gratipay/models/team/mixins/tip_migration.py b/gratipay/models/team/mixins/tip_migration.py new file mode 100644 index 0000000000..bef47a3c0e --- /dev/null +++ b/gratipay/models/team/mixins/tip_migration.py @@ -0,0 +1,101 @@ +"""Participants who received tips directly under Gittipay 1.0 will have their +tips migrated if and when they become the owner of a new Gratipay 2.0 team. +""" + +from __future__ import absolute_import, division, print_function, unicode_literals + + +class TipMigrationMixin(object): + """This mixin provides tip migration for teams. + """ + + def migrate_tips(self): + """Migrate the Team owner's Gratipay 1.0 tips into 2.0 payment instructions to the Team. + + :return: ``None`` + :raises: :py:exc:`~gratipay.models.team.AlreadyMigrated` if payment + instructions already exist for this Team + + This method gets called under :py:func:`migrate_all_tips` during payday. + + """ + payment_instructions = self.db.all(""" + SELECT pi.* + FROM payment_instructions pi + JOIN teams t ON t.id = pi.team_id + WHERE t.owner = %s + AND pi.ctime < t.ctime + """, (self.owner, )) + + # Make sure the migration hasn't been done already + if payment_instructions: + raise AlreadyMigrated + + return self.db.one(""" + WITH rows AS ( + + INSERT INTO payment_instructions + (ctime, mtime, participant_id, team_id, amount, is_funded) + SELECT ct.ctime + , ct.mtime + , (SELECT id FROM participants WHERE username=ct.tipper) + , %(team_id)s + , ct.amount + , ct.is_funded + FROM current_tips ct + JOIN participants p ON p.username = tipper + WHERE ct.tippee=%(owner)s + AND p.claimed_time IS NOT NULL + AND p.is_suspicious IS NOT TRUE + AND p.is_closed IS NOT TRUE + RETURNING 1 + + ) SELECT count(*) FROM rows; + """, {'team_id': self.id, 'owner': self.owner}) + + +def migrate_all_tips(db, print=print): + """Migrate tips for all teams. + + :param GratipayDB db: a database object + :param func print: a function that takes lines of log output + :returns: ``None`` + + This function loads :py:class:`~gratipay.models.team.Team` objects for all + Teams where the owner had tips under Gratipay 1.0 but those tips have not + yet been migrated into payment instructions under Gratipay 2.0. It then + migrates the tips using :py:meth:`~gratipay.models.team.Team.migrate_tips`. + + This function is wrapped in a script, ``bin/migrate-tips.py``, which is + `used during payday`_. + + .. _used during payday: http://inside.gratipay.com/howto/run-payday + + """ + teams = db.all(""" + SELECT distinct ON (t.id) t.*::teams + FROM teams t + JOIN tips ON t.owner = tips.tippee -- Only fetch teams whose owners had tips under Gratipay 1.0 + WHERE t.is_approved IS TRUE -- Only fetch approved teams + AND NOT EXISTS ( -- Make sure tips haven't been migrated for any teams with same owner + SELECT 1 + FROM payment_instructions pi + JOIN teams t2 ON t2.id = pi.team_id + WHERE t2.owner = t.owner + AND pi.ctime < t2.ctime + ) + """) + + for team in teams: + try: + ntips = team.migrate_tips() + print("Migrated {} tip(s) for '{}'".format(ntips, team.slug)) + except AlreadyMigrated: + print("'%s' already migrated." % team.slug) + + print("Done.") + + +class AlreadyMigrated(Exception): + """Raised by :py:meth:`~gratipay.models.team.migrate_tips`. + """ diff --git a/tests/py/test_tip_migration.py b/tests/py/test_tip_migration.py index fe1c53c0e3..3dcd1e11b4 100644 --- a/tests/py/test_tip_migration.py +++ b/tests/py/test_tip_migration.py @@ -2,7 +2,7 @@ import pytest from gratipay.testing import Harness -from gratipay.models.team import AlreadyMigrated, migrate_all_tips +from gratipay.models.team.mixins.tip_migration import AlreadyMigrated, migrate_all_tips class Tests(Harness): From 7cd2970f6d43352cb9603689fa5f665120516d43 Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Fri, 24 Jun 2016 16:16:17 -0400 Subject: [PATCH 02/10] Sort doc members by source order This gives us more control. Rarely is alphabetical order the right sort order. --- docs/autolib.py | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/autolib.py b/docs/autolib.py index 7ecfc13a87..2f64690182 100755 --- a/docs/autolib.py +++ b/docs/autolib.py @@ -28,6 +28,7 @@ def rst_for_module(toc_path): w(f, heading) w(f, "=" * len(heading)) w(f, ".. automodule:: {}", dotted) + w(f, " :member-order: bysource") return f From f23f0a5273546f8c6c47d93c5195f3b2712a4c5e Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Tue, 12 Jul 2016 22:07:23 -0400 Subject: [PATCH 03/10] Barely implement available Conflicts: sql/branch.sql --- gratipay/models/team/__init__.py | 4 ++-- gratipay/models/team/mixins/__init__.py | 3 ++- gratipay/models/team/mixins/available.py | 14 ++++++++++++++ gratipay/testing/__init__.py | 7 +++++-- sql/branch.sql | 6 ++++++ tests/py/test_team_available.py | 23 +++++++++++++++++++++++ 6 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 gratipay/models/team/mixins/available.py create mode 100644 sql/branch.sql create mode 100644 tests/py/test_team_available.py diff --git a/gratipay/models/team/__init__.py b/gratipay/models/team/__init__.py index 3805701a4f..1414245607 100644 --- a/gratipay/models/team/__init__.py +++ b/gratipay/models/team/__init__.py @@ -12,7 +12,7 @@ from postgres.orm import Model from gratipay.billing.exchanges import MINIMUM_CHARGE -from gratipay.models.team.mixins import TipMigration +from gratipay.models.team import mixins # Should have at least one letter. TEAM_NAME_PATTERN = re.compile(r'^(?=.*[A-Za-z])([A-Za-z0-9.,-_ ]+)$') @@ -33,7 +33,7 @@ def slugize(name): return slug -class Team(Model, TipMigration): +class Team(Model, mixins.Available, mixins.TipMigration): """Represent a Gratipay team. """ diff --git a/gratipay/models/team/mixins/__init__.py b/gratipay/models/team/mixins/__init__.py index 5be5769fb5..5add64b89e 100644 --- a/gratipay/models/team/mixins/__init__.py +++ b/gratipay/models/team/mixins/__init__.py @@ -1,3 +1,4 @@ +from .available import AvailableMixin as Available from .tip_migration import TipMigrationMixin as TipMigration -__all__ = ['TipMigration'] +__all__ = ['Available', 'TipMigration'] diff --git a/gratipay/models/team/mixins/available.py b/gratipay/models/team/mixins/available.py new file mode 100644 index 0000000000..5557d800cb --- /dev/null +++ b/gratipay/models/team/mixins/available.py @@ -0,0 +1,14 @@ +from __future__ import absolute_import, division, print_function, unicode_literals + + +class AvailableMixin(object): + """Teams can make money available for their members to take. + """ + + # Computed Values + # =============== + + #: The amount of money this team makes available for members to take each + #: week. Read-only; modified manually. + + available = 0 diff --git a/gratipay/testing/__init__.py b/gratipay/testing/__init__.py index c02efa2b98..434bd41f6c 100644 --- a/gratipay/testing/__init__.py +++ b/gratipay/testing/__init__.py @@ -169,6 +169,8 @@ def make_team(self, *a, **kw): _kw['slug_lower'] = _kw['slug'].lower() if 'is_approved' not in _kw: _kw['is_approved'] = False + if 'available' not in _kw: + _kw['available'] = 0 if Participant.from_username(_kw['owner']) is None: self.make_participant(_kw['owner'], claimed_time='now', last_paypal_result='') @@ -176,9 +178,10 @@ def make_team(self, *a, **kw): team = self.db.one(""" INSERT INTO teams (slug, slug_lower, name, homepage, product_or_service, todo_url, - onboarding_url, owner, is_approved) + onboarding_url, owner, is_approved, available) VALUES (%(slug)s, %(slug_lower)s, %(name)s, %(homepage)s, %(product_or_service)s, - %(todo_url)s, %(onboarding_url)s, %(owner)s, %(is_approved)s) + %(todo_url)s, %(onboarding_url)s, %(owner)s, %(is_approved)s, + %(available)s) RETURNING teams.*::teams """, _kw) diff --git a/sql/branch.sql b/sql/branch.sql new file mode 100644 index 0000000000..adc7dc711f --- /dev/null +++ b/sql/branch.sql @@ -0,0 +1,6 @@ +-- https://github.com/gratipay/gratipay.com/pull/4072 + +BEGIN; + ALTER TABLE teams ADD COLUMN available numeric(35,2) NOT NULL DEFAULT 0; + ALTER TABLE teams ADD CONSTRAINT available_not_negative CHECK ((available >= (0)::numeric)); +END; diff --git a/tests/py/test_team_available.py b/tests/py/test_team_available.py new file mode 100644 index 0000000000..5e6bbbaa12 --- /dev/null +++ b/tests/py/test_team_available.py @@ -0,0 +1,23 @@ +from __future__ import absolute_import, division, print_function, unicode_literals + +from gratipay.testing import Harness +from psycopg2 import IntegrityError +from pytest import raises + + +class Tests(Harness): + + def test_available_defaults_to_zero(self): + assert self.make_team().available == 0 + + def test_available_cant_be_negative(self): + self.make_team() + raises(IntegrityError, self.db.run, "UPDATE teams SET available = -537") + + def test_available_can_be_positive(self): + self.make_team() + self.db.run("UPDATE teams SET available = 537") + assert self.db.one("SELECT available FROM teams") == 537 + + def test_available_works_in_the_test_factory(self): + assert self.make_team(available=537).available == 537 From a1e60150cc7d132fb9c56e0e862b6c29e90fef66 Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Fri, 1 Jul 2016 10:26:09 -0400 Subject: [PATCH 04/10] Rename /%team/payroll/ to /%team/distributing/ --- www/%team/{payroll => distributing}/%membername.json.spt | 0 www/%team/{payroll => distributing}/index.html.spt | 0 www/%team/{payroll => distributing}/index.json.spt | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename www/%team/{payroll => distributing}/%membername.json.spt (100%) rename www/%team/{payroll => distributing}/index.html.spt (100%) rename www/%team/{payroll => distributing}/index.json.spt (100%) diff --git a/www/%team/payroll/%membername.json.spt b/www/%team/distributing/%membername.json.spt similarity index 100% rename from www/%team/payroll/%membername.json.spt rename to www/%team/distributing/%membername.json.spt diff --git a/www/%team/payroll/index.html.spt b/www/%team/distributing/index.html.spt similarity index 100% rename from www/%team/payroll/index.html.spt rename to www/%team/distributing/index.html.spt diff --git a/www/%team/payroll/index.json.spt b/www/%team/distributing/index.json.spt similarity index 100% rename from www/%team/payroll/index.json.spt rename to www/%team/distributing/index.json.spt From 5db876012019103f9a46d4076f36f4e188616bea Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Fri, 1 Jul 2016 10:42:31 -0400 Subject: [PATCH 05/10] Bring back /%team/distributing/ when available > 0 The page is broken, but that's okay because no-one will see it until we set available. --- tests/py/test_www_team_distributing.py | 15 +++++++++++++++ www/%team/distributing/index.html.spt | 12 ++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 tests/py/test_www_team_distributing.py diff --git a/tests/py/test_www_team_distributing.py b/tests/py/test_www_team_distributing.py new file mode 100644 index 0000000000..57bd10a1da --- /dev/null +++ b/tests/py/test_www_team_distributing.py @@ -0,0 +1,15 @@ +from __future__ import absolute_import, division, print_function, unicode_literals + +from gratipay.testing import Harness + + +class Tests(Harness): + + def test_distributing_redirects_when_no_money_is_available(self): + self.make_team() + assert self.client.GxT('/TheEnterprise/distributing/').code == 302 + + def test_distributing_doesnt_redirect_when_money_is_available(self): + self.make_team() + self.db.run("UPDATE teams SET available=537") + assert self.client.GET('/TheEnterprise/distributing/', raise_immediately=False).code == 500 diff --git a/www/%team/distributing/index.html.spt b/www/%team/distributing/index.html.spt index 52f1d64114..2c55990c2c 100644 --- a/www/%team/distributing/index.html.spt +++ b/www/%team/distributing/index.html.spt @@ -1,14 +1,10 @@ # encoding: utf8 -"""Show information about a single participant. It might be you! -""" -from gratipay.utils import get_participant +from gratipay.utils import get_team [-----------------------------------------------------------------------------] -website.redirect('..', base_url='') # XXX Migrating to Teams! Fix this up! -participant = team = get_participant(state, restrict=False) -if not team.show_as_team(user): - website.redirect('../', base_url='') -banner = team.username +team = get_team(state) +if team.available == 0: + website.redirect('..', base_url='') title = _("Team Members") [-----------------------------------------------------------------------------] From 17b9bd37de4a9b088b8d4cd4732943cc9bf28d21 Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Fri, 1 Jul 2016 11:19:38 -0400 Subject: [PATCH 06/10] 500 -> 200 --- tests/py/test_www_team_distributing.py | 2 +- www/%team/distributing/index.html.spt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/py/test_www_team_distributing.py b/tests/py/test_www_team_distributing.py index 57bd10a1da..4590bd9b5f 100644 --- a/tests/py/test_www_team_distributing.py +++ b/tests/py/test_www_team_distributing.py @@ -12,4 +12,4 @@ def test_distributing_redirects_when_no_money_is_available(self): def test_distributing_doesnt_redirect_when_money_is_available(self): self.make_team() self.db.run("UPDATE teams SET available=537") - assert self.client.GET('/TheEnterprise/distributing/', raise_immediately=False).code == 500 + assert self.client.GET('/TheEnterprise/distributing/').code == 200 diff --git a/www/%team/distributing/index.html.spt b/www/%team/distributing/index.html.spt index 2c55990c2c..e1d214ec55 100644 --- a/www/%team/distributing/index.html.spt +++ b/www/%team/distributing/index.html.spt @@ -8,7 +8,7 @@ if team.available == 0: title = _("Team Members") [-----------------------------------------------------------------------------] -{% extends "templates/profile.html" %} +{% extends "templates/team-base.html" %} {% block scripts %} @@ -32,7 +32,7 @@ title = _("Team Members") - {{ team.balance + team.receiving - team.giving }} + {{ team.available }} From b75a8ab224afbb3d0a6050f3c713a3330c651d99 Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Fri, 1 Jul 2016 11:23:33 -0400 Subject: [PATCH 07/10] Add "Distributing" to the nav --- templates/team-base.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/team-base.html b/templates/team-base.html index 7e1f8b7d47..d5a23ee13c 100644 --- a/templates/team-base.html +++ b/templates/team-base.html @@ -61,9 +61,9 @@ {% if team.is_approved and (user.participant == team.owner or user.ADMIN) %} {% set current_page = request.path.raw.split('/')[2] %} {% set nav_base = '/' + team.slug %} - {% set pages = [ ('/', _('Profile')) - , ('/receiving/', _('Receiving')) - ] %} + {% set pages = [ ('/', _('Profile')) + , ('/receiving/', _('Receiving')) + ] + ([('/distributing/', _('Distributing'))] if team.available else [])%} {% if pages %} {% include "templates/nav.html" %}
From 398a539248c2e383cd010d444319484850dbf9cc Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Fri, 1 Jul 2016 11:42:52 -0400 Subject: [PATCH 08/10] Kill the "Sharing" display for now Bring this back as "Distributing" and "Surplus" once we have those computed values tight. --- templates/team-base.html | 5 ----- www/index.html.spt | 5 ----- 2 files changed, 10 deletions(-) diff --git a/templates/team-base.html b/templates/team-base.html index d5a23ee13c..82d376e73c 100644 --- a/templates/team-base.html +++ b/templates/team-base.html @@ -18,11 +18,6 @@ {{ format_currency(team.receiving, 'USD') }} {{ team.nreceiving_from }} - - {{ _("Sharing") }} - {{ format_currency(0, 'USD') }} - 0 - {% endif %} diff --git a/www/index.html.spt b/www/index.html.spt index b173cf8281..a437d0eed3 100644 --- a/www/index.html.spt +++ b/www/index.html.spt @@ -135,11 +135,6 @@ suppress_welcome = 'suppress-welcome' in request.cookie if team.receiving else '-  '|safe }} {{ team.nreceiving_from if team.nreceiving_from else '-' }} - - {{ _("Sharing") }} - -   - - - {% endif %} From 88fb9efe78b58280bebfc258fe8cf612f29f0222 Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Fri, 1 Jul 2016 11:50:16 -0400 Subject: [PATCH 09/10] Start bringing back distributing/index.json --- tests/py/test_www_team_distributing.py | 10 ++++++++++ www/%team/distributing/index.json.spt | 10 ++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/tests/py/test_www_team_distributing.py b/tests/py/test_www_team_distributing.py index 4590bd9b5f..9ddd79eef9 100644 --- a/tests/py/test_www_team_distributing.py +++ b/tests/py/test_www_team_distributing.py @@ -13,3 +13,13 @@ def test_distributing_doesnt_redirect_when_money_is_available(self): self.make_team() self.db.run("UPDATE teams SET available=537") assert self.client.GET('/TheEnterprise/distributing/').code == 200 + + + def test_distributing_json_redirects_when_no_money_is_available(self): + self.make_team() + assert self.client.GxT('/TheEnterprise/distributing/index.json').code == 302 + + def test_distributing_json_doesnt_redirect_when_money_is_available(self): + self.make_team() + self.db.run("UPDATE teams SET available=537") + assert self.client.GET('/TheEnterprise/distributing/index.json', raise_immediately=False).code == 500 diff --git a/www/%team/distributing/index.json.spt b/www/%team/distributing/index.json.spt index 42453c0340..2a75c73892 100644 --- a/www/%team/distributing/index.json.spt +++ b/www/%team/distributing/index.json.spt @@ -1,14 +1,12 @@ """Endpoint to list team members. """ -from aspen import Response -from gratipay.utils import get_participant +from gratipay.utils import get_team [--------------------] -website.redirect('..', base_url='') # XXX Migrating to Teams! Fix this up! request.allow('GET') -team = get_participant(state, restrict=False) -if not team.show_as_team(user): - raise Response(404) +team = get_team(state) +if team.available == 0: + website.redirect('..', base_url='') [--------------------] application/json via json_dump team.get_members(user.participant) From 4cfd33f33c51f81a9defa06a4513b5a4b978f1cf Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Fri, 1 Jul 2016 12:01:42 -0400 Subject: [PATCH 10/10] Start bringing back individual member endpoint --- tests/py/test_pages.py | 2 +- tests/py/test_www_team_distributing.py | 14 ++++++++++++-- .../{%membername.json.spt => %member_id.json.spt} | 11 +++++------ 3 files changed, 18 insertions(+), 9 deletions(-) rename www/%team/distributing/{%membername.json.spt => %member_id.json.spt} (92%) diff --git a/tests/py/test_pages.py b/tests/py/test_pages.py index 284a52bafd..2deb0827b1 100644 --- a/tests/py/test_pages.py +++ b/tests/py/test_pages.py @@ -45,7 +45,7 @@ def browse(self, setup=None, **kw): .replace('/for/%slug/', '/for/wonderland/') \ .replace('/%platform/', '/github/') \ .replace('/%user_name/', '/gratipay/') \ - .replace('/%membername', '/alan') \ + .replace('/%member_id', '/1') \ .replace('/%country', '/TT') \ .replace('/%exchange_id.int', '/%s' % exchange_id) \ .replace('/%redirect_to', '/giving') \ diff --git a/tests/py/test_www_team_distributing.py b/tests/py/test_www_team_distributing.py index 9ddd79eef9..aca4c61120 100644 --- a/tests/py/test_www_team_distributing.py +++ b/tests/py/test_www_team_distributing.py @@ -15,11 +15,21 @@ def test_distributing_doesnt_redirect_when_money_is_available(self): assert self.client.GET('/TheEnterprise/distributing/').code == 200 - def test_distributing_json_redirects_when_no_money_is_available(self): + def test_json_redirects_when_no_money_is_available(self): self.make_team() assert self.client.GxT('/TheEnterprise/distributing/index.json').code == 302 - def test_distributing_json_doesnt_redirect_when_money_is_available(self): + def test_json_doesnt_redirect_when_money_is_available(self): self.make_team() self.db.run("UPDATE teams SET available=537") assert self.client.GET('/TheEnterprise/distributing/index.json', raise_immediately=False).code == 500 + + + def test_member_json_redirects_when_no_money_is_available(self): + self.make_team() + assert self.client.GxT('/TheEnterprise/distributing/1.json').code == 302 + + def test_member_json_doesnt_redirect_when_money_is_available(self): + self.make_team() + self.db.run("UPDATE teams SET available=537") + assert self.client.GET('/TheEnterprise/distributing/1.json', raise_immediately=False).code == 500 diff --git a/www/%team/distributing/%membername.json.spt b/www/%team/distributing/%member_id.json.spt similarity index 92% rename from www/%team/distributing/%membername.json.spt rename to www/%team/distributing/%member_id.json.spt index 2b235117c1..624411f11b 100644 --- a/www/%team/distributing/%membername.json.spt +++ b/www/%team/distributing/%member_id.json.spt @@ -4,20 +4,19 @@ from decimal import Decimal, InvalidOperation from aspen import Response from babel.numbers import NumberFormatError -from gratipay.utils import get_participant +from gratipay.utils import get_team from gratipay.models.participant import Participant ZERO = Decimal('0.00') A_PENNY = Decimal('0.01') [--------------------] -website.redirect('..', base_url='') # XXX Migrating to Teams! Fix this up! request.allow('GET', 'POST') -team = get_participant(state, restrict=False) -if not team.show_as_team(user): - raise Response(404) +team = get_team(state) +if team.available == 0: + website.redirect('..', base_url='') -member = Participant.from_username(request.path['membername']) +member = Participant.from_id(request.path['member_id']) if member is None or member.is_suspicious: raise Response(404, _("User not found.")) is_member = member.member_of(team)