summaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorJean-Philippe Lang <jp_lang@yahoo.fr>2008-03-11 19:33:38 +0000
committerJean-Philippe Lang <jp_lang@yahoo.fr>2008-03-11 19:33:38 +0000
commit624723d0cef9bd8a9528745f4b75ee22f6b1ad2e (patch)
treed622adeab661c9e833c260b5f5bdef076b14c034 /app
parent64fb0a561aebbc7583695deba29697f84c620dfb (diff)
downloadredmine-624723d0cef9bd8a9528745f4b75ee22f6b1ad2e.tar.gz
redmine-624723d0cef9bd8a9528745f4b75ee22f6b1ad2e.zip
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
Diffstat (limited to 'app')
-rw-r--r--app/controllers/projects_controller.rb80
-rw-r--r--app/models/attachment.rb1
-rw-r--r--app/models/changeset.rb4
-rw-r--r--app/models/project.rb27
-rw-r--r--app/models/wiki_content.rb4
-rw-r--r--app/views/common/feed.atom.rxml5
-rw-r--r--app/views/projects/activity.rhtml12
-rw-r--r--app/views/projects/list.rhtml5
-rw-r--r--app/views/welcome/index.rhtml5
9 files changed, 98 insertions, 45 deletions
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 7e4cc81f3..9268a19ea 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -24,8 +24,9 @@ class ProjectsController < ApplicationController
menu_item :settings, :only => :settings
menu_item :issues, :only => [:changelog]
- before_filter :find_project, :except => [ :index, :list, :add ]
- before_filter :authorize, :except => [ :index, :list, :add, :archive, :unarchive, :destroy ]
+ before_filter :find_project, :except => [ :index, :list, :add, :activity ]
+ 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 ]
accept_key_auth :activity, :calendar
@@ -228,12 +229,14 @@ class ProjectsController < ApplicationController
@date_from = @date_to - @days
@event_types = %w(issues news files documents changesets wiki_pages messages)
- @event_types.delete('wiki_pages') unless @project.wiki
- @event_types.delete('changesets') unless @project.repository
- @event_types.delete('messages') unless @project.boards.any?
- # only show what the user is allowed to view
- @event_types = @event_types.select {|o| User.current.allowed_to?("view_#{o}".to_sym, @project)}
-
+ if @project
+ @event_types.delete('wiki_pages') unless @project.wiki
+ @event_types.delete('changesets') unless @project.repository
+ @event_types.delete('messages') unless @project.boards.any?
+ # only show what the user is allowed to view
+ @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}"]}
# default events if none is specified in parameters
@scope = (@event_types - %w(wiki_pages messages))if @scope.empty?
@@ -241,21 +244,41 @@ class ProjectsController < ApplicationController
@events = []
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] )
- @events += @project.issues_status_changes(@date_from, @date_to)
+ cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_issues, :project => @project, :with_subprojects => @with_subprojects))
+ 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
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
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
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] )
- @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 = ARCondition.new(Project.allowed_to_condition(User.current, :view_documents, :project => @project, :with_subprojects => @with_subprojects))
+ 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
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}.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 "
- conditions = ["#{Wiki.table_name}.project_id = ? AND #{WikiContent.versioned_table_name}.updated_on BETWEEN ? AND ?",
- @project.id, @date_from, @date_to]
+ "LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id " +
+ "LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Wiki.table_name}.project_id"
- @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
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
if @scope.include?('messages')
- @events += Message.find(:all,
- :include => [:board, :author],
- :conditions => ["#{Board.table_name}.project_id=? AND #{Message.table_name}.created_on BETWEEN ? AND ?", @project.id, @date_from, @date_to])
+ cond = ARCondition.new(Project.allowed_to_condition(User.current, :view_messages, :project => @project, :with_subprojects => @with_subprojects))
+ cond.add(["#{Message.table_name}.created_on BETWEEN ? AND ?", @date_from, @date_to])
+ @events += Message.find(:all, :include => [{:board => :project}, :author], :conditions => cond.conditions)
end
@events_by_day = @events.group_by(&:event_date)
respond_to do |format|
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
@@ -381,6 +407,14 @@ private
render_404
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)
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 }
diff --git a/app/models/attachment.rb b/app/models/attachment.rb
index c9783b9ce..cdcb8d231 100644
--- a/app/models/attachment.rb
+++ b/app/models/attachment.rb
@@ -26,7 +26,6 @@ class Attachment < ActiveRecord::Base
validates_length_of :disk_filename, :maximum => 255
acts_as_event :title => :filename,
- :description => :filename,
:url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id}}
cattr_accessor :storage_path
diff --git a/app/models/changeset.rb b/app/models/changeset.rb
index 6bd15b158..dbe06935d 100644
--- a/app/models/changeset.rb
+++ b/app/models/changeset.rb
@@ -45,6 +45,10 @@ class Changeset < ActiveRecord::Base
super
end
+ def project
+ repository.project
+ end
+
def after_create
scan_comment_for_issue_ids
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 95a201454..ad2f1fb81 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -84,16 +84,6 @@ class Project < ActiveRecord::Base
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
# non public projects will be returned only if user is a member of those
def self.latest(user=nil, count=5)
@@ -110,19 +100,28 @@ class Project < ActiveRecord::Base
end
end
- def self.allowed_to_condition(user, permission)
+ def self.allowed_to_condition(user, permission, options={})
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?
# no restriction
elsif user.logged?
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}
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
- statements << "#{Project.table_name}.is_public = #{connection.quoted_true}" if Role.anonymous.allowed_to?(permission)
+ # anonymous user is not authorized
+ statements << "1=0"
end
- statements.empty? ? active_statement : "(#{active_statement} AND (#{statements.join(' OR ')}))"
+ statements.empty? ? base_statement : "((#{base_statement}) AND (#{statements.join(' OR ')}))"
end
def self.find(*args)
diff --git a/app/models/wiki_content.rb b/app/models/wiki_content.rb
index c307beb1d..13915c274 100644
--- a/app/models/wiki_content.rb
+++ b/app/models/wiki_content.rb
@@ -61,6 +61,10 @@ class WikiContent < ActiveRecord::Base
end
end
+ def project
+ page.project
+ end
+
# Returns the previous version or nil
def previous
@previous ||= WikiContent::Version.find(:first,
diff --git a/app/views/common/feed.atom.rxml b/app/views/common/feed.atom.rxml
index 6695565f4..b5cbeeed9 100644
--- a/app/views/common/feed.atom.rxml
+++ b/app/views/common/feed.atom.rxml
@@ -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; }
@items.each do |item|
xml.entry do
+ url = url_for(item.event_url(:only_path => false))
xml.title truncate(item.event_title, 100)
- xml.link "rel" => "alternate", "href" => url_for(item.event_url(:only_path => false))
- xml.id url_for(item.event_url(:only_path => false))
+ xml.link "rel" => "alternate", "href" => url
+ xml.id url
xml.updated item.event_datetime.xmlschema
author = item.event_author if item.respond_to?(:author)
xml.author do
diff --git a/app/views/projects/activity.rhtml b/app/views/projects/activity.rhtml
index 95c8d485f..e8832fccc 100644
--- a/app/views/projects/activity.rhtml
+++ b/app/views/projects/activity.rhtml
@@ -6,7 +6,7 @@
<dl>
<% @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>
- <%= 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? -%>
<span class="description"><%= format_activity_description(e.event_description) %></span><br />
<% end %>
@@ -35,16 +35,20 @@
</p>
<% 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 %>
<% content_for :sidebar do %>
-<% form_tag do %>
+<% form_tag({}, :method => :get) do %>
<h3><%= l(:label_activity) %></h3>
<p><% @event_types.each do |t| %>
<label><%= check_box_tag "show_#{t}", 1, @scope.include?(t) %> <%= l("label_#{t.singularize}_plural")%></label><br />
<% 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 %>
diff --git a/app/views/projects/list.rhtml b/app/views/projects/list.rhtml
index 15ea06483..b8bb62ebb 100644
--- a/app/views/projects/list.rhtml
+++ b/app/views/projects/list.rhtml
@@ -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>
<% @project_tree.keys.sort.each do |project| %>
diff --git a/app/views/welcome/index.rhtml b/app/views/welcome/index.rhtml
index d618fa6e1..5da5a1ed3 100644
--- a/app/views/welcome/index.rhtml
+++ b/app/views/welcome/index.rhtml
@@ -26,5 +26,8 @@
</div>
<% 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 %>