Move the remanants of the profiles app into the local app for more caminus-only bits

This commit is contained in:
Trever Fischer
2012-03-10 19:14:19 -05:00
parent 77314a81e7
commit 8ee0ce3365
25 changed files with 284 additions and 194 deletions

View File

@@ -5,5 +5,11 @@ class CurrencyAdmin(admin.ModelAdmin):
list_display = ('profile', 'balance')
search_fields = ('profile__mc_username',)
class InviteAdmin(admin.ModelAdmin):
list_display = ('code', 'creator', 'claimer', 'deleted')
search_fields = ('code', 'creator', 'claimer')
list_filter = ('deleted',)
admin.site.register(models.CurrencyAccount, CurrencyAdmin)
admin.site.register(models.Quote)
admin.site.register(models.Invite, InviteAdmin)

View File

@@ -10,3 +10,4 @@ class UserForm(forms.Form):
class InviteClaimForm(forms.Form):
code = forms.CharField()

View File

@@ -0,0 +1,98 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
from django.db.utils import DatabaseError
class Migration(SchemaMigration):
def forwards(self, orm):
try:
db.rename_table('profiles_invite', 'local_invite')
except DatabaseError, e:
# Adding model 'Invite'
db.create_table('local_invite', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('code', self.gf('django.db.models.fields.CharField')(max_length=30)),
('creator', self.gf('django.db.models.fields.related.ForeignKey')(related_name='invites', to=orm['auth.User'])),
('claimer', self.gf('django.db.models.fields.related.OneToOneField')(blank=True, related_name='claimed_invite', unique=True, null=True, to=orm['auth.User'])),
('deleted', self.gf('django.db.models.fields.BooleanField')(default=False)),
))
db.send_create_signal('local', ['Invite'])
def backwards(self, orm):
# Deleting model 'Invite'
db.rename_table('local_invite', 'profiles_invite')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
},
'auth.permission': {
'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
},
'contenttypes.contenttype': {
'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'local.currencyaccount': {
'Meta': {'object_name': 'CurrencyAccount'},
'balance': ('django.db.models.fields.FloatField', [], {'default': '3000'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'profile': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['minecraft.MinecraftProfile']", 'unique': 'True'}),
'status': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'username': ('django.db.models.fields.CharField', [], {'max_length': '255', 'unique': 'True', 'null': 'True'})
},
'local.invite': {
'Meta': {'ordering': "['deleted']", 'object_name': 'Invite'},
'claimer': ('django.db.models.fields.related.OneToOneField', [], {'blank': 'True', 'related_name': "'claimed_invite'", 'unique': 'True', 'null': 'True', 'to': "orm['auth.User']"}),
'code': ('django.db.models.fields.CharField', [], {'max_length': '30'}),
'creator': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'invites'", 'to': "orm['auth.User']"}),
'deleted': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'})
},
'local.quote': {
'Meta': {'object_name': 'Quote'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'text': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'minecraft.minecraftprofile': {
'Meta': {'object_name': 'MinecraftProfile'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'mc_username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}),
'user': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['auth.User']", 'unique': 'True'})
}
}
complete_apps = ['local']

View File

@@ -1,4 +1,6 @@
from django.db import models
from django.contrib.auth.models import User
import shortuuid
from minecraft.models import MinecraftProfile
from django.db.models.signals import post_save
@@ -22,6 +24,27 @@ class Quote(models.Model):
def __unicode__(self):
return self.text
class Invite(models.Model):
code = models.CharField(max_length=30)
creator = models.ForeignKey(User, related_name='invites')
claimer = models.OneToOneField(User, related_name='claimed_invite', blank=True, null=True)
deleted = models.BooleanField(default=False)
def __unicode__(self):
return self.code
def save(self, *args, **kwargs):
if not self.code:
self.code = shortuuid.uuid()[:6].upper()
super(Invite, self).save(*args, **kwargs)
class Meta:
ordering = ['deleted']
@models.permalink
def get_absolute_url(self):
return ('local.views.claimInvite', [], {'code': self.code})
def create_account(sender, instance, created, **kwargs):
if created:
CurrencyAccount.objects.create(profile=instance)

View File

@@ -1,6 +1,41 @@
from django.test import TestCase
from django.contrib.auth.models import User
from django.test.client import Client
from django.core.urlresolvers import reverse
import models
class InviteTest(TestCase):
def setUp(self):
self.client = Client()
self.user = User.objects.create_user('ValidUsername', 'test@example.com')
self.user.save()
self.invite = models.Invite()
self.invite.creator = self.user
self.invite.save()
def tearDown(self):
self.invite.delete()
self.user.delete()
def testTryBadInvite(self):
resp = self.client.get(reverse('local.views.claimInvite', kwargs={'code':self.invite.code+"-invalid"}), follow=True)
self.assertEqual(404, resp.status_code)
def testTryToReuseInvite(self):
self.invite.claimer = self.user
self.invite.save()
resp = self.client.get(reverse('local.views.claimInvite', kwargs={'code':self.invite.code}), follow=True)
self.assertEqual(404, resp.status_code)
def testTryToUseDeletedInvite(self):
self.invite.deleted = True
self.invite.save()
resp = self.client.get(reverse('local.views.claimInvite', kwargs={'code':self.invite.code}), follow=True)
self.assertEqual(404, resp.status_code)
def testUseInvite(self):
resp = self.client.get(reverse('local.views.claimInvite', kwargs={'code':self.invite.code}), follow=True)
self.assertEqual(200, resp.status_code)
class AccountCreationTest(TestCase):
def testCreation(self):

View File

@@ -2,7 +2,7 @@ from django.conf.urls.defaults import patterns, include, url
from django.views.generic.simple import direct_to_template
urlpatterns = patterns('profiles',
urlpatterns = patterns('local',
url(r'^me$', 'views.profile', name='user_profile'),
url(r'^list$', 'views.list'),
url(r'^register', 'views.register'),
@@ -12,5 +12,5 @@ urlpatterns = patterns('profiles',
url(r'^invites/new$', 'views.createInvite'),
url(r'^invites$', 'views.invites'),
url(r'^edit$', 'views.edit'),
url(r'^disabled$', direct_to_template, {'template': 'profiles/disabled.html'}, name='disabled_account')
url(r'^disabled$', direct_to_template, {'template': 'local/disabled.html'}, name='disabled_account')
)

View File

@@ -1 +1,105 @@
# Create your views here.
from django.contrib.auth.decorators import login_required
from django.contrib.sites.models import Site
from django.http import HttpResponseRedirect, Http404
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
import django.contrib.auth
from django.contrib.auth import authenticate, login
from django.core.exceptions import ObjectDoesNotExist
import forms
import models
from minecraft.forms import ProfileForm
@login_required
def profile(request):
return render_to_response('local/profile.html', context_instance = RequestContext(request))
@login_required
def edit(request):
if request.method == 'POST':
form = ProfileForm(request.POST, instance=request.user.minecraftprofile)
else:
form = ProfileForm(instance=request.user.minecraftprofile)
if form.is_valid():
profile = request.user.minecraftprofile
profile.mc_username = form.cleaned_data['mc_username']
profile.save()
return HttpResponseRedirect(reverse('local.views.profile'))
return render_to_response('local/edit.html', {"form":form}, context_instance = RequestContext(request))
@login_required
def invites(request):
invites = request.user.invites.all()
return render_to_response('local/invites.html', {'invites': invites}, context_instance = RequestContext(request))
@login_required
def createInvite(request):
invite = models.Invite()
invite.creator = request.user
invite.save()
return HttpResponseRedirect(reverse('local.views.invites'))
def register(request):
invite = request.session['profile-invite']
if request.method == 'POST':
userForm = forms.UserForm(request.POST, prefix='user')
profileForm = ProfileForm(request.POST, prefix='profile')
else:
userForm = forms.UserForm(prefix='user')
profileForm = ProfileForm(prefix='profile')
if userForm.is_valid() and profileForm.is_valid():
oldUser = None
try:
oldUser = User.objects.get(username__exact=userForm.cleaned_data['username'])
except ObjectDoesNotExist, e:
pass
if not oldUser:
user = User.objects.create_user(userForm.cleaned_data['username'], userForm.cleaned_data['email'], userForm.cleaned_data['password'])
user.save()
invite.claimer = user
invite.save()
profile = user.minecraftprofile
profile.mc_username = profileForm.cleaned_data['mc_username']
profile.save()
user = authenticate(username=userForm.cleaned_data['username'], password=userForm.cleaned_data['password'])
login(request, user)
del request.session['profile-invite']
return HttpResponseRedirect("/")
return render_to_response('local/register.html', {'userForm': userForm, 'profileForm': profileForm, 'invite':invite}, context_instance = RequestContext(request))
@login_required
def deleteInvite(request, code=None):
invite = models.Invite.objects.get(code__exact=code)
if invite.claimer:
return HttpResponseRedirect(reverse('local.views.invites'))
if request.method == 'POST':
invite.deleted = True
invite.save()
return HttpResponseRedirect(reverse('local.views.invites'))
return render_to_response('local/delete_invite.html', {'invite':invite}, context_instance = RequestContext(request))
def claimInvite(request, code=None):
if request.user.is_authenticated():
invite = models.Invite.objects.get(code__exact=code)
siteURL = Site.objects.get_current().domain
return render_to_response('local/show_invite.html', {'invite':invite, 'site_url': siteURL}, context_instance = RequestContext(request))
if request.method == 'POST':
form = forms.InviteClaimForm(request.POST)
else:
form = forms.InviteClaimForm()
if form.is_valid():
code = form.cleaned_data['code']
if code:
try:
invite = models.Invite.objects.get(code__exact=code, claimer__exact=None, deleted__exact=False)
except models.Invite.DoesNotExist:
raise Http404
request.session['profile-invite'] = invite
return HttpResponseRedirect(reverse('local.views.register'))
return render_to_response('local/claim_invite.html', {'form': form}, context_instance = RequestContext(request))
def list(request):
profiles = User.objects.all()
return render_to_response('local/list.html', {'profiles': profiles}, context_instance = RequestContext(request))

View File

View File

@@ -1,9 +0,0 @@
import models
from django.contrib import admin
class InviteAdmin(admin.ModelAdmin):
list_display = ('code', 'creator', 'claimer', 'deleted')
search_fields = ('code', 'creator', 'claimer')
list_filter = ('deleted',)
admin.site.register(models.Invite, InviteAdmin)

View File

@@ -1,25 +0,0 @@
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
import shortuuid
class Invite(models.Model):
code = models.CharField(max_length=30)
creator = models.ForeignKey(User, related_name='invites')
claimer = models.OneToOneField(User, related_name='claimed_invite', blank=True, null=True)
deleted = models.BooleanField(default=False)
def __unicode__(self):
return self.code
def save(self, *args, **kwargs):
if not self.code:
self.code = shortuuid.uuid()[:6].upper()
super(Invite, self).save(*args, **kwargs)
class Meta:
ordering = ['deleted']
@models.permalink
def get_absolute_url(self):
return ('profiles.views.claimInvite', [], {'code': self.code})

View File

@@ -1,38 +0,0 @@
from django.utils import unittest
from django.test.client import Client
import models
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
class InviteTest(unittest.TestCase):
def setUp(self):
self.client = Client()
self.user = User.objects.create_user('ValidUsername', 'test@example.com')
self.user.save()
self.invite = models.Invite()
self.invite.creator = self.user
self.invite.save()
def tearDown(self):
self.invite.delete()
self.user.delete()
def testTryBadInvite(self):
resp = self.client.get(reverse('profiles.views.claimInvite', kwargs={'code':self.invite.code+"-invalid"}), follow=True)
self.assertEqual(404, resp.status_code)
def testTryToReuseInvite(self):
self.invite.claimer = self.user
self.invite.save()
resp = self.client.get(reverse('profiles.views.claimInvite', kwargs={'code':self.invite.code}), follow=True)
self.assertEqual(404, resp.status_code)
def testTryToUseDeletedInvite(self):
self.invite.deleted = True
self.invite.save()
resp = self.client.get(reverse('profiles.views.claimInvite', kwargs={'code':self.invite.code}), follow=True)
self.assertEqual(404, resp.status_code)
def testUseInvite(self):
resp = self.client.get(reverse('profiles.views.claimInvite', kwargs={'code':self.invite.code}), follow=True)
self.assertEqual(200, resp.status_code)

View File

@@ -1,105 +0,0 @@
from django.contrib.auth.decorators import login_required
from django.contrib.sites.models import Site
from django.http import HttpResponseRedirect, Http404
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
import django.contrib.auth
from django.contrib.auth import authenticate, login
from django.core.exceptions import ObjectDoesNotExist
import forms
import models
from minecraft.forms import ProfileForm
@login_required
def profile(request):
return render_to_response('profiles/profile.html', context_instance = RequestContext(request))
@login_required
def edit(request):
if request.method == 'POST':
form = ProfileForm(request.POST, instance=request.user.minecraftprofile)
else:
form = ProfileForm(instance=request.user.minecraftprofile)
if form.is_valid():
profile = request.user.minecraftprofile
profile.mc_username = form.cleaned_data['mc_username']
profile.save()
return HttpResponseRedirect(reverse('profiles.views.profile'))
return render_to_response('profiles/edit.html', {"form":form}, context_instance = RequestContext(request))
@login_required
def invites(request):
invites = request.user.invites.all()
return render_to_response('profiles/invites.html', {'invites': invites}, context_instance = RequestContext(request))
@login_required
def createInvite(request):
invite = models.Invite()
invite.creator = request.user
invite.save()
return HttpResponseRedirect(reverse('profiles.views.invites'))
def register(request):
invite = request.session['profile-invite']
if request.method == 'POST':
userForm = forms.UserForm(request.POST, prefix='user')
profileForm = ProfileForm(request.POST, prefix='profile')
else:
userForm = forms.UserForm(prefix='user')
profileForm = ProfileForm(prefix='profile')
if userForm.is_valid() and profileForm.is_valid():
oldUser = None
try:
oldUser = User.objects.get(username__exact=userForm.cleaned_data['username'])
except ObjectDoesNotExist, e:
pass
if not oldUser:
user = User.objects.create_user(userForm.cleaned_data['username'], userForm.cleaned_data['email'], userForm.cleaned_data['password'])
user.save()
invite.claimer = user
invite.save()
profile = user.minecraftprofile
profile.mc_username = profileForm.cleaned_data['mc_username']
profile.save()
user = authenticate(username=userForm.cleaned_data['username'], password=userForm.cleaned_data['password'])
login(request, user)
del request.session['profile-invite']
return HttpResponseRedirect("/")
return render_to_response('profiles/register.html', {'userForm': userForm, 'profileForm': profileForm, 'invite':invite}, context_instance = RequestContext(request))
@login_required
def deleteInvite(request, code=None):
invite = models.Invite.objects.get(code__exact=code)
if invite.claimer:
return HttpResponseRedirect(reverse('profiles.views.invites'))
if request.method == 'POST':
invite.deleted = True
invite.save()
return HttpResponseRedirect(reverse('profiles.views.invites'))
return render_to_response('profiles/delete_invite.html', {'invite':invite}, context_instance = RequestContext(request))
def claimInvite(request, code=None):
if request.user.is_authenticated():
invite = models.Invite.objects.get(code__exact=code)
siteURL = Site.objects.get_current().domain
return render_to_response('profiles/show_invite.html', {'invite':invite, 'site_url': siteURL}, context_instance = RequestContext(request))
if request.method == 'POST':
form = forms.InviteClaimForm(request.POST)
else:
form = forms.InviteClaimForm()
if form.is_valid():
code = form.cleaned_data['code']
if code:
try:
invite = models.Invite.objects.get(code__exact=code, claimer__exact=None, deleted__exact=False)
except models.Invite.DoesNotExist:
raise Http404
request.session['profile-invite'] = invite
return HttpResponseRedirect(reverse('profiles.views.register'))
return render_to_response('profiles/claim_invite.html', {'form': form}, context_instance = RequestContext(request))
def list(request):
profiles = User.objects.all()
return render_to_response('profiles/list.html', {'profiles': profiles}, context_instance = RequestContext(request))

View File

@@ -125,7 +125,6 @@ INSTALLED_APPS = (
'mptt',
'api',
'django.contrib.markup',
'profiles',
'south',
'news',
'django.contrib.flatpages',
@@ -133,6 +132,7 @@ INSTALLED_APPS = (
'petition',
'local',
'messages',
'notification'
# Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs',
)

View File

@@ -53,7 +53,7 @@
</ul>
{% else %}
<h2 class="title">Login</h2>
<p>Welcome! Do you have an invite? <a href="{% url profiles.views.claimInvite %}">Claim it!</a><p>
<p>Welcome! Do you have an invite? <a href="{% url local.views.claimInvite %}">Claim it!</a><p>
<p><a href="{% url django.contrib.auth.views.password_reset %}">Forgot your password?</a>
<form method="POST" action="{%url django.contrib.auth.views.login %}">
{%csrf_token%}
@@ -73,7 +73,7 @@
<ul>
<li><a href="/">Home</a></li>
<li><a href="{%url forums.views.index%}">Forums</a></li>
<li><a href="{%url profiles.views.list %}">User List</a></li>
<li><a href="{%url local.views.list %}">User List</a></li>
<li><a href="{% url petition.views.create %}">Create Petition</a></li>
{% get_flatpages '/' as pages %}
{% for page in pages %}

View File

@@ -2,7 +2,7 @@
{%block title%}Claim an Invite{%endblock%}
{%block content %}
<form method="POST" action="{%url profiles.views.claimInvite%}">
<form method="POST" action="{%url local.views.claimInvite%}">
{% csrf_token %}
{{form.as_p}}
<input type="submit" value="Claim!"/>

View File

@@ -3,7 +3,7 @@
{% block title %}Delete Invite{% endblock %}
{% block content %}
<form method="POST" action="{%url profiles.views.deleteInvite code=invite.code %}">
<form method="POST" action="{%url local.views.deleteInvite code=invite.code %}">
{% csrf_token %}
<p>If you delete this invite, it may not be used to create an account. If you already gave this invite to someone, <em>they will not be able to use it!</em></p>
<p>Are you sure you want to delete this invite?</p>

View File

@@ -2,7 +2,7 @@
{% block content %}
<div class="item">
<form method="POST" action="{%url profiles.views.edit %}">
<form method="POST" action="{%url local.views.edit %}">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit"/>

View File

@@ -28,7 +28,7 @@
{% if invite.deleted %}
<em>Deleted</em>
{% else %}
<a href="{%url profiles.views.deleteInvite code=invite.code %}">Delete</a>
<a href="{%url local.views.deleteInvite code=invite.code %}">Delete</a>
{% endif %}
{% endif %}
</td>
@@ -41,7 +41,7 @@
{% endif %}
<tr class="actionBar">
<td colspan="2">
<a href="{% url profiles.views.createInvite %}">Create a new invite</a>
<a href="{% url local.views.createInvite %}">Create a new invite</a>
</td>
</tr>
</table>

View File

@@ -3,6 +3,6 @@
{% block sectiontitle %}Login{% endblock %}
{% block content %}
<div class="item">
{% include 'profiles/_login_form.html' %}
{% include 'local/_login_form.html' %}
</div>
{% endblock %}

View File

@@ -7,8 +7,8 @@
{%block content %}
<div class="item">
{% avatar user %}
<a href="{%url profiles.views.edit %}">Edit profile</a>
<a href="{%url profiles.views.invites %}">Invites</a>
<a href="{%url local.views.edit %}">Edit profile</a>
<a href="{%url local.views.invites %}">Invites</a>
<ul>
<li>Member Since: {{user.date_joined|date:"SHORT_DATE_FORMAT"}}</li>
<li>Last seen: {{user.last_login|date:"SHORT_DATE_FORMAT"}}</li>

View File

@@ -2,7 +2,7 @@
{%block title%}Register an Account{%endblock%}
{%block content %}
<form method="POST" action="{%url profiles.views.register %}">
<form method="POST" action="{%url local.views.register %}">
{% csrf_token %}
{{profileForm.as_p}}
{{userForm.as_p}}

View File

@@ -11,14 +11,14 @@ urlpatterns = patterns('',
url(r'^news/', include('news.urls')),
url(r'^minecraft/', include('minecraft.urls')),
url(r'^mail/', include('messages.urls')),
url(r'^profiles/', include('profiles.urls')),
url(r'^profiles/', include('local.urls')),
url(r'^accounts/logout', 'django.contrib.auth.views.logout', kwargs={'next_page':'/'}),
url(r'^accounts/', include('django.contrib.auth.urls')),
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
url(r'^admin/', include(admin.site.urls)),
url(r'^forums/', include('forums.urls')),
url(r'^api/', include('api.urls')),
url(r'^i/(?P<code>.+)', 'profiles.views.claimInvite')
url(r'^i/(?P<code>.+)', 'local.views.claimInvite')
)
urlpatterns += staticfiles_urlpatterns()