Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

added user profile support

As a result of adding user profile support, a heckton of other
stuff got added. I need to start being more atomic with my
commits...
  • Loading branch information...
commit 1261713503a67695267437738fe7f7b7199b47cb 1 parent 0d30331
@leafstorm leafstorm authored
View
12 lug_people/forms.py
@@ -0,0 +1,12 @@
+# -*- coding: utf-8 -*-
+from .models import MemberProfile, Bit
+from django.forms.models import ModelForm, inlineformset_factory
+
+
+class ProfileEditForm(ModelForm):
+ class Meta:
+ model = MemberProfile
+ fields = ('nickname', 'real_name', 'preferred_name', 'role')
+
+
+BitFormSet = inlineformset_factory(MemberProfile, Bit, fk_name="owner", extra=3)
View
23 lug_people/models.py
@@ -42,6 +42,7 @@ class MemberProfile(models.Model):
def __unicode__(self):
return u"%s (%s)" % self.names if self.has_both_names else self.name
+ # Name-related properties
@property
def name(self):
if not self.real_name or self.preferred_name == u"nick":
@@ -67,6 +68,18 @@ def names(self):
def has_both_names(self):
return bool(self.real_name)
+ # Bits!
+ def all_bits(self):
+ return self.bit_set.all()
+
+ def bits_as_dict(self):
+ return dict((bit.slug, bit.data) for bit in self.all_bits())
+
+ # Authentication-related properties
+ @property
+ def username(self):
+ return self.user.username
+
@property
def email(self):
return self.user.email
@@ -107,7 +120,7 @@ class Meta:
ordering = ('ordering', 'caption')
def __unicode__(self):
- return u"%s (%s)" % (self.caption, self.slug)
+ return self.caption
username_validator = validators.RegexValidator("^[a-zA-Z0-9_.-]+$",
@@ -136,6 +149,14 @@ def clean(self):
username_validator(self.data)
@property
+ def caption(self):
+ return self.bit_type.caption
+
+ @property
+ def slug(self):
+ return self.bit_type.slug
+
+ @property
def data_url(self):
bt = self.bit_type
if bt.format == u"url":
View
45 lug_people/views.py
@@ -1 +1,44 @@
-# Create your views here.
+# -*- coding: utf-8 -*-
+from .models import MemberProfile
+from .forms import ProfileEditForm, BitFormSet
+from django.contrib import messages
+from django.contrib.auth.decorators import login_required
+from django.core.urlresolvers import reverse
+from django.http import HttpResponseRedirect
+from django.utils.decorators import method_decorator
+from django.views.generic import DetailView
+from django.views.generic.base import View, TemplateResponseMixin
+
+
+class ProfileView(DetailView):
+ model = MemberProfile
+ slug_field = 'user__username'
+ slug_url_kwarg = 'username'
+ context_object_name = 'profile'
+
+
+class ProfileEditView(View, TemplateResponseMixin):
+ def get(self, request):
+ profile = request.user.get_profile()
+ form = ProfileEditForm(instance=profile)
+ formset = BitFormSet(instance=profile)
+ return self.render_to_response({'form': form, 'bit_forms': formset,
+ 'profile': profile})
+
+ def post(self, request):
+ profile = request.user.get_profile()
+ form = ProfileEditForm(request.POST, instance=profile)
+ formset = BitFormSet(request.POST, instance=profile)
+
+ if form.is_valid() and formset.is_valid():
+ form.save()
+ formset.save()
+ messages.success(request, u"Your profile has been updated!")
+ return HttpResponseRedirect(reverse('profile',
+ kwargs={'username': profile.username}))
+ return self.render_to_response({'form': form, 'bit_forms': formset,
+ 'profile': profile})
+
+ @method_decorator(login_required)
+ def dispatch(self, *args, **kwargs):
+ return super(ProfileEditView, self).dispatch(*args, **kwargs)
View
15 lug_site/settings.py
@@ -125,10 +125,25 @@
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.admin',
+ # Helper apps
'south',
+ 'gravatar',
+ 'bootstrap_toolkit',
+ # Actual project apps
'lug_people',
)
+# This is for Bootstrap
+from django.contrib.messages import constants as messages
+
+MESSAGE_TAGS = {
+ messages.DEBUG: 'alert-debug',
+ messages.INFO: 'alert-info',
+ messages.SUCCESS: 'alert-success',
+ messages.WARNING: 'alert-warning',
+ messages.ERROR: 'alert-error'
+}
+
AUTH_PROFILE_MODULE = 'lug_people.MemberProfile'
# A sample logging configuration. The only tangible logging
View
6 lug_site/templates/layout_base.html
@@ -18,6 +18,12 @@
{% include "site/navbar.html" %}
<div class="container container-main">
+ {% if messages %}
+ {% for message in messages %}
+ <div class="alert {{ message.tags }}">{{ message }}</div>
+ {% endfor %}
+ {% endif %}
+
{% block body %}
{% endblock body %}
View
78 lug_site/templates/profiles/edit.html
@@ -0,0 +1,78 @@
+{% extends "layout_base.html" %}
+{% load bootstrap_toolkit %}
+
+{% block title %}Edit Profile{% endblock title %}
+
+{% block body %}
+
+ <h1 class="page-header">
+ {{ profile.name }}
+ {% if profile.has_both_names %}
+ ({{ profile.alternate_name }})
+ {% endif %}
+ {% if profile.title %}
+ <small>{{ profile.title }}</small>
+ {% endif %}
+ <a href="{% url profile profile.username %}" class="btn btn-primary" style="float: right;">
+ <i class="icon-arrow-left icon-white"></i> Back to Profile
+ </a>
+ </h1>
+
+ <form action="" method="POST">
+ {% csrf_token %}
+ <div class="row">
+ <div class="span6 profile-bio">
+ <h2>Basic Information</h2>
+
+ {{ form|as_bootstrap }}
+ </div>
+
+ <div class="span6 profile-bits">
+ <h2>Bits</h2>
+
+ {{ bit_forms.management_form|as_bootstrap }}
+ {% if bit_forms.non_field_errors %}
+ {% include "bootstrap_toolkit/non_field_errors.html" with form=bit_forms %}
+ {% endif %}
+
+ <table class="table table-condensed">
+ <thead>
+ <tr>
+ <th>Type</th>
+ <th colspan="2">Data</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for bit_form in bit_forms.forms %}
+ <tr>
+ <td class="control-group{% if bit_form.bit_type.errors %} error{% endif %}">
+ {{ bit_form.bit_type }}
+ {% include "bootstrap_toolkit/field_errors.html" with field=bit_form.bit_type inline=False %}
+ </td>
+ <td class="control-group{% if bit_form.data.errors %} error{% endif %}">
+ {{ bit_form.data }}
+ {% include "bootstrap_toolkit/field_errors.html" with field=bit_form.data inline=False %}
+ </td>
+ <td style="white-space: nowrap;">
+ {{ bit_form.id }}
+ {{ bit_form.owner }}
+ <label for="{{ bit_form.DELETE.auto_id }}">
+ {{ bit_form.DELETE }}
+ <i class="icon-trash"></i>
+ </label>
+ </td>
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ </div>
+
+ <div class="row">
+ <div class="span12 form-actions">
+ <button class="btn btn-success" type="submit">Save</button>
+ </div>
+ </div>
+ </div>
+ </form>
+
+{% endblock body %}
View
49 lug_site/templates/profiles/show.html
@@ -0,0 +1,49 @@
+{% extends "layout_base.html" %}
+
+{% block title %}{{ profile }}{% endblock title %}
+
+{% block body %}
+
+ <h1 class="page-header">
+ {{ profile.name }}
+ {% if profile.has_both_names %}
+ ({{ profile.alternate_name }})
+ {% endif %}
+ {% if profile.title %}
+ <small>{{ profile.title }}</small>
+ {% endif %}
+ {% if profile.user == user %}
+ <a href="{% url profile_edit %}" class="btn btn-primary" style="float: right;">
+ <i class="icon-pencil icon-white"></i> Edit Profile
+ </a>
+ {% endif %}
+ </h1>
+
+ <div class="row">
+ <div class="span6 profile-bio">
+ <h2>Biography</h2>
+
+ {% if profile.biography %}
+ {{ profile.biography }}
+ {% else %}
+ <p>
+ ({{ profile.name }} hasn't written a biography yet.)
+ </p>
+ {% endif %}
+ </div>
+
+ <div class="span6 profile-bits">
+ <h2>More Information</h2>
+
+ <dl class="dl-horizontal">
+ <dt>Role:</dt>
+ <dd>{{ profile.get_role_display }}</dd>
+ {% for bit in profile.all_bits %}
+ <dt>{{ bit.bit_type.caption }}:</dt>
+ <dd>{{ bit.data_html }}</dd>
+ {% endfor %}
+ </dl>
+ </div>
+ </div>
+
+{% endblock body %}
View
4 lug_site/templates/site/navbar.html
@@ -14,10 +14,10 @@
<li class="dropdown">
{% if user.is_authenticated %}
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
- {{ user.name }} <b class="caret"></b>
+ {{ user.get_profile.name }} <b class="caret"></b>
</a>
<ul class="dropdown-menu">
- <li><a>My Profile</a></li>
+ <li><a href="{% url profile user.username %}">My Profile</a></li>
<li><a>Log Out</a></li>
{% if user.is_staff %}
<li class="divider"></li>
View
13 lug_site/urls.py
@@ -2,9 +2,20 @@
from django.views.generic import TemplateView
from django.contrib import admin
+from lug_people.views import ProfileView, ProfileEditView
+
admin.autodiscover()
urlpatterns = patterns('',
- url(r'^$', TemplateView.as_view(template_name="index.html")),
+ # General site views
+ url(r'^$', TemplateView.as_view(template_name="index.html"), name='index'),
+ # Profile views
+ url(r'^~(?P<username>[a-zA-Z0-9@+.-]+)/$',
+ ProfileView.as_view(template_name='profiles/show.html'),
+ name='profile'),
+ url(r'^edit-profile/$',
+ ProfileEditView.as_view(template_name='profiles/edit.html'),
+ name='profile_edit'),
+ # Admin interface and other internals
url(r'^admin/', include(admin.site.urls)),
)
View
3  requirements.txt
@@ -1,3 +1,6 @@
django>=1.4
django-registration>=0.8
+django-bootstrap-toolkit
+django-gravatar
South>=0.7
+
Please sign in to comment.
Something went wrong with that request. Please try again.