Skip to content
Browse files

Merge branch 'master' into feature-reviews

Conflicts:
	symposion_project/settings.py
	symposion_project/templates/dashboard.html
	symposion_project/urls.py
  • Loading branch information...
2 parents 18996cb + 0dbcbea commit 5f1670df5c1af08cf2d269121c4e24dbcff7d6fb @jtauber jtauber committed Aug 8, 2012
View
0 symposion/teams/__init__.py
No changes.
View
17 symposion/teams/admin.py
@@ -0,0 +1,17 @@
+from django.contrib import admin
+
+import reversion
+
+from symposion.teams.models import Team, Membership
+
+admin.site.register(Team,
+ prepopulated_fields={"slug": ("name",)},
+)
+
+
+class MembershipAdmin(reversion.VersionAdmin):
+ list_display = ["team", "user", "state"]
+ list_filter = ["team"]
+ search_fields = ["user__username"]
+
+admin.site.register(Membership, MembershipAdmin)
View
33 symposion/teams/backends.py
@@ -0,0 +1,33 @@
+from django.db.models import Q
+
+from .models import Team
+
+
+class TeamPermissionsBackend(object):
+
+ def authenticate(self, username=None, password=None):
+ return None
+
+ def get_team_permissions(self, user_obj, obj=None):
+ """
+ Returns a set of permission strings that this user has through his/her
+ team memberships.
+ """
+ if user_obj.is_anonymous() or obj is not None:
+ return set()
+ if not hasattr(user_obj, "_team_perm_cache"):
+ memberships = Team.objects.filter(
+ Q(memberships__user=user_obj),
+ Q(memberships__state="manager") | Q(memberships__state="member"),
+ )
+ perms = memberships.values_list(
+ "permissions__content_type__app_label",
+ "permissions__codename"
+ ).order_by()
+ user_obj._team_perm_cache = set(["%s.%s" % (ct, name) for ct, name in perms])
+ return user_obj._team_perm_cache
+
+ def has_perm(self, user_obj, perm, obj=None):
+ if not user_obj.is_active:
+ return False
+ return perm in self.get_team_permissions(user_obj, obj)
View
50 symposion/teams/forms.py
@@ -0,0 +1,50 @@
+from django import forms
+
+from django.contrib.auth.models import User
+
+from symposion.teams.models import Membership
+
+
+class TeamInvitationForm(forms.Form):
+
+ email = forms.EmailField(help_text="email address must be that of a user on the site")
+
+ def __init__(self, *args, **kwargs):
+ self.team = kwargs.pop("team")
+ super(TeamInvitationForm, self).__init__(*args, **kwargs)
+
+ def clean(self):
+ cleaned_data = super(TeamInvitationForm, self).clean()
+ email = cleaned_data.get("email")
+
+ if email is None:
+ raise forms.ValidationError("valid email address required")
+
+ try:
+ user = User.objects.get(email=email)
+ except User.DoesNotExist:
+ # eventually we can invite them but for now assume they are
+ # already on the site
+ raise forms.ValidationError("no known user with email address %s" % email)
+
+ state = self.team.get_state_for_user(user)
+
+ if state in ["member", "manager"]:
+ raise forms.ValidationError("user already in team")
+
+ if state in ["invited"]:
+ raise forms.ValidationError("user already invited to team")
+
+ self.user = user
+ self.state = state
+
+ return cleaned_data
+
+ def invite(self):
+ if self.state is None:
+ Membership.objects.create(team=self.team, user=self.user, state="invited")
+ elif self.state == "applied":
+ # if they applied we shortcut invitation process
+ membership = Membership.objects.get(team=self.team, user=self.user)
+ membership.state = "member"
+ membership.save()
View
72 symposion/teams/models.py
@@ -0,0 +1,72 @@
+import datetime
+
+from django.db import models
+
+import reversion
+
+from django.contrib.auth.models import Permission, User
+
+
+TEAM_ACCESS_CHOICES = [
+ ("open", "open"),
+ ("application", "by application"),
+ ("invitation", "by invitation")
+]
+
+
+class Team(models.Model):
+
+ slug = models.SlugField(unique=True)
+ name = models.CharField(max_length=100)
+ description = models.TextField(blank=True)
+ access = models.CharField(max_length=20, choices=TEAM_ACCESS_CHOICES)
+
+ # member permissions
+ permissions = models.ManyToManyField(Permission, blank=True, related_name="member_teams")
+
+ # manager permissions
+ manager_permissions = models.ManyToManyField(Permission, blank=True, related_name="manager_teams")
+
+ created = models.DateTimeField(default=datetime.datetime.now, editable=False)
+
+ def __unicode__(self):
+ return self.name
+
+ def get_state_for_user(self, user):
+ try:
+ return self.memberships.get(user=user).state
+ except Membership.DoesNotExist:
+ return None
+
+ def applicants(self):
+ return self.memberships.filter(state="applied")
+
+ def invitees(self):
+ return self.memberships.filter(state="invited")
+
+ def members(self):
+ return self.memberships.filter(state="member")
+
+ def managers(self):
+ return self.memberships.filter(state="manager")
+
+
+MEMBERSHIP_STATE_CHOICES = [
+ ("applied", "applied"),
+ ("invited", "invited"),
+ ("declined", "declined"),
+ ("rejected", "rejected"),
+ ("member", "member"),
+ ("manager", "manager"),
+]
+
+
+class Membership(models.Model):
+
+ user = models.ForeignKey(User, related_name="memberships")
+ team = models.ForeignKey(Team, related_name="memberships")
+ state = models.CharField(max_length=20, choices=MEMBERSHIP_STATE_CHOICES)
+ message = models.TextField(blank=True)
+
+
+reversion.register(Membership)
View
0 symposion/teams/templatetags/__init__.py
No changes.
View
39 symposion/teams/templatetags/teams_tags.py
@@ -0,0 +1,39 @@
+from django import template
+
+from symposion.teams.models import Team
+
+register = template.Library()
+
+
+class AvailableTeamsNode(template.Node):
+
+ @classmethod
+ def handle_token(cls, parser, token):
+ bits = token.split_contents()
+ if len(bits) == 3 and bits[1] == "as":
+ return cls(bits[2])
+ else:
+ raise template.TemplateSyntaxError("%r takes 'as var'" % bits[0])
+
+ def __init__(self, context_var):
+ self.context_var = context_var
+
+ def render(self, context):
+ request = context["request"]
+ teams = []
+ for team in Team.objects.all():
+ state = team.get_state_for_user(request.user)
+ if team.access == "open" and state is None:
+ teams.append(team)
+ elif request.user.is_staff and state is None:
+ teams.append(team)
+ context[self.context_var] = teams
+ return u""
+
+
+@register.tag
+def available_teams(parser, token):
+ """
+ {% available_teams as available_teams %}
+ """
+ return AvailableTeamsNode.handle_token(parser, token)
View
16 symposion/teams/urls.py
@@ -0,0 +1,16 @@
+from django.conf.urls.defaults import *
+
+
+urlpatterns = patterns("symposion.teams.views",
+ # team specific
+ url(r"^(?P<slug>[\w\-]+)/$", "team_detail", name="team_detail"),
+ url(r"^(?P<slug>[\w\-]+)/join/$", "team_join", name="team_join"),
+ url(r"^(?P<slug>[\w\-]+)/leave/$", "team_leave", name="team_leave"),
+ url(r"^(?P<slug>[\w\-]+)/apply/$", "team_apply", name="team_apply"),
+
+ # membership specific
+ url(r"^promote/(?P<pk>\d+)/$", "team_promote", name="team_promote"),
+ url(r"^demote/(?P<pk>\d+)/$", "team_demote", name="team_demote"),
+ url(r"^accept/(?P<pk>\d+)/$", "team_accept", name="team_accept"),
+ url(r"^reject/(?P<pk>\d+)/$", "team_reject", name="team_reject"),
+)
View
182 symposion/teams/views.py
@@ -0,0 +1,182 @@
+from django.http import Http404
+from django.shortcuts import render, redirect, get_object_or_404
+
+from django.contrib.auth.decorators import login_required
+from django.contrib import messages
+
+from symposion.teams.forms import TeamInvitationForm
+from symposion.teams.models import Team, Membership
+
+
+## perm checks
+#
+# @@@ these can be moved
+
+def can_join(team, user):
+ state = team.get_state_for_user(user)
+ if team.access == "open" and state is None:
+ return True
+ elif state == "invited":
+ return True
+ elif user.is_staff and state is None:
+ return True
+ else:
+ return False
+
+
+def can_leave(team, user):
+ state = team.get_state_for_user(user)
+ if state == "member": # managers can't leave at the moment
+ return True
+ else:
+ return False
+
+
+def can_apply(team, user):
+ state = team.get_state_for_user(user)
+ if team.access == "application" and state is None:
+ return True
+ else:
+ return False
+
+
+def can_invite(team, user):
+ state = team.get_state_for_user(user)
+ if team.access == "invitation":
+ if state == "manager" or user.is_staff:
+ return True
+ return False
+
+
+## views
+
+
+@login_required
+def team_detail(request, slug):
+ team = get_object_or_404(Team, slug=slug)
+ state = team.get_state_for_user(request.user)
+ if team.access == "invitation" and state is None and not request.user.is_staff:
+ raise Http404()
+
+ if can_invite(team, request.user):
+ if request.method == "POST":
+ form = TeamInvitationForm(request.POST, team=team)
+ if form.is_valid():
+ form.invite()
+ messages.success(request, "Invitation created.")
+ return redirect("team_detail", slug=slug)
+ else:
+ form = TeamInvitationForm(team=team)
+ else:
+ form = None
+
+ return render(request, "teams/team_detail.html", {
+ "team": team,
+ "state": state,
+ "invite_form": form,
+ "can_join": can_join(team, request.user),
+ "can_leave": can_leave(team, request.user),
+ "can_apply": can_apply(team, request.user),
+ })
+
+
+@login_required
+def team_join(request, slug):
+ team = get_object_or_404(Team, slug=slug)
+ state = team.get_state_for_user(request.user)
+ if team.access == "invitation" and state is None and not request.user.is_staff:
+ raise Http404()
+
+ if can_join(team, request.user) and request.method == "POST":
+ membership, created = Membership.objects.get_or_create(team=team, user=request.user)
+ membership.state = "member"
+ membership.save()
+ messages.success(request, "Joined team.")
+ return redirect("team_detail", slug=slug)
+ else:
+ return redirect("team_detail", slug=slug)
+
+
+@login_required
+def team_leave(request, slug):
+ team = get_object_or_404(Team, slug=slug)
+ state = team.get_state_for_user(request.user)
+ if team.access == "invitation" and state is None and not request.user.is_staff:
+ raise Http404()
+
+ if can_leave(team, request.user) and request.method == "POST":
+ membership = Membership.objects.get(team=team, user=request.user)
+ membership.delete()
+ messages.success(request, "Left team.")
+ return redirect("dashboard")
+ else:
+ return redirect("team_detail", slug=slug)
+
+
+@login_required
+def team_apply(request, slug):
+ team = get_object_or_404(Team, slug=slug)
+ state = team.get_state_for_user(request.user)
+ if team.access == "invitation" and state is None and not request.user.is_staff:
+ raise Http404()
+
+ if can_apply(team, request.user) and request.method == "POST":
+ membership, created = Membership.objects.get_or_create(team=team, user=request.user)
+ membership.state = "applied"
+ membership.save()
+ messages.success(request, "Applied to join team.")
+ return redirect("team_detail", slug=slug)
+ else:
+ return redirect("team_detail", slug=slug)
+
+
+@login_required
+def team_promote(request, pk):
+ if request.method == "POST":
+ membership = get_object_or_404(Membership, pk=pk)
+ state = membership.team.get_state_for_user(request.user)
+ if request.user.is_staff or state == "manager":
+ if membership.state == "member":
+ membership.state = "manager"
+ membership.save()
+ messages.success(request, "Promoted to manager.")
+ return redirect("team_detail", slug=membership.team.slug)
+
+
+@login_required
+def team_demote(request, pk):
+ if request.method == "POST":
+ membership = get_object_or_404(Membership, pk=pk)
+ state = membership.team.get_state_for_user(request.user)
+ if request.user.is_staff or state == "manager":
+ if membership.state == "manager":
+ membership.state = "member"
+ membership.save()
+ messages.success(request, "Demoted from manager.")
+ return redirect("team_detail", slug=membership.team.slug)
+
+
+@login_required
+def team_accept(request, pk):
+ if request.method == "POST":
+ membership = get_object_or_404(Membership, pk=pk)
+ state = membership.team.get_state_for_user(request.user)
+ if request.user.is_staff or state == "manager":
+ if membership.state == "applied":
+ membership.state = "member"
+ membership.save()
+ messages.success(request, "Accepted application.")
+ return redirect("team_detail", slug=membership.team.slug)
+
+
+@login_required
+def team_reject(request, pk):
+ if request.method == "POST":
+ membership = get_object_or_404(Membership, pk=pk)
+ state = membership.team.get_state_for_user(request.user)
+ if request.user.is_staff or state == "manager":
+ if membership.state == "applied":
+ membership.state = "rejected"
+ membership.save()
+ messages.success(request, "Rejected application.")
+ return redirect("team_detail", slug=membership.team.slug)
View
5 symposion_project/settings.py
@@ -169,6 +169,7 @@
"symposion.proposals",
"symposion.speakers",
"symposion.reviews",
+ "symposion.teams",
# project
"symposion_project.proposals",
@@ -195,6 +196,10 @@
ACCOUNT_USER_DISPLAY = lambda user: user.email
AUTHENTICATION_BACKENDS = [
+ # Permissions Backends
+ "symposion.teams.backends.TeamPermissionsBackend",
+
+ # Auth backends
"account.auth_backends.EmailAuthenticationBackend",
]
View
2 symposion_project/static/symposion/css/symposion.css
1 addition, 1 deletion not shown because the diff is too large. Please use a local Git client to view these changes.
View
7 symposion_project/static/symposion/less/symposion-components.less
@@ -34,14 +34,13 @@ header {
// Boxes
.content-box.editable {
- border: 1px dashed #bbb;
- padding: 5px;
+ border: 1px dashed #ccc;
+ padding: 1px;
min-height: 30px;
}
.edit-toggle {
position: relative;
- float: left;
- left: -20px;
+ float: right;
}
// Markitup
View
6 symposion_project/templates/boxes/box.html
@@ -16,16 +16,16 @@
</div>
<div class="modal-footer">
- <a href="#" class="btn" data-dismiss="modal">Close</a>
- <button type="submit" class="btn btn-primary">Save changes</a>
+ <a href="#" class="btn" data-dismiss="modal">{% trans "Close" %}</a>
+ <button type="submit" class="btn btn-primary">{% trans "Save changes" %}</a>
</div>
</form>
</div>
{% endif %}
<div id="content_{{ label }}" class="content-box {% if form %}editable{% endif %}">
{% if form %}
- <a href="#edit_{{ label }}" data-toggle="modal" class="btn edit-toggle"><i class="icon-pencil"></i></a>
+ <a href="#edit_{{ label }}" data-toggle="modal" class="btn edit-toggle"><i class="icon-pencil"></i> {% trans "Edit this content" %}</a>
{% endif %}
{{ box.content|safe }}
</div>
View
51 symposion_project/templates/dashboard.html
@@ -3,6 +3,7 @@
{% load i18n %}
{% load proposal_tags %}
{% load review_tags %}
+{% load teams_tags %}
{% block head_title %}Dashboard{% endblock %}
@@ -174,7 +175,55 @@
</tbody>
</table>
{% endcomment %}
-
+ </div>
+ </div>
+
+ <div class="dashboard-panel">
+ <div class="dashboard-panel-header">
+ <i class="icon-group"></i>
+ <h3>{% trans "Teams" %}</h3>
+ </div>
+
+ <div class="dashboard-panel-content">
+ {% if user.memberships.exists %}
+ <h4>Your Teams</h4>
+ <table class="table table-striped">
+ {% for membership in user.memberships.all %}
+ <tr>
+ <td>
+ <a href="{% url team_detail membership.team.slug %}">{{ membership.team.name }}</a>
+ {% if membership.team.description %}<br>{{ membership.team.description }}{% endif %}
+ </td>
+ <td>
+ <span class="label{% if membership.state == 'invited' %} label-info{% endif %}">{{ membership.get_state_display }}</span>
+ </td>
+ <td>
+ {% if membership.state == "manager" or user.is_staff %}
+ {% if membership.team.applicants %}{{ membership.team.applicants.count }} applicant{{ membership.team.applicants.count|pluralize }}{% endif %}
+ {% endif %}
+ </td>
+ </tr>
+ {% endfor %}
+ </table>
+ {% endif %}
+ {% available_teams as available_teams %}
+ {% if available_teams %}
+ <h4>Available Teams</h4>
+ <table class="table table-striped">
+ {% for team in available_teams %}
+ <tr>
+ <td>
+ <a href="{% url team_detail team.slug %}">{{ team }}</a>
+ {% if team.description %}<br>{{ team.description }}{% endif %}
+ </td>
+ <td>
+ <span class="label">{{ team.get_access_display }}</span>
+ </td>
+ </tr>
+
+ {% endfor %}
+ </table>
+ {% endif %}
</div>
</div>
{% endblock %}
View
91 symposion_project/templates/proposals/proposal_detail.html
@@ -1,58 +1,69 @@
{% extends "site_base.html" %}
+{% load i18n %}
+
{% block head_title %}{{ proposal.title }}{% endblock %}
{% block body %}
- <h1>{{ proposal.title }}</h1>
-
- <p>
+ <div class="pull-right">
{% if not proposal.cancelled %}
{% if request.user == proposal.speaker.user %}
- <a href="{% url proposal_edit proposal.pk %}">Edit</a>
- | <a href="{% url proposal_cancel proposal.pk %}">Cancel Talk</a>
+ <a href="{% url proposal_edit proposal.pk %}" class="btn">
+ {% trans "Edit this proposal" %}
+ </a>
+ <a href="{% url proposal_cancel proposal.pk %}" class="btn">
+ {% trans "Cancel this proposal" %}
+ </a>
{% else %}
- <a href="{% url proposal_leave proposal.pk %}">Leave</a>
+ <a href="{% url proposal_leave proposal.pk %}" class="btn">
+ {% trans "Remove me from this proposal" %}
+ </a>
{% endif %}
{% else %}
Cancelled
{% endif %}
- </p>
-
- <div>
- {{ proposal.description }}
- </div>
-
- <p><b>Type</b>: {{ proposal.kind.name }}</p>
-
- <div>
- {{ proposal.abstract|safe }}
</div>
+ <h2>{{ proposal.title }}</h2>
- <p><b>Audience level</b>: {{ proposal.get_audience_level_display }}</p>
-
- <p><b>Submitting speaker</b>: {{ proposal.speaker }}</p>
-
- {% if proposal.additional_speakers.all %}
- <p><b>Additional speakers</b>:</p>
- <ul>
- {% for speaker in proposal.additional_speakers.all %}
- {% if speaker.user %}
- <li><b>{{ speaker.name }}</b> &mdash; {{ speaker.email }}</li>
- {% else %}
- <li>{{ speaker.email }} &mdash; pending invitation</li>
- {% endif %}
- {% endfor %}
- </ul>
- {% endif %}
-
- {% if request.user == proposal.speaker.user %}
- <p><b>Additional Notes:</b></p>
-
- <p>{{ proposal.additional_notes }}</p>
- {% endif %}
+ <dl>
+ <dt>{% trans "Submitted by" %}</dt>
+ <dd>{{ proposal.speaker }}</dd>
+
+ {% if proposal.additional_speakers.all %}
+ <dt>{% trans "Additional Speakers" %}</dt>
+ <dd>
+ {% for speaker in proposal.additional_speakers.all %}
+ <li>
+ {% if speaker.user %}
+ <strong>{{ speaker.name }}</strong> &gt;{{ speaker.email }}&lt;
+ {% else %}
+ {{ speaker.email }} ({% trans "Invitation Sent" %})
+ {% endif %}
+ </li>
+ {% endfor %}
+ </dd>
+ {% endif %}
+
+ <dt>{% trans "Description" %}</dt>
+ <dd>{{ proposal.description }}</dd>
+
+ <dt>{% trans "Type" %}</dt>
+ <dd>{{ proposal.kind.name }}</dd>
+
+ <dt>{% trans "Audience Level" %}</dt>
+ <dd>{{ proposal.get_audience_level_display }}</dd>
+
+ <dt>{% trans "Abstract" %}</dt>
+ <dd>{{ proposal.abstract|safe }}</dd>
+
+ {% if request.user == proposal.speaker.user %}
+ <dt>{% trans "Private Notes" %}</dt>
+ <dd>{{ proposal.additional_notes }}</dd>
+ {% endif %}
+ </dl>
{% if request.user == proposal.speaker.user %}
- <h2>Supporting Documents</h2>
+ <h3>Supporting Documents</h3>
{% if proposal.supporting_documents.exists %}
<table class="table table-striped">
@@ -71,6 +82,6 @@
{% else %}
<p>No supporting documents attached to this proposal.</p>
{% endif %}
- <a class="btn btn-small{% if proposal.cancelled %} btn-disabled{% endif %}" href="{% url proposal_document_create proposal.pk %}"><i class="icon-plus"></i> add document</a>
+ <a class="btn btn-small{% if proposal.cancelled %} btn-disabled{% endif %}" href="{% url proposal_document_create proposal.pk %}"><i class="icon-upload"></i> Add Document</a>
{% endif %}
{% endblock %}
View
103 symposion_project/templates/teams/team_detail.html
@@ -0,0 +1,103 @@
+{% extends "site_base.html" %}
+
+{% load bootstrap_tags %}
+
+{% block head_title %}{{ team.name }}{% endblock %}
+
+{% block body_outer %}
+ <div class="row">
+ <div class="span12">
+ <div class="pull-right">
+ {% if can_join %}
+ <form method="post" action="{% url team_join team.slug %}">
+ {% csrf_token %}
+ <input type="submit" class="btn btn-primary" value="join">
+ </form>
+ {% endif %}
+
+ {% if can_leave %}
+ <form method="post" action="{% url team_leave team.slug %}">
+ {% csrf_token %}
+ <input type="submit" class="btn" value="leave">
+ </form>
+ {% endif %}
+
+ {% if can_apply %}
+ <form method="post" action="{% url team_apply team.slug %}">
+ {% csrf_token %}
+ <input type="submit" class="btn btn-primary" value="apply">
+ </form>
+ {% endif %}
+ </div>
+
+ <h1>{{ team.name }}{% if state %} <span class="label">{{ state }}</span>{% endif %}</h1>
+
+ {% if team.description %}<p>{{ team.description }}</p>{% endif %}
+
+ {% if state == "invited" %}<p>You have been invited to join this team. Click <b>join</b> to the right to accept.</p>{% endif %}
+
+ {% if user.is_staff or state == "manager" %}
+ {% if team.managers %}
+ <h2>Managers</h2>
+ <table class="table table-striped">
+ {% for membership in team.managers %}
+ <tr>
+ <td>{{ membership.user.email }}{% if user == membership.user %} <span class="label label-info">you</span>{% endif %}</td>
+ <td>
+ <form style="margin: 0;" method="post" action="{% url team_demote membership.pk %}">{% csrf_token %}<button type="submit" class="btn btn-mini">demote</button></form>
+ </td>
+ </tr>
+ {% endfor %}
+ </table>
+ {% endif %}
+ {% if team.members %}
+ <h2>Team Members</h2>
+ <table class="table table-striped">
+ {% for membership in team.members %}
+ <tr>
+ <td>{{ membership.user.email }}{% if user == membership.user %} <span class="label label-info">you</span>{% endif %}</td>
+ <td>
+ <form style="margin: 0;" method="post" action="{% url team_promote membership.pk %}">{% csrf_token %}<button type="submit" class="btn btn-mini">promote</button></form>
+ </td>
+ </tr>
+ {% endfor %}
+ </table>
+ {% endif %}
+ {% if team.applicants and team.access == "application" %}
+ <h2>Applicants</h2>
+ <table class="table table-striped">
+ {% for membership in team.applicants %}
+ <tr>
+ <td>{{ membership.user.email }}</td>
+ <td>
+ <form style="margin: 0; float: left;" method="post" action="{% url team_accept membership.pk %}">{% csrf_token %}<button type="submit" class="btn btn-mini">accept</button></form>
+ <form style="margin: 0; float: left;" method="post" action="{% url team_reject membership.pk %}">{% csrf_token %}<button type="submit" class="btn btn-mini">reject</button></form>
+ </td>
+ </tr>
+ {% endfor %}
+ </table>
+ {% endif %}
+ {% if team.invitees %}
+ <h2>Invitees</h2>
+ <table class="table table-striped">
+ {% for membership in team.invitees %}
+ <tr>
+ <td>{{ membership.user.email }}</td>
+ </tr>
+ {% endfor %}
+ </table>
+ {% endif %}
+ {% if invite_form %}
+ <form method="POST" action="" class="form-horizontal">
+ {% csrf_token %}
+ <legend>Invite User to Team</legend>
+ {{ invite_form|as_bootstrap }}
+ <div class="form-actions">
+ <input class="btn btn-primary" type="submit" value="Invite" />
+ </div>
+ </form>
+ {% endif %}
+ {% endif %}
+ </div>
+ </div>
+{% endblock %}
View
3 symposion_project/urls.py
@@ -30,6 +30,9 @@
url(r"^sponsors/", include("symposion.sponsorship.urls")),
url(r"^reviews/", include("symposion.reviews.urls")),
url(r"^boxes/", include("symposion.boxes.urls")),
+ url(r"^teams/", include("symposion.teams.urls")),
+ url(r"^markitup/", include("markitup.urls")),
+
url(r"^", include("symposion.cms.urls")),
)

0 comments on commit 5f1670d

Please sign in to comment.
Something went wrong with that request. Please try again.