From edfa22680e1b0bc87e154fb4eb954149a88a47f1 Mon Sep 17 00:00:00 2001 From: aandis Date: Sat, 22 Oct 2016 17:52:23 +0530 Subject: [PATCH 01/11] Add team reference to pacakges. --- sql/branch.sql | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 sql/branch.sql diff --git a/sql/branch.sql b/sql/branch.sql new file mode 100644 index 0000000000..60b32eb8f7 --- /dev/null +++ b/sql/branch.sql @@ -0,0 +1,4 @@ +BEGIN; + ALTER TABLE packages ADD COLUMN team_id integer DEFAULT NULL + REFERENCES teams (id) ON UPDATE RESTRICT ON DELETE RESTRICT; +END; From 490adfab0a5f8cd96139f1400fa1b3fda082406f Mon Sep 17 00:00:00 2001 From: aandis Date: Sat, 22 Oct 2016 18:06:00 +0530 Subject: [PATCH 02/11] Add package model init. --- gratipay/models/package/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 gratipay/models/package/__init__.py diff --git a/gratipay/models/package/__init__.py b/gratipay/models/package/__init__.py new file mode 100644 index 0000000000..e69de29bb2 From be9dd1533c176043500848b6224639a5cef7090b Mon Sep 17 00:00:00 2001 From: aandis Date: Sat, 22 Oct 2016 18:41:06 +0530 Subject: [PATCH 03/11] Add Package model --- gratipay/models/package/__init__.py | 85 +++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/gratipay/models/package/__init__.py b/gratipay/models/package/__init__.py index e69de29bb2..4b96fe449a 100644 --- a/gratipay/models/package/__init__.py +++ b/gratipay/models/package/__init__.py @@ -0,0 +1,85 @@ +from gratipay.models.team import Team + +from postgres.orm import Model + +class Package(Model): + """Represent a gratipackage. :-) + """ + + typname = 'packages' + + def __eq__(self, other): + if not isinstance(other, Package): + return False + return self.id == other.id + + def __ne__(self, other): + if not isinstance(other, Package): + return True + return self.id != other.id + + # Constructors + # ============ + + @classmethod + def from_id(cls, id): + """Return an existing package based on id. + """ + return cls._from_thing("id", id) + + @classmethod + def from_team_slug(cls, slug): + """Return an existing package based on team's slug. + """ + return cls._from_thing("team", slug) + + @classmethod + def _from_thing(cls, thing, value): + assert thing in ("id", "team") + return cls.db.one(""" + + SELECT packages.*::packages + FROM packages + WHERE {}=%s + + """.format(thing), (value,)) + + @classmethod + def insert(cls, owner, **fields): + return cls.db.one(""" + + INSERT INTO packages + (package_manager_id, name, description, + long_description, long_description_raw, + long_description_type) + VALUES (%(package_manager_id)s, %(name)s, %(description)s, + %(long_description)s, %(long_description_raw)s, + %(long_description_type)s) + RETURNING packages.*::packages + + """, fields) + + def set_team(self, team): + """ Set team for a package. + """ + if not isinstance(team, Team): + raise NotAllowed("Not a team!") + elif team.is_closed: + raise NotAllowed("team is closed") + elif not team.is_approved: + raise NotAllowed("team not approved") + + package_id = self.id + slug = team.slug + with self.db.get_cursor() as c: + # TODO add event + c.run(""" + UPDATE packages + SET team=%(slug)s + WHERE id=%(package_id)s + """, locals()) + self.set_attributes(team=team) + + +class NotAllowed(Exception): + pass From 049e32f48dc7bb9fb203c23ae91bf2d2f0141bcd Mon Sep 17 00:00:00 2001 From: aandis Date: Sun, 4 Dec 2016 22:22:43 +0530 Subject: [PATCH 04/11] Update insert columns. Cleanup --- gratipay/models/package/__init__.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/gratipay/models/package/__init__.py b/gratipay/models/package/__init__.py index 4b96fe449a..bc811a1a2f 100644 --- a/gratipay/models/package/__init__.py +++ b/gratipay/models/package/__init__.py @@ -47,20 +47,14 @@ def _from_thing(cls, thing, value): @classmethod def insert(cls, owner, **fields): return cls.db.one(""" - - INSERT INTO packages - (package_manager_id, name, description, - long_description, long_description_raw, - long_description_type) - VALUES (%(package_manager_id)s, %(name)s, %(description)s, - %(long_description)s, %(long_description_raw)s, - %(long_description_type)s) + INSERT INTO packages (package_manager, name, description, emails) + VALUES (%(package_manager)s, %(name)s, %(description)s, %(emails)s) RETURNING packages.*::packages """, fields) def set_team(self, team): - """ Set team for a package. + """Set team for a package. """ if not isinstance(team, Team): raise NotAllowed("Not a team!") @@ -68,7 +62,6 @@ def set_team(self, team): raise NotAllowed("team is closed") elif not team.is_approved: raise NotAllowed("team not approved") - package_id = self.id slug = team.slug with self.db.get_cursor() as c: From b92e076952f4e047637978654e7b77c9e0153b1b Mon Sep 17 00:00:00 2001 From: aandis Date: Sun, 4 Dec 2016 23:10:25 +0530 Subject: [PATCH 05/11] Dummy payment instruction method. --- gratipay/models/package/__init__.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/gratipay/models/package/__init__.py b/gratipay/models/package/__init__.py index bc811a1a2f..a1df9931e2 100644 --- a/gratipay/models/package/__init__.py +++ b/gratipay/models/package/__init__.py @@ -73,6 +73,15 @@ def set_team(self, team): """, locals()) self.set_attributes(team=team) + def set_payment_instruction(self, participant, amount): + team_id = self.team_id + if team_id: + team = Team.from_id(team_id) + participant.set_payment_instruction(team, amount) + else: + # TODO Add to pledges when we introduce it. + pass + class NotAllowed(Exception): pass From 47c1c454e24ea34b8bc202e5af80ec10428869cc Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Fri, 3 Feb 2017 15:09:01 -0500 Subject: [PATCH 06/11] Stub out a test file --- tests/py/test_packages.py | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/py/test_packages.py diff --git a/tests/py/test_packages.py b/tests/py/test_packages.py new file mode 100644 index 0000000000..84b8bd8565 --- /dev/null +++ b/tests/py/test_packages.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import, division, print_function, unicode_literals + +from gratipay.testing import Harness + + +class Tests(Harness): + + def test_foo(self): + pass From fb6f9a62c69e72a4715218b5f8335ca46faf23e4 Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Tue, 7 Feb 2017 07:55:12 -0500 Subject: [PATCH 07/11] Add defaults to make_package in test harness --- gratipay/testing/harness.py | 11 ++++++----- tests/py/test_www_npm_package.py | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/gratipay/testing/harness.py b/gratipay/testing/harness.py index fb9da6c765..bf8da42fe2 100644 --- a/gratipay/testing/harness.py +++ b/gratipay/testing/harness.py @@ -181,13 +181,14 @@ def make_team(self, *a, **kw): return team - def make_package(self, package_manager, name, description, emails): + def make_package(self, package_manager='npm', name='foo', description='Foo', + emails=['alice@example.com']): """Factory for packages. """ - self.db.one( 'INSERT INTO packages (package_manager, name, description, emails) ' - 'VALUES (%s, %s, %s, %s) RETURNING *' - , (package_manager, name, description, emails) - ) + return self.db.one( 'INSERT INTO packages (package_manager, name, description, emails) ' + 'VALUES (%s, %s, %s, %s) RETURNING *' + , (package_manager, name, description, emails) + ) def make_participant(self, username, **kw): diff --git a/tests/py/test_www_npm_package.py b/tests/py/test_www_npm_package.py index f719cb6930..8f9c5bec45 100644 --- a/tests/py/test_www_npm_package.py +++ b/tests/py/test_www_npm_package.py @@ -7,7 +7,7 @@ class TestAnon(Harness): def setUp(self): - self.make_package('npm', 'foo', 'The foo package', ['alice@example.com']) + self.make_package() def test_gets_signin_page(self): assert 'npm/foo has not been claimed' in self.client.GET('/on/npm/foo/').body From 9a530344f42856648de3839b6d2a79e8e78fd4cf Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Tue, 7 Feb 2017 08:00:19 -0500 Subject: [PATCH 08/11] Clean up Package instantiation --- gratipay/models/package/__init__.py | 34 +++++++++-------------------- gratipay/wireup.py | 3 ++- tests/py/test_packages.py | 12 +++++++--- 3 files changed, 21 insertions(+), 28 deletions(-) diff --git a/gratipay/models/package/__init__.py b/gratipay/models/package/__init__.py index a1df9931e2..a93fc25e31 100644 --- a/gratipay/models/package/__init__.py +++ b/gratipay/models/package/__init__.py @@ -1,7 +1,10 @@ -from gratipay.models.team import Team +# -*- coding: utf-8 -*- +from __future__ import absolute_import, division, print_function, unicode_literals +from gratipay.models.team import Team from postgres.orm import Model + class Package(Model): """Represent a gratipackage. :-) """ @@ -18,6 +21,7 @@ def __ne__(self, other): return True return self.id != other.id + # Constructors # ============ @@ -25,33 +29,15 @@ def __ne__(self, other): def from_id(cls, id): """Return an existing package based on id. """ - return cls._from_thing("id", id) + return cls.db.one("SELECT packages.*::packages FROM packages WHERE id=%s", (id,)) @classmethod - def from_team_slug(cls, slug): - """Return an existing package based on team's slug. + def from_names(cls, package_manager, name): + """Return an existing package based on package manager and package names. """ - return cls._from_thing("team", slug) - - @classmethod - def _from_thing(cls, thing, value): - assert thing in ("id", "team") - return cls.db.one(""" - - SELECT packages.*::packages - FROM packages - WHERE {}=%s - - """.format(thing), (value,)) - - @classmethod - def insert(cls, owner, **fields): - return cls.db.one(""" - INSERT INTO packages (package_manager, name, description, emails) - VALUES (%(package_manager)s, %(name)s, %(description)s, %(emails)s) - RETURNING packages.*::packages + return cls.db.one("SELECT packages.*::packages FROM packages " + "WHERE package_manager=%s and name=%s", (package_manager, name)) - """, fields) def set_team(self, team): """Set team for a package. diff --git a/gratipay/wireup.py b/gratipay/wireup.py index 66c0f18df8..8e5b36df59 100644 --- a/gratipay/wireup.py +++ b/gratipay/wireup.py @@ -33,6 +33,7 @@ from gratipay.models.community import Community from gratipay.models.country import Country from gratipay.models.exchange_route import ExchangeRoute +from gratipay.models.package import Package from gratipay.models.participant import Participant from gratipay.models.participant.mixins import Identity from gratipay.models.team import Team @@ -56,7 +57,7 @@ def db(env): maxconn = env.database_maxconn db = GratipayDB(dburl, maxconn=maxconn) - for model in (AccountElsewhere, Community, Country, ExchangeRoute, Participant, Team): + for model in (AccountElsewhere, Community, Country, ExchangeRoute, Package, Participant, Team): db.register_model(model) gratipay.billing.payday.Payday.db = db diff --git a/tests/py/test_packages.py b/tests/py/test_packages.py index 84b8bd8565..a479070c8b 100644 --- a/tests/py/test_packages.py +++ b/tests/py/test_packages.py @@ -1,10 +1,16 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function, unicode_literals +from gratipay.models.package import Package from gratipay.testing import Harness -class Tests(Harness): +class TestPackage(Harness): - def test_foo(self): - pass + def test_can_be_instantiated_from_id(self): + p = self.make_package() + assert Package.from_id(p.id).id == p.id + + def test_can_be_instantiated_from_names(self): + self.make_package() + assert Package.from_names('npm', 'foo').name == 'foo' From 2b40ed050040bbee3e3b5fc48b73291b2ab0684d Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Tue, 7 Feb 2017 17:12:14 -0500 Subject: [PATCH 09/11] Prune stubbed out code --- gratipay/models/package/__init__.py | 35 ----------------------------- sql/branch.sql | 4 ---- 2 files changed, 39 deletions(-) delete mode 100644 sql/branch.sql diff --git a/gratipay/models/package/__init__.py b/gratipay/models/package/__init__.py index a93fc25e31..64eda95ba7 100644 --- a/gratipay/models/package/__init__.py +++ b/gratipay/models/package/__init__.py @@ -1,7 +1,6 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function, unicode_literals -from gratipay.models.team import Team from postgres.orm import Model @@ -37,37 +36,3 @@ def from_names(cls, package_manager, name): """ return cls.db.one("SELECT packages.*::packages FROM packages " "WHERE package_manager=%s and name=%s", (package_manager, name)) - - - def set_team(self, team): - """Set team for a package. - """ - if not isinstance(team, Team): - raise NotAllowed("Not a team!") - elif team.is_closed: - raise NotAllowed("team is closed") - elif not team.is_approved: - raise NotAllowed("team not approved") - package_id = self.id - slug = team.slug - with self.db.get_cursor() as c: - # TODO add event - c.run(""" - UPDATE packages - SET team=%(slug)s - WHERE id=%(package_id)s - """, locals()) - self.set_attributes(team=team) - - def set_payment_instruction(self, participant, amount): - team_id = self.team_id - if team_id: - team = Team.from_id(team_id) - participant.set_payment_instruction(team, amount) - else: - # TODO Add to pledges when we introduce it. - pass - - -class NotAllowed(Exception): - pass diff --git a/sql/branch.sql b/sql/branch.sql deleted file mode 100644 index 60b32eb8f7..0000000000 --- a/sql/branch.sql +++ /dev/null @@ -1,4 +0,0 @@ -BEGIN; - ALTER TABLE packages ADD COLUMN team_id integer DEFAULT NULL - REFERENCES teams (id) ON UPDATE RESTRICT ON DELETE RESTRICT; -END; From a72e9002017ebc09a770add034e20342a05436cf Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Tue, 7 Feb 2017 20:37:13 -0500 Subject: [PATCH 10/11] Smoke 'em if ya got 'em? :-) --- www/on/npm/%package/index.html.spt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/www/on/npm/%package/index.html.spt b/www/on/npm/%package/index.html.spt index 626306c03c..e9d0693bff 100644 --- a/www/on/npm/%package/index.html.spt +++ b/www/on/npm/%package/index.html.spt @@ -2,10 +2,10 @@ import requests from aspen import Response from gratipay.utils import markdown +from gratipay.models.package import Package [---] package_name = request.path['package'] -package = website.db.one("select * from packages where package_manager='npm' " - "and name=%s", (package_name,)) +package = Package.from_names('npm', package_name) if package is None: raise Response(404) banner = package_name From 9c052766cd54a80c3885808d0c2e5e0aeb9afd1f Mon Sep 17 00:00:00 2001 From: Chad Whitacre Date: Tue, 7 Feb 2017 20:45:42 -0500 Subject: [PATCH 11/11] Use constant instead of string literal for 'npm' --- gratipay/models/package/__init__.py | 4 ++++ tests/py/test_packages.py | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/gratipay/models/package/__init__.py b/gratipay/models/package/__init__.py index 64eda95ba7..24af56d724 100644 --- a/gratipay/models/package/__init__.py +++ b/gratipay/models/package/__init__.py @@ -4,6 +4,10 @@ from postgres.orm import Model +NPM = 'npm' # We are starting with a single package manager. If we see + # traction we will expand. + + class Package(Model): """Represent a gratipackage. :-) """ diff --git a/tests/py/test_packages.py b/tests/py/test_packages.py index a479070c8b..b97e888377 100644 --- a/tests/py/test_packages.py +++ b/tests/py/test_packages.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, division, print_function, unicode_literals -from gratipay.models.package import Package +from gratipay.models.package import NPM, Package from gratipay.testing import Harness @@ -13,4 +13,4 @@ def test_can_be_instantiated_from_id(self): def test_can_be_instantiated_from_names(self): self.make_package() - assert Package.from_names('npm', 'foo').name == 'foo' + assert Package.from_names(NPM, 'foo').name == 'foo'