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:
parent
1399f3dd12
commit
ed314caf7d
|
@ -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 %>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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+
|
|
@ -0,0 +1,2 @@
|
||||||
|
require 'gravatar'
|
||||||
|
ActionView::Base.send :include, GravatarHelper::PublicMethods
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue