user profile (bug 543597)
This commit is contained in:
Родитель
97e30b275f
Коммит
66db367524
|
@ -15,8 +15,17 @@ from users.models import UserProfile
|
|||
class AddonManager(amo.models.ManagerBase):
|
||||
|
||||
def public(self):
|
||||
"""Get public add-ons only"""
|
||||
return self.filter(inactive=False, status=amo.STATUS_PUBLIC)
|
||||
|
||||
def experimental(self):
|
||||
"""Get only experimental add-ons"""
|
||||
return self.filter(inactive=False, status__in=EXPERIMENTAL_STATUSES)
|
||||
|
||||
def valid(self):
|
||||
"""Get valid, enabled add-ons only"""
|
||||
return self.filter(status__in=amo.VALID_STATUSES, inactive=False)
|
||||
|
||||
def featured(self, app):
|
||||
"""Filter for all featured add-ons for an application in all locales."""
|
||||
today = date.today()
|
||||
|
|
|
@ -64,6 +64,8 @@ STATUS_CHOICES = {
|
|||
}
|
||||
|
||||
EXPERIMENTAL_STATUSES = (STATUS_SANDBOX, STATUS_PENDING, STATUS_NOMINATED)
|
||||
VALID_STATUSES = (STATUS_SANDBOX, STATUS_PENDING, STATUS_NOMINATED,
|
||||
STATUS_PUBLIC, STATUS_LISTED)
|
||||
|
||||
# Add-on author roles.
|
||||
AUTHOR_ROLE_NONE = 0
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import random
|
||||
|
||||
import jinja2
|
||||
|
||||
from jingo import register
|
||||
from jingo import register, env
|
||||
|
||||
|
||||
@register.filter
|
||||
|
@ -23,5 +25,23 @@ def emaillink(email):
|
|||
|
||||
@register.filter
|
||||
def user_link(user):
|
||||
return jinja2.Markup('<a href="%s">%s</a>' %
|
||||
(user.get_absolute_url(), user.display_name))
|
||||
return jinja2.Markup(_user_link(user))
|
||||
|
||||
|
||||
@register.filter
|
||||
def users_list(users):
|
||||
return jinja2.Markup(', '.join(map(_user_link, users)))
|
||||
|
||||
|
||||
def _user_link(user):
|
||||
return u'<a href="%s">%s</a>' % (
|
||||
user.get_absolute_url(), unicode(jinja2.escape(user.display_name)))
|
||||
|
||||
|
||||
@register.filter
|
||||
def user_vcard(user, table_class='person-info',
|
||||
about_addons=True):
|
||||
c = {'profile': user, 'table_class': table_class,
|
||||
'about_addons': about_addons}
|
||||
t = env.get_template('users/vcard.html').render(**c)
|
||||
return jinja2.Markup(t)
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
from datetime import datetime
|
||||
import hashlib
|
||||
import random
|
||||
import re
|
||||
import string
|
||||
import urlparse
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.contrib.auth.models import User as DjangoUser
|
||||
from django.db import models
|
||||
|
@ -64,6 +67,23 @@ class UserProfile(amo.models.ModelBase):
|
|||
def get_absolute_url(self):
|
||||
return reverse('users.profile', args=[self.id])
|
||||
|
||||
@amo.cached_property
|
||||
def addons_listed(self):
|
||||
"""public add-ons this user is listed as author of"""
|
||||
return self.addons.valid().filter(addonuser__listed=True)
|
||||
|
||||
@property
|
||||
def picture_url(self):
|
||||
# TODO this used to be /user/1234/picture, and the regex stuff was
|
||||
# in htaccess. Should we let the web server take care of it again?
|
||||
split_id = re.match(r'((\d*?)(\d{0,3}?))\d{1,3}$', str(self.id))
|
||||
return (settings.MEDIA_URL + 'img/uploads/userpics/%s/%s/%s.jpg' % (
|
||||
split_id.group(2) or 0, split_id.group(1) or 0, self.id))
|
||||
|
||||
@amo.cached_property
|
||||
def is_developer(self):
|
||||
return bool(self.addons.filter(authors=self, addonuser__listed=True)[:1])
|
||||
|
||||
@property
|
||||
def display_name(self):
|
||||
if not self.nickname:
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
{% extends "base_side_categories.html" %}
|
||||
|
||||
{% block title %}{{ page_title(_('User Info for {0}')|f(profile.display_name)) }}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if user.is_staff: %}{# TODO restrict this to admins with user edit rights only #}
|
||||
<a href="{{ url("admin:users_userprofile_change", profile.id) }}">{{ _('Edit User') }}</a>
|
||||
{% endif %}
|
||||
|
||||
<div class="vcard">
|
||||
<h2 class="fn n">{{ profile.display_name }}</h2>
|
||||
<div class="featured">
|
||||
<div class="featured-inner object-lead">
|
||||
<h3>{{ _('About Me')}}</h3>
|
||||
<img class="avatar thumbnail" alt="" src="{{ profile.picture_url }}"/>
|
||||
<div class="object-content">
|
||||
{% if profile.is_developer %}
|
||||
<p class="user-role">{{ _('Add-ons Developer') }}</p>
|
||||
{% endif %}
|
||||
|
||||
{{ profile|user_vcard(table_class='', about_addons=False) }}
|
||||
|
||||
</div>{# /object-content #}
|
||||
{% if profile.bio %}{# TODO purified field #}
|
||||
<h4>{{ _('In a little more detail…') }}</h4>
|
||||
<div class="prose userinput">
|
||||
<p class="description">{{ profile.bio|nl2br }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>{# /featured-inner #}
|
||||
</div>{# /featured #}
|
||||
</div>{# /vcard #}
|
||||
|
||||
{% if profile.is_developer %}
|
||||
<div class="separated-listing">
|
||||
{{ separated_list_items(profile.addons_listed, src='userprofile') }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if profile.reviews.all()|length %}
|
||||
<div class="primary">
|
||||
<h3>{{ _('My Reviews') }}</h3>
|
||||
<div class="article">
|
||||
{% for review in profile.reviews.all() %}
|
||||
{% set addon = review.version.addon %}
|
||||
<div class="hreview">
|
||||
<h4 class="summary">
|
||||
<a class="url" href="{{ addon.get_absolute_url() }}">{{ addon.name }}</a>
|
||||
</h4>
|
||||
<p class="description" locale="{{ review.body.locale }}">
|
||||
{{ review.body|nl2br }}
|
||||
</p>
|
||||
<p>
|
||||
{{ review.rating|stars }}
|
||||
<abbr class="dtreviewed" title="{{ review.created|isotime }}">
|
||||
{{ review.created|datetime }}
|
||||
</abbr>
|
||||
</p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>{# /article #}
|
||||
</div>{# /primary #}
|
||||
{% endif %}
|
||||
|
||||
{% if own_coll or fav_coll %}
|
||||
<div class="secondary" role="complementary">
|
||||
<h3>{{ _('My Collections') }}</h3>
|
||||
<div class="secondary-item-list">
|
||||
{{ user_collection_list(heading=_('Favorites'), collections=fav_coll) }}
|
||||
{{ user_collection_list(heading=_('Created by Me'),
|
||||
collections=own_coll) }}
|
||||
</div>
|
||||
</div>{# secondary #}
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
|
@ -0,0 +1,58 @@
|
|||
<div>
|
||||
<table class="{{ table_class }}" summary="{{ _('Developer Information') }}">
|
||||
<tbody>
|
||||
{# TODO msgctxt for table headers #}
|
||||
<tr>
|
||||
<th>{{ _('Name') }}</th>
|
||||
<td class="fn n">{{ profile.display_name }}</td>
|
||||
</tr>
|
||||
{% if profile.location %}
|
||||
<tr>
|
||||
<th>{{ _('Location') }}</th>
|
||||
<td class="adr">{{ profile.location }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if profile.occupation %}
|
||||
<tr>
|
||||
<th>{{ _('Occupation') }}</th>
|
||||
<td class="role">{{ profile.occupation }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{# TODO cleaned external links #}
|
||||
{% if profile.homepage %}
|
||||
<tr>
|
||||
<th>{{ _('Homepage') }}</th>
|
||||
<td><a class="url" href="{{ profile.homepage }}">{{ profile.homepage }}</a></td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if not profile.emailhidden %}
|
||||
<tr>
|
||||
<th>{{ _('Email address') }}</th>
|
||||
<td>{{ profile.email|emaillink }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<th>{{ _('User since') }}</th>
|
||||
<td>{{ profile.created|datetime }}</td>
|
||||
</tr>
|
||||
{% if about_addons %}
|
||||
<tr>
|
||||
<th>{{ _('Number of Add-ons Developed') }}</th>
|
||||
<td>
|
||||
<a href="{{ profile.get_absolute_url() }}">
|
||||
{% trans num=profile.addons_listed|length %}
|
||||
{{ num }} Add-on
|
||||
{% pluralize %}
|
||||
{{ num }} Add-ons
|
||||
{% endtrans %}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>{{ _('Average rating for their Add-ons') }}</th>
|
||||
<td>{{ profile.averagerating|float|stars }}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
|
@ -1,6 +1,10 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from nose.tools import eq_
|
||||
|
||||
from users.helpers import emaillink, user_link
|
||||
from users.helpers import emaillink, user_link, users_list
|
||||
from users.models import UserProfile
|
||||
|
||||
|
||||
|
@ -19,4 +23,18 @@ def test_emaillink():
|
|||
|
||||
def test_user_link():
|
||||
u = UserProfile(firstname='John', lastname='Connor', pk=1)
|
||||
eq_(user_link(u), """<a href="/users/1">John Connor</a>""")
|
||||
eq_(user_link(u), '<a href="%s">John Connor</a>' %
|
||||
reverse('users.profile', args=[1]))
|
||||
|
||||
|
||||
def test_users_list():
|
||||
u1 = UserProfile(firstname='John', lastname='Connor', pk=1)
|
||||
u2 = UserProfile(firstname='Sarah', lastname='Connor', pk=2)
|
||||
eq_(users_list([u1, u2]), ', '.join((user_link(u1), user_link(u2))))
|
||||
|
||||
|
||||
def test_user_link_unicode():
|
||||
"""make sure helper won't choke on unicode input"""
|
||||
u = UserProfile(firstname=u'Jürgen', lastname=u'Müller', pk=1)
|
||||
eq_(user_link(u), u'<a href="%s">Jürgen Müller</a>' %
|
||||
reverse('users.profile', args=[1]))
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
from django.contrib.auth import logout
|
||||
from django.http import HttpResponseRedirect, HttpResponse
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import get_object_or_404
|
||||
|
||||
import jingo
|
||||
|
||||
import amo
|
||||
from bandwagon.models import Collection
|
||||
|
||||
from .models import UserProfile
|
||||
from .signals import logged_out
|
||||
|
||||
|
@ -11,7 +14,25 @@ from .signals import logged_out
|
|||
def profile(request, user_id):
|
||||
"""user profile display page"""
|
||||
user = get_object_or_404(UserProfile, id=user_id)
|
||||
return HttpResponse()
|
||||
|
||||
# get user's own and favorite collections, if they allowed that
|
||||
if user.display_collections:
|
||||
own_coll = Collection.objects.filter(
|
||||
collectionuser__user=user,
|
||||
collectionuser__role=amo.COLLECTION_ROLE_ADMIN,
|
||||
listed=True).order_by('name')
|
||||
else:
|
||||
own_coll = []
|
||||
if user.display_collections_fav:
|
||||
fav_coll = Collection.objects.filter(
|
||||
collectionsubscription__user=user,
|
||||
listed=True).order_by('name')
|
||||
else:
|
||||
fav_coll = []
|
||||
|
||||
return jingo.render(request, 'users/profile.html',
|
||||
{'profile': user, 'own_coll': own_coll,
|
||||
'fav_coll': fav_coll})
|
||||
|
||||
|
||||
def logout_view(request):
|
||||
|
|
Загрузка…
Ссылка в новой задаче