Merge pull request #1725 from opf/fix/use_default_avatar_lib

Fix/use default avatar lib
pull/1719/merge
Alex Coles 10 years ago
commit 02a556b71f
  1. 2
      Gemfile
  2. 2
      Gemfile.lock
  3. 53
      app/assets/stylesheets/_work_packages.scss
  4. 4
      app/assets/stylesheets/content/_journal.css.sass
  5. 5
      app/assets/stylesheets/content/_user_avatars.sass
  6. 14
      app/assets/stylesheets/content/_watchers.sass
  7. 2
      app/assets/stylesheets/default.css.sass
  8. 67
      app/assets/stylesheets/default/main.css.erb
  9. 10
      app/assets/stylesheets/layout/_split_view.sass
  10. 58
      app/assets/stylesheets/layout/_work_package.sass
  11. 2
      app/assets/stylesheets/layout/all.sass
  12. 2
      app/helpers/application_helper.rb
  13. 70
      app/helpers/avatar_helper.rb
  14. 2
      app/helpers/journals_helper.rb
  15. 3
      app/helpers/watchers_helper.rb
  16. 4
      app/helpers/work_packages_helper.rb
  17. 2
      app/views/activities/index.html.erb
  18. 4
      app/views/messages/show.html.erb
  19. 2
      app/views/news/index.html.erb
  20. 4
      app/views/news/show.html.erb
  21. 2
      app/views/project_associations/index.html.erb
  22. 2
      app/views/users/edit.html.erb
  23. 2
      app/views/users/index.html.erb
  24. 2
      app/views/users/show.html.erb
  25. 2
      app/views/work_packages/_show_attributes.html.erb
  26. 2
      app/views/work_packages/show.html.erb
  27. 2
      features/work_packages/work_package_show.feature
  28. 1
      lib/api/v3/activities/activity_model.rb
  29. 1
      lib/api/v3/users/user_model.rb
  30. 5
      lib/api/v3/users/user_representer.rb
  31. 1
      lib/api/v3/work_packages/work_package_model.rb
  32. 20
      lib/plugins/gravatar/MIT-LICENSE
  33. 55
      lib/plugins/gravatar/README.rdoc
  34. 32
      lib/plugins/gravatar/Rakefile
  35. 35
      lib/plugins/gravatar/about.yml
  36. 3
      lib/plugins/gravatar/init.rb
  37. 88
      lib/plugins/gravatar/lib/gravatar.rb
  38. 44
      lib/plugins/gravatar/spec/gravatar_spec.rb
  39. 2
      public/templates/work_packages/tabs/_user_field.html
  40. 110
      spec/helpers/avatar_helper_spec.rb
  41. 35
      spec/lib/api/v3/users/user_representer_spec.rb

@ -52,7 +52,7 @@ gem "rdoc", ">= 2.4.2"
gem 'globalize'
gem 'omniauth'
gem 'request_store'
gem 'gravatar_image_tag'
gem 'gravatar_image_tag', '~> 1.2.0'
# TODO: adds #auto_link which was deprecated in rails 3.1
gem 'rails_autolink'

@ -469,7 +469,7 @@ DEPENDENCIES
globalize
gon (~> 4.0)
grape (~> 0.7.0)
gravatar_image_tag
gravatar_image_tag (~> 1.2.0)
htmldiff
i18n (>= 0.6.8)
i18n-js!

@ -1,53 +0,0 @@
/*-- copyright
OpenProject is a project management system.
Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License version 3.
OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
Copyright (C) 2006-2013 Jean-Philippe Lang
Copyright (C) 2010-2013 the ChiliProject Team
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
See doc/COPYRIGHT.rdoc for more details.
++*/
#work-packages-query-selection .select2-container {
margin-left: 5px;
}
.issue .attributes td.work_package_attribute_header {
font-weight: bold;
}
.icon-button {
cursor: pointer;
}
.sort-header {
cursor: pointer;
}
.action-icon {
cursor: pointer;
}
select.to-validate.ng-dirty.ng-valid, input.to-validate.ng-dirty.ng-valid { border:1px solid Green; }
select.to-validate.ng-dirty.ng-invalid, input.to-validate.ng-dirty.ng-invalid { border:1px solid Red; }
select.to-validate.ng-dirty.ng-valid ~ span.ok, input.to-validate.ng-dirty.ng-valid ~ span.ok { color:green; display:inline; }
select.to-validate.ng-dirty.ng-invalid ~ span.ko, input.to-validate.ng-dirty.ng-invalid ~ span.ko { color:red; display:inline; }

@ -44,10 +44,6 @@
bottom: 20px
left: 3px
clear: left
img.gravatar
float: none
margin: 0
padding: 0
.journal
width: 700px

