Skip to content

Commit

Permalink
[#1396,merge][s]: fix #1396 (improvements to user UX) by merging bran…
Browse files Browse the repository at this point in the history
…ch 'feature-1396-user-page-ux'.
  • Loading branch information
rufuspollock committed Feb 2, 2012
2 parents ff90b3f + a359ea9 commit a22624f
Show file tree
Hide file tree
Showing 9 changed files with 167 additions and 63 deletions.
5 changes: 1 addition & 4 deletions ckan/controllers/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,10 @@ def index(self):
return render('user/list.html')

def read(self, id=None):

context = {'model': model,
'user': c.user or c.author}

data_dict = {'id':id,
'user_obj':c.userobj}

try:
check_access('user_show',context, data_dict)
except NotAuthorized:
Expand All @@ -103,7 +100,7 @@ def read(self, id=None):
c.user_dict = user_dict
c.is_myself = user_dict['name'] == c.user
c.about_formatted = self._format_about(user_dict['about'])

c.created_formatted = h.date_str_to_datetime(user_dict['created']).strftime('%b %d, %Y')
return render('user/read.html')

def me(self):
Expand Down
11 changes: 9 additions & 2 deletions ckan/lib/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,10 +253,17 @@ def icon(name, alt=None):
return icon_html(icon_url(name),alt)

def linked_gravatar(email_hash, size=100, default="mm"):
return literal('<a href="http://gravatar.com" target="_blank">%s</a>' % gravatar(email_hash,size,default))
return literal('''<a href="https://gravatar.com/" target="_blank"
title="Update your avatar at gravatar.com">
%s</a>''' %
gravatar(email_hash,size,default)
)

def gravatar(email_hash, size=100, default="mm"):
return literal('<img src="http://gravatar.com/avatar/%s?s=%d&amp;d=%s" />' % (email_hash, size, default))
return literal('''<img src="http://gravatar.com/avatar/%s?s=%d&amp;d=%s"
class="gravatar" />'''
% (email_hash, size, default)
)

def pager_url(page, partial=None, **kwargs):
routes_dict = url.environ['pylons.routes_dict']
Expand Down
10 changes: 9 additions & 1 deletion ckan/logic/action/get.py
Original file line number Diff line number Diff line change
Expand Up @@ -494,9 +494,17 @@ def user_show(context, data_dict):
revision_dict = revision_show(context,{'id':revision.id})
revision_dict['state'] = revision.state
revisions_list.append(revision_dict)

user_dict['activity'] = revisions_list

user_dict['datasets'] = []
dataset_q = model.Session.query(model.Package).join(model.PackageRole
).filter_by(user=user_obj, role=model.Role.ADMIN
).limit(50)

for dataset in dataset_q:
dataset_dict = package_show(context, {'id': dataset.id})
user_dict['datasets'].append(dataset_dict)

return user_dict

def package_show_rest(context, data_dict):
Expand Down
82 changes: 67 additions & 15 deletions ckan/public/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
body.no-sidebar #sidebar { display: none; }
body.no-sidebar #content {
border-right: 0;
width: 950px;
width: 960px;
}

.header.outer {
Expand Down Expand Up @@ -78,8 +78,9 @@ header .account {
float: right;
}

header .account img {
margin-bottom: -3px;
header .account img.gravatar {
margin: 0 5px -5px 0;
border-radius: 3px;
}


Expand Down Expand Up @@ -671,11 +672,72 @@ ul.userlist .badge {
margin-top: 5px;
}


/* ================== */
/* = User Read page = */
/* ================== */

body.user.read #sidebar { display: none; }
body.user.read #content {
border-right: 0;
width: 960px;
}

.user.read .page_heading {
font-weight: bold;
}

.user.read .page_heading img.gravatar {
padding: 2px;
border: solid 1px #ddd;
vertical-align: middle;
margin-right: 5px;
margin-top: -3px;
}

.user.read .page_heading .fullname {
font-weight: normal;
color: #999;
}

.user.read .rule {
clear: both;
margin-bottom: 15px;
padding-top: 20px;
border-bottom: 1px solid #ddd;
}

.vcard dt {
width: 115px;
float: left;
font-weight: normal;
color: #999;
}

.vcard dd {
margin-left: 115px;
}

.user.read ul.stats {
margin-left: 0;
padding-left: 0;
}

.user.read ul.stats li {
display: inline-block;
color: inherit;
width: 115px;
}

.user.read ul.stats li strong {
font-size: 36px;
display: block;
line-height: 35px;
}

.user.read ul.stats li span {
color: #999;
}


/* ========================= */
/* = Dataset Snapshot View = */
Expand Down Expand Up @@ -925,16 +987,6 @@ ul.dataset-edit-nav li a:hover {
}



.gravatar {
border: 1px solid #777;
padding: 1px;
width: 120px;
height: 120px;
margin: 0 auto 10px auto;
}


/* ===================== */
/* = Edit Dataset Page = */
/* ===================== */
Expand Down Expand Up @@ -1263,7 +1315,7 @@ body.package.read #sidebar li.widget-container {
body.package.resource_read #sidebar { display: none; }
body.package.resource_read #content {
border-right: 0;
width: 950px;
width: 960px;
}

