Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added some silly statistics to the user pages.

Also cleaned up the styles slightly.
  • Loading branch information...
commit 20a21e15e267a3fc3bab4ad5b75da1de3f1482be 1 parent 3d1a65a
@jacobian jacobian authored
View
18 django_website/accounts/views.py
@@ -1,3 +1,5 @@
+from __future__ import absolute_import
+
import hashlib
import json
from django.shortcuts import render, get_object_or_404
@@ -5,6 +7,7 @@
from django.conf import settings
from django.core import cache
from django.http import HttpResponse
+from ..trac import stats as trac_stats
from ..cla.models import find_agreements
def user_profile(request, username):
@@ -14,6 +17,7 @@ def user_profile(request, username):
'email_hash': hashlib.md5(u.email).hexdigest(),
'user_can_commit': u.has_perm('auth.commit'),
'clas': find_agreements(u),
+ 'stats': get_user_stats(u),
}
return render(request, "accounts/user_profile.html", ctx)
@@ -57,6 +61,20 @@ def get_user_info(username):
c.set(key, info, 60*60)
return info
+def get_user_stats(user):
+ c = cache.get_cache('default')
+ key = 'user_vital_status:%s' % hashlib.md5(user.username).hexdigest()
+ info = c.get(key)
+ if info is None:
+ info = trac_stats.get_user_stats(user.username)
+ # Hide any stat with a value = 0 so that we don't accidentally insult
+ # non-contributors.
+ for k, v in info.items():
+ if v == 0:
+ info.pop(k)
+ c.set(key, info, 60*60)
+ return info
+
class JSONResponse(HttpResponse):
def __init__(self, obj):
super(JSONResponse, self).__init__(
View
1  django_website/settings/www.py
@@ -76,6 +76,7 @@
'registration',
'south',
'djangosecure',
+ 'gunicorn',
]
CACHE_MIDDLEWARE_SECONDS = 60 * 5 # 5 minutes
View
58 django_website/templates/accounts/user_profile.html
@@ -4,45 +4,51 @@
{% block extrahead %}
<style type="text/css">
#avatar { float: left; margin-top: 16px; }
- #user-info { padding-left: 150px; }
- #user-info ul { padding-left: 48px; }
+ #user-info { padding-left: 180px; }
+ #user-info ul li { margin-left: 1em; }
+ h1 span.badge {
+ font-size: 12px;
+ background-color: #FFC757;
+ border-radius: 4px;
+ padding: 2px 6px;
+ position: relative;
+ bottom: 0.3em;
+ }
</style>
{% endblock extrahead %}
{% block content-related %}{% endblock %}
{% block content %}
+ {% load humanize %}
<img id='avatar' width='150' height='150'
src="http://robohash.org/{{ email_hash }}?gravatar=hashed&amp;set=set3">
<div id="user-info">
- <h1>{% firstof user.get_full_name user.username %}</h1>
- <p>
- Member since {{ user.date_joined.date }}.
- </p>
- {% if user_can_commit %}<p>Committer!</p>{% endif %}
- {% if clas %}
- {% for cla in clas %}
- {% if cla.ccla %}
- {# it's a corporate cla #}
- <p>
- Contributions covered by CLA on file for {{ cla.ccla.company_name }}
- (signed {{ cla.ccla.date_signed }}).
- </p>
- {% else %}
- <p>
- CLA on file (signed {{ cla.date_signed }}).
- </p>
- {% endif %}
- {% endfor %}
+ <h1>
+ {% firstof user.get_full_name user.username %}
+ {% if user_can_commit %}<span class="badge" title="Core committer.">core</span>{% endif %}
+ {% if clas %}<span class="badge" title="Contributor License Agreement on file.">cla</span>{% endif %}
+ </h1>
+
+ <h3 class="deck">
+ Contributor since {{ user.date_joined.date }}.
+ </h2>
+
+ {% if stats %}
+ <h2>Lies, damned lies, and statistics:</h2>
+ <ul>
+ {% for stat, value in stats.items %}
+ <li>{{ stat }}: {{ value|intcomma }}.</li>
+ {% endfor %}
+ </ul>
{% endif %}
+
{% with user.owned_feeds.all as feeds %}
{% if feeds %}
<h2>Community feeds:</h2>
<ul>
- <li>
- {% for f in feeds %}
- <li><a href="{{ f.public_url }}">{{ f.title }}</a></li>
- {% endfor %}
- </li>
+ {% for f in feeds %}
+ <li><a href="{{ f.public_url }}">{{ f.title }}</a></li>
+ {% endfor %}
</ul>
{% endif %}
{% endwith %}
View
60 django_website/trac/stats.py
@@ -0,0 +1,60 @@
+"""
+Various queries for grabbing interesting user stats from Trac.
+"""
+
+from __future__ import absolute_import
+import operator
+import django.db
+from .models import Revision, Ticket, TicketChange
+
+_statfuncs = []
+
+def stat(title):
+ """
+ Register a function as a "stat"
+
+ The function should take a username and return a number.
+ """
+
+ def _inner(f):
+ _statfuncs.append(f)
+ f.title = title
+ return f
+ return _inner
+
+def get_user_stats(username):
+ stats = {}
+ for func in sorted(_statfuncs, key=operator.attrgetter('title')):
+ stats[func.title] = func(username)
+ return stats
+
+@stat('Commits')
+def commit_count(username):
+ return Revision.objects.filter(author=username).count()
+
+@stat('Tickets closed')
+def tickets_closed(username):
+ # Raw query so that we can do COUNT(DISTINCT ticket).
+ q = """SELECT COUNT(DISTINCT ticket) FROM ticket_change
+ WHERE author = %s AND field = 'status' AND newvalue = 'closed';"""
+ return run_single_value_query(q, username)
+
+@stat('Tickets opened')
+def tickets_opened(username):
+ return Ticket.objects.filter(reporter=username).count()
+
+@stat('New tickets reviewed')
+def new_tickets_reviewed(username):
+ # We don't want to de-dup as for tickets_closed: multiple reviews of the
+ # same ticket should "count" as a review.
+ qs = TicketChange.objects.filter(author=username, field='stage', oldvalue='Unreviewed')
+ qs = qs.exclude(newvalue='Unreviewed')
+ return qs.count()
+
+def run_single_value_query(query, *params):
+ """
+ Helper: run a query returning a single value (e.g. a COUNT) and return the value.
+ """
+ c = django.db.connections['trac'].cursor()
+ c.execute(query, params)
+ return c.fetchone()[0]
Please sign in to comment.
Something went wrong with that request. Please try again.