Gravatar support. Avatars may be disabled via params or user preference.

FIXME: Remove hardcoded Mozilla skin name (used to choose avatar position)
hinted-selects
Vitaliy Filippov 2014-09-10 15:38:11 +04:00
parent 248f5884d5
commit eb21c917e3
9 changed files with 132 additions and 84 deletions

View File

@ -11,6 +11,12 @@ our $sortkey = 910;
sub get_param_list
{
return (
{
name => 'gravatar_url',
type => 't',
default => 'http://www.gravatar.com/avatar/$MD5',
},
{
name => 'wiki_url',
type => 't',

View File

@ -77,11 +77,13 @@ use constant SETTINGS => {
# CustIS Bug 87696 - Setting to change comments which are allowed to be marked as collapsed by default ("worktime-only")
showhide_comments => { options => ['none', 'worktime', 'all'], default => 'worktime' },
# CustIS Bug 125374 - Select whether to show comments in full page width
comment_width => { options => ['off', 'on'], default => 'off' },
comment_width => { options => ['off', 'on'], default => 'on' },
# CustIS Bug 138596 - Choose whether to hide long comments by default
preview_long_comments => { options => ['off', 'on'], default => 'off' },
# Clear all flag requests when changing bug status to 'closed_bug_status' parameter
clear_requests_on_close => { options => ['off', 'on'], default => 'off' },
# Select whether to show avatar
show_gravatars => { options => ['off', 'on'], default => 'on' },
};
# Initial system groups.

View File

@ -210,6 +210,7 @@ $Bugzilla::messages->{en} = {
'comment_width' => 'Show comments in the full screen width',
'preview_long_comments' => 'Fold long comments',
'clear_requests_on_close' => 'Clear flag requests when closing bugs',
'show_gravatars' => 'Show avatar images (Gravatars)',
},
system_groups => {
admin => 'Administrator group. Usually allows to access <b>all</b> administrative functions.',

View File

@ -49,6 +49,7 @@ use Bugzilla::Field;
use Bugzilla::Group;
use Bugzilla::Status;
use Digest::MD5 qw(md5_hex);
use POSIX;
use DateTime::TimeZone;
use Scalar::Util qw(blessed);
@ -316,6 +317,19 @@ sub cryptpassword
return $pw;
}
sub gravatar_url
{
my ($self, $params) = @_;
my $url = Bugzilla->params->{gravatar_url} or return '';
$url =~ s/\$MD5/md5_hex(lc $self->email)/e or $url =~ s/\$EMAIL/url_quote(lc $self->email)/e;
if ($params)
{
$url .= $url =~ /\?/ ? '&' : '?';
$url .= $params;
}
return $url;
}
sub set_authorizer
{
my ($self, $authorizer) = @_;

BIN
images/noavatar40.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1007 B

View File

@ -538,7 +538,6 @@ input.required, select.required, span.required_explanation {
.bz_first_comment_head, .bz_comment_head, .bz_comment_wthead {
font-weight: normal;
line-height: 32px;
padding-bottom: 2px;
padding-left: 0px;
margin-left: -5px;

View File

@ -5,6 +5,7 @@
.bz_comment_user, .bz_comment_time,
.bz_comment_number, .bz_private_checkbox,
.bz_comment_actions { margin: 0 .5em; white-space: nowrap; }
.bz_comment_avatar { display: block; float: right; margin: -8px 8px 0; }
.bz_comment_user, .bz_comment_time, .bz_comment_user_images,
.bz_comment_worktime, .bz_comment_unmark_wtonly { float: left; }

View File

@ -12,7 +12,11 @@
"<p style='margin: 0'>Perl regular expressions for checking 'See Also' field. Only values that match one of these regexes are allowed. Format:</p>"
_ "<pre style='margin: 8px 0; padding: 4px; background: white;"
_ " border: 1px solid gray;'># Lines that start with # are treated as comments\n&lt;REGEX&gt; &lt;REPLACEMENT&gt;</pre>",
gravatar_url =>
"URL template for Gravatar-like avatars. You can use either \$MD5 or \$EMAIL in it to get avatar picture by user email."
_ " \$EMAIL will be replaced by cleartext user email, so you should only never use it in public networks;"
_ " \$MD5 will be replaced by MD5 hash of user email, just like it is required by real Gravatar service."
_ " You can also disable avatar display by clearing this parameter.",
viewvc_url => "ViewVC query URL for browsing bug code",
wiki_url => "Default MediaWiki URL for bug links",
mediawiki_urls =>

View File

@ -40,6 +40,9 @@
</div>
[% END %]
[% show_avatars = Param('gravatar_url') && user.settings.show_gravatars.value == 'on' %]
[% show_avatars = show_avatars ? (user.settings.skin.value == 'Mozilla' ? 1 : 2) : 0 %]
[% FOREACH comment = comments %]
[% PROCESS a_comment %]
[% END %]
@ -76,95 +79,113 @@
&& (wt_wt && (has_worktime || wt_only) || wt_all)
&& (comment.who == user.id || user.in_group('worktimeadmin'))
%]
<div class="bz_comment
[%- " bz_private" IF comment.is_private %]
[%- " bz_comment_hilite" IF marks.$count %]
[%- " bz_first_comment" IF comment.count == 0 %]">
[% IF comment.count == 0 %]
[% class_name = "bz_first_comment_head" %]
[% comment_label = "Description" %]
[% ELSE %]
[% class_name = wt_only ? "bz_comment_wthead" : "bz_comment_head" %]
[% comment_label = "Comment " _ comment.count %]
<div class="bz_comment[%- " bz_private" IF comment.is_private %][%- " bz_comment_hilite" IF marks.$count %]
[%- " bz_first_comment" IF comment.count == 0 %]">
[% IF comment.count == 0 %]
[% class_name = "bz_first_comment_head" %]
[% comment_label = "Description" %]
[% ELSE %]
[% class_name = wt_only ? "bz_comment_wthead" : "bz_comment_head" %]
[% comment_label = "Comment " _ comment.count %]
[% END %]
<div class="[% class_name %]"[% IF show_avatars == 1 %] style="line-height: 40px"[% END %]>
<span class="bz_comment_actions" id="comment_act_[% comment.id %]">
[% IF wt_btn %]
<img src="images/clock[% IF !wt_only %]g[% END %].gif" width="16" height="16"
alt="[% wt_only ? 'Comment is worktime-only' : 'Comment is not worktime-only' %]"
title="[% wt_only ? 'Comment is worktime-only' : 'Comment is not worktime-only' %]"
style="cursor: pointer; vertical-align: middle"
onclick="edit_wtonly(this, [% comment.id %])" />
<select class="cmt_wtonly" id="wtonly_[% comment.id %]" style="display: none">
<option value="0">normal</option>
<option value="1"[% " selected" IF wt_only %]>worktime-only</option>
</select>
[% END %]
</span>
<div class="[% class_name %]">
<span class="bz_comment_actions" id="comment_act_[% comment.id %]">
[% IF wt_btn %]
<img src="images/clock[% IF !wt_only %]g[% END %].gif" width="16" height="16"
alt="[% wt_only ? 'Comment is worktime-only' : 'Comment is not worktime-only' %]"
title="[% wt_only ? 'Comment is worktime-only' : 'Comment is not worktime-only' %]"
style="cursor: pointer; vertical-align: middle"
onclick="edit_wtonly(this, [% comment.id %])" />
<select class="cmt_wtonly" id="wtonly_[% comment.id %]" style="display: none">
<option value="0">normal</option>
<option value="1"[% " selected" IF wt_only %]>worktime-only</option>
</select>
[% END %]
</span>
[% IF mode == "edit" && user.is_insider %]
<div class="bz_private_checkbox">
<input type="hidden" value="1"
name="defined_isprivate_[% comment.id %]" />
<input type="checkbox"
name="isprivate_[% comment.id %]" value="1"
id="isprivate_[% comment.id %]"
onClick="updateCommentPrivacy(this, [% comment.id %])"
[% " checked=\"checked\"" IF comment.is_private %] />
<label for="isprivate_[% comment.id %]">Private</label>
</div>
[% END %]
<a name="[% comment.bug_when FILTER timestamp %]"></a>
[% IF NOT wt_only %]
<span class="bz_comment_number">
[% IF (comment.author.id == user.id || !comment.count) && collision != 1 %]
[<a href="#" onclick="showEditComment([% comment.id %]); return false;">Edit</a>]
[% END %]
<a name="c[% comment.count %]" href="show_bug.cgi?id=[% bug.bug_id %]#c[% comment.count %]">
[%- comment_label FILTER html %]</a>
</span>
[% END %]
<span class="bz_comment_user">
[% INCLUDE global/user.html.tmpl who = comment.author %]
</span>
<span class="bz_comment_user_images">
[% FOREACH group = comment.author.direct_group_membership %]
[% NEXT UNLESS group.icon_url %]
<img src="[% group.icon_url FILTER html %]"
alt="[% group.name FILTER html %]"
title="[% group.name FILTER html %] - [% group.description FILTER html %]">
[% END %]
</span>
<span class="bz_comment_time">
[%+ comment.creation_ts FILTER time %]
</span>
[% IF wt_only && has_worktime %]
<div class="bz_comment_worktime" title="Additional hours worked: [% PROCESS formattimeunit time_unit=comment.work_time %]">
[% PROCESS formattimeunit time_unit=comment.work_time %]h
[% IF mode == "edit" && user.is_insider %]
<div class="bz_private_checkbox">
<input type="hidden" value="1"
name="defined_isprivate_[% comment.id %]" />
<input type="checkbox"
name="isprivate_[% comment.id %]" value="1"
id="isprivate_[% comment.id %]"
onClick="updateCommentPrivacy(this, [% comment.id %])"
[% " checked=\"checked\"" IF comment.is_private %] />
<label for="isprivate_[% comment.id %]">Private</label>
</div>
[% END %]
<a name="[% comment.bug_when FILTER timestamp %]"></a>
[% IF NOT wt_only %]
<span class="bz_comment_number">
[% IF (comment.author.id == user.id || !comment.count) && collision != 1 %]
[<a href="#" onclick="showEditComment([% comment.id %]); return false;">Edit</a>]
[% END %]
<a name="c[% comment.count %]" href="show_bug.cgi?id=[% bug.bug_id %]#c[% comment.count %]">
[%- comment_label FILTER html %]</a>
</span>
[% END %]
<div style="clear: both"></div>
</div>
[%# FIXME: Mozilla skin is hardcoded :-( %]
[% IF show_avatars == 1 %]
<span class="bz_comment_user">
<a href="[% Param("user_mailto") %][% comment.author.email | html %]"
title="[% comment.author.identity | html %]">
<img src="[% comment.author.gravatar_url('s=40&d=' _ urlbase _ '/images/noavatar40.png') %]" />
</a>
</span>
[% END %]
[% IF !wt_only && has_worktime %]
<div class="bz_comment_hours">
Additional hours worked: [%+ PROCESS formattimeunit time_unit=comment.work_time %]
<span class="bz_comment_user">
[% INCLUDE global/user.html.tmpl who = comment.author %]
</span>
<span class="bz_comment_user_images">
[% FOREACH group = comment.author.direct_group_membership %]
[% NEXT UNLESS group.icon_url %]
<img src="[% group.icon_url FILTER html %]"
alt="[% group.name FILTER html %]"
title="[% group.name FILTER html %] - [% group.description FILTER html %]">
[% END %]
</span>
<span class="bz_comment_time">
[%+ comment.creation_ts FILTER time %]
</span>
[% IF wt_only && has_worktime %]
<div class="bz_comment_worktime" title="Additional hours worked: [% PROCESS formattimeunit time_unit=comment.work_time %]">
[% PROCESS formattimeunit time_unit=comment.work_time %]h
</div>
[% END %]
[%# Don't indent the <pre> block, since then the spaces are displayed in the
# generated HTML
#%]
<div class="bz_comment_text[% " collapsed" IF wt_only %][% " bz_fullscreen_comment" IF user.settings.comment_width.value == 'on' %]" id="comment_text_[% comment.id %]">
[%- comment.body_full({ wrap => 1, wo_preview => (user.settings.preview_long_comments.value == 'off') }) -%]
</div>
<div style="clear: both"></div>
</div>
[% IF !wt_only && has_worktime %]
<div class="bz_comment_hours">
Additional hours worked: [%+ PROCESS formattimeunit time_unit=comment.work_time %]
</div>
[% END %]
<div class="bz_comment_text[% " collapsed" IF wt_only %][% " bz_fullscreen_comment" IF user.settings.comment_width.value == 'on' %]" id="comment_text_[% comment.id %]">
[%# FIXME: Mozilla skin is hardcoded :-( %]
[% IF show_avatars == 2 %]
<span class="bz_comment_avatar">
<a href="[% Param("user_mailto") %][% comment.author.email | html %]"
title="[% comment.author.identity | html %]">
<img src="[% comment.author.gravatar_url('s=80') %]"
onerror="this.style.display='none'" />
</a>
</span>
[% END %]
[%- comment.body_full({ wrap => 1, wo_preview => (user.settings.preview_long_comments.value == 'off') }) -%]
</div>
[% IF !wt_only && Param('gravatar_url') && user.settings.skin.value != 'Mozilla' %]
<div style="clear: both"></div>
[% END %]
</div>
[% END %]