Activity enhancements:

* overall activity view and feed added, link is available on the project list (#423, #494)
* switch added on the project activity view to include subprojects (closes #530)

git-svn-id: http://redmine.rubyforge.org/svn/trunk@1227 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
Jean-Philippe Lang 2008-03-11 19:33:38 +00:00
parent 64fb0a561a
commit 624723d0ce
39 changed files with 198 additions and 63 deletions

View File

@ -24,8 +24,9 @@ class ProjectsController < ApplicationController
menu_item :settings, :only => :settings menu_item :settings, :only => :settings
menu_item :issues, :only => [:changelog] menu_item :issues, :only => [:changelog]
before_filter :find_project, :except => [ :index, :list, :add ] before_filter :find_project, :except => [ :index, :list, :add, :activity ]
before_filter :authorize, :except => [ :index, :list, :add, :archive, :unarchive, :destroy ] before_filter :find_optional_project, :only => :activity
before_filter :authorize, :except => [ :index, :list, :add, :archive, :unarchive, :destroy, :activity ]
before_filter :require_admin, :only => [ :add, :archive, :unarchive, :destroy ] before_filter :require_admin, :only => [ :add, :archive, :unarchive, :destroy ]
accept_key_auth :activity, :calendar accept_key_auth :activity, :calendar
@ -228,12 +229,14 @@ class ProjectsController < ApplicationController
@date_from = @date_to - @days @date_from = @date_to - @days
@event_types = %w(issues news files documents changesets wiki_pages messages) @event_types = %w(issues news files documents changesets wiki_pages messages)
if @project
@event_types.delete('wiki_pages') unless @project.wiki @event_types.delete('wiki_pages') unless @project.wiki
@event_types.delete('changesets') unless @project.repository @event_types.delete('changesets') unless @project.repository
@event_types.delete('messages') unless @project.boards.any? @event_types.delete('messages') unless @project.boards.any?
# only show what the user is allowed to view # only show what the user is allowed to view
@event_types = @event_types.select {|o| User.current.allowed_to?("view_#{o}".to_sym, @project)} @event_types = @event_types.select {|o| User.current.allowed_to?("view_#{o}".to_sym, @project)}
@with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
end
@scope = @event_types.select {|t| params["show_#{t}"]} @scope = @event_types.select {|t| params["show_#{t}"]}
# default events if none is specified in parameters # default events if none is specified in parameters
@scope = (@event_types - %w(wiki_pages messages))if @scope.empty? @scope = (@event_types - %w(wiki_pages messages))if @scope.empty?
@ -241,21 +244,41 @@ class ProjectsController < ApplicationController
@events = [] @events = []
if @scope.include?('issues') if @scope.include?('issues')
@events += @project.issues.find(:all, :include => [:author, :tracker], :conditions => ["#{Issue.table_name}.created_on>=? and #{Issue.table_name}.created_on<=?", @date_from, @date_to] ) cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_issues, :project => @project, :with_subprojects => @with_subprojects))
@events += @project.issues_status_changes(@date_from, @date_to) cond.add(["#{Issue.table_name}.created_on BETWEEN ? AND ?", @date_from, @date_to])
@events += Issue.find(:all, :include => [:project, :author, :tracker], :conditions => cond.conditions)
cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_issues, :project => @project, :with_subprojects => @with_subprojects))
cond.add(["#{Journal.table_name}.journalized_type = 'Issue' AND #{JournalDetail.table_name}.prop_key = 'status_id' AND #{Journal.table_name}.created_on BETWEEN ? AND ?", @date_from, @date_to])
@events += Journal.find(:all, :include => [{:issue => :project}, :details, :user], :conditions => cond.conditions)
end end
if @scope.include?('news') if @scope.include?('news')
@events += @project.news.find(:all, :conditions => ["#{News.table_name}.created_on>=? and #{News.table_name}.created_on<=?", @date_from, @date_to], :include => :author ) cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_news, :project => @project, :with_subprojects => @with_subprojects))
cond.add(["#{News.table_name}.created_on BETWEEN ? AND ?", @date_from, @date_to])
@events += News.find(:all, :include => [:project, :author], :conditions => cond.conditions)
end end
if @scope.include?('files') if @scope.include?('files')
@events += Attachment.find(:all, :select => "#{Attachment.table_name}.*", :joins => "LEFT JOIN #{Version.table_name} ON #{Version.table_name}.id = #{Attachment.table_name}.container_id", :conditions => ["#{Attachment.table_name}.container_type='Version' and #{Version.table_name}.project_id=? and #{Attachment.table_name}.created_on>=? and #{Attachment.table_name}.created_on<=?", @project.id, @date_from, @date_to], :include => :author ) cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_files, :project => @project, :with_subprojects => @with_subprojects))
cond.add(["#{Attachment.table_name}.created_on BETWEEN ? AND ?", @date_from, @date_to])
@events += Attachment.find(:all, :select => "#{Attachment.table_name}.*",
:joins => "LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Version' AND #{Version.table_name}.id = #{Attachment.table_name}.container_id " +
"LEFT JOIN #{Project.table_name} ON #{Version.table_name}.project_id = #{Project.table_name}.id",
:conditions => cond.conditions)
end end
if @scope.include?('documents') if @scope.include?('documents')
@events += @project.documents.find(:all, :conditions => ["#{Document.table_name}.created_on>=? and #{Document.table_name}.created_on<=?", @date_from, @date_to] ) cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_documents, :project => @project, :with_subprojects => @with_subprojects))
@events += Attachment.find(:all, :select => "attachments.*", :joins => "LEFT JOIN #{Document.table_name} ON #{Document.table_name}.id = #{Attachment.table_name}.container_id", :conditions => ["#{Attachment.table_name}.container_type='Document' and #{Document.table_name}.project_id=? and #{Attachment.table_name}.created_on>=? and #{Attachment.table_name}.created_on<=?", @project.id, @date_from, @date_to], :include => :author ) cond.add(["#{Document.table_name}.created_on BETWEEN ? AND ?", @date_from, @date_to])
@events += Document.find(:all, :include => :project, :conditions => cond.conditions)
cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_documents, :project => @project, :with_subprojects => @with_subprojects))
cond.add(["#{Attachment.table_name}.created_on BETWEEN ? AND ?", @date_from, @date_to])
@events += Attachment.find(:all, :select => "#{Attachment.table_name}.*",
:joins => "LEFT JOIN #{Document.table_name} ON #{Attachment.table_name}.container_type='Document' AND #{Document.table_name}.id = #{Attachment.table_name}.container_id " +
"LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id",
:conditions => cond.conditions)
end end
if @scope.include?('wiki_pages') if @scope.include?('wiki_pages')
@ -264,28 +287,31 @@ class ProjectsController < ApplicationController
"#{WikiContent.versioned_table_name}.page_id, #{WikiContent.versioned_table_name}.author_id, " + "#{WikiContent.versioned_table_name}.page_id, #{WikiContent.versioned_table_name}.author_id, " +
"#{WikiContent.versioned_table_name}.id" "#{WikiContent.versioned_table_name}.id"
joins = "LEFT JOIN #{WikiPage.table_name} ON #{WikiPage.table_name}.id = #{WikiContent.versioned_table_name}.page_id " + joins = "LEFT JOIN #{WikiPage.table_name} ON #{WikiPage.table_name}.id = #{WikiContent.versioned_table_name}.page_id " +
"LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id " "LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id " +
conditions = ["#{Wiki.table_name}.project_id = ? AND #{WikiContent.versioned_table_name}.updated_on BETWEEN ? AND ?", "LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Wiki.table_name}.project_id"
@project.id, @date_from, @date_to]
@events += WikiContent.versioned_class.find(:all, :select => select, :joins => joins, :conditions => conditions) cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_wiki_pages, :project => @project, :with_subprojects => @with_subprojects))
cond.add(["#{WikiContent.versioned_table_name}.updated_on BETWEEN ? AND ?", @date_from, @date_to])
@events += WikiContent.versioned_class.find(:all, :select => select, :joins => joins, :conditions => cond.conditions)
end end
if @scope.include?('changesets') if @scope.include?('changesets')
@events += Changeset.find(:all, :include => :repository, :conditions => ["#{Repository.table_name}.project_id = ? AND #{Changeset.table_name}.committed_on BETWEEN ? AND ?", @project.id, @date_from, @date_to]) cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_changesets, :project => @project, :with_subprojects => @with_subprojects))
cond.add(["#{Changeset.table_name}.committed_on BETWEEN ? AND ?", @date_from, @date_to])
@events += Changeset.find(:all, :include => {:repository => :project}, :conditions => cond.conditions)
end end
if @scope.include?('messages') if @scope.include?('messages')
@events += Message.find(:all, cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_messages, :project => @project, :with_subprojects => @with_subprojects))
:include => [:board, :author], cond.add(["#{Message.table_name}.created_on BETWEEN ? AND ?", @date_from, @date_to])
:conditions => ["#{Board.table_name}.project_id=? AND #{Message.table_name}.created_on BETWEEN ? AND ?", @project.id, @date_from, @date_to]) @events += Message.find(:all, :include => [{:board => :project}, :author], :conditions => cond.conditions)
end end
@events_by_day = @events.group_by(&:event_date) @events_by_day = @events.group_by(&:event_date)
respond_to do |format| respond_to do |format|
format.html { render :layout => false if request.xhr? } format.html { render :layout => false if request.xhr? }
format.atom { render_feed(@events, :title => "#{@project.name}: #{l(:label_activity)}") } format.atom { render_feed(@events, :title => "#{@project || Setting.app_title}: #{l(:label_activity)}") }
end end
end end
@ -381,6 +407,14 @@ private
render_404 render_404
end end
def find_optional_project
return true unless params[:id]
@project = Project.find(params[:id])
authorize
rescue ActiveRecord::RecordNotFound
render_404
end
def retrieve_selected_tracker_ids(selectable_trackers) def retrieve_selected_tracker_ids(selectable_trackers)
if ids = params[:tracker_ids] if ids = params[:tracker_ids]
@selected_tracker_ids = (ids.is_a? Array) ? ids.collect { |id| id.to_i.to_s } : ids.split('/').collect { |id| id.to_i.to_s } @selected_tracker_ids = (ids.is_a? Array) ? ids.collect { |id| id.to_i.to_s } : ids.split('/').collect { |id| id.to_i.to_s }

