##// END OF EJS Templates
Gravatar support for issue detai, user grid, and activity stream...
Eric Davis -
r1960:ed314caf7d6e
parent child
Show More
@@ -0,0 +1,20
1 Copyright (c) 2007 West Arete Computing, Inc.
2
3 Permission is hereby granted, free of charge, to any person obtaining
4 a copy of this software and associated documentation files (the
5 "Software"), to deal in the Software without restriction, including
6 without limitation the rights to use, copy, modify, merge, publish,
7 distribute, sublicense, and/or sell copies of the Software, and to
8 permit persons to whom the Software is furnished to do so, subject to
9 the following conditions:
10
11 The above copyright notice and this permission notice shall be
12 included in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. No newline at end of file
@@ -0,0 +1,52
1 == Gravatar Plugin
2
3 This plugin provides a handful of view helpers for displaying gravatars
4 (globally-recognized avatars).
5
6 Gravatars allow users to configure an avatar to go with their email address at
7 a central location: http://gravatar.com. Gravatar-aware websites (such
8 as yours) can then look up and display each user's preferred avatar, without
9 having to handle avatar management. The user gets the benefit of not having to
10 set up an avatar for each site that they post on.
11
12 == Installation
13
14 cd ~/myapp
15 ruby script/plugin install svn://rubyforge.org//var/svn/gravatarplugin/plugins/gravatar
16
17 or, if you're using piston[http://piston.rubyforge.org] (worth it!):
18
19 cd ~/myapp/vendor/plugins
20 piston import svn://rubyforge.org//var/svn/gravatarplugin/plugins/gravatar
21
22 == Example
23
24 If you represent your users with a model that has an +email+ method (typical
25 for most rails authentication setups), then you can simply use this method
26 in your views:
27
28 <%= gravatar_for @user %>
29
30 This will be replaced with the full HTML +img+ tag necessary for displaying
31 that user's gravatar.
32
33 Other helpers are documented under GravatarHelper::PublicMethods.
34
35 == Acknowledgments
36
37 The following people have also written gravatar-related Ruby libraries:
38 * Seth Rasmussen created the gravatar gem[http://gravatar.rubyforge.org]
39 * Matt McCray has also created a gravatar
40 plugin[http://mattmccray.com/svn/rails/plugins/gravatar_helper]
41
42 == Author
43
44 Scott A. Woods
45 West Arete Computing, Inc.
46 http://westarete.com
47 scott at westarete dot com
48
49 == TODO
50
51 * Get full spec coverage
52 * Finish rdoc documentation No newline at end of file
@@ -0,0 +1,33
1 require 'spec/rake/spectask'
2 require 'rake/rdoctask'
3
4 desc 'Default: run all specs'
5 task :default => :spec
6
7 desc 'Run all application-specific specs'
8 Spec::Rake::SpecTask.new(:spec) do |t|
9 t.warning = true
10 t.rcov = true
11 end
12
13 desc "Report code statistics (KLOCs, etc) from the application"
14 task :stats do
15 RAILS_ROOT = File.dirname(__FILE__)
16 STATS_DIRECTORIES = [
17 %w(Libraries lib/),
18 %w(Specs spec/),
19 ].collect { |name, dir| [ name, "#{RAILS_ROOT}/#{dir}" ] }.select { |name, dir| File.directory?(dir) }
20 require 'code_statistics'
21 CodeStatistics.new(*STATS_DIRECTORIES).to_s
22 end
23
24 namespace :doc do
25 desc 'Generate documentation for the assert_request plugin.'
26 Rake::RDocTask.new(:plugin) do |rdoc|
27 rdoc.rdoc_dir = 'rdoc'
28 rdoc.title = 'Gravatar Rails Plugin'
29 rdoc.options << '--line-numbers' << '--inline-source' << '--accessor' << 'cattr_accessor=rw'
30 rdoc.rdoc_files.include('README')
31 rdoc.rdoc_files.include('lib/**/*.rb')
32 end
33 end
@@ -0,0 +1,7
1 author: Scott Woods, West Arete Computing
2 summary: View helpers for displaying gravatars.
3 homepage: http://gravatarplugin.rubyforge.org/
4 plugin: svn://rubyforge.org//var/svn/gravatarplugin/plugins/gravatar
5 license: MIT
6 version: 0.1
7 rails_version: 1.0+
@@ -0,0 +1,2
1 require 'gravatar'
2 ActionView::Base.send :include, GravatarHelper::PublicMethods
@@ -0,0 +1,67
1 require 'digest/md5'
2 require 'cgi'
3
4 module GravatarHelper
5
6 # These are the options that control the default behavior of the public
7 # methods. They can be overridden during the actual call to the helper,
8 # or you can set them in your environment.rb as such:
9 #
10 # # Allow racier gravatars
11 # GravatarHelper::DEFAULT_OPTIONS[:rating] = 'R'
12 #
13 DEFAULT_OPTIONS = {
14 # The URL of a default image to display if the given email address does
15 # not have a gravatar.
16 :default => nil,
17
18 # The default size in pixels for the gravatar image (they're square).
19 :size => 50,
20
21 # The maximum allowed MPAA rating for gravatars. This allows you to
22 # exclude gravatars that may be out of character for your site.
23 :rating => 'PG',
24
25 # The alt text to use in the img tag for the gravatar.
26 :alt => 'avatar',
27
28 # The class to assign to the img tag for the gravatar.
29 :class => 'gravatar',
30 }
31
32 # The methods that will be made available to your views.
33 module PublicMethods
34
35 # Return the HTML img tag for the given user's gravatar. Presumes that
36 # the given user object will respond_to "email", and return the user's
37 # email address.
38 def gravatar_for(user, options={})
39 gravatar(user.email, options)
40 end
41
42 # Return the HTML img tag for the given email address's gravatar.
43 def gravatar(email, options={})
44 src = h(gravatar_url(email, options))
45 options = DEFAULT_OPTIONS.merge(options)
46 [:class, :alt, :size].each { |opt| options[opt] = h(options[opt]) }
47 "<img class=\"#{options[:class]}\" alt=\"#{options[:alt]}\" width=\"#{options[:size]}\" height=\"#{options[:size]}\" src=\"#{src}\" />"
48 end
49
50 # Return the gravatar URL for the given email address.
51 def gravatar_url(email, options={})
52 email_hash = Digest::MD5.hexdigest(email)
53 options = DEFAULT_OPTIONS.merge(options)
54 options[:default] = CGI::escape(options[:default]) unless options[:default].nil?
55 returning "http://www.gravatar.com/avatar.php?gravatar_id=#{email_hash}" do |url|
56 [:rating, :size, :default].each do |opt|
57 unless options[opt].nil?
58 value = h(options[opt])
59 url << "&#{opt}=#{value}"
60 end
61 end
62 end
63 end
64
65 end
66
67 end No newline at end of file
@@ -0,0 +1,37
1 require 'rubygems'
2 require 'erb' # to get "h"
3 require 'active_support' # to get "returning"
4 require File.dirname(__FILE__) + '/../lib/gravatar'
5 include GravatarHelper, GravatarHelper::PublicMethods, ERB::Util
6
7 context "gravatar_url with a custom default URL" do
8 setup do
9 @original_options = DEFAULT_OPTIONS.dup
10 DEFAULT_OPTIONS[:default] = "no_avatar.png"
11 @url = gravatar_url("somewhere")
12 end
13
14 specify "should include the \"default\" argument in the result" do
15 @url.should match(/&default=no_avatar.png/)
16 end
17
18 teardown do
19 DEFAULT_OPTIONS.merge!(@original_options)
20 end
21
22 end
23
24 context "gravatar_url with default settings" do
25 setup do
26 @url = gravatar_url("somewhere")
27 end
28
29 specify "should have a nil default URL" do
30 DEFAULT_OPTIONS[:default].should be_nil
31 end
32
33 specify "should not include the \"default\" argument in the result" do
34 @url.should_not match(/&default=/)
35 end
36
37 end No newline at end of file
@@ -1,14 +1,15
1 <% reply_links = authorize_for('issues', 'edit') -%>
1 <% reply_links = authorize_for('issues', 'edit') -%>
2 <% for journal in journals %>
2 <% for journal in journals %>
3 <div id="change-<%= journal.id %>" class="journal">
3 <div id="change-<%= journal.id %>" class="journal">
4 <h4><div style="float:right;"><%= link_to "##{journal.indice}", :anchor => "note-#{journal.indice}" %></div>
4 <%= gravatar(journal.user.mail.blank? ? "" : journal.user.mail, :size => "48") %>
5 <%= content_tag('a', '', :name => "note-#{journal.indice}")%>
5 <h4><div style="float:right;"><%= link_to "##{journal.indice}", :anchor => "note-#{journal.indice}" %></div>
6 <%= format_time(journal.created_on) %> - <%= journal.user.name %></h4>
6 <%= content_tag('a', '', :name => "note-#{journal.indice}")%>
7 <ul>
7 <%= format_time(journal.created_on) %> - <%= journal.user.name %></h4>
8 <% for detail in journal.details %>
8 <ul>
9 <li><%= show_detail(detail) %></li>
9 <% for detail in journal.details %>
10 <% end %>
10 <li><%= show_detail(detail) %></li>
11 </ul>
11 <% end %>
12 <%= render_notes(journal, :reply_links => reply_links) unless journal.notes.blank? %>
12 </ul>
13 </div>
13 <%= render_notes(journal, :reply_links => reply_links) unless journal.notes.blank? %>
14 </div>
14 <% end %>
15 <% end %>
@@ -10,6 +10,7
10 <h2><%= @issue.tracker.name %> #<%= @issue.id %></h2>
10 <h2><%= @issue.tracker.name %> #<%= @issue.id %></h2>
11
11
12 <div class="issue <%= "status-#{@issue.status.position} priority-#{@issue.priority.position}" %>">
12 <div class="issue <%= "status-#{@issue.status.position} priority-#{@issue.priority.position}" %>">
13 <%= gravatar(@issue.author.mail, :size => "64") %>
13 <h3><%=h @issue.subject %></h3>
14 <h3><%=h @issue.subject %></h3>
14 <p class="author">
15 <p class="author">
15 <%= authoring @issue.created_on, @issue.author %>.
16 <%= authoring @issue.created_on, @issue.author %>.
@@ -18,28 +19,28
18
19
19 <table width="100%">
20 <table width="100%">
20 <tr>
21 <tr>
21 <td style="width:15%"><b><%=l(:field_status)%>:</b></td><td style="width:35%"><%= @issue.status.name %></td>
22 <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>
22 <td style="width:15%"><b><%=l(:field_start_date)%>:</b></td><td style="width:35%"><%= format_date(@issue.start_date) %></td>
23 <td style="width:15%" class="start-date"><b><%=l(:field_start_date)%>:</b></td><td style="width:35%"><%= format_date(@issue.start_date) %></td>
23 </tr>
24 </tr>
24 <tr>
25 <tr>
25 <td><b><%=l(:field_priority)%>:</b></td><td><%= @issue.priority.name %></td>
26 <td class="priority"><b><%=l(:field_priority)%>:</b></td><td class="priority priority-<%= @issue.priority.name %>"><%= @issue.priority.name %></td>
26 <td><b><%=l(:field_due_date)%>:</b></td><td><%= format_date(@issue.due_date) %></td>
27 <td class="due-date"><b><%=l(:field_due_date)%>:</b></td><td class="due-date"><%= format_date(@issue.due_date) %></td>
27 </tr>
28 </tr>
28 <tr>
29 <tr>
29 <td><b><%=l(:field_assigned_to)%>:</b></td><td><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %></td>
30 <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>
30 <td><b><%=l(:field_done_ratio)%>:</b></td><td><%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %></td>
31 <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>
31 </tr>
32 </tr>
32 <tr>
33 <tr>
33 <td><b><%=l(:field_category)%>:</b></td><td><%=h @issue.category ? @issue.category.name : "-" %></td>
34 <td class="category"><b><%=l(:field_category)%>:</b></td><td><%=h @issue.category ? @issue.category.name : "-" %></td>
34 <% if User.current.allowed_to?(:view_time_entries, @project) %>
35 <% if User.current.allowed_to?(:view_time_entries, @project) %>
35 <td><b><%=l(:label_spent_time)%>:</b></td>
36 <td class="spent-time"><b><%=l(:label_spent_time)%>:</b></td>
36 <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>
37 <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>
37 <% end %>
38 <% end %>
38 </tr>
39 </tr>
39 <tr>
40 <tr>
40 <td><b><%=l(:field_fixed_version)%>:</b></td><td><%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %></td>
41 <td class="fixed-version"><b><%=l(:field_fixed_version)%>:</b></td><td><%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %></td>
41 <% if @issue.estimated_hours %>
42 <% if @issue.estimated_hours %>
42 <td><b><%=l(:field_estimated_hours)%>:</b></td><td><%= lwr(:label_f_hour, @issue.estimated_hours) %></td>
43 <td class="estimated-hours"><b><%=l(:field_estimated_hours)%>:</b></td><td><%= lwr(:label_f_hour, @issue.estimated_hours) %></td>
43 <% end %>
44 <% end %>
44 </tr>
45 </tr>
45 <tr>
46 <tr>
@@ -6,7 +6,10
6 <h3><%= format_activity_day(day) %></h3>
6 <h3><%= format_activity_day(day) %></h3>
7 <dl>
7 <dl>
8 <% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%>
8 <% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%>
9 <dt class="<%= e.event_type %> <%= User.current.logged? && e.respond_to?(:event_author) && User.current == e.event_author ? 'me' : nil %>">
9 <dt class="<%= e.event_type %> <%= User.current.logged? && e.respond_to?(:event_author) && User.current == e.event_author ? 'me' : nil %>">
10 <%= gravatar(e.user.mail, :size => "24") if e.respond_to?(:user) rescue nil%>
11 <%= gravatar(e.author.mail, :size => "24") if e.respond_to?(:author) rescue nil%>
12 <%= gravatar(e.committer.match('\\<.+?\\>')[0].gsub(/[<>]/, ''), :size => "24") if e.respond_to?(:committer) rescue nil%>
10 <span class="time"><%= format_time(e.event_datetime, false) %></span>
13 <span class="time"><%= format_time(e.event_datetime, false) %></span>
11 <%= content_tag('span', h(e.project), :class => 'project') if @project.nil? || @project != e.project %>
14 <%= content_tag('span', h(e.project), :class => 'project') if @project.nil? || @project != e.project %>
12 <%= link_to format_activity_title(e.event_title), e.event_url %></dt>
15 <%= link_to format_activity_title(e.event_title), e.event_url %></dt>
@@ -29,7 +29,7
29 <tbody>
29 <tbody>
30 <% for user in @users -%>
30 <% for user in @users -%>
31 <tr class="user <%= cycle("odd", "even") %> <%= %w(anon active registered locked)[user.status] %>">
31 <tr class="user <%= cycle("odd", "even") %> <%= %w(anon active registered locked)[user.status] %>">
32 <td class="username"><%= link_to h(user.login), :action => 'edit', :id => user %></td>
32 <td class="username"><%= gravatar(user.mail, :size => "24") %><%= link_to h(user.login), :action => 'edit', :id => user %></td>
33 <td class="firstname"><%= h(user.firstname) %></td>
33 <td class="firstname"><%= h(user.firstname) %></td>
34 <td class="lastname"><%= h(user.lastname) %></td>
34 <td class="lastname"><%= h(user.lastname) %></td>
35 <td class="email"><%= mail_to(h(user.mail)) %></td>
35 <td class="email"><%= mail_to(h(user.mail)) %></td>
@@ -615,6 +615,42 vertical-align: middle;
615 .icon22-settings { background-image: url(../images/22x22/settings.png); }
615 .icon22-settings { background-image: url(../images/22x22/settings.png); }
616 .icon22-plugin { background-image: url(../images/22x22/plugin.png); }
616 .icon22-plugin { background-image: url(../images/22x22/plugin.png); }
617
617
618 img.gravatar {
619 padding: 2px;
620 border: solid 1px #d5d5d5;
621 background: #fff;
622 }
623
624 div.issue img.gravatar {
625 float: right;
626 margin: 0 0 1em 1em;
627 padding: 5px;
628 }
629
630 div.issue table img.gravatar {
631 height: 24px;
632 width: 24px;
633 padding: 2px;
634 float: left;
635 margin: 0 1em 0 0;
636 }
637
638 #history img.gravatar {
639 padding: 3px;
640 margin: 0 2em 1em 0;
641 float: left;
642 }
643
644 td.username img.gravatar {
645 float: left;
646 margin: 0 1em 0 0;
647 }
648
649 #activity dt img.gravatar {
650 float: left;
651 margin: 0 1em 1em 0;
652 }
653
618 /***** Media print specific styles *****/
654 /***** Media print specific styles *****/
619 @media print {
655 @media print {
620 #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; }
656 #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; }
General Comments 0
You need to be logged in to leave comments. Login now