changeset 35:290dd9208cc4

Implement editing user profiles and fix bugs related to the login/logout buttons. Implement 403 exception
author Jordi Gutiérrez Hermoso <jordigh@gmail.com>
date Mon, 05 Jul 2010 00:31:20 -0500
parents 22d514498935
children bc0137b6c264
files apps/bundle/views.py apps/profile/views.py middleware/__init__.py middleware/http.py settings.py templates/403.html templates/base.djhtml templates/profile/edit-user.djhtml templates/profile/user.djhtml templates/user.djhtml urls.py
diffstat 10 files changed, 276 insertions(+), 85 deletions(-) [+]
line wrap: on
line diff
--- a/apps/bundle/views.py	Fri Jul 02 02:18:22 2010 -0500
+++ b/apps/bundle/views.py	Mon Jul 05 00:31:20 2010 -0500
@@ -1,9 +1,15 @@
 from django.shortcuts import render_to_response, get_object_or_404
 from agora.apps.bundle.models import *
+from django.template import RequestContext
 
 def detail(request, user, bundle):
     b = get_object_or_404(Bundle, uploader__username=user, name=bundle)
     f = BundleFile.objects.filter(bundle=b)
 
-    return render_to_response('bundle/index.djhtml', {'bundle':b,
-                                                      'files': f,})
+    return render_to_response('bundle/index.djhtml',
+                              {
+                                'bundle':b,
+                                'files': f,
+                               },
+                              RequestContext(request),
+                              )
--- a/apps/profile/views.py	Fri Jul 02 02:18:22 2010 -0500
+++ b/apps/profile/views.py	Mon Jul 05 00:31:20 2010 -0500
@@ -1,37 +1,87 @@
 from django.shortcuts import render_to_response, get_object_or_404
-from agora.apps.profile.models import Profile
 from django.contrib.auth.models import User
-from django.http import Http404
+from django.http import Http404, HttpResponseRedirect
+from django.core.urlresolvers import reverse
+from django.contrib.auth.decorators import login_required
+from django.template import RequestContext
+
 from agora.apps.free_license.models import FreeLicense
 from agora.apps.bundle.models import Bundle
 from agora.apps.snippet.models import Snippet
+from agora.apps.profile.models import Profile
 
-def showprofile(request, user):
+from agora.middleware.http import Http403
+
+def getprofile(user):
     u = get_object_or_404(User, username=user)
 
     #Inactive users "don't exist"
     if not u.is_active:
         raise Http404
 
+    #Get profile or create a default if none exists
     try:
         p = u.get_profile()
-    #Create a default profile if none exists
     except Profile.DoesNotExist:
         #At least one FreeLicense *must* exist.
         p = Profile(user=u, preferred_license=FreeLicense.objects.get(id=1))
         p.save()
 
+    return [u,p]
+
+def showprofile(request, user):
+    [u,p] = getprofile(user)
+
     if u.first_name or u.last_name:
-        n = u.first_name + " " + u.last_name
+        n = u.get_full_name()
     else:
         n = u.username
 
     b = Bundle.objects.filter(uploader=u)
     s = Snippet.objects.filter(uploader=u)
 
-    return render_to_response('user.djhtml', {'user' : u,
-                                              'profile' : p,
-                                              'bundles' : b,
-                                              'snippets' : s,
-                                              'name' : n,
-                                              })
+    return render_to_response('profile/user.djhtml',
+                              {
+                                  'profile' : p,
+                                  'bundles' : b,
+                                  'snippets' : s,
+                                  'name' : n,
+                               },
+                               RequestContext(request)
+                              )
+
+@login_required
+def editprofile(request, user):
+    [u,p] = getprofile(user)
+
+    #Make sure user can only edit own profile
+    if request.user != u:
+        raise Http403
+
+    if request.method=='POST':
+        u.first_name = request.POST['first-name']
+        u.last_name  = request.POST['last-name']
+        u.save()
+
+        try:
+            p.preferred_license = \
+                            FreeLicense.objects.get(id=request.POST['license'])
+        except:
+            p.preferred_license = FreeLicense.objects.get(id=1)
+
+        p.interests = request.POST['interests']
+        p.blurb = request.POST['blurb']
+        p.save()
+        return HttpResponseRedirect(reverse(
+                                    'agora.apps.profile.views.showprofile',
+                                    args=(u,))
+                                    )
+
+    licenses = FreeLicense.objects.all()
+    return render_to_response('profile/edit-user.djhtml',
+                              {
+                                  'profile' : p,
+                                  'licenses' : licenses,
+                              },
+                              RequestContext(request)
+                              )
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/middleware/http.py	Mon Jul 05 00:31:20 2010 -0500
@@ -0,0 +1,30 @@
+from django.template import RequestContext
+from django.conf import settings
+from django.core.exceptions import PermissionDenied
+from django.http import HttpResponseForbidden
+from django.template import loader
+
+class Http403(Exception):
+    pass
+
+def render_to_403(*args, **kwargs):
+    """
+        Returns a HttpResponseForbidden whose content is filled with
+        the result of calling
+        django.template.loader.render_to_string() with the passed
+        arguments.
+    """
+    if not isinstance(args,list):
+        args = []
+        args.append('403.html')
+
+    httpresponse_kwargs = {'mimetype': kwargs.pop('mimetype', None)}
+    response = HttpResponseForbidden(loader.render_to_string(*args, **kwargs),
+                                     **httpresponse_kwargs)
+
+    return response
+
+class Http403Middleware(object):
+    def process_exception(self,request,exception):
+        if isinstance(exception,Http403):
+            return render_to_403(context_instance=RequestContext(request))
--- a/settings.py	Fri Jul 02 02:18:22 2010 -0500
+++ b/settings.py	Mon Jul 05 00:31:20 2010 -0500
@@ -97,11 +97,14 @@
 )
 
 MIDDLEWARE_CLASSES = (
-    'django.middleware.common.CommonMiddleware',
-    'django.contrib.sessions.middleware.SessionMiddleware',
-    'django.middleware.csrf.CsrfViewMiddleware',
-    'django.contrib.auth.middleware.AuthenticationMiddleware',
-    'django.contrib.messages.middleware.MessageMiddleware',
+  'django.middleware.common.CommonMiddleware',
+  'django.contrib.sessions.middleware.SessionMiddleware',
+  'django.middleware.csrf.CsrfViewMiddleware',
+  'django.contrib.auth.middleware.AuthenticationMiddleware',
+  'django.contrib.messages.middleware.MessageMiddleware',
+
+  #Agora-specific middleware
+  'agora.middleware.http.Http403Middleware',
 )
 
 ROOT_URLCONF = 'agora.urls'
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/403.html	Mon Jul 05 00:31:20 2010 -0500
@@ -0,0 +1,16 @@
+{% extends "whitebox.djhtml" %}
+
+{% block title %}
+Access denied
+{% endblock %}
+
+{% block boxtitle %}
+Access denied
+{% endblock %}
+
+{% block boxcontents %}
+<p>
+  You requested access to a portion of Agora for which you don't have
+  permission. If you believe this is a mistake, please let us know.
+</p>
+{% endblock %}
--- a/templates/base.djhtml	Fri Jul 02 02:18:22 2010 -0500
+++ b/templates/base.djhtml	Mon Jul 05 00:31:20 2010 -0500
@@ -7,7 +7,7 @@
 
     <title>Agora Octave &mdash;
       {% block title %}
