summaryrefslogtreecommitdiffstats
path: root/hyperkitty
diff options
context:
space:
mode:
authorAurélien Bompard <aurelien@bompard.org>2013-07-31 09:12:12 +0200
committerAurélien Bompard <aurelien@bompard.org>2013-08-02 10:54:14 +0200
commitf7521efee66e5297528f52290b670df6c2ddb2aa (patch)
treeaa265d38a7957244f771fc1067e127aca7d3c015 /hyperkitty
parent36555737b8773b765cbeb81a2417eb431d2da008 (diff)
downloadhyperkitty-f7521efee66e5297528f52290b670df6c2ddb2aa.tar.gz
hyperkitty-f7521efee66e5297528f52290b670df6c2ddb2aa.tar.xz
hyperkitty-f7521efee66e5297528f52290b670df6c2ddb2aa.zip
Add User profiles
Diffstat (limited to 'hyperkitty')
-rw-r--r--hyperkitty/models.py7
-rw-r--r--hyperkitty/static/hyperkitty/css/hyperkitty-message.css9
-rw-r--r--hyperkitty/static/hyperkitty/css/hyperkitty-user.css5
-rw-r--r--hyperkitty/templates/messages/message.html9
-rw-r--r--hyperkitty/templates/user_public_profile.html80
-rw-r--r--hyperkitty/urls.py2
-rw-r--r--hyperkitty/views/accounts.py75
7 files changed, 176 insertions, 11 deletions
diff --git a/hyperkitty/models.py b/hyperkitty/models.py
index ac7e091..f734952 100644
--- a/hyperkitty/models.py
+++ b/hyperkitty/models.py
@@ -29,14 +29,9 @@ from paintstore.fields import ColorPickerField
class Rating(models.Model):
- # @TODO: instead of list_address, user list model from kittystore?
list_address = models.CharField(max_length=255, db_index=True)
-
- # @TODO: instead of messsageid, use message model from kittystore?
messageid = models.CharField(max_length=100, db_index=True)
-
user = models.ForeignKey(User)
-
vote = models.SmallIntegerField()
def __unicode__(self):
@@ -65,9 +60,7 @@ class UserProfile(models.Model):
class Tag(models.Model):
- # @TODO: instead of list_address, user list model from kittystore?
list_address = models.CharField(max_length=255, db_index=True)
- # @TODO: instead of threadid, use thread model from kittystore?
threadid = models.CharField(max_length=100, db_index=True)
user = models.ForeignKey(User)
tag = models.CharField(max_length=255)
diff --git a/hyperkitty/static/hyperkitty/css/hyperkitty-message.css b/hyperkitty/static/hyperkitty/css/hyperkitty-message.css
index 2f76e4e..4efd882 100644
--- a/hyperkitty/static/hyperkitty/css/hyperkitty-message.css
+++ b/hyperkitty/static/hyperkitty/css/hyperkitty-message.css
@@ -199,7 +199,6 @@
.email-header .gravatar {
margin-right: 10px;
display: inline-block;
- vertical-align: middle;
}
.email-author .name{
@@ -211,6 +210,14 @@
font-size: 80%;
font-weight: bold;
}
+.email-author .messagelink {
+ font-style: italic;
+ font-size: 90%;
+ color: rgb(167, 169, 172);
+}
+.email-author .messagelink a {
+ color: rgb(167, 169, 172);
+}
.email-first .email-date {
text-align: right;
diff --git a/hyperkitty/static/hyperkitty/css/hyperkitty-user.css b/hyperkitty/static/hyperkitty/css/hyperkitty-user.css
index 17b1fa9..23a8c2c 100644
--- a/hyperkitty/static/hyperkitty/css/hyperkitty-user.css
+++ b/hyperkitty/static/hyperkitty/css/hyperkitty-user.css
@@ -91,3 +91,8 @@ table.user-data input {
margin-left: 0;
position: absolute;
}
+
+
+#user-profile table.subscriptions {
+ width: auto;
+}
diff --git a/hyperkitty/templates/messages/message.html b/hyperkitty/templates/messages/message.html
index 453e248..7140d75 100644
--- a/hyperkitty/templates/messages/message.html
+++ b/hyperkitty/templates/messages/message.html
@@ -28,9 +28,14 @@
</div>
<div class="email-author inline-block">
<span class="name"><a
- href="{% url 'message_index' mlist_fqdn=mlist.name message_id_hash=email.message_id_hash %}"
- title="{{ email.subject }}"
+ href="{% url 'public_user_profile' email=email.sender_email %}"
+ title="See {{ email.sender_name|escapeemail|escape }}'s profile"
>{{email.sender_name|escapeemail}}</a></span>
+ <br />
+ <span class="messagelink">
+ (<a href="{% url 'message_index' mlist_fqdn=mlist.name message_id_hash=email.message_id_hash %}"
+ title="{{ email.subject }}">permalink</a>)
+ </span>
{% if use_mockups %}
<br />
<span class="rank">
diff --git a/hyperkitty/templates/user_public_profile.html b/hyperkitty/templates/user_public_profile.html
new file mode 100644
index 0000000..b62002d
--- /dev/null
+++ b/hyperkitty/templates/user_public_profile.html
@@ -0,0 +1,80 @@
+{% extends "base.html" %}
+{% load url from future %}
+{% load i18n %}
+{% load hk_generic %}
+{% load gravatar %}
+
+
+{% block title %}
+{% trans 'User Profile' %} for {{ email }} - {{ app_name|title }}
+{% endblock %}
+
+{% block content %}
+
+<div id="user-profile">
+
+ <h1>User profile <small>for {{ email }}</small></h1>
+
+ <table class="table table-bordered table-striped user-data">
+ <tbody>
+ <tr>
+ <th>{% trans 'Name:' %}</th>
+ <td>{{ fullname }}</td>
+ </tr>
+ <tr>
+ <th>{% trans 'Email:' %}</th>
+ <td>{{ email }}</td>
+ </tr>
+ {% if creation %}
+ <tr>
+ <th>{% trans 'Creation:' %}</th>
+ <td>{{ creation|date:"l, j F Y H:i:s" }} ({{ creation|timesince }})</td>
+ </tr>
+ {% endif %}
+ <tr>
+ <th>{% trans 'Votes for this user:' %}</th>
+ <td><span class="likestatus {{ likestatus }}">+{{ likes }}/-{{ dislikes }}</span></td>
+ </tr>
+ </tbody>
+ </table>
+
+ <h3>Subscriptions</h3>
+ {% if subscriptions %}
+ <table class="table table-striped table-bordered table-condensed subscriptions">
+ <thead>
+ <tr>
+ <th>List</th>
+ <th>Time of first activity</th>
+ <th>First post</th>
+ <th>Posts to this list</th>
+ <th>Votes</th>
+ </tr>
+ </thead>
+ <tbody>
+ {% for sub in subscriptions %}
+ <tr>
+ <td>
+ <a href="{% url 'list_overview' sub.list_name %}">{{ sub.list_name }}</a>
+ </td>
+ {% if sub.first_post %}
+ <td>
+ {{ sub.first_post|get_date|date:"l, j F Y H:i:s" }}
+ {{ sub.first_post|get_date|timesince }}
+ </td>
+ <td>{{ sub.first_post.subject }}</td>
+ <td><a href="{{ sub.all_posts_url }}">{{ sub.posts_count }} post{{ sub.posts_count|pluralize }}</a></td>
+ <td><span class="likestatus {{ sub.likestatus }}">+{{ sub.likes }}/-{{ sub.dislikes }}</span></td>
+ {% else %}
+ <td colspan="4" style="text-align:center"><em>no post yet</em></td>
+ {% endif %}
+ </tr>
+ {% endfor %}
+ </tbody>
+ </table>
+ {% else %}
+ <p><em>no subscriptions</em></p>
+ {% endif %}
+
+</div>
+
+{% endblock %}
diff --git a/hyperkitty/urls.py b/hyperkitty/urls.py
index 9dfe63c..3cc24e5 100644
--- a/hyperkitty/urls.py
+++ b/hyperkitty/urls.py
@@ -50,6 +50,8 @@ urlpatterns = patterns('hyperkitty.views',
url(r'^accounts/profile/votes$', 'accounts.votes', name='user_votes'),
url(r'^accounts/register/$', 'accounts.user_registration', {'SSL': True}, name='user_registration'),
+ # Users
+ url(r'^user/(?P<email>[^/@]+@[^/@]+)/$', 'accounts.public_profile', name='public_user_profile'),
# List archives and overview
url(r'^list/(?P<mlist_fqdn>[^/@]+@[^/@]+)/(?P<year>\d{4})/(?P<month>\d\d?)/(?P<day>\d\d?)/$',
diff --git a/hyperkitty/views/accounts.py b/hyperkitty/views/accounts.py
index 373390b..5d7a9fc 100644
--- a/hyperkitty/views/accounts.py
+++ b/hyperkitty/views/accounts.py
@@ -20,6 +20,7 @@
#
import logging
+from urllib2 import HTTPError
from django.conf import settings
from django.core.urlresolvers import reverse
@@ -29,10 +30,12 @@ from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.contrib.auth.views import login as django_login_view
from django.shortcuts import render, redirect
-from django.utils.http import is_safe_url
+from django.utils.http import is_safe_url, urlquote
from django.utils.timezone import utc, get_current_timezone
+from django.http import Http404
#from django.utils.translation import gettext as _
from social_auth.backends import SocialAuthBackend
+import dateutil.parser
from hyperkitty.models import UserProfile, Rating, Favorite, LastView
from hyperkitty.views.forms import RegistrationForm, UserProfileForm
@@ -203,3 +206,73 @@ def votes(request):
return render(request, 'ajax/votes.html', {
"votes": votes,
})
+
+
+def public_profile(request, email):
+ from mailmanclient import Client, MailmanConnectionError
+ try:
+ client = Client('%s/3.0' % settings.MAILMAN_REST_SERVER,
+ settings.MAILMAN_API_USER, settings.MAILMAN_API_PASS)
+ mm_user = client.get_user(email)
+ except HTTPError:
+ raise Http404("No user with this email: %s" % email)
+ except MailmanConnectionError:
+ class EmptyMailmanUser:
+ created_on = None
+ subscription_list_ids = []
+ mm_user = EmptyMailmanUser()
+ subscriptions = []
+ store = get_store(request)
+ # Subscriptions
+ for mlist_id in mm_user.subscription_list_ids:
+ mlist = client.get_list(mlist_id).fqdn_listname
+ # de-duplicate subscriptions
+ if mlist in [ s["list_name"] for s in subscriptions ]:
+ continue
+ email_hashes = store.get_message_hashes_by_sender(email, mlist)
+ try: # Compute the average vote value
+ votes = Rating.objects.filter(list_address=mlist,
+ messageid__in=email_hashes)
+ except Rating.DoesNotExist:
+ votes = []
+ likes = dislikes = 0
+ for v in votes:
+ if v.vote == 1:
+ likes += 1
+ elif v.vote == -1:
+ dislikes += 1
+ all_posts_url = "%s?list=%s&query=sender:%s" % \
+ (reverse("search"), mlist, urlquote(email))
+ likestatus = "neutral"
+ if likes - dislikes >= 10:
+ likestatus = "likealot"
+ elif likes - dislikes > 0:
+ likestatus = "like"
+ subscriptions.append({
+ "list_name": mlist,
+ "first_post": store.get_first_post(mlist, email),
+ "likes": likes,
+ "dislikes": dislikes,
+ "likestatus": likestatus,
+ "all_posts_url": all_posts_url,
+ "posts_count": len(email_hashes),
+ })
+ likes = sum([s["likes"] for s in subscriptions])
+ dislikes = sum([s["dislikes"] for s in subscriptions])
+ likestatus = "neutral"
+ if likes - dislikes >= 10:
+ likestatus = "likealot"
+ elif likes - dislikes > 0:
+ likestatus = "like"
+ context = {
+ "email": email,
+ "fullname": store.get_sender_name(email),
+ "mm_user": mm_user,
+ "creation": dateutil.parser.parse(mm_user.created_on),
+ "subscriptions": subscriptions,
+ "posts_count": sum([s["posts_count"] for s in subscriptions]),
+ "likes": likes,
+ "dislikes": dislikes,
+ "likestatus": likestatus,
+ }
+ return render(request, "user_public_profile.html", context)