ship impala profile pages! (bug 683238)

This commit is contained in:
Chris Van 2011-10-06 11:46:25 -07:00
Родитель c658e36308
Коммит 9aaafa2c98
10 изменённых файлов: 158 добавлений и 378 удалений

Просмотреть файл

@ -95,9 +95,7 @@
</aside>
<section class="primary">
<div class="vcard">
{% with profile=author, table_class='person-info' %}
{% include "users/impala/vcard.html" %}
{% endwith %}
{{ author|user_vcard }}
</div>
<div class="prose">
{% if author.bio %}

Просмотреть файл

@ -61,10 +61,8 @@ def _user_link(user):
@register.filter
def user_vcard(user, table_class='person-info',
about_addons=True):
c = {'profile': user, 'table_class': table_class,
'about_addons': about_addons}
def user_vcard(user, table_class='person-info', is_profile=False):
c = {'profile': user, 'table_class': table_class, 'is_profile': is_profile}
t = env.get_template('users/vcard.html').render(**c)
return jinja2.Markup(t)

Просмотреть файл

@ -1,107 +0,0 @@
{% extends "impala/base.html" %}
{% block title %}{{ page_title(_('User Info for {0}')|f(profile.name)) }}{% endblock %}
{% block js %}{% include("amo/recaptcha_js.html") %}{% endblock %}
{% block bodyclass %}meet gutter{% endblock %}
{% block content %}
{% include "messages.html" %}
{{ impala_breadcrumbs([(None, profile.name)]) }}
<div id="profile-actions" class="c">
{% if own_profile %}
<a class="button" href="{{ url('users.edit') }}">{{ _('Edit profile') }}</a>
{% endif %}
{% if edit_any_user %}
{# TODO XXX Once zamboni can delete users, uncomment this line. bug 595035 #}
{# <a href="{{ url("admin:users_userprofile_change", profile.id) }}">{{ _('Manage user') }}</a> #}
<a class="button" href="{{ remora_url("/admin/users/%s" % profile.id) }}">{{ _('Manage user') }}</a>
{% endif %}
{% if abuse_form %}
<a id="report-user-abuse" class="button" href="{{ url('users.abuse', profile.id) }}">
{{ _('Report user') }}</a>
{% endif %}
</div>
<h1 class="fn n">{{ profile.name }}</h1>
<div class="island c">
<aside class="secondary">
<img class="avatar" src="{{ profile.picture_url }}"
{% if not profile.picture_type %}alt="{{ _('No Photo') }}"{% endif %}>
{% if profile.is_developer %}
<div class="user-role"><p>{{ _('Add-ons Developer') }}</p></div>
{% endif %}
</aside>
<section class="primary">
<h2>{{ _('About me') }}</h2>
<div class="vcard">
{% with table_class='person-info', is_profile=True %}
{% include "users/impala/vcard.html" %}
{% endwith %}
</div>
<div class="prose">
{% if profile.bio %}
<h3>{{ _('In a little more detail...') }}</h3>
<p class="intro">{{ profile.bio|nl2br }}</p>
{% endif %}
</div>
</section>
</div>
{% if addons.object_list %}
<div id="my-addons" class="island primary listing c">
<h2>{{ _("Add-ons I've created") }}</h2>
{% cache addons.object_list %}
<div class="items">
{{ impala_addon_listing_items(addons.object_list, field=sorting, src='userprofile') }}
</div>
{{ addons|impala_paginator }}
{% endcache %}
</div>
{% endif %}
{% if own_coll or fav_coll %}
<aside class="secondary" id="my-collections">
<div class="island">
<h2>{{ _('My Collections') }}</h2>
{{ user_collection_list(heading=_('Followed by Me'), collections=fav_coll,
link=url('collections.following'), id='my-favorite') }}
{{ user_collection_list(heading=_('Created by Me'), collections=own_coll,
id='my-created',
link=url('collections.user', profile.username)) }}
</div>
</aside>
{% endif %}
<div class="island primary c{{ ' full' if not (own_col or fav_coll) }}" id="reviews">
{% cache reviews %}
<h2>{{ _('My Reviews') }}</h2>
<div class="items">
{% if reviews %}
{% for review in reviews %}
{% set addon = review.addon %}
{% with show_addon = True %}
{% include "reviews/review.html" %}
{% endwith %}
{% endfor %}
{{ edit_review_form() }}
{% else %}
<p class="no-reviews">{{ _('No add-on reviews yet.') }}</p>
{% endif %}
</div>
{% endcache %}
</div>
{% endblock %}
{% block popups %}
{{ report_review_popup() }}
{% if abuse_form %}
<div id="report-user-modal" class="modal hidden">
<a href="#" class="close">{{ _('close') }}</a>
<h2>{{ _('Report User') }}</h2>
{{ user_report_abuse(hide=False, profile=profile) }}
</div>
{% endif %}
{% endblock %}

Просмотреть файл

@ -1,54 +0,0 @@
<table class="{{ table_class }}">
<caption>{{ _('Developer Information') }}</caption>
<tbody>
<tr>
<th>{{ _('Name') }}</th>
<td class="fn n">{{ profile.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 %}
{% if profile.homepage %}
<tr>
<th>{{ _('Homepage') }}</th>
<td><a class="url" href="{{ profile.homepage|external_url }}">
{{ profile.homepage }}</a></td>
</tr>
{% endif %}
{% if not profile.emailhidden %}
<tr>
<th>{{ _('Email address') }}</th>
<td>{{ emaillink(profile.email) }}</td>
</tr>
{% endif %}
<tr>
<th>{{ _('User since') }}</th>
<td>{{ profile.created|datetime }}</td>
</tr>
<tr>
<th>{{ _('Number of add-ons developed') }}</th>
<td class="num-addons">
<a href="{{ '#my-addons' if is_profile else profile.get_url_path() }}">
{% 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>
</tbody>
</table>

Просмотреть файл

@ -1,105 +1,105 @@
{% extends "base_side_categories.html" %}
{% extends "impala/base.html" %}
{% block title %}{{ page_title(_('User Info for {0}')|f(profile.name)) }}{% endblock %}
{% block js %}{% include("amo/recaptcha_js.html") %}{% endblock %}
{% block bodyclass %}meet gutter profile{% endblock %}
{% block content %}
<div class="vcard">
{{ breadcrumbs([(None, profile.name)]) }}
<h2 class="fn n">{{ profile.name }}</h2>
{% include "messages.html" %}
<div class="featured">
<div class="featured-inner object-lead">
<h3>{{ _('About Me')}}</h3>
{% include "messages.html" %}
<img class="avatar thumbnail"
alt="{% if not profile.picture_type %}{{ _('No Photo') }}{% endif %}"
src="{{ profile.picture_url }}" />
<div class="object-content">
{% if profile.is_developer %}
<p class="user-role">{{ _('Add-ons Developer') }}</p>
{% endif %}
{{ impala_breadcrumbs([(None, profile.name)]) }}
<div id="profile-actions" class="c">
{% if own_profile %}
<a id="edit-profile" class="button" href="{{ url('users.edit') }}">{{ _('Edit profile') }}</a>
{% endif %}
{% if edit_any_user %}
{# TODO XXX Once zamboni can delete users, uncomment this line. bug 595035 #}
{# <a href="{{ url("admin:users_userprofile_change", profile.id) }}">{{ _('Manage user') }}</a> #}
<a id="manage-user" class="button" href="{{ remora_url("/admin/users/%s" % profile.id) }}">{{ _('Manage user') }}</a>
{% endif %}
{% if abuse_form %}
<a id="report-user-abuse" class="button" href="{{ url('users.abuse', profile.id) }}">
{{ _('Report user') }}</a>
{% endif %}
</div>
<h1 class="fn n">{{ profile.name }}</h1>
{{ profile|user_vcard(table_class='', about_addons=False) }}
{% 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 %}
{% if edit_any_user or own_profile %}
<p class="editprofile">
{% if own_profile %}
<a href="{{ url("users.edit") }}">{{ _('Edit Profile') }}</a>
{% endif %}
{% if edit_any_user %}
{# TODO XXX Once zamboni can delete users, uncomment this line. bug 595035 #}
{# <a href="{{ url("admin:users_userprofile_change", profile.id) }}">{{ _('Manage User') }}</a> #}
<a href="{{ remora_url("/admin/users/%s" % profile.id) }}">{{ _('Manage User') }}</a>
{% endif %}
</p>
{% endif %}
{% if abuse_form %}
<div class="abuse-wrapper">{{ user_report_abuse(hide=True, profile=profile) }}</div>
{% endif %}
</div>{# /object-content #}
</div>{# /featured-inner #}
</div>{# /featured #}
</div>{# /vcard #}
<div class="island c">
<aside class="secondary">
<img class="avatar" src="{{ profile.picture_url }}"
{% if not profile.picture_type %}alt="{{ _('No Photo') }}"{% endif %}>
{% if profile.is_developer %}
<div class="user-role"><p>{{ _('Add-ons Developer') }}</p></div>
{% endif %}
</aside>
<section class="primary">
<h2>{{ _('About me') }}</h2>
<div class="vcard">
{{ profile|user_vcard(is_profile=True) }}
</div>
<div class="prose">
{% if profile.bio %}
<h3>{{ _('In a little more detail...') }}</h3>
<p class="intro">{{ profile.bio|nl2br }}</p>
{% endif %}
</div>
</section>
</div>
{% if addons.object_list %}
<h3>{{ _("Add-ons I've created") }}</h3>
{% cache addons.object_list %}
<div class="featured listing">
<div class="featured-inner">
{{ addon_listing_items(addons.object_list, src='userprofile') }}
</div>
<div id="my-addons" class="island primary listing c">
<h2>{{ _("Add-ons I've created") }}</h2>
{% cache addons.object_list %}
<div class="items">
{{ impala_addon_listing_items(addons.object_list, field=sorting, src='userprofile') }}
</div>
{{ addons|impala_paginator }}
{% endcache %}
</div>
{{ addons|paginator }}
{% endcache %}
{% endif %}
{% if own_coll or fav_coll %}
<aside class="secondary" id="my-collections">
<div class="island">
<h2>{{ _('My Collections') }}</h2>
{{ user_collection_list(heading=_('Followed by Me'), collections=fav_coll,
link=url('collections.following'), id='my-favorite') }}
{{ user_collection_list(heading=_('Created by Me'), collections=own_coll,
id='my-created',
link=url('collections.user', profile.username)) }}
</div>
</aside>
{% endif %}
<div class="island primary c{{ ' full' if not (own_col or fav_coll) }}" id="reviews">
{% cache reviews %}
<div class="primary" id="userprofile-reviews">
<h3>{{ _('My Reviews') }}</h3>
<div class="article">
<h2>{{ _('My Reviews') }}</h2>
<div class="items">
{% if reviews %}
{% for review in reviews %}
{% set addon = review.addon %}
<div class="review-detail">
<h4 class="summary">
<a class="url" href="{{ addon.get_url_path() }}">{{ addon.name }}</a>
</h4>
<p class="description" {{ review.body|locale_html }}>
{{ review.body|nl2br }}
</p>
<p>
{{ review.rating|stars }}
<abbr class="dtreviewed" title="{{ review.created|isotime }}">
{{ review.created|datetime }}
</abbr>
</p>
</div>
{% with show_addon = True %}
{% include "reviews/review.html" %}
{% endwith %}
{% endfor %}
{{ edit_review_form() }}
{% else %}
<p class="noreviews">{{ _('No add-on reviews yet.') }}</p>
<p class="no-reviews">{{ _('No add-on reviews yet.') }}</p>
{% endif %}
</div>{# /article #}
</div>{# /primary #}
</div>
{% endcache %}
{% if own_coll or fav_coll %}
<div class="secondary" role="complementary">
<h3>{{ _('My Collections') }}</h3>
<div class="secondary-item-list n">
{{ user_collection_list(heading=_('Followed by Me'), collections=fav_coll,
link=url('collections.following')) }}
{{ user_collection_list(heading=_('Created by Me'), collections=own_coll,
link=url('collections.user', profile.username)) }}
</div>
</div>{# secondary #}
{% endif %}
</div>
{% endblock %}
{% block popups %}
{{ report_review_popup() }}
{% if abuse_form %}
<div id="report-user-modal" class="modal hidden">
<a href="#" class="close">{{ _('close') }}</a>
<h2>{{ _('Report User') }}</h2>
{{ user_report_abuse(hide=False, profile=profile) }}
</div>
{% endif %}
{% endblock %}

Просмотреть файл

@ -1,60 +1,54 @@
<div>
<table class="{{ table_class }}">
<caption>{{ _('Developer Information') }}</caption>
<tbody>
{# TODO msgctxt for table headers #}
<table class="{{ table_class }}">
<caption>{{ _('Developer Information') }}</caption>
<tbody>
<tr>
<th>{{ _('Name') }}</th>
<td class="fn n">{{ profile.name }}</td>
</tr>
{% if profile.location %}
<tr>
<th>{{ _('Name') }}</th>
<td class="fn n">{{ profile.name }}</td>
<th>{{ _('Location') }}</th>
<td class="adr">{{ profile.location }}</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|external_url
}}">{{ profile.homepage }}</a></td>
</tr>
{% endif %}
{% if not profile.emailhidden %}
<tr>
<th>{{ _('Email address') }}</th>
<td>{{ emaillink(profile.email) }}</td>
</tr>
{% endif %}
{% endif %}
{% if profile.occupation %}
<tr>
<th>{{ _('User since') }}</th>
<td>{{ profile.created|datetime }}</td>
<th>{{ _('Occupation') }}</th>
<td class="role">{{ profile.occupation }}</td>
</tr>
{% if about_addons %}
<tr>
<th>{{ _('Number of Add-ons Developed') }}</th>
<td>
<a href="{{ profile.get_url_path() }}">
{% 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>
{% endif %}
{% if profile.homepage %}
<tr>
<th>{{ _('Homepage') }}</th>
<td><a class="url" href="{{ profile.homepage|external_url }}">
{{ profile.homepage }}</a></td>
</tr>
{% endif %}
{% if not profile.emailhidden %}
<tr>
<th>{{ _('Email address') }}</th>
<td>{{ emaillink(profile.email) }}</td>
</tr>
{% endif %}
<tr>
<th>{{ _('User since') }}</th>
<td>{{ profile.created|datetime }}</td>
</tr>
<tr>
<th>{{ _('Number of add-ons developed') }}</th>
<td class="num-addons">
<a href="{{ '#my-addons' if is_profile else profile.get_url_path() }}">
{% 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>
</tbody>
</table>

Просмотреть файл

@ -594,9 +594,8 @@ class TestRegistration(UserViewBase):
#self.assertContains(r, 'An email has been sent to your address')
class TestProfile(UserViewBase):
fixtures = ['base/featured',
'users/test_backends']
class TestProfileLinks(UserViewBase):
fixtures = ['base/featured', 'users/test_backends']
def test_edit_buttons(self):
"""Ensure admin/user edit buttons are shown."""
@ -605,16 +604,19 @@ class TestProfile(UserViewBase):
"""Grab profile, return edit links."""
url = reverse('users.profile', args=[id])
r = self.client.get(url)
return pq(r.content)('p.editprofile a')
return pq(r.content)('#profile-actions a')
# Anonymous user.
links = get_links(self.user.id)
eq_(links.length, 0)
eq_(links.length, 1)
eq_(links.eq(0).attr('href'), reverse('users.abuse',
args=[self.user.id]))
# Non-admin, someone else's profile.
self.client.login(username='jbalogh@mozilla.com', password='foo')
links = get_links(9945)
eq_(links.length, 0)
eq_(links.length, 1)
eq_(links.eq(0).attr('href'), reverse('users.abuse', args=[9945]))
# Non-admin, own profile.
links = get_links(self.user.id)
@ -627,6 +629,11 @@ class TestProfile(UserViewBase):
GroupUser.objects.create(group=admingroup, user=self.user_profile)
cache.clear()
links = get_links(self.user.id)
eq_(links.length, 2)
eq_(links.filter('#edit-profile').length, 1)
eq_(links.filter('#manage-user').length, 1)
# TODO XXX Uncomment this when zamboni can delete users. Bug 595035
#links = get_links(9945)
#eq_(links.length, 1)
@ -651,32 +658,25 @@ class TestProfile(UserViewBase):
assert hasattr(request.amo_user, 'favorite_addons')
assert hasattr(request.user.get_profile(), 'favorite_addons')
def test_profile_addons_sort(self):
u = UserProfile.objects.get(id=9945)
for a in Addon.objects.public():
AddonUser.objects.create(user=u, addon=a)
r = self.client.get(reverse('users.profile', args=[9945]))
addons = r.context['addons'].object_list
assert all(addons[i].weekly_downloads >= addons[i + 1].weekly_downloads
for i in xrange(len(addons) - 1))
class TestImpalaProfile(amo.tests.TestCase):
class TestProfileSections(amo.tests.TestCase):
fixtures = ['base/apps', 'base/users', 'base/addon_3615',
'base/addon_5299_gcal', 'base/collections',
'reviews/dev-reply.json']
def setUp(self):
self.user = UserProfile.objects.get(id=10482)
self.url = reverse('i_users.profile', args=[self.user.id])
self.url = reverse('users.profile', args=[self.user.id])
def test_my_addons(self):
AddonUser.objects.create(user=self.user, addon_id=3615)
AddonUser.objects.create(user=self.user, addon_id=5299)
doc = pq(self.client.get(self.url).content)
r = self.client.get(self.url)
a = r.context['addons'].object_list
eq_(list(a), sorted(a, key=lambda x: x.weekly_downloads, reverse=True))
doc = pq(r.content)
eq_(doc('.num-addons a[href="#my-addons"]').length, 1)
items = doc('#my-addons .item')
eq_(items.length, 2)

Просмотреть файл

@ -21,9 +21,6 @@ detail_patterns = patterns('',
url('^abuse', views.report_abuse, name='users.abuse'),
)
impala_detail_patterns = patterns('',
url('^$', views.impala_profile, name='i_users.profile'),
)
users_patterns = patterns('',
url('^ajax$', views.ajax, name='users.ajax'),
@ -66,7 +63,6 @@ users_patterns = patterns('',
urlpatterns = patterns('',
# URLs for a single user.
('^i/user/(?P<user_id>\d+)/', include(impala_detail_patterns)),
('^user/(?P<user_id>\d+)/', include(detail_patterns)),
('^users/', include(users_patterns)),
)

Просмотреть файл

@ -391,51 +391,6 @@ def logout(request):
def profile(request, user_id):
"""user profile display page"""
user = get_object_or_404(UserProfile, id=user_id)
# get user's own and favorite collections, if they allowed that
if user.display_collections:
own_coll = (Collection.objects.listed().filter(author=user)
.order_by('-created'))[:10]
else:
own_coll = []
if user.display_collections_fav:
fav_coll = (Collection.objects.listed()
.filter(following__user=user)
.order_by('-following__created'))[:10]
else:
fav_coll = []
edit_any_user = acl.action_allowed(request, 'Admin', 'EditAnyUser')
own_profile = request.user.is_authenticated() and (
request.amo_user.id == user.id)
if user.is_developer:
addons = amo.utils.paginate(
request,
user.addons_listed.order_by('-weekly_downloads'))
else:
addons = []
def get_addons(reviews):
if not reviews:
return
qs = Addon.objects.filter(id__in=set(r.addon_id for r in reviews))
addons = dict((addon.id, addon) for addon in qs)
for review in reviews:
review.addon = addons.get(review.addon_id)
reviews = user.reviews.transform(get_addons)
data = {'profile': user, 'own_coll': own_coll, 'reviews': reviews,
'fav_coll': fav_coll, 'edit_any_user': edit_any_user,
'addons': addons, 'own_profile': own_profile,
'abuse_form': AbuseForm(request=request)}
return jingo.render(request, 'users/profile.html', data)
def impala_profile(request, user_id):
user = get_object_or_404(UserProfile, id=user_id)
# Get user's own and favorite collections, if they allowed that.
@ -475,7 +430,7 @@ def impala_profile(request, user_id):
if not own_profile:
data['abuse_form'] = AbuseForm(request=request)
return jingo.render(request, 'users/impala/profile.html', data)
return jingo.render(request, 'users/profile.html', data)
@anonymous_csrf

Просмотреть файл

@ -153,7 +153,7 @@ img.icon {
}
}
.gutter.meet {
.profile {
aside.secondary {
background: #fff;
padding: 0;