Gravatar support for issue detai, user grid, and activity stream

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@1962 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
Eric Davis 2008-10-30 02:58:04 +00:00
parent 1399f3dd12
commit ed314caf7d
12 changed files with 283 additions and 24 deletions

View File

@ -1,14 +1,15 @@
<% reply_links = authorize_for('issues', 'edit') -%> <% reply_links = authorize_for('issues', 'edit') -%>
<% for journal in journals %> <% for journal in journals %>
<div id="change-<%= journal.id %>" class="journal"> <div id="change-<%= journal.id %>" class="journal">
<h4><div style="float:right;"><%= link_to "##{journal.indice}", :anchor => "note-#{journal.indice}" %></div> <%= gravatar(journal.user.mail.blank? ? "" : journal.user.mail, :size => "48") %>
<%= content_tag('a', '', :name => "note-#{journal.indice}")%> <h4><div style="float:right;"><%= link_to "##{journal.indice}", :anchor => "note-#{journal.indice}" %></div>
<%= format_time(journal.created_on) %> - <%= journal.user.name %></h4> <%= content_tag('a', '', :name => "note-#{journal.indice}")%>
<ul> <%= format_time(journal.created_on) %> - <%= journal.user.name %></h4>
<% for detail in journal.details %> <ul>
<li><%= show_detail(detail) %></li> <% for detail in journal.details %>
<% end %> <li><%= show_detail(detail) %></li>
</ul> <% end %>
<%= render_notes(journal, :reply_links => reply_links) unless journal.notes.blank? %> </ul>
</div> <%= render_notes(journal, :reply_links => reply_links) unless journal.notes.blank? %>
</div>
<% end %> <% end %>

View File