.resource_read .notes {
Expand Down
2 changes: 1 addition & 1 deletion ckan/templates/layout_base.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
<header class="container">
<div class="menu account">
<span class="ckan-logged-in" style="display: none;">
<a href="${h.url_for(controller='user',action='me')}">${h.gravatar((c.userobj.email_hash if c and c.userobj else ''),size=16)}${c.user}</a>
<a href="${h.url_for(controller='user',action='me')}">${h.gravatar((c.userobj.email_hash if c and c.userobj else ''),size=20)}${c.user}</a>
<a href="${h.url_for('/user/logout')}">Logout</a>
</span>
<span class="ckan-logged-out">
Expand Down
93 changes: 63 additions & 30 deletions ckan/templates/user/read.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,72 @@
py:strip="">

<py:def function="page_title">${c.user_dict['display_name']} - User</py:def>
<py:def function="page_heading">${c.user_dict['display_name']}</py:def>
<py:def function="body_class">user-view</py:def>

<py:match path="primarysidebar">
<div class="gravatar">
${h.gravatar(c.user_dict['email_hash'],120)}
</div>
<li class="widget-container widget_text" py:if="not c.hide_welcome_message">
<h3>Activity</h3>
<ul>
<li><strong>Number of edits:</strong> ${c.user_dict['number_of_edits']}</li>
<li><strong>Number of datasets administered:</strong> ${c.user_dict['number_administered_packages']}</li>
</ul>
</li>
</py:match>

<div py:match="content">
<py:if test="c.is_myself">
<h3>My Account</h3>

<p>You are logged in.</p>
<ul>
<li>Your API key is: ${c.user_dict['apikey']}</li>
</ul>
<py:def function="page_heading">
${h.linked_gravatar(c.user_dict['email_hash'],48)}
<span class="username">
${c.user_dict['name']}
</span>
<py:if test="c.user_dict['fullname']">
<span class="fullname">
(${c.user_dict['fullname']})
</span>
</py:if>

<div class="about">
${c.about_formatted}
</py:def>

<div py:match="content" py:strip="">
<div class="row summary">
<div class="span-12">
<dl class="vcard">
<dt>Name</dt>
<dd>${c.user_dict['fullname'] or 'No name provided'}</dd>
<dt>Email</dt>
<dd>
<py:if test="c.user_dict['email']">
${h.mail_to(c.user_dict['email'], encode='javascript')}
</py:if>
No email
</dd>
<dt>Member since</dt>
<dd>${c.created_formatted}</dd>
<dt>About</dt>
<dd>${c.about_formatted}</dd>
<py:if test="c.is_myself">
<!--checkpoint:is-myself-->
<dt>API Key</dt>
<dd>
${c.user_dict['apikey']}
<br />
<em>&ndash; Note: your API key is visible only to you!</em>
</dd>
</py:if>
</dl>
</div>
<div class="span-11">
<ul class="stats">
<li>
<strong>${c.user_dict['number_administered_packages']}</strong>
<span>Datasets</span>
</li>
<li>
<strong>${c.user_dict['number_of_edits']}</strong>
<span>Edits</span>
</li>
</ul>
</div>
</div>
<div class="rule"></div>

<div class="changes">
<h3>Recent changes</h3>
${revision_list_from_dict(c.user_dict['activity'])}
<div class="row listing">
<div class="datasets span-12">
<h2>Datasets</h2>
${package_list_from_dict(c.user_dict['datasets'])}
</div>
<div class="changes span-12">
<h2>Public Activity</h2>
<py:if test="c.user_dict['activity']">
${revision_list_from_dict(c.user_dict['activity'])}
</py:if>
</div>
</div>
</div>

Expand Down
13 changes: 5 additions & 8 deletions ckan/tests/functional/test_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,17 +48,14 @@ def test_user_read(self):
main_res = self.main_div(res)
assert 'annafan' in res, res
assert 'Logged in' not in main_res, main_res
assert 'My Account' not in main_res, main_res
assert 'checkpoint:is-myself' not in main_res, main_res
assert 'about' in main_res, main_res
assert 'I love reading Annakarenina' in res, main_res
self.check_named_element(res, 'a',
'http://anna.com',
'target="_blank"',
'rel="nofollow"')
assert 'Edit Profile' not in main_res, main_res
assert 'Number of edits:</strong> 3' in res, res
assert 'Number of datasets administered:</strong> 1' in res, res
assert 'Revision History' in res, res

def test_user_read_without_id(self):
offset = '/user/'
Expand All @@ -74,15 +71,15 @@ def test_user_read_without_id_but_logged_in(self):
res = self.app.get(offset, status=200, extra_environ={'REMOTE_USER': str(user.name)})
main_res = self.main_div(res)
assert 'annafan' in main_res, main_res
assert 'My Account' in main_res, main_res
assert 'checkpoint:is-myself' in main_res, main_res

def test_user_read_logged_in(self):
user = model.User.by_name(u'annafan')
offset = '/user/%s' % user.id
res = self.app.get(offset, extra_environ={'REMOTE_USER': str(user.name)})
main_res = self.main_div(res)
assert 'annafan' in res, res
assert 'My Account' in main_res, main_res
assert 'checkpoint:is-myself' in main_res, main_res
assert 'Edit Profile' in main_res, main_res

def test_user_read_about_unfinished(self):
Expand Down Expand Up @@ -181,7 +178,7 @@ def test_login(self):
res = res.follow()
assert_equal(res.status, 200)
assert 'testlogin is now logged in' in res.body
assert 'My Account' in res.body
assert 'checkpoint:is-myself' in res.body

# check user object created
user = model.User.by_name(username)
Expand Down Expand Up @@ -262,7 +259,7 @@ def test_apikey(self):

offset = url_for(controller='user', action='read', id='okfntest')
res = self.app.get(offset, extra_environ={'REMOTE_USER': 'okfntest'})
assert 'Your API key is: %s' % user.apikey in res, res
assert user.apikey in res, res

def test_user_create(self):
# create/register user
Expand Down
4 changes: 2 additions & 2 deletions ckan/tests/lib/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ def test_time_ago_in_words_from_str(self):

def test_gravatar(self):
email = 'zephod@gmail.com'
expected =['<a href="http://gravatar.com" target="_blank">', '<img src="http://gravatar.com/avatar/7856421db6a63efa5b248909c472fbd2?s=200&amp;d=mm" />', '</a>']
expected =['<a href="https://gravatar.com/"', '<img src="http://gravatar.com/avatar/7856421db6a63efa5b248909c472fbd2?s=200&amp;d=mm"', '</a>']
# Hash the email address
import hashlib
email_hash = hashlib.md5(email).hexdigest()
res = h.linked_gravatar(email_hash, 200)
for e in expected:
assert e in res, e
assert e in res, (e,res)
10 changes: 10 additions & 0 deletions ckan/tests/logic/test_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,16 @@ def test_05_user_show_edits(self):
assert_equal(set(edit['packages']), set(('warandpeace', 'annakarenina')))
assert 'id' in edit

def test_05b_user_show_datasets(self):
postparams = '%s=1' % json.dumps({'id':'annafan'})
res = self.app.post('/api/action/user_show', params=postparams)
res_obj = json.loads(res.body)
result = res_obj['result']
datasets = result['datasets']
assert_equal(len(datasets), 1)
dataset = result['datasets'][0]
assert_equal(dataset['name'], u'annakarenina')

def test_06_tag_list(self):
postparams = '%s=1' % json.dumps({})
res = self.app.post('/api/action/tag_list', params=postparams)
Expand Down

0 comments on commit a22624f

Please sign in to comment.