--- /dev/null
+class ActivitiesController < ApplicationController
+ menu_item :activity
+ before_filter :find_optional_project
+ accept_key_auth :index
+
+ def index
+ @days = Setting.activity_days_default.to_i
+
+ if params[:from]
+ begin; @date_to = params[:from].to_date + 1; rescue; end
+ end
+
+ @date_to ||= Date.today + 1
+ @date_from = @date_to - @days
+ @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
+ @author = (params[:user_id].blank? ? nil : User.active.find(params[:user_id]))
+
+ @activity = Redmine::Activity::Fetcher.new(User.current, :project => @project,
+ :with_subprojects => @with_subprojects,
+ :author => @author)
+ @activity.scope_select {|t| !params["show_#{t}"].nil?}
+ @activity.scope = (@author.nil? ? :default : :all) if @activity.scope.empty?
+
+ events = @activity.events(@date_from, @date_to)
+
+ if events.empty? || stale?(:etag => [events.first, User.current])
+ respond_to do |format|
+ format.html {
+ @events_by_day = events.group_by(&:event_date)
+ render :layout => false if request.xhr?
+ }
+ format.atom {
+ title = l(:label_activity)
+ if @author
+ title = @author.name
+ elsif @activity.scope.size == 1
+ title = l("label_#{@activity.scope.first.singularize}_plural")
+ end
+ render_feed(events, :title => "#{@project || Setting.app_title}: #{title}")
+ }
+ end
+ end
+
+ rescue ActiveRecord::RecordNotFound
+ render_404
+ end
+
+ private
+
+ # TODO: refactor, duplicated in projects_controller
+ def find_optional_project
+ return true unless params[:id]
+ @project = Project.find(params[:id])
+ authorize
+ rescue ActiveRecord::RecordNotFound
+ render_404
+ end
+
+end
class ProjectsController < ApplicationController
menu_item :overview
- menu_item :activity, :only => :activity
menu_item :roadmap, :only => :roadmap
menu_item :files, :only => [:list_files, :add_file]
menu_item :settings, :only => :settings
- before_filter :find_project, :except => [ :index, :list, :add, :copy, :activity ]
- before_filter :find_optional_project, :only => :activity
- before_filter :authorize, :except => [ :index, :list, :add, :copy, :archive, :unarchive, :destroy, :activity ]
+ before_filter :find_project, :except => [ :index, :list, :add, :copy ]
+ before_filter :authorize, :except => [ :index, :list, :add, :copy, :archive, :unarchive, :destroy]
before_filter :authorize_global, :only => :add
before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ]
- accept_key_auth :activity, :index
+ accept_key_auth :index
after_filter :only => [:add, :edit, :archive, :unarchive, :destroy] do |controller|
if controller.request.post?
@versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?}
end
- def activity
- @days = Setting.activity_days_default.to_i
-
- if params[:from]
- begin; @date_to = params[:from].to_date + 1; rescue; end
- end
-
- @date_to ||= Date.today + 1
- @date_from = @date_to - @days
- @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
- @author = (params[:user_id].blank? ? nil : User.active.find(params[:user_id]))
-
- @activity = Redmine::Activity::Fetcher.new(User.current, :project => @project,
- :with_subprojects => @with_subprojects,
- :author => @author)
- @activity.scope_select {|t| !params["show_#{t}"].nil?}
- @activity.scope = (@author.nil? ? :default : :all) if @activity.scope.empty?
-
- events = @activity.events(@date_from, @date_to)
-
- if events.empty? || stale?(:etag => [events.first, User.current])
- respond_to do |format|
- format.html {
- @events_by_day = events.group_by(&:event_date)
- render :layout => false if request.xhr?
- }
- format.atom {
- title = l(:label_activity)
- if @author
- title = @author.name
- elsif @activity.scope.size == 1
- title = l("label_#{@activity.scope.first.singularize}_plural")
- end
- render_feed(events, :title => "#{@project || Setting.app_title}: #{title}")
- }
- end
- end
-
- rescue ActiveRecord::RecordNotFound
- render_404
- end
-
private
def find_optional_project
return true unless params[:id]
--- /dev/null
+<h2><%= @author.nil? ? l(:label_activity) : l(:label_user_activity, link_to_user(@author)) %></h2>
+<p class="subtitle"><%= l(:label_date_from_to, :start => format_date(@date_to - @days), :end => format_date(@date_to-1)) %></p>
+
+<div id="activity">
+<% @events_by_day.keys.sort.reverse.each do |day| %>
+<h3><%= format_activity_day(day) %></h3>
+<dl>
+<% @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 %>">
+ <%= avatar(e.event_author, :size => "24") if e.respond_to?(:event_author) %>
+ <span class="time"><%= format_time(e.event_datetime, false) %></span>
+ <%= 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>
+ <dd><span class="description"><%= format_activity_description(e.event_description) %></span>
+ <span class="author"><%= e.event_author if e.respond_to?(:event_author) %></span></dd>
+<% end -%>
+</dl>
+<% end -%>
+</div>
+
+<%= content_tag('p', l(:label_no_data), :class => 'nodata') if @events_by_day.empty? %>
+
+<div style="float:left;">
+<%= link_to_remote(('« ' + l(:label_previous)),
+ {:update => "content", :url => params.merge(:from => @date_to - @days - 1), :method => :get, :complete => 'window.scrollTo(0,0)'},
+ {:href => url_for(params.merge(:from => @date_to - @days - 1)),
+ :title => l(:label_date_from_to, :start => format_date(@date_to - 2*@days), :end => format_date(@date_to - @days - 1))}) %>
+</div>
+<div style="float:right;">
+<%= link_to_remote((l(:label_next) + ' »'),
+ {:update => "content", :url => params.merge(:from => @date_to + @days - 1), :method => :get, :complete => 'window.scrollTo(0,0)'},
+ {:href => url_for(params.merge(:from => @date_to + @days - 1)),
+ :title => l(:label_date_from_to, :start => format_date(@date_to), :end => format_date(@date_to + @days - 1))}) unless @date_to >= Date.today %>
+</div>
+
+<% other_formats_links do |f| %>
+ <%= f.link_to 'Atom', :url => params.merge(:from => nil, :key => User.current.rss_key) %>
+<% end %>
+
+<% content_for :header_tags do %>
+<%= auto_discovery_link_tag(:atom, params.merge(:format => 'atom', :from => nil, :key => User.current.rss_key)) %>
+<% end %>
+
+<% content_for :sidebar do %>
+<% form_tag({}, :method => :get) do %>
+<h3><%= l(:label_activity) %></h3>
+<p><% @activity.event_types.each do |t| %>
+<%= check_box_tag "show_#{t}", 1, @activity.scope.include?(t) %>
+<%= link_to(l("label_#{t.singularize}_plural"), {"show_#{t}" => 1, :user_id => params[:user_id]})%>
+<br />
+<% end %></p>
+<% if @project && @project.descendants.active.any? %>
+ <%= hidden_field_tag 'with_subprojects', 0 %>
+ <p><label><%= check_box_tag 'with_subprojects', 1, @with_subprojects %> <%=l(:label_subproject_plural)%></label></p>
+<% end %>
+<%= hidden_field_tag('user_id', params[:user_id]) unless params[:user_id].blank? %>
+<p><%= submit_tag l(:button_apply), :class => 'button-small', :name => nil %></p>
+<% end %>
+<% end %>
+
+<% html_title(l(:label_activity), @author) -%>
</table>
<% other_formats_links do |f| %>
- <%= f.link_to 'Atom', :url => {:controller => 'projects', :action => 'activity', :id => @project, :show_messages => 1, :key => User.current.rss_key} %>
+ <%= f.link_to 'Atom', :url => {:controller => 'activities', :action => 'index', :id => @project, :show_messages => 1, :key => User.current.rss_key} %>
<% end %>
<% content_for :header_tags do %>
- <%= auto_discovery_link_tag(:atom, {:controller => 'projects', :action => 'activity', :id => @project, :format => 'atom', :show_messages => 1, :key => User.current.rss_key}) %>
+ <%= auto_discovery_link_tag(:atom, {:controller => 'activities', :action => 'index', :id => @project, :format => 'atom', :show_messages => 1, :key => User.current.rss_key}) %>
<% end %>
<% html_title l(:label_board_plural) %>
+++ /dev/null
-<h2><%= @author.nil? ? l(:label_activity) : l(:label_user_activity, link_to_user(@author)) %></h2>
-<p class="subtitle"><%= l(:label_date_from_to, :start => format_date(@date_to - @days), :end => format_date(@date_to-1)) %></p>
-
-<div id="activity">
-<% @events_by_day.keys.sort.reverse.each do |day| %>
-<h3><%= format_activity_day(day) %></h3>
-<dl>
-<% @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 %>">
- <%= avatar(e.event_author, :size => "24") if e.respond_to?(:event_author) %>
- <span class="time"><%= format_time(e.event_datetime, false) %></span>
- <%= 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>
- <dd><span class="description"><%= format_activity_description(e.event_description) %></span>
- <span class="author"><%= e.event_author if e.respond_to?(:event_author) %></span></dd>
-<% end -%>
-</dl>
-<% end -%>
-</div>
-
-<%= content_tag('p', l(:label_no_data), :class => 'nodata') if @events_by_day.empty? %>
-
-<div style="float:left;">
-<%= link_to_remote(('« ' + l(:label_previous)),
- {:update => "content", :url => params.merge(:from => @date_to - @days - 1), :method => :get, :complete => 'window.scrollTo(0,0)'},
- {:href => url_for(params.merge(:from => @date_to - @days - 1)),
- :title => l(:label_date_from_to, :start => format_date(@date_to - 2*@days), :end => format_date(@date_to - @days - 1))}) %>
-</div>
-<div style="float:right;">
-<%= link_to_remote((l(:label_next) + ' »'),
- {:update => "content", :url => params.merge(:from => @date_to + @days - 1), :method => :get, :complete => 'window.scrollTo(0,0)'},
- {:href => url_for(params.merge(:from => @date_to + @days - 1)),
- :title => l(:label_date_from_to, :start => format_date(@date_to), :end => format_date(@date_to + @days - 1))}) unless @date_to >= Date.today %>
-</div>
-
-<% other_formats_links do |f| %>
- <%= f.link_to 'Atom', :url => params.merge(:from => nil, :key => User.current.rss_key) %>
-<% end %>
-
-<% content_for :header_tags do %>
-<%= auto_discovery_link_tag(:atom, params.merge(:format => 'atom', :from => nil, :key => User.current.rss_key)) %>
-<% end %>
-
-<% content_for :sidebar do %>
-<% form_tag({}, :method => :get) do %>
-<h3><%= l(:label_activity) %></h3>
-<p><% @activity.event_types.each do |t| %>
-<%= check_box_tag "show_#{t}", 1, @activity.scope.include?(t) %>
-<%= link_to(l("label_#{t.singularize}_plural"), {"show_#{t}" => 1, :user_id => params[:user_id]})%>
-<br />
-<% end %></p>
-<% if @project && @project.descendants.active.any? %>
- <%= hidden_field_tag 'with_subprojects', 0 %>
- <p><label><%= check_box_tag 'with_subprojects', 1, @with_subprojects %> <%=l(:label_subproject_plural)%></label></p>
-<% end %>
-<%= hidden_field_tag('user_id', params[:user_id]) unless params[:user_id].blank? %>
-<p><%= submit_tag l(:button_apply), :class => 'button-small', :name => nil %></p>
-<% end %>
-<% end %>
-
-<% html_title(l(:label_activity), @author) -%>
<%= link_to(l(:label_project_new), {:controller => 'projects', :action => 'add'}, :class => 'icon icon-add') + ' |' if User.current.allowed_to?(:add_project, nil, :global => true) %>
<%= link_to(l(:label_issue_view_all), { :controller => 'issues' }) + ' |' if User.current.allowed_to?(:view_issues, nil, :global => true) %>
<%= link_to(l(:label_overall_spent_time), { :controller => 'time_entries' }) + ' |' if User.current.allowed_to?(:view_time_entries, nil, :global => true) %>
- <%= link_to l(:label_overall_activity), { :controller => 'projects', :action => 'activity' }%>
+ <%= link_to l(:label_overall_activity), { :controller => 'activities', :action => 'index' }%>
</div>
<h2><%=l(:label_project_plural)%></h2>
<% end %>
<% content_for :header_tags do %>
-<%= auto_discovery_link_tag(:atom, {:action => 'activity', :id => @project, :format => 'atom', :key => User.current.rss_key}) %>
+<%= auto_discovery_link_tag(:atom, {:controller => 'activities', :action => 'index', :id => @project, :format => 'atom', :key => User.current.rss_key}) %>
<% end %>
<% html_title(l(:label_overview)) -%>
<div class="splitcontentright">
<% unless @events_by_day.empty? %>
-<h3><%= link_to l(:label_activity), :controller => 'projects', :action => 'activity', :id => nil, :user_id => @user, :from => @events_by_day.keys.first %></h3>
+<h3><%= link_to l(:label_activity), :controller => 'activities', :action => 'index', :id => nil, :user_id => @user, :from => @events_by_day.keys.first %></h3>
<p>
<%=l(:label_reported_issues)%>: <%= Issue.count(:conditions => ["author_id=?", @user.id]) %>
</div>
<% other_formats_links do |f| %>
- <%= f.link_to 'Atom', :url => {:controller => 'projects', :action => 'activity', :id => nil, :user_id => @user, :key => User.current.rss_key} %>
+ <%= f.link_to 'Atom', :url => {:controller => 'activities', :action => 'index', :id => nil, :user_id => @user, :key => User.current.rss_key} %>
<% end %>
<% content_for :header_tags do %>
- <%= auto_discovery_link_tag(:atom, :controller => 'projects', :action => 'activity', :user_id => @user, :format => :atom, :key => User.current.rss_key) %>
+ <%= auto_discovery_link_tag(:atom, :controller => 'activities', :action => 'index', :user_id => @user, :format => :atom, :key => User.current.rss_key) %>
<% end %>
<% end %>
<%= call_hook :view_account_right_bottom, :user => @user %>
<% content_for :header_tags do %>
<%= 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'},
+<%= auto_discovery_link_tag(:atom, {:controller => 'activities', :action => 'index', :key => User.current.rss_key, :format => 'atom'},
:title => "#{Setting.app_title}: #{l(:label_activity)}") %>
<% end %>
<% unless @pages.empty? %>
<% other_formats_links do |f| %>
- <%= f.link_to 'Atom', :url => {:controller => 'projects', :action => 'activity', :id => @project, :show_wiki_edits => 1, :key => User.current.rss_key} %>
+ <%= f.link_to 'Atom', :url => {:controller => 'activities', :action => 'index', :id => @project, :show_wiki_edits => 1, :key => User.current.rss_key} %>
<%= f.link_to('HTML', :url => {:action => 'special', :page => 'export'}) if User.current.allowed_to?(:export_wiki_pages, @project) %>
<% end %>
<% end %>
<% content_for :header_tags do %>
-<%= auto_discovery_link_tag(:atom, :controller => 'projects', :action => 'activity', :id => @project, :show_wiki_edits => 1, :format => 'atom', :key => User.current.rss_key) %>
+<%= auto_discovery_link_tag(:atom, :controller => 'activities', :action => 'index', :id => @project, :show_wiki_edits => 1, :format => 'atom', :key => User.current.rss_key) %>
<% end %>
project_views.connect 'projects/:id/settings/:tab', :action => 'settings'
end
- projects.with_options :action => 'activity', :conditions => {:method => :get} do |activity|
+ projects.with_options :controller => 'activities', :action => 'index', :conditions => {:method => :get} do |activity|
activity.connect 'projects/:id/activity'
activity.connect 'projects/:id/activity.:format'
activity.connect 'activity', :id => nil
# Permissions
Redmine::AccessControl.map do |map|
- map.permission :view_project, {:projects => [:show, :activity]}, :public => true
+ map.permission :view_project, {:projects => [:show], :activities => [:index]}, :public => true
map.permission :search_project, {:search => :index}, :public => true
map.permission :add_project, {:projects => :add}, :require => :loggedin
map.permission :edit_project, {:projects => [:settings, :edit]}, :require => :member
Redmine::MenuManager.map :project_menu do |menu|
menu.push :overview, { :controller => 'projects', :action => 'show' }
- menu.push :activity, { :controller => 'projects', :action => 'activity' }
+ menu.push :activity, { :controller => 'activities', :action => 'index' }
menu.push :roadmap, { :controller => 'projects', :action => 'roadmap' },
:if => Proc.new { |p| p.shared_versions.any? }
menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural
--- /dev/null
+require File.dirname(__FILE__) + '/../test_helper'
+
+class ActivitiesControllerTest < ActionController::TestCase
+ fixtures :all
+
+ def test_project_index
+ get :index, :id => 1, :with_subprojects => 0
+ assert_response :success
+ assert_template 'index'
+ assert_not_nil assigns(:events_by_day)
+
+ assert_tag :tag => "h3",
+ :content => /#{2.days.ago.to_date.day}/,
+ :sibling => { :tag => "dl",
+ :child => { :tag => "dt",
+ :attributes => { :class => /issue-edit/ },
+ :child => { :tag => "a",
+ :content => /(#{IssueStatus.find(2).name})/,
+ }
+ }
+ }
+ end
+
+ def test_previous_project_index
+ get :index, :id => 1, :from => 3.days.ago.to_date
+ assert_response :success
+ assert_template 'index'
+ assert_not_nil assigns(:events_by_day)
+
+ assert_tag :tag => "h3",
+ :content => /#{3.day.ago.to_date.day}/,
+ :sibling => { :tag => "dl",
+ :child => { :tag => "dt",
+ :attributes => { :class => /issue/ },
+ :child => { :tag => "a",
+ :content => /#{Issue.find(1).subject}/,
+ }
+ }
+ }
+ end
+
+ def test_global_index
+ get :index
+ assert_response :success
+ assert_template 'index'
+ assert_not_nil assigns(:events_by_day)
+
+ assert_tag :tag => "h3",
+ :content => /#{5.day.ago.to_date.day}/,
+ :sibling => { :tag => "dl",
+ :child => { :tag => "dt",
+ :attributes => { :class => /issue/ },
+ :child => { :tag => "a",
+ :content => /#{Issue.find(5).subject}/,
+ }
+ }
+ }
+ end
+
+ def test_user_index
+ get :index, :user_id => 2
+ assert_response :success
+ assert_template 'index'
+ assert_not_nil assigns(:events_by_day)
+
+ assert_tag :tag => "h3",
+ :content => /#{3.day.ago.to_date.day}/,
+ :sibling => { :tag => "dl",
+ :child => { :tag => "dt",
+ :attributes => { :class => /issue/ },
+ :child => { :tag => "a",
+ :content => /#{Issue.find(1).subject}/,
+ }
+ }
+ }
+ end
+
+ def test_index_atom_feed
+ get :index, :format => 'atom'
+ assert_response :success
+ assert_template 'common/feed.atom.rxml'
+ assert_tag :tag => 'entry', :child => {
+ :tag => 'link',
+ :attributes => {:href => 'http://test.host/issues/11'}}
+ end
+
+end
assert assigns(:versions).include?(Version.find(4)), "Shared version not found"
assert assigns(:versions).include?(@subproject_version), "Subproject version not found"
end
- def test_project_activity
- get :activity, :id => 1, :with_subprojects => 0
- assert_response :success
- assert_template 'activity'
- assert_not_nil assigns(:events_by_day)
-
- assert_tag :tag => "h3",
- :content => /#{2.days.ago.to_date.day}/,
- :sibling => { :tag => "dl",
- :child => { :tag => "dt",
- :attributes => { :class => /issue-edit/ },
- :child => { :tag => "a",
- :content => /(#{IssueStatus.find(2).name})/,
- }
- }
- }
- end
-
- def test_previous_project_activity
- get :activity, :id => 1, :from => 3.days.ago.to_date
- assert_response :success
- assert_template 'activity'
- assert_not_nil assigns(:events_by_day)
-
- assert_tag :tag => "h3",
- :content => /#{3.day.ago.to_date.day}/,
- :sibling => { :tag => "dl",
- :child => { :tag => "dt",
- :attributes => { :class => /issue/ },
- :child => { :tag => "a",
- :content => /#{Issue.find(1).subject}/,
- }
- }
- }
- end
-
- def test_global_activity
- get :activity
- assert_response :success
- assert_template 'activity'
- assert_not_nil assigns(:events_by_day)
-
- assert_tag :tag => "h3",
- :content => /#{5.day.ago.to_date.day}/,
- :sibling => { :tag => "dl",
- :child => { :tag => "dt",
- :attributes => { :class => /issue/ },
- :child => { :tag => "a",
- :content => /#{Issue.find(5).subject}/,
- }
- }
- }
- end
-
- def test_user_activity
- get :activity, :user_id => 2
- assert_response :success
- assert_template 'activity'
- assert_not_nil assigns(:events_by_day)
-
- assert_tag :tag => "h3",
- :content => /#{3.day.ago.to_date.day}/,
- :sibling => { :tag => "dl",
- :child => { :tag => "dt",
- :attributes => { :class => /issue/ },
- :child => { :tag => "a",
- :content => /#{Issue.find(1).subject}/,
- }
- }
- }
- end
-
- def test_activity_atom_feed
- get :activity, :format => 'atom'
- assert_response :success
- assert_template 'common/feed.atom.rxml'
- assert_tag :tag => 'entry', :child => {
- :tag => 'link',
- :attributes => {:href => 'http://test.host/issues/11'}}
- end
-
def test_archive
@request.session[:user_id] = 1 # admin
post :archive, :id => 1
class RoutingTest < ActionController::IntegrationTest
context "activities" do
- should_route :get, "/activity", :controller => 'projects', :action => 'activity', :id => nil
- should_route :get, "/activity.atom", :controller => 'projects', :action => 'activity', :id => nil, :format => 'atom'
+ should_route :get, "/activity", :controller => 'activities', :action => 'index', :id => nil
+ should_route :get, "/activity.atom", :controller => 'activities', :action => 'index', :id => nil, :format => 'atom'
end
context "attachments" do
should_route :get, "/projects/33/files", :controller => 'projects', :action => 'list_files', :id => '33'
should_route :get, "/projects/33/files/new", :controller => 'projects', :action => 'add_file', :id => '33'
should_route :get, "/projects/33/roadmap", :controller => 'projects', :action => 'roadmap', :id => '33'
- should_route :get, "/projects/33/activity", :controller => 'projects', :action => 'activity', :id => '33'
- should_route :get, "/projects/33/activity.atom", :controller => 'projects', :action => 'activity', :id => '33', :format => 'atom'
+ should_route :get, "/projects/33/activity", :controller => 'activities', :action => 'index', :id => '33'
+ should_route :get, "/projects/33/activity.atom", :controller => 'activities', :action => 'index', :id => '33', :format => 'atom'
should_route :post, "/projects/new", :controller => 'projects', :action => 'add'
should_route :post, "/projects.xml", :controller => 'projects', :action => 'add', :format => 'xml'