@ -10,6 +10,7 @@
<h2><%= @issue.tracker.name %> #<%= @issue.id %></h2> <h2><%= @issue.tracker.name %> #<%= @issue.id %></h2>
<div class="issue <%= "status-#{@issue.status.position} priority-#{@issue.priority.position}" %>"> <div class="issue <%= "status-#{@issue.status.position} priority-#{@issue.priority.position}" %>">
<%= gravatar(@issue.author.mail, :size => "64") %>
<h3><%=h @issue.subject %></h3> <h3><%=h @issue.subject %></h3>
<p class="author"> <p class="author">
<%= authoring @issue.created_on, @issue.author %>. <%= authoring @issue.created_on, @issue.author %>.
@ -18,28 +19,28 @@
<table width="100%"> <table width="100%">
<tr> <tr>
<td style="width:15%"><b><%=l(:field_status)%>:</b></td><td style="width:35%"><%= @issue.status.name %></td> <td style="width:15%" class="status"><b><%=l(:field_status)%>:</b></td><td style="width:35%" class="status status-<%= @issue.status.name %>"><%= @issue.status.name %></td>
<td style="width:15%"><b><%=l(:field_start_date)%>:</b></td><td style="width:35%"><%= format_date(@issue.start_date) %></td> <td style="width:15%" class="start-date"><b><%=l(:field_start_date)%>:</b></td><td style="width:35%"><%= format_date(@issue.start_date) %></td>
</tr> </tr>
<tr> <tr>
<td><b><%=l(:field_priority)%>:</b></td><td><%= @issue.priority.name %></td> <td class="priority"><b><%=l(:field_priority)%>:</b></td><td class="priority priority-<%= @issue.priority.name %>"><%= @issue.priority.name %></td>
<td><b><%=l(:field_due_date)%>:</b></td><td><%= format_date(@issue.due_date) %></td> <td class="due-date"><b><%=l(:field_due_date)%>:</b></td><td class="due-date"><%= format_date(@issue.due_date) %></td>
</tr> </tr>
<tr> <tr>
<td><b><%=l(:field_assigned_to)%>:</b></td><td><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %></td> <td class="assigned-to"><b><%=l(:field_assigned_to)%>:</b></td><td><%= gravatar(@issue.assigned_to.mail, :size => "24") %><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %></td>
<td><b><%=l(:field_done_ratio)%>:</b></td><td><%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %></td> <td class="progress"><b><%=l(:field_done_ratio)%>:</b></td><td class="progress"><%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %></td>
</tr> </tr>
<tr> <tr>
<td><b><%=l(:field_category)%>:</b></td><td><%=h @issue.category ? @issue.category.name : "-" %></td> <td class="category"><b><%=l(:field_category)%>:</b></td><td><%=h @issue.category ? @issue.category.name : "-" %></td>
<% if User.current.allowed_to?(:view_time_entries, @project) %> <% if User.current.allowed_to?(:view_time_entries, @project) %>
<td><b><%=l(:label_spent_time)%>:</b></td> <td class="spent-time"><b><%=l(:label_spent_time)%>:</b></td>
<td><%= @issue.spent_hours > 0 ? (link_to lwr(:label_f_hour, @issue.spent_hours), {:controller => 'timelog', :action => 'details', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time') : "-" %></td> <td class="spent-hours"><%= @issue.spent_hours > 0 ? (link_to lwr(:label_f_hour, @issue.spent_hours), {:controller => 'timelog', :action => 'details', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time') : "-" %></td>
<% end %> <% end %>
</tr> </tr>
<tr> <tr>
<td><b><%=l(:field_fixed_version)%>:</b></td><td><%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %></td> <td class="fixed-version"><b><%=l(:field_fixed_version)%>:</b></td><td><%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %></td>
<% if @issue.estimated_hours %> <% if @issue.estimated_hours %>
<td><b><%=l(:field_estimated_hours)%>:</b></td><td><%= lwr(:label_f_hour, @issue.estimated_hours) %></td> <td class="estimated-hours"><b><%=l(:field_estimated_hours)%>:</b></td><td><%= lwr(:label_f_hour, @issue.estimated_hours) %></td>
<% end %> <% end %>
</tr> </tr>
<tr> <tr>

View File

@ -6,7 +6,10 @@
<h3><%= format_activity_day(day) %></h3> <h3><%= format_activity_day(day) %></h3>
<dl> <dl>
<% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%> <% @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 %>"> <dt class="<%= e.event_type %> <%= User.current.logged? && e.respond_to?(:event_author) && User.current == e.event_author ? 'me' : nil %>">
<%= gravatar(e.user.mail, :size => "24") if e.respond_to?(:user) rescue nil%>
<%= gravatar(e.author.mail, :size => "24") if e.respond_to?(:author) rescue nil%>
<%= gravatar(e.committer.match('\\<.+?\\>')[0].gsub(/[<>]/, ''), :size => "24") if e.respond_to?(:committer) rescue nil%>
<span class="time"><%= format_time(e.event_datetime, false) %></span> <span class="time"><%= format_time(e.event_datetime, false) %></span>
<%= content_tag('span', h(e.project), :class => 'project') if @project.nil? || @project != e.project %> <%= content_tag('span', h(e.project), :class => 'project') if @project.nil? || @project != e.project %>
<%= link_to format_activity_title(e.event_title), e.event_url %></dt> <%= link_to format_activity_title(e.event_title), e.event_url %></dt>

View File

@ -29,7 +29,7 @@
<tbody> <tbody>
<% for user in @users -%> <% for user in @users -%>
<tr class="user <%= cycle("odd", "even") %> <%= %w(anon active registered locked)[user.status] %>"> <tr class="user <%= cycle("odd", "even") %> <%= %w(anon active registered locked)[user.status] %>">
<td class="username"><%= link_to h(user.login), :action => 'edit', :id => user %></td> <td class="username"><%= gravatar(user.mail, :size => "24") %><%= link_to h(user.login), :action => 'edit', :id => user %></td>
<td class="firstname"><%= h(user.firstname) %></td> <td class="firstname"><%= h(user.firstname) %></td>
<td class="lastname"><%= h(user.lastname) %></td> <td class="lastname"><%= h(user.lastname) %></td>
<td class="email"><%= mail_to(h(user.mail)) %></td> <td class="email"><%= mail_to(h(user.mail)) %></td>

View File

@ -615,6 +615,42 @@ vertical-align: middle;
.icon22-settings { background-image: url(../images/22x22/settings.png); } .icon22-settings { background-image: url(../images/22x22/settings.png); }
.icon22-plugin { background-image: url(../images/22x22/plugin.png); } .icon22-plugin { background-image: url(../images/22x22/plugin.png); }
img.gravatar {
padding: 2px;
border: solid 1px #d5d5d5;
background: #fff;
}
div.issue img.gravatar {
float: right;
margin: 0 0 1em 1em;
padding: 5px;
}
div.issue table img.gravatar {
height: 24px;
width: 24px;
padding: 2px;
float: left;
margin: 0 1em 0 0;
}
#history img.gravatar {
padding: 3px;
margin: 0 2em 1em 0;
float: left;
}
td.username img.gravatar {
float: left;
margin: 0 1em 0 0;
}
#activity dt img.gravatar {
float: left;
margin: 0 1em 1em 0;
}
/***** Media print specific styles *****/ /***** Media print specific styles *****/
@media print { @media print {
#top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; } #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; }

20
vendor/plugins/gravatar/MIT-LICENSE vendored Normal file
View File

@ -0,0 +1,20 @@
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.

52
vendor/plugins/gravatar/README vendored Normal file
View File

@ -0,0 +1,52 @@
== 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 svn://rubyforge.org//var/svn/gravatarplugin/plugins/gravatar
or, if you're using piston[http://piston.rubyforge.org] (worth it!):
cd ~/myapp/vendor/plugins
piston import svn://rubyforge.org//var/svn/gravatarplugin/plugins/gravatar
== 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
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
* Get full spec coverage
* Finish rdoc documentation

33
vendor/plugins/gravatar/Rakefile vendored Normal file
View File

@ -0,0 +1,33 @@
require 'spec/rake/spectask'
require 'rake/rdoctask'
desc 'Default: run all specs'
task :default => :spec
desc 'Run all application-specific specs'
Spec::Rake::SpecTask.new(:spec) do |t|
t.warning = true
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

7
vendor/plugins/gravatar/about.yml vendored Normal file
View File

@ -0,0 +1,7 @@
author: Scott Woods, West Arete Computing
summary: View helpers for displaying gravatars.
homepage: http://gravatarplugin.rubyforge.org/
plugin: svn://rubyforge.org//var/svn/gravatarplugin/plugins/gravatar
license: MIT
version: 0.1
rails_version: 1.0+

2
vendor/plugins/gravatar/init.rb vendored Normal file
View File

@ -0,0 +1,2 @@
require 'gravatar'
ActionView::Base.send :include, GravatarHelper::PublicMethods

67
vendor/plugins/gravatar/lib/gravatar.rb vendored Normal file
View File

@ -0,0 +1,67 @@
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.
:alt => 'avatar',
# The class to assign to the img tag for the gravatar.
:class => 'gravatar',
}
# 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].each { |opt| options[opt] = h(options[opt]) }
"<img class=\"#{options[:class]}\" alt=\"#{options[:alt]}\" width=\"#{options[:size]}\" height=\"#{options[:size]}\" src=\"#{src}\" />"
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?
returning "http://www.gravatar.com/avatar.php?gravatar_id=#{email_hash}" do |url|
[:rating, :size, :default].each do |opt|
unless options[opt].nil?
value = h(options[opt])
url << "&#{opt}=#{value}"
end
end
end
end
end
end

View File

@ -0,0 +1,37 @@
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
context "gravatar_url with a custom default URL" do
setup do
@original_options = DEFAULT_OPTIONS.dup
DEFAULT_OPTIONS[:default] = "no_avatar.png"
@url = gravatar_url("somewhere")
end
specify "should include the \"default\" argument in the result" do
@url.should match(/&default=no_avatar.png/)
end
teardown do
DEFAULT_OPTIONS.merge!(@original_options)
end
end
context "gravatar_url with default settings" do
setup do
@url = gravatar_url("somewhere")
end
specify "should have a nil default URL" do
DEFAULT_OPTIONS[:default].should be_nil
end
specify "should not include the \"default\" argument in the result" do
@url.should_not match(/&default=/)
end
end