From 1fbc351c6f884fe99ba969da2c3bc4283c77e582 Mon Sep 17 00:00:00 2001 From: Jacob Wegner Date: Tue, 1 Mar 2016 09:43:34 -0600 Subject: [PATCH 01/17] add the ability to nest teams --- pinax/teams/admin.py | 6 +- pinax/teams/hooks.py | 1 + pinax/teams/migrations/0002_team_parent.py | 19 ++++++ pinax/teams/models.py | 70 ++++++++++++++++++-- pinax/teams/templatetags/pinax_teams_tags.py | 43 +++++++++++- 5 files changed, 129 insertions(+), 10 deletions(-) create mode 100644 pinax/teams/migrations/0002_team_parent.py diff --git a/pinax/teams/admin.py b/pinax/teams/admin.py index 817cc66..ab022a9 100644 --- a/pinax/teams/admin.py +++ b/pinax/teams/admin.py @@ -3,6 +3,7 @@ from reversion.admin import VersionAdmin +from .hooks import hookset from .models import Team, Membership @@ -21,10 +22,11 @@ def members_count(obj): "description", "member_access", "manager_access", - "creator" + "creator", + "parent", ], prepopulated_fields={"slug": ("name",)}, - raw_id_fields=["creator"] + raw_id_fields=["creator", "parent"] ) diff --git a/pinax/teams/hooks.py b/pinax/teams/hooks.py index 4ac356c..6a9dadb 100644 --- a/pinax/teams/hooks.py +++ b/pinax/teams/hooks.py @@ -13,6 +13,7 @@ "on-team-blacklist": "You can not create a team by this name", "user-member-exists": "User already on team.", "invitee-member-exists": "Invite already sent.", + "self-referencing-parent": "A team cannot be a parent of itself.", } diff --git a/pinax/teams/migrations/0002_team_parent.py b/pinax/teams/migrations/0002_team_parent.py new file mode 100644 index 0000000..3b54117 --- /dev/null +++ b/pinax/teams/migrations/0002_team_parent.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('teams', '0001_initial'), + ] + + operations = [ + migrations.AddField( + model_name='team', + name='parent', + field=models.ForeignKey(related_name=b'children', blank=True, to='pinax_teams.Team', null=True), + ), + ] diff --git a/pinax/teams/models.py b/pinax/teams/models.py index c2420c3..6f1dbf7 100644 --- a/pinax/teams/models.py +++ b/pinax/teams/models.py @@ -4,6 +4,7 @@ from django.conf import settings from django.core.urlresolvers import reverse +from django.core.exceptions import ValidationError from django.db import models from django.utils import timezone from django.utils.encoding import python_2_unicode_compatible @@ -14,6 +15,10 @@ from slugify import slugify from . import signals +from .hooks import hookset + + +MESSAGE_STRINGS = hookset.get_message_strings() def avatar_upload(instance, filename): @@ -22,8 +27,14 @@ def avatar_upload(instance, filename): return os.path.join("avatars", filename) -def create_slug(name): - return slugify(name)[:50] +def create_slug(name, parent=None): + slug = slugify(name) + if parent: + slug = "{parent_pk}-{slug}".format( + parent_pk=parent.pk, + slug=slug, + ) + return slug[:50] @python_2_unicode_compatible @@ -56,12 +67,18 @@ class Team(models.Model): creator = models.ForeignKey(settings.AUTH_USER_MODEL, related_name="teams_created", verbose_name=_("creator")) created = models.DateTimeField(default=timezone.now, editable=False, verbose_name=_("created")) + parent = models.ForeignKey("self", blank=True, null=True, related_name="children") + def get_absolute_url(self): return reverse("team_detail", args=[self.slug]) def __str__(self): return self.name + def clean(self): + if self.pk and self.pk == self.parent_id: + raise ValidationError({"parent": MESSAGE_STRINGS["self-referencing-parent"]}) + def can_join(self, user): state = self.state_for(user) if self.member_access == Team.MEMBER_ACCESS_OPEN and state is None: @@ -80,6 +97,28 @@ def can_apply(self, user): state = self.state_for(user) return self.member_access == Team.MEMBER_ACCESS_APPLICATION and state is None + #@@@ + def get_root_team(team): + while getattr(team, "parent"): + team = team.parent + return team + + # @@@ + @property + def ancestors(team): + chain = [] + while getattr(team, "parent"): + chain.append(team) + team = team.parent + chain.append(team) + #filo + chain.reverse() + return chain + + @property + def full_name(self): + return " : ".join([a.name for a in self.ancestors]) + @property def applicants(self): return self.memberships.filter(state=Membership.STATE_APPLIED) @@ -174,10 +213,27 @@ def invite_user(self, from_user, to_email, role, message=None): return membership def for_user(self, user): - try: - return self.memberships.get(user=user) - except Membership.DoesNotExist: - pass + """ + Return the first membership found for the current team and user + or for any of the team's parents and the user + + @@@ we may decide to explicitly add membership for "children" if a + user is a manager or member of a parent org + """ + attr = "_membership_for_user" + + if hasattr(self, attr) is False: + team = self + membership = None + while team: + try: + membership = team.memberships.get(user=user) + break + except Membership.DoesNotExist: + team = team.parent + # @@@ care about the type of membership if retrieved from a parent + setattr(self, attr, membership) + return getattr(self, attr) def state_for(self, user): membership = self.for_user(user=user) @@ -191,7 +247,7 @@ def role_for(self, user): def save(self, *args, **kwargs): if not self.id: - self.slug = create_slug(self.name) + self.slug = create_slug(self.name, self.parent) self.full_clean() super(Team, self).save(*args, **kwargs) diff --git a/pinax/teams/templatetags/pinax_teams_tags.py b/pinax/teams/templatetags/pinax_teams_tags.py index ffdfc75..9f967d7 100644 --- a/pinax/teams/templatetags/pinax_teams_tags.py +++ b/pinax/teams/templatetags/pinax_teams_tags.py @@ -1,6 +1,6 @@ from django import template -from ..models import Team +from ..models import Team, Membership register = template.Library() @@ -38,3 +38,44 @@ def available_teams(parser, token): {% available_teams as available_teams %} """ return AvailableTeamsNode.handle_token(parser, token) + + +@register.assignment_tag(takes_context=True) +def ancestors_for(context, team=None): + if team is None: + team = context["team"] + + ancestors = [] + for ancestor in team.ancestors: + ancestors.append({ + "team": ancestor, + "can_manage": ancestor.role_for(context["user"]) in [Membership.ROLE_MANAGER, Membership.ROLE_OWNER] + }) + context["ancestors"] = ancestors + return ancestors + + +@register.assignment_tag(takes_context=True) +def descendants_for(context, team=None): + if team is None: + team = context["team"] + + descendants = [] + for descendant in team.children.order_by("slug"): + descendants.append({ + "team": descendant, + "can_manage": descendant.role_for(context["user"]) in [Membership.ROLE_MANAGER, Membership.ROLE_OWNER] + }) + return descendants + + +# @@@ document template +@register.inclusion_tag("teams/_breadcrumbs.html", takes_context=True) +def get_team_breadcrumbs(context): + context["ancestors"] = ancestors_for(context) + return context + + +@register.filter() +def is_managed_by(team, user): + return team.role_for(user) in [Membership.ROLE_MANAGER, Membership.ROLE_OWNER] From daa656c1589077e9f60ab652b284b2601c6fd79a Mon Sep 17 00:00:00 2001 From: Jacob Wegner Date: Tue, 1 Mar 2016 10:16:05 -0600 Subject: [PATCH 02/17] remove unused import --- pinax/teams/admin.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pinax/teams/admin.py b/pinax/teams/admin.py index ab022a9..8e8761d 100644 --- a/pinax/teams/admin.py +++ b/pinax/teams/admin.py @@ -3,7 +3,6 @@ from reversion.admin import VersionAdmin -from .hooks import hookset from .models import Team, Membership From 0c9dffc95df7e316a2b8283ddd73e69ef71e55e2 Mon Sep 17 00:00:00 2001 From: Jacob Wegner Date: Tue, 1 Mar 2016 10:51:46 -0600 Subject: [PATCH 03/17] update migration 0002 to use pinax_teams app label --- pinax/teams/migrations/0002_team_parent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pinax/teams/migrations/0002_team_parent.py b/pinax/teams/migrations/0002_team_parent.py index 3b54117..eb654ea 100644 --- a/pinax/teams/migrations/0002_team_parent.py +++ b/pinax/teams/migrations/0002_team_parent.py @@ -7,7 +7,7 @@ class Migration(migrations.Migration): dependencies = [ - ('teams', '0001_initial'), + ('pinax_teams', '0001_initial'), ] operations = [ From 51062aaf2811e102047be77de17cc80db87b9e80 Mon Sep 17 00:00:00 2001 From: Jacob Wegner Date: Sun, 3 Jul 2016 17:06:33 -0500 Subject: [PATCH 04/17] bump version number for next release --- changelog.md | 2 ++ setup.py | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/changelog.md b/changelog.md index a0f35a6..7330970 100644 --- a/changelog.md +++ b/changelog.md @@ -1,5 +1,7 @@ # Change Log +## 0.12 + ## 0.11.5 * Add initiating user to membership signals [PR #42](https://github.com/pinax/pinax-teams/pull/42) diff --git a/setup.py b/setup.py index df2ae30..2326827 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ def read(*parts): description="An app for Django sites that supports open, by invitation, and by application teams", name="pinax-teams", long_description=read("README.rst"), - version="0.11.5", + version="0.12", url="http://pinax-teams.rtfd.org/", license="MIT", packages=find_packages(), From 77c248858d1cceec41018aa9503eb7425d896563 Mon Sep 17 00:00:00 2001 From: Jacob Wegner Date: Tue, 19 Jul 2016 00:26:57 -0400 Subject: [PATCH 05/17] fix failing test --- pinax/teams/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pinax/teams/models.py b/pinax/teams/models.py index cf67ca0..130e72e 100644 --- a/pinax/teams/models.py +++ b/pinax/teams/models.py @@ -38,7 +38,6 @@ def create_slug(name, parent=None): return slug[:50] -@python_2_unicode_compatible class BaseTeam(models.Model): MEMBER_ACCESS_OPEN = "open" From 5301f9a877543683eb589893e1b243a2dcc797fa Mon Sep 17 00:00:00 2001 From: Jacob Wegner Date: Wed, 20 Jul 2016 21:12:24 -0400 Subject: [PATCH 06/17] factor out is_managed_by_as_filter --- pinax/teams/templatetags/pinax_teams_tags.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pinax/teams/templatetags/pinax_teams_tags.py b/pinax/teams/templatetags/pinax_teams_tags.py index 9f967d7..515c001 100644 --- a/pinax/teams/templatetags/pinax_teams_tags.py +++ b/pinax/teams/templatetags/pinax_teams_tags.py @@ -49,7 +49,7 @@ def ancestors_for(context, team=None): for ancestor in team.ancestors: ancestors.append({ "team": ancestor, - "can_manage": ancestor.role_for(context["user"]) in [Membership.ROLE_MANAGER, Membership.ROLE_OWNER] + "can_manage": is_managed_by(ancestor, context["user"]) }) context["ancestors"] = ancestors return ancestors @@ -64,7 +64,7 @@ def descendants_for(context, team=None): for descendant in team.children.order_by("slug"): descendants.append({ "team": descendant, - "can_manage": descendant.role_for(context["user"]) in [Membership.ROLE_MANAGER, Membership.ROLE_OWNER] + "can_manage": is_managed_by(descendant, context["user"]) }) return descendants @@ -76,6 +76,10 @@ def get_team_breadcrumbs(context): return context -@register.filter() def is_managed_by(team, user): return team.role_for(user) in [Membership.ROLE_MANAGER, Membership.ROLE_OWNER] + + +@register.filter(name="is_managed_by") +def is_managed_by_as_filter(team, user): + return is_managed_by(team, user) From 43749271273e1d1c9a18afa19cc5b5355b8bbeb5 Mon Sep 17 00:00:00 2001 From: Jacob Wegner Date: Wed, 20 Jul 2016 21:16:02 -0400 Subject: [PATCH 07/17] fix get_root_team and ancestors to refer to Team instance using self --- pinax/teams/models.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/pinax/teams/models.py b/pinax/teams/models.py index 130e72e..b5ddb71 100644 --- a/pinax/teams/models.py +++ b/pinax/teams/models.py @@ -89,24 +89,31 @@ def can_apply(self, user): state = self.state_for(user) return self.member_access == BaseTeam.MEMBER_ACCESS_APPLICATION and state is None - #@@@ - def get_root_team(team): + def get_root_team(self): + """ + Returns the top-most parent for a team + """ + team = self while getattr(team, "parent"): team = team.parent return team - # @@@ @property - def ancestors(team): + def ancestors(self): + """ + Returns the parent(s) of a team + """ + team = self chain = [] while getattr(team, "parent"): chain.append(team) team = team.parent chain.append(team) - #filo + # first in, last out chain.reverse() return chain + @property def full_name(self): return " : ".join([a.name for a in self.ancestors]) From 138e02f6532b848ae662ffe2b8d96fdb34f67acb Mon Sep 17 00:00:00 2001 From: Jacob Wegner Date: Wed, 20 Jul 2016 21:23:14 -0400 Subject: [PATCH 08/17] add docstring to ancestors_for assignment tag --- pinax/teams/templatetags/pinax_teams_tags.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/pinax/teams/templatetags/pinax_teams_tags.py b/pinax/teams/templatetags/pinax_teams_tags.py index 515c001..91a9eec 100644 --- a/pinax/teams/templatetags/pinax_teams_tags.py +++ b/pinax/teams/templatetags/pinax_teams_tags.py @@ -42,6 +42,10 @@ def available_teams(parser, token): @register.assignment_tag(takes_context=True) def ancestors_for(context, team=None): + """ + Retrives the ancestors for a given team and indicates + if the user can manage each ancestor + """ if team is None: team = context["team"] From 10762c773e4a8976c068414452dc8acf2bc2c28f Mon Sep 17 00:00:00 2001 From: Jacob Wegner Date: Wed, 20 Jul 2016 21:23:46 -0400 Subject: [PATCH 09/17] add docstring and rename descendants_for to children_for --- pinax/teams/templatetags/pinax_teams_tags.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/pinax/teams/templatetags/pinax_teams_tags.py b/pinax/teams/templatetags/pinax_teams_tags.py index 91a9eec..e447fb5 100644 --- a/pinax/teams/templatetags/pinax_teams_tags.py +++ b/pinax/teams/templatetags/pinax_teams_tags.py @@ -60,17 +60,21 @@ def ancestors_for(context, team=None): @register.assignment_tag(takes_context=True) -def descendants_for(context, team=None): +def children_for(context, team=None): + """ + Retrieves the children of a given team and indicates + if the user can manage each child + """ if team is None: team = context["team"] - descendants = [] - for descendant in team.children.order_by("slug"): - descendants.append({ - "team": descendant, - "can_manage": is_managed_by(descendant, context["user"]) + children = [] + for child in team.children.order_by("slug"): + children.append({ + "team": child, + "can_manage": is_managed_by(child, context["user"]) }) - return descendants + return children # @@@ document template From 661d8f136616e8dfb22aa0c8014b9f6ec5735478 Mon Sep 17 00:00:00 2001 From: Jacob Wegner Date: Wed, 20 Jul 2016 22:03:02 -0400 Subject: [PATCH 10/17] add descendants to Team --- pinax/teams/models.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pinax/teams/models.py b/pinax/teams/models.py index b5ddb71..93a63cf 100644 --- a/pinax/teams/models.py +++ b/pinax/teams/models.py @@ -113,6 +113,16 @@ def ancestors(self): chain.reverse() return chain + @property + def descendants(self): + """ + Return descendants of a team + """ + _descendants = [] + for child in self.children.all() + _descendants.extend(child.descendants) + return _descendants + @property def full_name(self): From ed9daa8c3166c03ff220707cb36f5bde77747598 Mon Sep 17 00:00:00 2001 From: Jacob Wegner Date: Mon, 17 Jul 2017 16:35:51 -0500 Subject: [PATCH 11/17] fix syntax error --- pinax/teams/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pinax/teams/models.py b/pinax/teams/models.py index af7d17b..85fdcc6 100644 --- a/pinax/teams/models.py +++ b/pinax/teams/models.py @@ -119,7 +119,7 @@ def descendants(self): Return descendants of a team """ _descendants = [] - for child in self.children.all() + for child in self.children.all(): _descendants.extend(child.descendants) return _descendants From 5b6888fc83d4c9a4ac2fa49e9d264dbad1fb7d1d Mon Sep 17 00:00:00 2001 From: Jacob Wegner Date: Mon, 17 Jul 2017 16:35:59 -0500 Subject: [PATCH 12/17] pin pinax-invitations --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2420cac..7749a7a 100644 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ def read(*parts): install_requires=[ "Django>=1.8", "django-reversion>=1.8.1", - "pinax-invitations>=4.0.4", + "pinax-invitations==4.0.4", "unicode-slugify>=0.1.1", "Pillow>=2.3.0", "django-user-accounts>=1.3", From d4b8f771465c7035104c99ab12ac2d2cd65cbc99 Mon Sep 17 00:00:00 2001 From: Jacob Wegner Date: Mon, 17 Jul 2017 16:39:08 -0500 Subject: [PATCH 13/17] resolve migration conflict --- .../teams/migrations/0003_add_team_parent.py | 19 -------------- .../teams/migrations/0005_add_team_parent.py | 26 +++++++++++++++++++ 2 files changed, 26 insertions(+), 19 deletions(-) delete mode 100644 pinax/teams/migrations/0003_add_team_parent.py create mode 100644 pinax/teams/migrations/0005_add_team_parent.py diff --git a/pinax/teams/migrations/0003_add_team_parent.py b/pinax/teams/migrations/0003_add_team_parent.py deleted file mode 100644 index 62305c2..0000000 --- a/pinax/teams/migrations/0003_add_team_parent.py +++ /dev/null @@ -1,19 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals - -from django.db import models, migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('pinax_teams', '0002_add_simple_model'), - ] - - operations = [ - migrations.AddField( - model_name='team', - name='parent', - field=models.ForeignKey(related_name=b'children', blank=True, to='pinax_teams.Team', null=True), - ), - ] diff --git a/pinax/teams/migrations/0005_add_team_parent.py b/pinax/teams/migrations/0005_add_team_parent.py new file mode 100644 index 0000000..7e44d89 --- /dev/null +++ b/pinax/teams/migrations/0005_add_team_parent.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.3 on 2017-07-17 21:34 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('pinax_teams', '0004_auto_20170511_0856'), + ] + + operations = [ + migrations.AddField( + model_name='simpleteam', + name='parent', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='pinax_teams.SimpleTeam'), + ), + migrations.AddField( + model_name='team', + name='parent', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='pinax_teams.Team'), + ), + ] From 704662e2e8b2d0edbd3d5f106f890df923e65942 Mon Sep 17 00:00:00 2001 From: Jacob Wegner Date: Mon, 11 Sep 2017 10:58:37 -0500 Subject: [PATCH 14/17] fix migrations for pinax-invitations --- pinax/teams/migrations/0001_initial.py | 4 ++-- pinax/teams/migrations/0002_add_simple_models.py | 4 ++-- setup.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pinax/teams/migrations/0001_initial.py b/pinax/teams/migrations/0001_initial.py index 3127544..0f81a0e 100644 --- a/pinax/teams/migrations/0001_initial.py +++ b/pinax/teams/migrations/0001_initial.py @@ -10,7 +10,7 @@ class Migration(migrations.Migration): dependencies = [ - ('invitations', '0001_initial'), + ('pinax_invitations', '0001_initial'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] @@ -22,7 +22,7 @@ class Migration(migrations.Migration): ('state', models.CharField(max_length=20, verbose_name='state', choices=[(b'applied', 'applied'), (b'invited', 'invited'), (b'declined', 'declined'), (b'rejected', 'rejected'), (b'accepted', 'accepted'), (b'auto-joined', 'auto joined')])), ('role', models.CharField(default=b'member', max_length=20, verbose_name='role', choices=[(b'member', 'member'), (b'manager', 'manager'), (b'owner', 'owner')])), ('created', models.DateTimeField(default=django.utils.timezone.now, verbose_name='created')), - ('invite', models.ForeignKey(related_name=b'memberships', verbose_name='invite', blank=True, to='invitations.JoinInvitation', null=True)), + ('invite', models.ForeignKey(related_name=b'memberships', verbose_name='invite', blank=True, to='pinax_invitations.JoinInvitation', null=True)), ], options={ 'verbose_name': 'Team', diff --git a/pinax/teams/migrations/0002_add_simple_models.py b/pinax/teams/migrations/0002_add_simple_models.py index ff69f0a..afc6c32 100644 --- a/pinax/teams/migrations/0002_add_simple_models.py +++ b/pinax/teams/migrations/0002_add_simple_models.py @@ -11,7 +11,7 @@ class Migration(migrations.Migration): dependencies = [ - ('invitations', '0001_initial'), + ('pinax_invitations', '0001_initial'), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ('pinax_teams', '0001_initial'), ] @@ -24,7 +24,7 @@ class Migration(migrations.Migration): ('state', models.CharField(choices=[(b'applied', 'applied'), (b'invited', 'invited'), (b'declined', 'declined'), (b'rejected', 'rejected'), (b'accepted', 'accepted'), (b'auto-joined', 'auto joined')], max_length=20, verbose_name='state')), ('role', models.CharField(choices=[(b'member', 'member'), (b'manager', 'manager'), (b'owner', 'owner')], default=b'member', max_length=20, verbose_name='role')), ('created', models.DateTimeField(default=django.utils.timezone.now, verbose_name='created')), - ('invite', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='simple_memberships', to='invitations.JoinInvitation', verbose_name='invite')), + ('invite', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='simple_memberships', to='pinax_invitations.JoinInvitation', verbose_name='invite')), ], options={ 'verbose_name': 'Simple Membership', diff --git a/setup.py b/setup.py index 7749a7a..2c247d5 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ def read(*parts): tests_require=[ "Django>=1.8", "django-reversion>=1.8.1", - "pinax-invitations==4.0.4", # 5.0.0 changes label from invitations to pinax_invitations + "pinax-invitations>=5.0.0,<6.0.0", "unicode-slugify>=0.1.1", "Pillow>=2.3.0", "django-user-accounts>=1.3", @@ -32,7 +32,7 @@ def read(*parts): install_requires=[ "Django>=1.8", "django-reversion>=1.8.1", - "pinax-invitations==4.0.4", + "pinax-invitations>=5.0.0,<6.0.0", "unicode-slugify>=0.1.1", "Pillow>=2.3.0", "django-user-accounts>=1.3", From b34420d6b5723298bebfa330c46815340da4d1b2 Mon Sep 17 00:00:00 2001 From: Jacob Wegner Date: Mon, 11 Sep 2017 11:58:26 -0500 Subject: [PATCH 15/17] locate templates within pinax/teams --- pinax/teams/templatetags/pinax_teams_tags.py | 2 +- pinax/teams/views.py | 23 ++++++++++---------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/pinax/teams/templatetags/pinax_teams_tags.py b/pinax/teams/templatetags/pinax_teams_tags.py index e447fb5..1737e96 100644 --- a/pinax/teams/templatetags/pinax_teams_tags.py +++ b/pinax/teams/templatetags/pinax_teams_tags.py @@ -78,7 +78,7 @@ def children_for(context, team=None): # @@@ document template -@register.inclusion_tag("teams/_breadcrumbs.html", takes_context=True) +@register.inclusion_tag("pinax/teams/_breadcrumbs.html", takes_context=True) def get_team_breadcrumbs(context): context["ancestors"] = ancestors_for(context) return context diff --git a/pinax/teams/views.py b/pinax/teams/views.py index 672c3f2..e498af2 100644 --- a/pinax/teams/views.py +++ b/pinax/teams/views.py @@ -28,7 +28,7 @@ class TeamSignupView(SignupView): - template_name = "teams/signup.html" + template_name = "pinax/teams/signup.html" def get_form_class(self): if self.signup_code: @@ -47,6 +47,7 @@ class TeamCreateView(LoginRequiredMixin, CreateView): form_class = TeamForm model = Team + template_name = "pinax/teams/team_form.html" def form_valid(self, form): self.object = form.save(commit=False) @@ -59,7 +60,7 @@ class TeamListView(ListView): model = Team context_object_name = "teams" - + template_name = "pinax/teams/team_list.html" @team_required @login_required @@ -74,7 +75,7 @@ def team_update(request): return redirect(team.get_absolute_url()) else: form = TeamForm(instance=team) - return render(request, "teams/team_form.html", {"form": form, "team": team}) + return render(request, "pinax/teams/team_form.html", {"form": form, "team": team}) @team_required @@ -85,7 +86,7 @@ def team_detail(request): role = team.role_for(request.user) if team.member_access == Team.MEMBER_ACCESS_INVITATION and state is None: raise Http404() - return render(request, "teams/team_detail.html", { + return render(request, "pinax/teams/team_detail.html", { "team": team, "state": state, "role": role, @@ -98,7 +99,7 @@ def team_detail(request): class TeamManageView(TemplateView): - template_name = "teams/team_manage.html" + template_name = "pinax/teams/team_manage.html" @method_decorator(manager_required) def dispatch(self, *args, **kwargs): @@ -234,7 +235,7 @@ def get_form_success_data(self, form): """ data = { "html": render_to_string( - "teams/_invite_form.html", + "pinax/teams/_invite_form.html", { "invite_form": self.get_unbound_form(), "team": self.team @@ -258,7 +259,7 @@ def get_form_success_data(self, form): data.update({ "append-fragments": { fragment_class: render_to_string( - "teams/_membership.html", + "pinax/teams/_membership.html", { "membership": membership, "team": self.team @@ -284,7 +285,7 @@ def form_valid(self, form): def form_invalid(self, form): data = { - "html": render_to_string("teams/_invite_form.html", { + "html": render_to_string("pinax/teams/_invite_form.html", { "invite_form": form, "team": self.team }, context_instance=RequestContext(self.request)) @@ -313,7 +314,7 @@ def team_member_resend_invite(request, pk): membership.resend_invite(by=request.user) data = { "html": render_to_string( - "teams/_membership.html", + "pinax/teams/_membership.html", { "membership": membership, "team": request.team @@ -331,7 +332,7 @@ def team_member_promote(request, pk): membership.promote(by=request.user) data = { "html": render_to_string( - "teams/_membership.html", + "pinax/teams/_membership.html", { "membership": membership, "team": request.team @@ -349,7 +350,7 @@ def team_member_demote(request, pk): membership.demote(by=request.user) data = { "html": render_to_string( - "teams/_membership.html", + "pinax/teams/_membership.html", { "membership": membership, "team": request.team From 8fce42906c45fd9429003dfd413a56fad515e746 Mon Sep 17 00:00:00 2001 From: Jacob Wegner Date: Mon, 11 Sep 2017 12:15:59 -0500 Subject: [PATCH 16/17] fix render_to_string --- pinax/teams/views.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/pinax/teams/views.py b/pinax/teams/views.py index e498af2..30832b4 100644 --- a/pinax/teams/views.py +++ b/pinax/teams/views.py @@ -2,7 +2,6 @@ from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpResponseForbidden, JsonResponse from django.shortcuts import render, redirect, get_object_or_404 -from django.template import RequestContext from django.template.loader import render_to_string from django.utils.decorators import method_decorator from django.views.decorators.http import require_POST @@ -240,7 +239,7 @@ def get_form_success_data(self, form): "invite_form": self.get_unbound_form(), "team": self.team }, - context_instance=RequestContext(self.request) + request=self.request ) } @@ -264,7 +263,7 @@ def get_form_success_data(self, form): "membership": membership, "team": self.team }, - context_instance=RequestContext(self.request) + request=self.request ) } }) @@ -288,7 +287,7 @@ def form_invalid(self, form): "html": render_to_string("pinax/teams/_invite_form.html", { "invite_form": form, "team": self.team - }, context_instance=RequestContext(self.request)) + }, request=self.request) } return self.render_to_response(data) @@ -319,7 +318,7 @@ def team_member_resend_invite(request, pk): "membership": membership, "team": request.team }, - context_instance=RequestContext(request) + request=request ) } return HttpResponse(json.dumps(data), content_type="application/json") @@ -337,7 +336,7 @@ def team_member_promote(request, pk): "membership": membership, "team": request.team }, - context_instance=RequestContext(request) + request=request ) } return HttpResponse(json.dumps(data), content_type="application/json") @@ -355,7 +354,7 @@ def team_member_demote(request, pk): "membership": membership, "team": request.team }, - context_instance=RequestContext(request) + request=request ) } return HttpResponse(json.dumps(data), content_type="application/json") From f25b1e42d84d56e09aee0c33f5d87bab1773d7b9 Mon Sep 17 00:00:00 2001 From: Jacob Wegner Date: Mon, 11 Sep 2017 16:45:15 -0500 Subject: [PATCH 17/17] fix linting errors --- pinax/teams/models.py | 1 - pinax/teams/views.py | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/pinax/teams/models.py b/pinax/teams/models.py index 85fdcc6..e1ac6fa 100644 --- a/pinax/teams/models.py +++ b/pinax/teams/models.py @@ -123,7 +123,6 @@ def descendants(self): _descendants.extend(child.descendants) return _descendants - @property def full_name(self): return " : ".join([a.name for a in self.ancestors]) diff --git a/pinax/teams/views.py b/pinax/teams/views.py index 30832b4..697bda9 100644 --- a/pinax/teams/views.py +++ b/pinax/teams/views.py @@ -61,6 +61,7 @@ class TeamListView(ListView): context_object_name = "teams" template_name = "pinax/teams/team_list.html" + @team_required @login_required def team_update(request):