@ -5,3 +5,8 @@
.avatar-mini
border-radius: $user_avatar_mini_border_radius
width: $user_avatar_mini_width
h1, h2, h3, h4, tr
.avatar, .avatar-mini
vertical-align: middle
margin-right: 7px

@ -0,0 +1,14 @@
#watchers
img
vertical-align: middle
margin-right: 7px
.delete
vertical-align: sub
li
list-style-type: none
margin: 0px 10px 0px 0px
padding: 0px 0px 0px 0px
float: left
line-height: $user_avatar_mini_width

@ -38,7 +38,6 @@
@import print
@import scm
@import top-shelf
@import work_packages
@import openproject_plugins
@import layout/all
@import content/accounts
@ -53,6 +52,7 @@
@import content/buttons
@import content/boxes
@import content/tabular
@import content/watchers
@import content/work_packages
@import content/work_packages_filters
@import content/work_packages_relations

@ -122,9 +122,8 @@ tr.version td.name { padding-left: 20px; }
tr.version.shared td.name { background: url(<%= asset_path 'link.png' %>) no-repeat 0% 70%; }
tr.version td.date, tr.version td.status, tr.version td.sharing { text-align: left; white-space: nowrap; }
tr.user td { width: 13%; }
tr.user td { width: 13%; white-space: nowrap; }
tr.user td.email { width: 18%; }
tr.user td { white-space: nowrap; }
tr.user.locked, tr.user.registered { color: #aaa; }
tr.user.locked a, tr.user.registered a { color: #aaa; }
@ -159,11 +158,9 @@ table.attributes td { vertical-align: top; }
td.center, th.center {text-align: center;}
#watchers ul {margin: 0; padding: 0;}
#watchers li {list-style-type: none;margin: 0px 10px 0px 0px; padding: 0px 0px 0px 0px;float: left;}
#watchers select {width: 200px; display: block;float: left;margin-right: 10px;}
#watchers a.delete {opacity: 0.4;}
#watchers a.delete:hover {opacity: 1;}
#watchers img.gravatar {vertical-align: middle;margin: 0 10px 0px 0;}
.highlight { background-color: #FCFD8D;}
.highlight.token-1 { background-color: #faa;}
@ -534,7 +531,7 @@ div.tooltip:hover span.tip, div.tooltip.hover span.tip {
empty-cells: show;
text-align: center;
float: left;
margin: 1px 6px 1px 0px;
margin: 3px 6px 1px 0px;
border: 1px solid #BBBBBB;
border-collapse: separate;
-moz-border-radius: 3px;
@ -691,50 +688,6 @@ ins.diffmod, ins.diffins { background: #cfc; }
}
/***** My page layout *****/
img.gravatar {
background: #fff;
}
div.issue img.gravatar {
float: right;
margin: 0 0 0 1em;
padding: 5px;
}
div.issue table img.gravatar {
height: 14px;
width: 14px;
padding: 2px;
float: left;
margin: 0 0.5em 0 0;
}
h2 img.gravatar {
margin: -2px 4px -4px 0;
vertical-align: top;
}
h4 img.gravatar {
margin: -6px 0 -4px 0;
vertical-align: top;
}
td.username img.gravatar {
margin: 0 0.5em 0 0;
vertical-align: top;
}
#activity dt img.gravatar {
float: left;
margin: 0 1em 1em 0;
}
/* Used on 12px Gravatar img tags without the icon background */
.icon-gravatar {
float: left;
margin-right: 4px;
}
#activity dt {
clear: left;
}
@ -953,9 +906,6 @@ div.issue hr {
#content div.issue table th {
font-weight: bold;
}
.issue p {
margin-bottom: 5px;
}
.attachments h4 {
margin-bottom: 6px;
background: url(<%= asset_path 'files-showhide.png' %>) no-repeat right bottom;
@ -1109,11 +1059,6 @@ ul.projects li div.root {
.profile-box ul li:last-child {
border-bottom: 0;
}
.profile-box .gravatar {
border: 0;
float: left;
margin-right: 6px;
}
/* file table hovers */
a.has-thumb img {
@ -1306,14 +1251,10 @@ div.issue hr {
#content h2 + h3 {
margin-top: 12px;
}
div.issue img.gravatar {
float: none;
margin: 0;
padding: 0;
}
p.author {
margin-bottom: 15px;
font-style: italic;
/* to accomodate the .profile-wrap class */
height: 42px;
}
/* add filter select box on non-issue pages */
fieldset#filters div.add-filter {

@ -104,7 +104,6 @@ div
list-style-type: none
li
clear: both
height: 36px
margin-bottom: 10px
.user-field-user-link
@ -170,15 +169,14 @@ div.detail-panel-latest-activity
margin: 0 0 20px 0
padding: 0
img
div.work-package-details-tab
img
&.avatar
width: 36px
float: left
margin: -2px 10px 0 0
&.avatar-small
width: 16px
&.avatar-mini
float: left
margin: 0 7px 0 0
margin: -3px 7px 0 0
span
&.user

@ -0,0 +1,58 @@
/*-- copyright
* OpenProject is a project management system.
* Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version 3.
*
* OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
* Copyright (C) 2006-2013 Jean-Philippe Lang
* Copyright (C) 2010-2013 the ChiliProject Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* See doc/COPYRIGHT.rdoc for more details.
*
*/
.controller-work_packages
#work-packages-query-selection
.select2-container
margin-left: 5px
.issue
.attributes
td.work_package_attribute_header
font-weight: bold
.icon-button, .sort-header, .action-icon
cursor: pointer
select, input
&.to-validate.ng-dirty.ng-valid
border: 1px solid Green
&.to-validate.ng-dirty.ng-valid ~ span.ok
color: green
display: inline
&.to-validate.ng-dirty.ng-invalid
border: 1px solid Red
&.to-validate.ng-dirty.ng-invalid ~ span.ok
color: red
display: inline
.work_package
tr
line-height: $user_avatar_mini_width
.avatar-mini
float: left

@ -33,4 +33,4 @@
@import layout/footer
@import layout/drop_down
@import layout/toolbar
@import layout/split_view
@import layout/work_package

@ -470,7 +470,7 @@ module ApplicationHelper
end
number = content_tag 'p', :class => 'pourcent' do
legend + " " + l(:total_progress)
legend + '% ' + l(:total_progress)
end
bar + number

@ -27,25 +27,81 @@
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'gravatar_image_tag'
module AvatarHelper
include GravatarHelper::PublicMethods
include GravatarImageTag
GravatarImageTag.configure do |c|
c.include_size_attributes = false
c.secure = Setting.protocol == 'https'
c.default_image = Setting.gravatar_default.blank? ? nil : Setting.gravatar_default
end
Setting.register_callback(:protocol) do |values|
GravatarImageTag.configure do |c|
c.secure = values[:value] == 'https'
end
end
Setting.register_callback(:gravatar_default) do |values|
GravatarImageTag.configure do |c|
c.default_image = values[:value].blank? ? nil : values[:value]
end
end
def self.secure?
GravatarImageTag.configuration.secure
end
def self.default
GravatarImageTag.configuration.default_image
end
# Returns the avatar image tag for the given +user+ if avatars are enabled
# +user+ can be a User or a string that will be scanned for an email address (eg. 'joe <joe@foo.bar>')
def avatar(user, options = { })
avatar = if Setting.gravatar_enabled? && (email = extract_email_address(user)).present?
options.merge!({ :ssl => (defined?(request) && request.ssl?),
:default => Setting.gravatar_default })
avatar = with_default_avatar_options(user, options) do |email, opts|
tag_options = merge_image_options(user, opts)
gravatar(email.to_s.downcase, options)
gravatar_image_tag(email, tag_options)
end
ensure
# return is actually needed here
ensure # return is actually needed here
return (avatar || ''.html_safe)
end
def avatar_url(user, options = {})
url = with_default_avatar_options(user, options) do |email, opts|
gravatar_image_url(email, opts)
end
ensure # return is actually needed here
return (url || ''.html_safe)
end
private
def merge_image_options(user, options)
default_options = { class: 'avatar' }
default_options[:title] = user.name if user.respond_to?(:name)
options.reverse_merge(default_options)
end
def with_default_avatar_options(user, options, &block)
if options.delete(:size)
warn <<-DOC
[DEPRECATION] The :size option is no longer supported for #avatar.
Use css styling (:class attribute). The classes '.avatar', '.gravatar', and '.avatar-mini' are provided for this
Called from #{caller[1]}
DOC
end
if Setting.gravatar_enabled? && (email = extract_email_address(user)).present?
block.call(email.to_s.downcase, options)
end
end
def extract_email_address(object)
if object.respond_to?(:mail)
object.mail

@ -51,7 +51,7 @@ module JournalsHelper
def render_journal_details(journal, header_label = :label_updated_time_by, model=nil, options={})
header = <<-HTML
<div class="profile-wrap">
#{avatar(journal.user, :size => "40")}
#{avatar(journal.user)}
</div>
<h4>
<div class="journal-link" style="float:right;">#{link_to "##{journal.anchor}", :anchor => "note-#{journal.anchor}"}</div>

@ -63,7 +63,7 @@ module WatchersHelper
lis = object.watcher_users.sort.collect do |user|
watcher = object.watchers(true).find{|u| u.user_id == user.id }
content_tag :li do
avatar(user, :size => "16") +
avatar(user, :class => 'avatar-mini') +
link_to_user(user, :class => 'user') +
if remove_allowed
' '.html_safe + link_to(icon_wrapper('icon-context icon-close delete-ctrl',
@ -71,7 +71,6 @@ module WatchersHelper
watcher_path(watcher),
:method => :delete,
:remote => true,
:style => "vertical-align: middle",
:title => l(:button_delete_watcher, name: user.name),
:class => "delete no-decoration-on-hover")
else

@ -373,7 +373,7 @@ module WorkPackagesHelper
def work_package_show_assigned_to_attribute(work_package)
work_package_show_table_row(:assigned_to) do
content = avatar(work_package.assigned_to, :size => "14").html_safe
content = avatar(work_package.assigned_to, class: 'avatar-mini').html_safe
content << (work_package.assigned_to ? link_to_user(work_package.assigned_to) : empty_element_tag)
content
end
@ -381,7 +381,7 @@ module WorkPackagesHelper
def work_package_show_responsible_attribute(work_package)
work_package_show_table_row(:responsible) do
content = avatar(work_package.responsible, :size => "14").html_safe
content = avatar(work_package.responsible, class: 'avatar-mini').html_safe
content << (work_package.responsible ? link_to_user(work_package.responsible) : empty_element_tag)
content
end

@ -41,7 +41,7 @@ See doc/COPYRIGHT.rdoc for more details.
<% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%>
<dt class="<%= e.event_type %> <%= User.current.logged? && e.respond_to?(:event_author) && User.current == e.event_author ? 'me' : nil %>">
<%= icon_wrapper("icon-context icon-#{e.event_type}", e.event_name) %>
<%= avatar(e.event_author, :size => "24") if e.respond_to?(:event_author) %>
<%= avatar(e.event_author) if e.respond_to?(:event_author) %>
<span class="time"><%= format_time(e.event_datetime.to_time, false) %></span>
<%= content_tag('span', link_to(e.project.name, e.project), :class => 'project') if (@project.nil? || @project != e.project) && e.project %>
<%= link_to format_activity_title(e.event_title), e.event_path%>

@ -52,7 +52,7 @@ See doc/COPYRIGHT.rdoc for more details.
<div class="top-page">
<%= render :partial => 'layouts/action_menu_specific' %>
<h2 title="<%= h @topic.subject %>"><%= avatar(@topic.author, :size => "24") %><%=h @topic.subject %></h2>
<h2 title="<%= h @topic.subject %>"><%= avatar(@topic.author) %><%=h @topic.subject %></h2>
</div>
<div class="message">
@ -69,7 +69,7 @@ See doc/COPYRIGHT.rdoc for more details.
<% @replies.each do |message| %>
<div class="message reply" id="<%= "message-#{message.id}" %>">
<h4>
<%= avatar(message.author, :size => "24") %>
<%= avatar(message.author) %>
<%= link_to h(message.subject), topic_path(@topic,
:r => message,
:anchor => "message-#{message.id}") %>

@ -33,7 +33,7 @@ See doc/COPYRIGHT.rdoc for more details.
<p class="nodata"><%= l(:label_no_data) %></p>
<% else %>
<% @newss.each do |news| %>
<h3><%= avatar(news.author, :size => "24") %><%= link_to_project(news.project) + ': ' unless news.project == @project %>
<h3><%= avatar(news.author) %><%= link_to_project(news.project) + ': ' unless news.project == @project %>
<%= link_to h(news.title), news_path(news) %>
<%= "(#{l(:label_x_comments, :count => news.comments_count)})" if news.comments_count > 0 %></h3>
<p class="author"><%= authoring news.created_on, news.author %></p>

@ -43,7 +43,7 @@ See doc/COPYRIGHT.rdoc for more details.
<div class="top-page">
<%= render :partial => 'layouts/action_menu_specific' %>
<h2 title="<%= h @news.title %>"><%= avatar(@news.author, :size => "24") %><%=h @news.title %></h2>
<h2 title="<%= h @news.title %>"><%= avatar(@news.author) %><%=h @news.title %></h2>
</div>
<% if authorize_for('news', 'edit') %>
@ -78,7 +78,7 @@ See doc/COPYRIGHT.rdoc for more details.
:title => l(:button_delete),
:alt => l(:button_delete) %>
</div>
<h4 class="comment"><%= avatar(comment.author, :size => "24") %><%= authoring comment.created_on, comment.author %></h4>
<h4 class="comment"><%= avatar(comment.author) %><%= authoring comment.created_on, comment.author %></h4>
<%= format_text(comment.comments, :object => comment) %>
<% end %>
</div>

@ -89,7 +89,7 @@ See doc/COPYRIGHT.rdoc for more details.
</td>
<td class="timelines-pa-responsible">
<% if other.responsible.present? %>
<%= avatar(other.responsible, :size => "14") %>
<%= avatar(other.responsible, class: 'avatar-mini') %>
<%= link_to_user(other.responsible) %>
<% else %>
-

@ -36,7 +36,7 @@ See doc/COPYRIGHT.rdoc for more details.
<% html_title(l(:label_administration), "#{l(:label_edit)} #{User.model_name.human} #{h(@user.login)}") -%>
<h2><%= link_to l(:label_user_plural), :controller => '/users', :action => 'index' %> &#187; <%=h @user.login %></h2>
<h2><%= link_to l(:label_user_plural), :controller => '/users', :action => 'index' %> &#187; <%= avatar(@user) %> <%=h @user.login %></h2>
<%= render :partial => 'layouts/action_menu_specific' %>

@ -81,7 +81,7 @@ See doc/COPYRIGHT.rdoc for more details.
<tbody>
<% for user in @users -%>
<tr class="user <%= cycle("odd", "even") %> <%= %w(anon active registered locked)[user.status] %> <%= 'blocked' if user.failed_too_many_recent_login_attempts? %>">
<td class="username"><%= avatar(user, :size => "14") %><%= link_to h(user.login), edit_user_path(user) %></td>
<td class="username"><%= avatar(user, class: 'avatar-mini') %><%= link_to h(user.login), edit_user_path(user) %></td>
<td class="firstname"><%= h(user.firstname) %></td>
<td class="lastname"><%= h(user.lastname) %></td>
<td class="email"><%= mail_to(h(user.mail)) %></td>

@ -38,7 +38,7 @@ See doc/COPYRIGHT.rdoc for more details.
accesskey: accesskey(:edit)) if User.current.admin? %>
<% end %>
<h2><%= avatar @user, :size => "50" %> <%=h @user.name %></h2>
<h2><%= avatar @user %> <%=h @user.name %></h2>
<%= render :partial => 'layouts/action_menu_specific' %>

@ -27,7 +27,7 @@ See doc/COPYRIGHT.rdoc for more details.
++#%>
<div class="issue details">
<div class="work_package issue details">
<div class="meta">
<% attributes = work_package_show_attributes(work_package) %>
<div id="left" style="float:left; width:50%;">

@ -39,7 +39,7 @@ See doc/COPYRIGHT.rdoc for more details.
<div class = "details">
<div class="profile-wrap">
<%= avatar(work_package.author, :size => "40") %>
<%= avatar(work_package.author) %>
</div>
<p class="author">

@ -87,7 +87,7 @@ Feature: Viewing a work package
When I go to the page of the work package "issue1"
Then I should see "Bug #1: issue1"
Then I should see "Bug #2: issue2" within ".idnt-1"
And I should see "0 Total progress"
And I should see "0% Total progress"
Scenario: View work package with issue done ratio disabled
Given the "work_package_done_ratio" setting is set to disabled

@ -39,7 +39,6 @@ module API
include OpenProject::TextFormatting
include OpenProject::StaticRouting::UrlHelpers
include WorkPackagesHelper
include GravatarImageTag
# N.B. required by ActionView::Helpers::UrlHelper
def controller; nil; end

@ -35,7 +35,6 @@ module API
module Users
class UserModel < Reform::Form
include Coercion
include GravatarImageTag
property :login, type: String
property :firstname, type: String

@ -37,6 +37,7 @@ module API
include Roar::Representer::JSON::HAL
include Roar::Representer::Feature::Hypermedia
include OpenProject::StaticRouting::UrlHelpers
include AvatarHelper
self.as_strategy = API::Utilities::CamelCasingStrategy.new
@ -68,7 +69,9 @@ module API
property :lastname, as: :lastName, render_nil: true
property :name, getter: -> (*) { model.try(:name) }, render_nil: true
property :mail, render_nil: true
property :avatar, getter: ->(*) { gravatar_image_url(mail) }, render_nil: true
property :avatar, getter: -> (*) { avatar_url(represented) },
render_nil: true,
exec_context: :decorator
property :created_at, getter: -> (*) { model.created_on.utc.iso8601 }, render_nil: true
property :updated_at, getter: -> (*) { model.updated_on.utc.iso8601 }, render_nil: true
property :status, getter: -> (*) { model.status }, render_nil: true

@ -40,7 +40,6 @@ module API
include OpenProject::TextFormatting
include OpenProject::StaticRouting::UrlHelpers
include WorkPackagesHelper
include GravatarImageTag
# N.B. required by ActionView::Helpers::UrlHelper
def controller; nil; end

@ -1,20 +0,0 @@
Copyright (c) 2007 West Arete Computing, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

@ -1,55 +0,0 @@
== Gravatar Plugin
This plugin provides a handful of view helpers for displaying gravatars
(globally-recognized avatars).
Gravatars allow users to configure an avatar to go with their email address at
a central location: http://gravatar.com. Gravatar-aware websites (such
as yours) can then look up and display each user's preferred avatar, without
having to handle avatar management. The user gets the benefit of not having to
set up an avatar for each site that they post on.
== Installation
cd ~/myapp
ruby script/plugin install git://github.com/woods/gravatar-plugin.git
or, if you're using piston[http://piston.rubyforge.org] (worth it!):
cd ~/myapp/vendor/plugins
piston import git://github.com/woods/gravatar-plugin.git
== Example
If you represent your users with a model that has an +email+ method (typical
for most rails authentication setups), then you can simply use this method
in your views:
<%= gravatar_for @user %>
This will be replaced with the full HTML +img+ tag necessary for displaying
that user's gravatar.
Other helpers are documented under GravatarHelper::PublicMethods.
== Acknowledgments
Thanks to Magnus Bergmark (http://github.com/Mange), who contributed the SSL
support in this plugin, as well as a few minor fixes.
The following people have also written gravatar-related Ruby libraries:
* Seth Rasmussen created the gravatar gem[http://gravatar.rubyforge.org]
* Matt McCray has also created a gravatar
plugin[http://mattmccray.com/svn/rails/plugins/gravatar_helper]
== Author
Scott A. Woods
West Arete Computing, Inc.
http://westarete.com
scott at westarete dot com
== TODO
* Add specs for ssl support
* Finish rdoc documentation

@ -1,32 +0,0 @@
require 'spec/rake/spectask'
require 'rake/rdoctask'
desc 'Default: run all specs'
task :default => :spec
desc 'Run all application-specific specs'
RSpec::Rake::SpecTask.new(:spec) do |t|
# t.rcov = true
end
desc "Report code statistics (KLOCs, etc) from the application"
task :stats do
RAILS_ROOT = File.dirname(__FILE__)
STATS_DIRECTORIES = [
%w(Libraries lib/),
%w(Specs spec/),
].collect { |name, dir| [ name, "#{RAILS_ROOT}/#{dir}" ] }.select { |name, dir| File.directory?(dir) }
require 'code_statistics'
CodeStatistics.new(*STATS_DIRECTORIES).to_s
end
namespace :doc do
desc 'Generate documentation for the assert_request plugin.'
Rake::RDocTask.new(:plugin) do |rdoc|
rdoc.rdoc_dir = 'rdoc'
rdoc.title = 'Gravatar Rails Plugin'
rdoc.options << '--line-numbers' << '--inline-source' << '--accessor' << 'cattr_accessor=rw'
rdoc.rdoc_files.include('README')
rdoc.rdoc_files.include('lib/**/*.rb')
end
end

@ -1,35 +0,0 @@
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2013 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
author: Scott Woods, West Arete Computing
summary: View helpers for displaying gravatars.
homepage: http://github.com/woods/gravatar-plugin/
plugin: git://github.com/woods/gravatar-plugin.git
license: MIT
version: 0.1
rails_version: 1.0+

@ -1,3 +0,0 @@
#-- encoding: UTF-8
require 'gravatar'
ActionView::Base.send :include, GravatarHelper::PublicMethods

@ -1,88 +0,0 @@
#-- encoding: UTF-8
require 'digest/md5'
require 'cgi'
module GravatarHelper
# These are the options that control the default behavior of the public
# methods. They can be overridden during the actual call to the helper,
# or you can set them in your environment.rb as such:
#
# # Allow racier gravatars
# GravatarHelper::DEFAULT_OPTIONS[:rating] = 'R'
#
DEFAULT_OPTIONS = {
# The URL of a default image to display if the given email address does
# not have a gravatar.
:default => nil,
# The default size in pixels for the gravatar image (they're square).
:size => 50,
# The maximum allowed MPAA rating for gravatars. This allows you to
# exclude gravatars that may be out of character for your site.
:rating => 'PG',
# The alt text to use in the img tag for the gravatar. Since it's a
# decorational picture, the alt text should be empty according to the
# XHTML specs.
:alt => '',
# The title text to use for the img tag for the gravatar.
:title => '',
# The class to assign to the img tag for the gravatar.
:class => 'gravatar',
# Whether or not to display the gravatars using HTTPS instead of HTTP
:ssl => false,
}
# The methods that will be made available to your views.
module PublicMethods
# Return the HTML img tag for the given user's gravatar. Presumes that
# the given user object will respond_to "email", and return the user's
# email address.
def gravatar_for(user, options={})
gravatar(user.email, options)
end
# Return the HTML img tag for the given email address's gravatar.
def gravatar(email, options={})
src = h(gravatar_url(email, options))
options = DEFAULT_OPTIONS.merge(options)
[:class, :alt, :size, :title].each { |opt| options[opt] = h(options[opt]) }
image_tag src, options
end
# Returns the base Gravatar URL for the given email hash. If ssl evaluates to true,
# a secure URL will be used instead. This is required when the gravatar is to be
# displayed on a HTTPS site.
def gravatar_api_url(hash, ssl=false)
if ssl
"https://secure.gravatar.com/avatar/#{hash}"
else
"http://www.gravatar.com/avatar/#{hash}"
end
end
# Return the gravatar URL for the given email address.
def gravatar_url(email, options={})
email_hash = Digest::MD5.hexdigest(email)
options = DEFAULT_OPTIONS.merge(options)
options[:default] = CGI::escape(options[:default]) unless options[:default].nil?
gravatar_api_url(email_hash, options.delete(:ssl)).tap do |url|
opts = []
[:rating, :size, :default].each do |opt|
unless options[opt].nil?
value = h(options[opt])
opts << [opt, value].join('=')
end
end
url << "?#{opts.join('&')}" unless opts.empty?
end
end
end
end

@ -1,44 +0,0 @@
#-- encoding: UTF-8
require 'rubygems'
require 'erb' # to get "h"
require 'active_support' # to get "returning"
require File.dirname(__FILE__) + '/../lib/gravatar'
include GravatarHelper, GravatarHelper::PublicMethods, ERB::Util
describe "gravatar_url with a custom default URL" do
before(:each) do
@original_options = DEFAULT_OPTIONS.dup
DEFAULT_OPTIONS[:default] = "no_avatar.png"
@url = gravatar_url("somewhere")
end
it "should include the \"default\" argument in the result" do
expect(@url).to match(/&default=no_avatar.png/)
end
after(:each) do
DEFAULT_OPTIONS.merge!(@original_options)
end
end
describe "gravatar_url with default settings" do
before(:each) do
@url = gravatar_url("somewhere")
end
it "should have a nil default URL" do
expect(DEFAULT_OPTIONS[:default]).to be_nil
end
it "should not include the \"default\" argument in the result" do
expect(@url).not_to match(/&default=/)
end
end
describe "gravatar with a custom title option" do
it "should include the title in the result" do
expect(gravatar('example@example.com', :title => "This is a title attribute")).to match(/This is a title attribute/)
end
end

@ -1,6 +1,6 @@
<p>
<span ng-if="userName">
<img class="avatar"
<img class="avatar-mini"
ng-if="user.props.avatar"
ng-src="{{user.props.avatar}}" />
<span class="user">

@ -33,75 +33,137 @@ describe AvatarHelper, :type => :helper do
let(:user) { FactoryGirl.build_stubbed(:user) }
def expected_image_tag(digest, options = {})
# there are some attributes in here that are wrong but are returned by the
# bundled plugin. I will not fix the lib at the given moment. I would rather, we
# remove the bundled gem and reference one in the Gemfile or
# implement the thing ourselves.
tag_options = options.reverse_merge(title: user.name,
alt: 'Gravatar',
class: 'avatar').delete_if { |key, value| value.nil? || key == :ssl}
host = options[:ssl] ?
image_tag expected_url(digest, options), tag_options
end
def expected_url(digest, options = {})
ssl = !!options[:ssl]
host = ssl ?
"https://secure.gravatar.com" :
"http://www.gravatar.com"
"http://gravatar.com"
expected_src = "#{host}/avatar/#{digest}?rating=PG&size=50&default="
"#{host}/avatar/#{digest}?secure=#{ssl}"
end
image_tag expected_src, :class => "gravatar",
:title => '',
:ssl => options[:ssl] || false,
:alt => '',
:default => '',
:rating => 'PG'
describe 'ssl dependent on protocol settings' do
it "should be set to secure if protocol is 'https'" do
with_settings protocol: 'https' do
expect(described_class.secure?).to be true
end
end
it "should be set to unsecure if protocol is 'http'" do
with_settings protocol: 'http' do
expect(described_class.secure?).to be false
end
end
end
describe 'default avatar dependent on settings' do
it "should be set to value of setting" do
with_settings gravatar_default: 'Wavatars' do
expect(described_class.default).to eq 'Wavatars'
end
end
it "should be set to unsecure if protocol is 'http'" do
with_settings gravatar_default: '' do
expect(described_class.default).to be_nil
end
end
end
describe :avatar do
it "should return a gravatar image tag if a user is provided" do
digest = Digest::MD5.hexdigest(user.mail)
with_settings :gravatar_enabled => '1' do
with_settings gravatar_enabled: '1', protocol: 'http' do
expect(helper.avatar(user)).to eq(expected_image_tag(digest))
end
end
it "should return a gravatar image tag with ssl if the request was ssl required" do
digest = Digest::MD5.hexdigest(user.mail)
allow(helper.request).to receive(:ssl?).and_return(true)
with_settings :gravatar_enabled => '1' do
with_settings :gravatar_enabled => '1', protocol: 'https' do
expect(helper.avatar(user)).to eq(expected_image_tag(digest, :ssl => true))
end
end
it "should return an empty string if a non parsable (e-mail) string is provided" do
with_settings :gravatar_enabled => '1' do
expect(helper.avatar('just the name')).to eq('')
end
end
it "should return an empty string if nil is provided" do
with_settings :gravatar_enabled => '1' do
expect(helper.avatar(nil)).to eq('')
end
end
it "should return an empty string if gravatar is disabled" do
with_settings :gravatar_enabled => '0' do
expect(helper.avatar(user)).to eq('')
end
end
it "should return a gravatar image tag if a parsable e-mail string is provided" do
with_settings :gravatar_enabled => '1' do
mail = "<e-mail@mail.de>"
digest = Digest::MD5.hexdigest("e-mail@mail.de")
expect(helper.avatar(mail)).to eq(expected_image_tag(digest))
expect(helper.avatar(mail)).to eq(expected_image_tag(digest, title: nil))
end
end
end
describe :avatar_url do
it "should return a gravatar url if a user is provided" do
digest = Digest::MD5.hexdigest(user.mail)
with_settings gravatar_enabled: '1', protocol: 'http' do
expect(helper.avatar_url(user)).to eq(expected_url(digest))
end
end
it "should return a gravatar image tag with ssl if the request was ssl required" do
digest = Digest::MD5.hexdigest(user.mail)
with_settings :gravatar_enabled => '1', protocol: 'https' do
expect(helper.avatar_url(user)).to eq(expected_url(digest, :ssl => true))
end
end
it "should return an empty string if a non parsable (e-mail) string is provided" do
with_settings :gravatar_enabled => '1' do
expect(helper.avatar('just the name')).to eq('')
expect(helper.avatar_url('just the name')).to eq('')
end
end
it "should return an empty string if nil is provided" do
with_settings :gravatar_enabled => '1' do
expect(helper.avatar(nil)).to eq('')
expect(helper.avatar_url(nil)).to eq('')
end
end
it "should return an empty string if gravatar is disabled" do
with_settings :gravatar_enabled => '0' do
expect(helper.avatar(user)).to eq('')
expect(helper.avatar_url(user)).to eq('')
end
end
it "should return an empty string if any error is produced in the lib" do
allow(helper).to receive(:gravatar).and_raise(ArgumentError)
it "should return a gravatar image tag if a parsable e-mail string is provided" do
with_settings :gravatar_enabled => '1' do
expect(helper.avatar(user)).to eq('')
mail = "<e-mail@mail.de>"
digest = Digest::MD5.hexdigest("e-mail@mail.de")
expect(helper.avatar_url(mail)).to eq(expected_url(digest))
end
end
end

@ -29,7 +29,9 @@
require 'spec_helper'
describe ::API::V3::Users::UserRepresenter do
let(:user) { FactoryGirl.create(:user) }
let(:user) { FactoryGirl.build_stubbed(:user,
created_on: Time.now,
updated_on: Time.now) }
let(:model) { ::API::V3::Users::UserModel.new(user) }
let(:representer) { described_class.new(model) }
@ -49,6 +51,7 @@ describe ::API::V3::Users::UserRepresenter do
it { is_expected.to have_json_path('createdAt') }
it { is_expected.to have_json_path('updatedAt') }
it { is_expected.to have_json_path('status') }
it { is_expected.to have_json_path('avatar') }
end
describe '_links' do
@ -56,5 +59,35 @@ describe ::API::V3::Users::UserRepresenter do
expect(subject).to have_json_path('_links/self/href')
end
end
describe 'avatar' do
before do
user.mail = 'foo@bar.com'
Setting.stub(:gravatar_enabled?).and_return(true)
end
it 'should have an url to gravatar if settings permit and mail is set' do
expect(parse_json(subject, 'avatar')).to start_with('http://gravatar.com/avatar')
end
it 'should be blank if gravatar is disabled' do
Setting.stub(:gravatar_enabled?).and_return(false)
expect(parse_json(subject, 'avatar')).to be_blank
end
it 'should be blank if email is missing (e.g. anonymous)' do
user.mail = nil
expect(parse_json(subject, 'avatar')).to be_blank
end
it 'should be https if setting set to https' do
# have to actually set the setting for the lib to pick up the change
with_settings protocol: 'https' do
expect(parse_json(subject, 'avatar')).to start_with('https://secure.gravatar.com/avatar')
end
end
end
end
end

Loading…
Cancel
Save