View File

@ -26,7 +26,6 @@ class Attachment < ActiveRecord::Base
validates_length_of :disk_filename, :maximum => 255 validates_length_of :disk_filename, :maximum => 255
acts_as_event :title => :filename, acts_as_event :title => :filename,
:description => :filename,
:url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id}} :url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id}}
cattr_accessor :storage_path cattr_accessor :storage_path

View File

@ -45,6 +45,10 @@ class Changeset < ActiveRecord::Base
super super
end end
def project
repository.project
end
def after_create def after_create
scan_comment_for_issue_ids scan_comment_for_issue_ids
end end

View File

@ -84,16 +84,6 @@ class Project < ActiveRecord::Base
end end
end end
# Return all issues status changes for the project between the 2 given dates
def issues_status_changes(from, to)
Journal.find(:all, :include => [:issue, :details, :user],
:conditions => ["#{Journal.table_name}.journalized_type = 'Issue'" +
" AND #{Issue.table_name}.project_id = ?" +
" AND #{JournalDetail.table_name}.prop_key = 'status_id'" +
" AND #{Journal.table_name}.created_on BETWEEN ? AND ?",
id, from, to+1])
end
# returns latest created projects # returns latest created projects
# non public projects will be returned only if user is a member of those # non public projects will be returned only if user is a member of those
def self.latest(user=nil, count=5) def self.latest(user=nil, count=5)
@ -110,19 +100,28 @@ class Project < ActiveRecord::Base
end end
end end
def self.allowed_to_condition(user, permission) def self.allowed_to_condition(user, permission, options={})
statements = [] statements = []
active_statement = "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}" base_statement = "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}"
if options[:project]
project_statement = "#{Project.table_name}.id = #{options[:project].id}"
project_statement << " OR #{Project.table_name}.parent_id = #{options[:project].id}" if options[:with_subprojects]
base_statement = "(#{project_statement}) AND (#{base_statement})"
end
if user.admin? if user.admin?
# no restriction # no restriction
elsif user.logged? elsif user.logged?
statements << "#{Project.table_name}.is_public = #{connection.quoted_true}" if Role.non_member.allowed_to?(permission) statements << "#{Project.table_name}.is_public = #{connection.quoted_true}" if Role.non_member.allowed_to?(permission)
allowed_project_ids = user.memberships.select {|m| m.role.allowed_to?(permission)}.collect {|m| m.project_id} allowed_project_ids = user.memberships.select {|m| m.role.allowed_to?(permission)}.collect {|m| m.project_id}
statements << "#{Project.table_name}.id IN (#{allowed_project_ids.join(',')})" if allowed_project_ids.any? statements << "#{Project.table_name}.id IN (#{allowed_project_ids.join(',')})" if allowed_project_ids.any?
elsif Role.anonymous.allowed_to?(permission)
# anonymous user allowed on public project
statements << "#{Project.table_name}.is_public = #{connection.quoted_true}"
else else
statements << "#{Project.table_name}.is_public = #{connection.quoted_true}" if Role.anonymous.allowed_to?(permission) # anonymous user is not authorized
statements << "1=0"
end end
statements.empty? ? active_statement : "(#{active_statement} AND (#{statements.join(' OR ')}))" statements.empty? ? base_statement : "((#{base_statement}) AND (#{statements.join(' OR ')}))"
end end
def self.find(*args) def self.find(*args)

