Teams work.

master
Nick Sergeant 2015-10-15 22:37:54 -04:00
parent 002fbc45c5
commit ae1d532c06
7 changed files with 155 additions and 9 deletions

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('teams', '0005_auto_20150930_2124'),
]
operations = [
migrations.AddField(
model_name='team',
name='plan',
field=models.CharField(default=b'snipt-teams-25-monthly', max_length=100, choices=[(b'snipt-teams-25-monthly', b'25 users, monthly'), (b'snipt-teams-100-monthly', b'100 users, monthly'), (b'snipt-teams-250-monthly', b'250 users, monthly'), (b'snipt-teams-unlimited-monthly', b'Unlimited users, monthly'), (b'snipt-teams-25-yearly', b'25 users, yearly'), (b'snipt-teams-100-yearly', b'100 users, yearly'), (b'snipt-teams-250-yearly', b'250 users, yearly'), (b'snipt-teams-unlimited-yearly', b'Unlimited users, yearly')]),
),
]

View File

@ -4,6 +4,18 @@ from snipts.utils import slugify_uniquely
class Team(models.Model): class Team(models.Model):
PLANS = (
('snipt-teams-25-monthly', '25 users, monthly'),
('snipt-teams-100-monthly', '100 users, monthly'),
('snipt-teams-250-monthly', '250 users, monthly'),
('snipt-teams-unlimited-monthly', 'Unlimited users, monthly'),
('snipt-teams-25-yearly', '25 users, yearly'),
('snipt-teams-100-yearly', '100 users, yearly'),
('snipt-teams-250-yearly', '250 users, yearly'),
('snipt-teams-unlimited-yearly', 'Unlimited users, yearly'),
)
email = models.EmailField(max_length=255) email = models.EmailField(max_length=255)
members = models.ManyToManyField(User, related_name='member', blank=True) members = models.ManyToManyField(User, related_name='member', blank=True)
name = models.CharField(max_length=30) name = models.CharField(max_length=30)
@ -11,6 +23,8 @@ class Team(models.Model):
slug = models.SlugField(max_length=255, blank=True) slug = models.SlugField(max_length=255, blank=True)
stripe_id = models.CharField(max_length=100, null=True, blank=True) stripe_id = models.CharField(max_length=100, null=True, blank=True)
user = models.OneToOneField(User, blank=True, null=True) user = models.OneToOneField(User, blank=True, null=True)
plan = models.CharField(max_length=100, default='snipt-teams-25-monthly',
choices=PLANS)
created = models.DateTimeField(auto_now_add=True, editable=False) created = models.DateTimeField(auto_now_add=True, editable=False)
modified = models.DateTimeField(auto_now=True, editable=False) modified = models.DateTimeField(auto_now=True, editable=False)
@ -22,3 +36,21 @@ class Team(models.Model):
def __unicode__(self): def __unicode__(self):
return self.name return self.name
@property
def member_limit(self):
plan_map = {
'snipt-teams-25-monthly': 25,
'snipt-teams-100-monthly': 100,
'snipt-teams-250-monthly': 250,
'snipt-teams-unlimited-monthly': float('inf'),
'snipt-teams-25-yearly': 25,
'snipt-teams-100-yearly': 100,
'snipt-teams-250-yearly': 250,
'snipt-teams-unlimited-yearly': float('inf')
}
if plan_map[self.plan] == float('inf'):
return 'Unlimited'
else:
return plan_map[self.plan]

View File

@ -37,7 +37,7 @@
<li>Public team posts are public to the world, as they are now.</li> <li>Public team posts are public to the world, as they are now.</li>
<li>Private team posts are editable by all team members.</li> <li>Private team posts are editable by all team members.</li>
<li>All team members are automatically granted personal <a href="/pro/"><span class="pro">Pro</span></a> accounts.</li> <li>All team members are automatically granted personal <a href="/pro/"><span class="pro">Pro</span></a> accounts.</li>
<li>Plans from $49/month, all with a 7-day free trial.</li> <li>Plans from $49/month, all with a 14-day free trial.</li>
</ul> </ul>
</div> </div>
{% if not request.user.is_authenticated %} {% if not request.user.is_authenticated %}
@ -61,7 +61,7 @@
<div class="control-group"> <div class="control-group">
<label class="control-label" for="email">Team email:</label> <label class="control-label" for="email">Team email:</label>
<div class="controls"> <div class="controls">
<input required type="text" class="input-xlarge" name="email" id="email" /> <input required type="email" class="input-xlarge" name="email" id="email" />
<p class="sub" style="margin-top: 3px; color: #999999;"> <p class="sub" style="margin-top: 3px; color: #999999;">
For billing and your team's Gravatar. Will remain private. For billing and your team's Gravatar. Will remain private.
</p> </p>
@ -72,12 +72,12 @@
<div class="controls"> <div class="controls">
<select name="plan" type="text" class="input-xlarge" id="plan"> <select name="plan" type="text" class="input-xlarge" id="plan">
<option value="snipt-teams-25-monthly">25 users - $49/month</option> <option value="snipt-teams-25-monthly">25 users - $49/month</option>
<option value="snipt-teams-25-yearly">25 users - $588/year</option>
<option value="snipt-teams-100-monthly">100 users - $149/month</option> <option value="snipt-teams-100-monthly">100 users - $149/month</option>
<option value="snipt-teams-100-yearly">100 users - $1,788/year</option>
<option value="snipt-teams-250-monthly">250 users - $299/month</option> <option value="snipt-teams-250-monthly">250 users - $299/month</option>
<option value="snipt-teams-250-yearly">250 users - $3,588/year</option>
<option value="snipt-teams-unlimited-monthly">Unlimited users - $499/month</option> <option value="snipt-teams-unlimited-monthly">Unlimited users - $499/month</option>
<option value="snipt-teams-25-yearly">25 users - $588/year</option>
<option value="snipt-teams-100-yearly">100 users - $1,788/year</option>
<option value="snipt-teams-250-yearly">250 users - $3,588/year</option>
<option value="snipt-teams-unlimited-yearly">Unlimited users - $5,988/year</option> <option value="snipt-teams-unlimited-yearly">Unlimited users - $5,988/year</option>
</select> </select>
</div> </div>

View File

@ -0,0 +1,56 @@
{% extends "base.html" %}
{% block page-title %}Team Billing{% endblock %}
{% block body-class %}account {{ block.super }}{% endblock %}
{% block breadcrumb %}
<li><a href="/{{ team.user.username }}/">{{ team.user.username }}</a></li>
<span class="prompt">/</span> <li><a href="/{{ team.user.username }}/billing/">Billing</a></li>
{% endblock %}
{% block content %}
<section class="snipts" id="snipts"></section>
<section class="profile group">
<aside>
<ul class="nav nav-list ng-cloak" ng-cloak>
<li class="nav-header">Team: {{ team.name }}</li>
<li>
<a href="/{{ team.slug }}/members/">Members</a>
</li>
<li class="active">
<a href="/{{ team.slug }}/billing/">Billing</a>
</li>
</ul>
</aside>
<section class="content">
<div class="def" data-title="Plan">
25 users
</div>
<div class="def" data-title="Price">
$49.00 USD / month
</div>
<div class="def" data-title="Card">
xxxx-xxxx-xxxx-4242
</div>
<div class="def" data-title="Status">
Active
</div>
<div class="def" data-title="Team since">
August 29, 2015
</div>
<div class="def" data-title="Next bill date" ng-show="user.stripeAccount.status != 'inactive'">
November 29, 2015
</div>
<p class="alert alert-info group" style="padding-right: 8px;">
<a href="/{{ team.slug }}/billing/cancel/" class="btn btn-danger pull-right">Cancel subscription</a>
</p>
</section>
</section>
{% endblock %}
{% block analytics %}
{% if not debug %}
window.ll('tagScreen', 'Team billing view');
{% endif %}
{% endblock %}

View File

@ -2,7 +2,7 @@
{% block page-title %}Team Members{% endblock %} {% block page-title %}Team Members{% endblock %}
{% block body-class %}{{ block.super }}{% endblock %} {% block body-class %}account {{ block.super }}{% endblock %}
{% block breadcrumb %} {% block breadcrumb %}
<li><a href="/{{ team.user.username }}/">{{ team.user.username }}</a></li> <li><a href="/{{ team.user.username }}/">{{ team.user.username }}</a></li>
@ -10,7 +10,32 @@
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<section class="snipts" id="snipts"></section>
<section class="profile group">
<aside>
<ul class="nav nav-list ng-cloak" ng-cloak>
<li class="nav-header">Team: {{ team.name }}</li>
<li class="active">
<a href="/{{ team.slug }}/members/">Members</a>
</li>
<li>
<a href="/{{ team.slug }}/billing/">Billing</a>
</li>
</ul>
</aside>
<section class="content">
<div class="def" data-title="Owner">
{{ team.owner }}
</div>
<div class="def" data-title="Members ({{ team.members.all|length }} of {{ team.member_limit }})">
<ul style="margin-bottom: 0">
{% for member in team.members.all %}
<li>{{ member }}</li>
{% endfor %}
</ul>
</div>
</section>
</section>
{% endblock %} {% endblock %}
{% block analytics %} {% block analytics %}

View File

@ -8,4 +8,7 @@ urlpatterns = \
url(r'^for-teams/complete/$', views.for_teams_complete), url(r'^for-teams/complete/$', views.for_teams_complete),
url(r'^(?P<username>[^/]+)/members/$', url(r'^(?P<username>[^/]+)/members/$',
views.team_members, views.team_members,
name='team-members')) name='team-members'),
url(r'^(?P<username>[^/]+)/billing/$',
views.team_billing,
name='team-billing'))

View File

@ -5,7 +5,7 @@ import uuid
from annoying.decorators import render_to from annoying.decorators import render_to
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.http import HttpResponseRedirect, HttpResponseBadRequest from django.http import Http404, HttpResponseRedirect, HttpResponseBadRequest
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from teams.models import Team from teams.models import Team
@ -19,9 +19,19 @@ def for_teams(request):
return {} return {}
@render_to('teams/team-billing.html')
def team_billing(request, username):
team = get_object_or_404(Team, slug=username)
return {
'team': team
}
@render_to('teams/team-members.html') @render_to('teams/team-members.html')
def team_members(request, username): def team_members(request, username):
team = get_object_or_404(Team, slug=username) team = get_object_or_404(Team, slug=username)
if team.owner != request.user:
raise Http404
return { return {
'team': team 'team': team
} }
@ -49,6 +59,7 @@ def for_teams_complete(request):
team = Team(name=request.POST['team-name'], team = Team(name=request.POST['team-name'],
email=request.POST['email'], email=request.POST['email'],
plan=plan,
owner=request.user) owner=request.user)
team.stripe_id = customer.id team.stripe_id = customer.id
team.save() team.save()