diff --git a/gratipay/models/team/__init__.py b/gratipay/models/team/__init__.py index 5e0ec230fe..5e53da9723 100644 --- a/gratipay/models/team/__init__.py +++ b/gratipay/models/team/__init__.py @@ -7,6 +7,7 @@ from aspen import json, log from gratipay.exceptions import InvalidTeamName from gratipay.models import add_event +from gratipay.models.team import mixins from postgres.orm import Model from gratipay.billing.exchanges import MINIMUM_CHARGE @@ -30,7 +31,7 @@ def slugize(name): return slug -class Team(Model): +class Team(Model, mixins.Takes): """Represent a Gratipay team. """ diff --git a/gratipay/models/team/mixins/__init__.py b/gratipay/models/team/mixins/__init__.py new file mode 100644 index 0000000000..ba9a106282 --- /dev/null +++ b/gratipay/models/team/mixins/__init__.py @@ -0,0 +1,3 @@ +from .takes import TakesMixin as Takes + +__all__ = ['Takes'] diff --git a/gratipay/models/team/mixins/takes.py b/gratipay/models/team/mixins/takes.py new file mode 100644 index 0000000000..ef2123d6c4 --- /dev/null +++ b/gratipay/models/team/mixins/takes.py @@ -0,0 +1,28 @@ +from __future__ import absolute_import, division, print_function, unicode_literals + +from gratipay.models import add_event + + +class TakesMixin(object): + """This mixin provides management of takes for + :py:class:`~gratipay.models.team.Team` objects. + """ + + def set_takes_enabled(self, to): + """Update whether takes are enabled for this team. + + :param bool to: whether the team should have takes enabled + + """ + if type(to) is not bool: + raise TypeError('Boolean required.') + with self.db.get_cursor() as cursor: + cursor.run("UPDATE teams SET takes_enabled=%s WHERE id=%s", (to, self.id)) + add_event( cursor + , 'team' + , dict( action='set takes_enabled' + , id=self.id + , old_value=self.takes_enabled + , new_value=to + ) + ) diff --git a/sql/branch.sql b/sql/branch.sql index fbd24f756a..6bb3208e8f 100644 --- a/sql/branch.sql +++ b/sql/branch.sql @@ -68,3 +68,8 @@ CREATE TRIGGER propagate_is_verified_removal EXECUTE PROCEDURE update_has_verified_identity(); -- We don't need an INSERT trigger, because of the way the defaults play out. + + +-- https://github.com/gratipay/gratipay.com/pull/4017 + +ALTER TABLE teams ADD COLUMN takes_enabled bool NOT NULL DEFAULT false; diff --git a/tests/py/test_team_takes.py b/tests/py/test_team_takes.py new file mode 100644 index 0000000000..f1eccb58eb --- /dev/null +++ b/tests/py/test_team_takes.py @@ -0,0 +1,44 @@ +from __future__ import absolute_import, division, print_function, unicode_literals + +from gratipay.testing import Harness +from gratipay.models.team import Team, mixins +from pytest import raises + + +class Tests(Harness): + + def setUp(self): + self.enterprise = self.make_team('The Enterprise') + + + def test_team_object_subclasses_takes_mixin(self): + assert isinstance(self.enterprise, mixins.Takes) + + def test_takes_enabled_defaults_to_false(self): + assert self.enterprise.takes_enabled is False + + + # ste - set_takes_enabled + + def test_ste_sets_takes_enabled(self): + self.enterprise.set_takes_enabled(True) + assert Team.from_slug('TheEnterprise').takes_enabled is True + + def test_ste_sets_takes_enabled_back_to_false(self): + self.enterprise.set_takes_enabled(False) + assert Team.from_slug('TheEnterprise').takes_enabled is False + + def test_ste_sets_takes_rejects_non_boolean_values(self): + raises(TypeError, self.enterprise.set_takes_enabled, None) + raises(TypeError, self.enterprise.set_takes_enabled, 'foo') + raises(TypeError, self.enterprise.set_takes_enabled, 123) + + def test_ste_setting_takes_enabled_is_a_logged_event(self): + self.enterprise.set_takes_enabled(True) + events = self.db.all("SELECT * FROM events") + assert len(events) == 1 + assert events[0].type == 'team' + assert events[0].payload['action'] == 'set takes_enabled' + assert events[0].payload['old_value'] == False + assert events[0].payload['new_value'] == True + assert events[0].payload['id'] == self.enterprise.id