View File

@ -61,6 +61,10 @@ class WikiContent < ActiveRecord::Base
end end
end end
def project
page.project
end
# Returns the previous version or nil # Returns the previous version or nil
def previous def previous
@previous ||= WikiContent::Version.find(:first, @previous ||= WikiContent::Version.find(:first,

View File

@ -9,9 +9,10 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do
xml.generator(:uri => Redmine::Info.url, :version => Redmine::VERSION) { xml.text! Redmine::Info.versioned_name; } xml.generator(:uri => Redmine::Info.url, :version => Redmine::VERSION) { xml.text! Redmine::Info.versioned_name; }
@items.each do |item| @items.each do |item|
xml.entry do xml.entry do
url = url_for(item.event_url(:only_path => false))
xml.title truncate(item.event_title, 100) xml.title truncate(item.event_title, 100)
xml.link "rel" => "alternate", "href" => url_for(item.event_url(:only_path => false)) xml.link "rel" => "alternate", "href" => url
xml.id url_for(item.event_url(:only_path => false)) xml.id url
xml.updated item.event_datetime.xmlschema xml.updated item.event_datetime.xmlschema
author = item.event_author if item.respond_to?(:author) author = item.event_author if item.respond_to?(:author)
xml.author do xml.author do

View File

@ -6,7 +6,7 @@
<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.class.name.downcase %>"><span class="time"><%= format_time(e.event_datetime, false) %></span> <dt class="<%= e.class.name.downcase %>"><span class="time"><%= format_time(e.event_datetime, false) %></span>
<%= link_to h(truncate(e.event_title, 100)), e.event_url %></dt> <%= content_tag('span', h(e.project), :class => 'project') if @project.nil? || @project != e.project %> <%= link_to h(truncate(e.event_title, 100)), e.event_url %></dt>
<dd><% unless e.event_description.blank? -%> <dd><% unless e.event_description.blank? -%>
<span class="description"><%= format_activity_description(e.event_description) %></span><br /> <span class="description"><%= format_activity_description(e.event_description) %></span><br />
<% end %> <% end %>
@ -35,16 +35,20 @@
</p> </p>
<% content_for :header_tags do %> <% content_for :header_tags do %>
<%= auto_discovery_link_tag(:atom, params.merge(:format => 'atom', :year => nil, :month => nil, :key => User.current.rss_key).delete_if{|k,v|k=="commit"}) %> <%= auto_discovery_link_tag(:atom, params.merge(:format => 'atom', :year => nil, :month => nil, :key => User.current.rss_key)) %>
<% end %> <% end %>
<% content_for :sidebar do %> <% content_for :sidebar do %>
<% form_tag do %> <% form_tag({}, :method => :get) do %>
<h3><%= l(:label_activity) %></h3> <h3><%= l(:label_activity) %></h3>
<p><% @event_types.each do |t| %> <p><% @event_types.each do |t| %>
<label><%= check_box_tag "show_#{t}", 1, @scope.include?(t) %> <%= l("label_#{t.singularize}_plural")%></label><br /> <label><%= check_box_tag "show_#{t}", 1, @scope.include?(t) %> <%= l("label_#{t.singularize}_plural")%></label><br />
<% end %></p> <% end %></p>
<p><%= submit_tag l(:button_apply), :class => 'button-small' %></p> <% if @project && @project.active_children.any? %>
<p><label><%= check_box_tag 'with_subprojects', 1, @with_subprojects %> <%=l(:label_subproject_plural)%></label></p>
<%= hidden_field_tag 'with_subprojects', 0 %>
<% end %>
<p><%= submit_tag l(:button_apply), :class => 'button-small', :name => nil %></p>
<% end %> <% end %>
<% end %> <% end %>

View File

@ -1,3 +1,8 @@
<div class="contextual">
<%= link_to l(:label_issue_view_all), { :controller => 'issues' } %> |
<%= link_to l(:label_overall_activity), { :controller => 'projects', :action => 'activity' }%>
</div>
<h2><%=l(:label_project_plural)%></h2> <h2><%=l(:label_project_plural)%></h2>
<% @project_tree.keys.sort.each do |project| %> <% @project_tree.keys.sort.each do |project| %>

View File

@ -26,5 +26,8 @@
</div> </div>
<% content_for :header_tags do %> <% content_for :header_tags do %>
<%= auto_discovery_link_tag(:atom, {:controller => 'news', :action => 'index', :key => User.current.rss_key, :format => 'atom'}, {:title => l(:label_news_latest)}) %> <%= auto_discovery_link_tag(:atom, {:controller => 'news', :action => 'index', :key => User.current.rss_key, :format => 'atom'},
:title => "#{Setting.app_title}: #{l(:label_news_latest)}") %>
<%= auto_discovery_link_tag(:atom, {:controller => 'projects', :action => 'activity', :key => User.current.rss_key, :format => 'atom'},
:title => "#{Setting.app_title}: #{l(:label_activity)}") %>
<% end %> <% end %>

View File

@ -613,3 +613,4 @@ field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
setting_display_subprojects_issues: Display subprojects issues on main projects by default setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Overall activity

View File

@ -613,3 +613,4 @@ field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
setting_display_subprojects_issues: Display subprojects issues on main projects by default setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Overall activity

View File

@ -615,3 +615,4 @@ field_comments_sorting: Display comments
text_reassign_time_entries: 'Reassign reported hours to this issue:' text_reassign_time_entries: 'Reassign reported hours to this issue:'
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
label_overall_activity: Overall activity

View File

@ -614,3 +614,4 @@ field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
setting_display_subprojects_issues: Display subprojects issues on main projects by default setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Overall activity

View File

@ -280,6 +280,7 @@ label_last_updates: Last updated
label_last_updates_plural: %d last updated label_last_updates_plural: %d last updated
label_registered_on: Registered on label_registered_on: Registered on
label_activity: Activity label_activity: Activity
label_overall_activity: Overall activity
label_new: New label_new: New
label_logged_as: Logged as label_logged_as: Logged as
label_environment: Environment label_environment: Environment

View File

@ -616,3 +616,4 @@ field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
setting_display_subprojects_issues: Display subprojects issues on main projects by default setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Overall activity

View File

@ -620,3 +620,4 @@ setting_display_subprojects_issues: Display subprojects issues on main projects
field_comments_sorting: Display comments field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
label_overall_activity: Overall activity

View File

@ -165,6 +165,7 @@ field_start_page: Page de démarrage
field_subproject: Sous-projet field_subproject: Sous-projet
field_hours: Heures field_hours: Heures
field_activity: Activité field_activity: Activité
label_overall_activity: Activité globale
field_spent_on: Date field_spent_on: Date
field_identifier: Identifiant field_identifier: Identifiant
field_is_filter: Utilisé comme filtre field_is_filter: Utilisé comme filtre
@ -452,7 +453,7 @@ label_start_to_start: début à début
label_start_to_end: début à fin label_start_to_end: début à fin
label_stay_logged_in: Rester connecté label_stay_logged_in: Rester connecté
label_disabled: désactivé label_disabled: désactivé
label_show_completed_versions: Voire les versions passées label_show_completed_versions: Voir les versions passées
label_me: moi label_me: moi
label_board: Forum label_board: Forum
label_board_new: Nouveau forum label_board_new: Nouveau forum

View File

@ -613,3 +613,4 @@ field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
setting_display_subprojects_issues: Display subprojects issues on main projects by default setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Overall activity

View File

@ -613,3 +613,4 @@ field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
setting_display_subprojects_issues: Display subprojects issues on main projects by default setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Overall activity

View File

@ -614,3 +614,4 @@ field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
setting_display_subprojects_issues: Display subprojects issues on main projects by default setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Overall activity

View File

@ -613,3 +613,4 @@ field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
setting_display_subprojects_issues: Display subprojects issues on main projects by default setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Overall activity

View File

@ -614,3 +614,4 @@ field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
setting_display_subprojects_issues: Display subprojects issues on main projects by default setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Overall activity

View File

@ -614,3 +614,4 @@ field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
setting_display_subprojects_issues: Display subprojects issues on main projects by default setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Overall activity

View File

@ -613,3 +613,4 @@ setting_display_subprojects_issues: Display subprojects issues on main projects
field_comments_sorting: Display comments field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
label_overall_activity: Overall activity

View File

@ -613,3 +613,4 @@ field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
setting_display_subprojects_issues: Display subprojects issues on main projects by default setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Overall activity

View File

@ -613,3 +613,4 @@ field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
setting_display_subprojects_issues: Display subprojects issues on main projects by default setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Overall activity

View File

@ -613,3 +613,4 @@ field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
setting_display_subprojects_issues: Display subprojects issues on main projects by default setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Overall activity

View File

@ -617,3 +617,4 @@ field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
setting_display_subprojects_issues: Display subprojects issues on main projects by default setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Overall activity

View File

@ -614,3 +614,4 @@ field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
setting_display_subprojects_issues: Display subprojects issues on main projects by default setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Overall activity

View File

@ -614,3 +614,4 @@ field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
setting_display_subprojects_issues: Display subprojects issues on main projects by default setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Overall activity

View File

@ -615,3 +615,4 @@ field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences label_preferences: Preferences
setting_display_subprojects_issues: Display subprojects issues on main projects by default setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Overall activity

View File

@ -614,3 +614,4 @@ default_activity_development: 開發
enumeration_issue_priorities: 項目優先權 enumeration_issue_priorities: 項目優先權
enumeration_doc_categories: 文件分類 enumeration_doc_categories: 文件分類
enumeration_activities: 活動 (time tracking) enumeration_activities: 活動 (time tracking)
label_overall_activity: Overall activity

View File

@ -614,3 +614,4 @@ default_activity_development: 开发
enumeration_issue_priorities: 问题优先级 enumeration_issue_priorities: 问题优先级
enumeration_doc_categories: 文档类别 enumeration_doc_categories: 文档类别
enumeration_activities: 活动(时间跟踪) enumeration_activities: 活动(时间跟踪)
label_overall_activity: Overall activity

View File

@ -20,7 +20,7 @@ class ARCondition
def initialize(condition=nil) def initialize(condition=nil)
@conditions = ['1=1'] @conditions = ['1=1']
@conditions.add(condition) if condition add(condition) if condition
end end
def add(condition) def add(condition)

View File

@ -169,6 +169,7 @@ div#activity dd { margin-bottom: 1em; }
div#activity dt { margin-bottom: 1px; } div#activity dt { margin-bottom: 1px; }
div#activity dt .time { color: #777; font-size: 80%; } div#activity dt .time { color: #777; font-size: 80%; }
div#activity dd .description { font-style: italic; } div#activity dd .description { font-style: italic; }
div#activity span.project:after { content: " -"; }
div#roadmap fieldset.related-issues { margin-bottom: 1em; } div#roadmap fieldset.related-issues { margin-bottom: 1em; }
div#roadmap fieldset.related-issues ul { margin-top: 0.3em; margin-bottom: 0.3em; } div#roadmap fieldset.related-issues ul { margin-top: 0.3em; margin-bottom: 0.3em; }

View File

@ -44,9 +44,9 @@ issues_003:
start_date: <%= 1.day.from_now.to_date.to_s(:db) %> start_date: <%= 1.day.from_now.to_date.to_s(:db) %>
due_date: <%= 40.day.ago.to_date.to_s(:db) %> due_date: <%= 40.day.ago.to_date.to_s(:db) %>
issues_004: issues_004:
created_on: 2006-07-19 21:07:27 +02:00 created_on: <%= 5.days.ago.to_date.to_s(:db) %>
project_id: 2 project_id: 2
updated_on: 2006-07-19 21:07:27 +02:00 updated_on: <%= 2.days.ago.to_date.to_s(:db) %>
priority_id: 4 priority_id: 4
subject: Issue on project 2 subject: Issue on project 2
id: 4 id: 4
@ -57,4 +57,18 @@ issues_004:
assigned_to_id: assigned_to_id:
author_id: 2 author_id: 2
status_id: 1 status_id: 1
issues_005:
created_on: <%= 5.days.ago.to_date.to_s(:db) %>
project_id: 3
updated_on: <%= 2.days.ago.to_date.to_s(:db) %>
priority_id: 4
subject: Subproject issue
id: 5
fixed_version_id:
category_id:
description: This is an issue on a cookbook subproject
tracker_id: 1
assigned_to_id:
author_id: 2
status_id: 1

View File

@ -45,8 +45,8 @@ messages_004:
parent_id: parent_id:
board_id: 1 board_id: 1
messages_005: messages_005:
created_on: 2007-09-12 17:18:00 +02:00 created_on: <%= 3.days.ago.to_date.to_s(:db) %>
updated_on: 2007-09-12 17:18:00 +02:00 updated_on: <%= 3.days.ago.to_date.to_s(:db) %>
subject: 'RE: post 2' subject: 'RE: post 2'
id: 5 id: 5
replies_count: 0 replies_count: 0

View File

@ -22,7 +22,8 @@ require 'projects_controller'
class ProjectsController; def rescue_action(e) raise e end; end class ProjectsController; def rescue_action(e) raise e end; end
class ProjectsControllerTest < Test::Unit::TestCase class ProjectsControllerTest < Test::Unit::TestCase
fixtures :projects, :versions, :users, :roles, :members, :issues, :journals, :journal_details, :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations fixtures :projects, :versions, :users, :roles, :members, :issues, :journals, :journal_details,
:trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages
def setup def setup
@controller = ProjectsController.new @controller = ProjectsController.new
@ -129,11 +130,15 @@ class ProjectsControllerTest < Test::Unit::TestCase
assert assigns(:versions).include?(Version.find(1)) assert assigns(:versions).include?(Version.find(1))
end end
def test_activity def test_project_activity
get :activity, :id => 1 get :activity, :id => 1, :with_subprojects => 0
assert_response :success assert_response :success
assert_template 'activity' assert_template 'activity'
assert_not_nil assigns(:events_by_day) assert_not_nil assigns(:events_by_day)
assert_not_nil assigns(:events)
# subproject issue not included by default
assert !assigns(:events).include?(Issue.find(5))
assert_tag :tag => "h3", assert_tag :tag => "h3",
:content => /#{2.days.ago.to_date.day}/, :content => /#{2.days.ago.to_date.day}/,
@ -163,6 +168,53 @@ class ProjectsControllerTest < Test::Unit::TestCase
} }
end end
def test_activity_with_subprojects
get :activity, :id => 1, :with_subprojects => 1
assert_response :success
assert_template 'activity'
assert_not_nil assigns(:events)
assert assigns(:events).include?(Issue.find(1))
assert !assigns(:events).include?(Issue.find(4))
# subproject issue
assert assigns(:events).include?(Issue.find(5))
end
def test_global_activity_anonymous
get :activity
assert_response :success
assert_template 'activity'
assert_not_nil assigns(:events)
assert assigns(:events).include?(Issue.find(1))
# Issue of a private project
assert !assigns(:events).include?(Issue.find(4))
end
def test_global_activity_logged_user
@request.session[:user_id] = 2 # manager
get :activity
assert_response :success
assert_template 'activity'
assert_not_nil assigns(:events)
assert assigns(:events).include?(Issue.find(1))
# Issue of a private project the user belongs to
assert assigns(:events).include?(Issue.find(4))
end
def test_global_activity_with_all_types
get :activity, :show_issues => 1, :show_news => 1, :show_files => 1, :show_documents => 1, :show_changesets => 1, :show_wiki_pages => 1, :show_messages => 1
assert_response :success
assert_template 'activity'
assert_not_nil assigns(:events)
assert assigns(:events).include?(Issue.find(1))
assert !assigns(:events).include?(Issue.find(4))
assert assigns(:events).include?(Message.find(5))
end
def test_calendar def test_calendar
get :calendar, :id => 1 get :calendar, :id => 1
assert_response :success assert_response :success

View File

@ -126,13 +126,4 @@ class ProjectTest < Test::Unit::TestCase
assert_equal [1, 2, 3], parent.rolled_up_trackers.collect(&:id) assert_equal [1, 2, 3], parent.rolled_up_trackers.collect(&:id)
assert_equal [2, 3], child.rolled_up_trackers.collect(&:id) assert_equal [2, 3], child.rolled_up_trackers.collect(&:id)
end end
def test_issues_status_changes
journals = @ecookbook.issues_status_changes 3.days.ago.to_date, Date.today
assert_equal 1, journals.size
assert_kind_of Journal, journals.first
journals = @ecookbook.issues_status_changes 30.days.ago.to_date, 10.days.ago.to_date
assert_equal 0, journals.size
end
end end