-      Free your math!
+      Free your numbers!
       {% endblock %}
     </title>
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/profile/edit-user.djhtml	Mon Jul 05 00:31:20 2010 -0500
@@ -0,0 +1,76 @@
+{% extends "profile/user.djhtml" %}
+
+{% block boxtitle %}
+Edit your profile
+{% endblock boxtitle %}
+
+{% block boxcontents %}
+<p class="explanation">
+You can provide some extra optional information about yourself. We
+recommend that you provide us with a real name. If you do, it will be
+displayed next to all of your contributions instead of your Agora
+username.
+</p>
+<form id="userinfo" method="post" action=".">
+
+  {% csrf_token %}
+
+  <p class="explanation">
+    We will display your name according to most Western European
+    conventions, your given name(s) followed by your surname(s).
+  </p>
+  <span class="userfield">Given name(s)</span>
+  <input type="text"
+         name="first-name"
+         id="edit-first-name"
+         value="{{user.first_name}}" /> <br />
+  <span class="userfield">Surname(s)</span>
+  <input type="text"
+         id="edit-last-name"
+         name="last-name"
+         value="{{user.last_name}}" /> <br />
+
+  <p class="explanation">
+    By default, all of your submissions will be under the following
+    license, and will be displayed next to your submissions.
+    <a href="/licenses">
+      Here is a thorough explanation of the available licenses.
+    </a>
+  </p>
+
+  <span class="userfield">Preferred license</span>
+  <select name="license" id="edit-license">
+  {% for license in licenses %}
+  <option value="{{ license.id }}"
+          {% if license = profile.preferred_license %}
+          selected="true"
+          {% endif %}
+          />
+  {{license.name}}
+  </option>
+  {% endfor %}
+  </select>
+
+  <p class="explanation">
+    Tell us about your research interests (e.g. <em>signal processing</em>,
+    <em>hyperbolic PDEs</em>). These keywords will be used when
+    searching for submissions.
+  </p>
+  <span class="userfield">Research interests</span>
+  <input type="text"
+         name="interests"
+         id="edit-interests"
+         value="{{profile.interests}}" /> <br />
+
+  <p class="explanation">
+    Finally, anything else you would like to say about yourself.
+  </p>
+
+  <span class="userfield">Blurb</span>
+
+  <textarea name="blurb" id="edit-blurb">{{profile.blurb}}</textarea>
+  <br/>
+
+  <input type="submit" value="Update profile" />
+</form>
+{% endblock boxcontents %}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/profile/user.djhtml	Mon Jul 05 00:31:20 2010 -0500
@@ -0,0 +1,74 @@
+{% extends "whitebox.djhtml" %}
+
+{% block boxtitle %}
+{{profile.user.username}} <br/>
+{% if profile.user = user %}
+<small>
+  (<a href="{% url agora.apps.profile.views.editprofile user %}">
+    edit profile
+  </a>)
+</small>
+{% endif %}
+{% endblock boxtitle%}
+
+{% block boxcontents %}
+<div id="userinfo">
+  {% if profile.user.first_name or profile.user.last_name %}
+  <span class="userfield">Name</span>
+  <span class="userdata">{{name}}</span>
+  <br />
+  {% endif %}
+  <span class="userfield">Preferred license</span>
+  <span class="userdata">{{profile.preferred_license}}</span>
+  <br />
+  {% if profile.interests %}
+  <h4>
+    Interests
+  </h4>
+  <p class="userdata">
+    {{profile.interests}}
+  </p>
+  {% endif %}
+
+  {% if profile.blurb %}
+  <h4>
+    About {{name}}
+  </h4>
+  <p class="userdata">
+    {{profile.blurb}}
+  </p>
+</div>
+{% endif %}
+{% endblock boxcontents %}
+
+{% block content-related %}
+{% if bundles or snippets %}
+<div id="info">
+  <h3>
+    Contributions by {{name}}
+  </h3>
+  <div class="whitebox">
+    {% if bundles %}
+    <h5>
+      Bundles
+    </h5>
+    <ul>
+      {% for b in bundles %}
+      <li> <a href="/{{profile.user.username}}/{{b.name}}">{{b.name}} </a></li>
+      {% endfor %}
+    </ul>
+    {% endif %}
+    {% if snippets %}
+    <h5>
+      Snippets
+    </h5>
+    <ul>
+      {% for s in snippets %}
+      <li><a href="/snippet/{{s}}"}{{s}}</a></li>
+      {% endfor %}
+      {% endif %}
+    </ul>
+  </div>
+</div>
+{% endif %}
+{% endblock content-related %}
--- a/templates/user.djhtml	Fri Jul 02 02:18:22 2010 -0500
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,65 +0,0 @@
-{% extends "whitebox.djhtml" %}
-{% block boxtitle %}
-{{user.username}}
-{% endblock %}
-{% block boxcontents %}
-<div id="userinfo">
-  {% if user.first_name or user.last_name %}
-  <span class="userfield">Name</span>
-  <span class="userdata">{{name}}</span>
-  <br />
-  {% endif %}
-  <span class="userfield">Preferred license</span>
-  <span class="userdata">{{profile.preferred_license}}</span>
-  <br />
-  {% if profile.interests %}
-  <h4>
-    Interests
-  </h4>
-  <p class="userdata">
-    {{profile.interests}}
-  </p>
-  {% endif %}
-
-  {% if profile.blurb %}
-  <h4>
-    About {{name}}
-  </h4>
-  <p class="userdata">
-    {{profile.blurb}}
-  </p>
-</div>
-{% endif %}
-{% endblock %} {# boxcontents #}
-
-{% block content-related %}
-{% if bundles or snippets %}
-<div id="info">
-  <h3>
-    Contributions by {{name}}
-  </h3>
-  <div class="whitebox">
-    {% if bundles %}
-    <h5>
-      Bundles
-    </h5>
-    <ul>
-      {% for b in bundles %}
-      <li> <a href="/{{user.username}}/{{b.name}}">{{b.name}} </a></li>
-      {% endfor %}
-    </ul>
-    {% endif %}
-    {% if snippets %}
-    <h5>
-      Snippets
-    </h5>
-    <ul>
-      {% for s in snippets %}
-      <li><a href="/snippet/{{s}}"}{{s}}</a></li>
-      {% endfor %}
-      {% endif %}
-    </ul>
-  </div>
-</div>
-{% endif %}
-{% endblock %} {# content-related #}
--- a/urls.py	Fri Jul 02 02:18:22 2010 -0500
+++ b/urls.py	Mon Jul 05 00:31:20 2010 -0500
@@ -18,7 +18,8 @@
 
      (r'^accounts/', include('registration.urls')),
 
-     (r'^(?P<user>[\w|_]*)/$', 'agora.apps.profile.views.showprofile'),
+     (r'^editprofile/(?P<user>\w*)/$', 'agora.apps.profile.views.editprofile'),
+     (r'^(?P<user>\w*)/$',      'agora.apps.profile.views.showprofile'),
 
      (r'^', include('agora.apps.bundle.urls')),