Merge pull request #277 from opf/feature/rails3_activity_module

Feature/rails3 activity module
pull/168/merge
sschu 11 years ago
commit 82ce771bb5
  1. 28
      app/controllers/activities_controller.rb
  2. 4
      app/helpers/application_helper.rb
  3. 4
      app/helpers/timelines_journals_helper.rb
  4. 21
      db/migrate/20130723092240_add_activity_module.rb
  5. 1
      doc/CHANGELOG.md
  6. 36
      features/activities/index.feature
  7. 7
      features/step_definitions/general_steps.rb
  8. 3
      features/support/paths.rb
  9. 5
      lib/redmine.rb
  10. 2
      lib/redmine/activity/fetcher.rb
  11. 51
      spec/controllers/activities_controller_spec.rb
  12. 143
      spec/controllers/projects_controller_spec.rb
  13. 106
      spec/controllers/settings_controller_spec.rb
  14. 20
      test/fixtures/enabled_modules.yml

@ -12,7 +12,7 @@
class ActivitiesController < ApplicationController class ActivitiesController < ApplicationController
menu_item :activity menu_item :activity
before_filter :find_optional_project before_filter :find_optional_project, :verify_activities_module_activated
accept_key_auth :index accept_key_auth :index
def index def index
@ -34,6 +34,7 @@ class ActivitiesController < ApplicationController
@activity.scope = (@author.nil? ? :default : :all) if @activity.scope.empty? @activity.scope = (@author.nil? ? :default : :all) if @activity.scope.empty?
events = @activity.events(@date_from, @date_to) events = @activity.events(@date_from, @date_to)
censor_events_from_projects_with_disabled_activity!(events) unless @project
if events.empty? || stale?(:etag => [@activity.scope, @date_to, @date_from, @with_subprojects, @author, events.first, User.current, current_language]) if events.empty? || stale?(:etag => [@activity.scope, @date_to, @date_from, @with_subprojects, @author, events.first, User.current, current_language])
respond_to do |format| respond_to do |format|
@ -69,4 +70,29 @@ class ActivitiesController < ApplicationController
render_404 render_404
end end
def verify_activities_module_activated
render_403 if @project && !@project.module_enabled?("activity")
end
# Do not show events, which are associated with projects where activities are disabled.
# In a better world this would be implemented (with better performance) in SQL.
# TODO: make the world a better place.
def censor_events_from_projects_with_disabled_activity!(events)
allowed_project_ids = EnabledModule.where(:name => 'activity').map(&:project_id)
events.select! do |event|
project_ids = []
if event.respond_to?(:changed_data) and event.changed_data['project_id']
project_ids = event.changed_data['project_id']
elsif event.respond_to?(:project_id)
project_ids = [ event.project_id ]
end
if project_ids.empty?
# show this event if it is not associated with a project
true
else
# show this event if the activity module is enabled in any of the associated projects
project_ids.any? { |id| allowed_project_ids.include? id }
end
end
end
end end

@ -388,8 +388,8 @@ module ApplicationHelper
def time_tag(time) def time_tag(time)
text = distance_of_time_in_words(Time.now, time) text = distance_of_time_in_words(Time.now, time)
if @project if @project and @project.module_enabled?("activity")
link_to(text, {:controller => '/activities', :action => 'index', :id => @project, :from => time.to_date}, :title => format_time(time)) link_to(text, {:controller => '/activities', :action => 'index', :project_id => @project, :from => time.to_date}, :title => format_time(time))
else else
content_tag('label', text, :title => format_time(time), :class => "timestamp") content_tag('label', text, :title => format_time(time), :class => "timestamp")
end end

@ -32,8 +32,8 @@ module TimelinesJournalsHelper
def timelines_time_tag(time) def timelines_time_tag(time)
text = format_time(time) text = format_time(time)
if @project if @project and @project.module_enabled?("activity")
link_to(text, {:controller => '/activities', :action => 'index', :id => @project, :from => time.to_date}, :title => format_time(time)) link_to(text, {:controller => '/activities', :action => 'index', :project_id => @project, :from => time.to_date}, :title => format_time(time))
else else
content_tag('label', text, :title => format_time(time), :class => "timestamp") content_tag('label', text, :title => format_time(time), :class => "timestamp")
end end

@ -0,0 +1,21 @@
class AddActivityModule < ActiveRecord::Migration
def up
# activate activity module for all projects
Project.all.each do |project|
project.enabled_module_names = ["activity"] | project.enabled_module_names
end
# add activity module from default settings
Setting["default_projects_modules"] = ["activity"] | Setting.default_projects_modules
end
def down
# deactivate activity module for all projects
Project.all.each do |project|
project.enabled_module_names = project.enabled_module_names - ["activity"]
end
# remove activity module from default settings
Setting["default_projects_modules"] = Setting.default_projects_modules - ["activity"]
end
end

@ -2,6 +2,7 @@
* `#1517` Journal changed_data cannot contain the changes of a wiki_content content * `#1517` Journal changed_data cannot contain the changes of a wiki_content content
* `#779` Integrate password expiration * `#779` Integrate password expiration
* `#1461` Integration Activity Plugin
* `#1505` Removing all roles from a membership removes the project membership * `#1505` Removing all roles from a membership removes the project membership
* `#1405` Incorrect message when trying to login with a permanently blocked account * `#1405` Incorrect message when trying to login with a permanently blocked account
* `#1488` Fixes multiple and missing error messages on project settings' member tab (now with support for success messages) * `#1488` Fixes multiple and missing error messages on project settings' member tab (now with support for success messages)

@ -0,0 +1,36 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
Feature: Activities
Background:
Given there is 1 project with the following:
| Name | project1 |
And the project "project1" has the following trackers:
| name | position |
| Bug | 1 |
And the project "project1" has 1 issue with the following:
| subject | issue1 |
And there is 1 project with the following:
| Name | project2 |
And the project "project2" has the following trackers:
| name | position |
| Bug | 1 |
And the project "project2" does not use the following modules:
| activity |
And the project "project2" has 1 issue with the following:
| subject | issue2 |
And I am already logged in as "admin"
Scenario: Hide activity from Projects with disabled activity module
When I go to the overall activity page
Then I should see "project1" within "#activity"
And I should not see "project2" within "#activity"

@ -101,6 +101,13 @@ Given /^(?:the )?[pP]roject "([^\"]*)" uses the following [mM]odules:$/ do |proj
p.reload p.reload
end end
Given /^(?:the )?[pP]roject "([^\"]*)" does not use the following [mM]odules:$/ do |project, table|
p = Project.find_by_name(project)
p.enabled_module_names -= table.raw.map { |row| row.first }
p.reload
end
Given /^the [Uu]ser "([^\"]*)" is a "([^\"]*)" (?:in|of) the [Pp]roject "([^\"]*)"$/ do |user, role, project| Given /^the [Uu]ser "([^\"]*)" is a "([^\"]*)" (?:in|of) the [Pp]roject "([^\"]*)"$/ do |user, role, project|
u = User.find_by_login(user) u = User.find_by_login(user)
r = Role.find_by_name(role) r = Role.find_by_name(role)

@ -77,6 +77,9 @@ module NavigationHelpers
project_identifier = Project.find_by_name(project_identifier).identifier.gsub(' ', '%20') project_identifier = Project.find_by_name(project_identifier).identifier.gsub(' ', '%20')
"/projects/#{project_identifier}/activity" "/projects/#{project_identifier}/activity"
when /^the overall activity page$/
"/activity"
when /^the page (?:for|of) the issue "([^\"]+)"$/ when /^the page (?:for|of) the issue "([^\"]+)"$/
issue = Issue.find_by_subject($1) issue = Issue.find_by_subject($1)
"/work_packages/#{issue.id}" "/work_packages/#{issue.id}"

@ -278,7 +278,8 @@ end
Redmine::MenuManager.map :project_menu do |menu| Redmine::MenuManager.map :project_menu do |menu|
menu.push :overview, { :controller => '/projects', :action => 'show' } menu.push :overview, { :controller => '/projects', :action => 'show' }
menu.push :activity, { :controller => '/activities', :action => 'index' }, :param => :project_id menu.push :activity, { :controller => '/activities', :action => 'index' }, :param => :project_id,
:if => Proc.new { |p| p.module_enabled?("activity") }
menu.push :roadmap, { :controller => '/versions', :action => 'index' }, :param => :project_id, menu.push :roadmap, { :controller => '/versions', :action => 'index' }, :param => :project_id,
:if => Proc.new { |p| p.shared_versions.any? } :if => Proc.new { |p| p.shared_versions.any? }
@ -368,3 +369,5 @@ Redmine::WikiFormatting.map do |format|
end end
ActionView::Template.register_template_handler :rsb, Redmine::Views::ApiTemplateHandler ActionView::Template.register_template_handler :rsb, Redmine::Views::ApiTemplateHandler
Redmine::AccessControl.available_project_modules << :activity

@ -40,7 +40,7 @@ module Redmine
p.activity_provider_options[o].try(:[], :permission) p.activity_provider_options[o].try(:[], :permission)
end.compact end.compact
return @user.allowed_to?("view_#{o}".to_sym, @project) if permissions.blank? return @user.allowed_to?("view_#{o}".to_sym, @project) if permissions.blank?
permissions.all? {|p| @user.allowed_to?(p, @project) } if @project permissions.all? {|p| @user.allowed_to?(p, @project) }
end end
end end
end end

@ -0,0 +1,51 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'spec_helper'
describe ActivitiesController do
before :each do
@controller.stub(:set_localization)
admin = FactoryGirl.create(:admin)
User.stub(:current).and_return admin
@params = {}
end
describe 'index' do
describe 'with activated activity module' do
before do
@project = FactoryGirl.create(:project, :enabled_module_names => %w[activity wiki])
@params[:project_id] = @project.id
end
it 'renders activity' do
get 'index', @params
response.should be_success
response.should render_template 'index'
end
end
describe 'without activated activity module' do
before do
@project = FactoryGirl.create(:project, :enabled_module_names => %w[wiki])
@params[:project_id] = @project.id
end
it 'renders 403' do
get 'index', @params
response.status.should == 403
response.should render_template 'common/error'
end
end
end
end

@ -27,6 +27,18 @@ describe ProjectsController do
@params = {} @params = {}
end end
def clear_settings_cache
Rails.cache.clear
end
# this is the base method for get, post, etc.
def process(*args)
clear_settings_cache
result = super
clear_settings_cache
result
end
describe 'show' do describe 'show' do
render_views render_views
@ -98,5 +110,136 @@ describe ProjectsController do
end end
end end
end end
describe 'with activated activity module' do
before do
@project = FactoryGirl.create(:project, :enabled_module_names => %w[activity])
@params[:id] = @project.id
end
it 'renders show' do
get 'show', @params
response.should be_success
response.should render_template 'show'
end
it 'renders main menu with activity tab' do
get 'show', @params
assert_select '#main-menu a.activity'
end
end
describe 'without activated activity module' do
before do
@project = FactoryGirl.create(:project, :enabled_module_names => %w[wiki])
@params[:id] = @project.id
end
it 'renders show' do
get 'show', @params
response.should be_success
response.should render_template 'show'
end
it 'renders main menu without activity tab' do
get 'show', @params
response.body.should_not have_selector '#main-menu a.activity'
end
end
end
describe 'new' do
render_views
before(:all) do
@previous_projects_modules = Setting.default_projects_modules
end
after(:all) do
Setting.default_projects_modules = @previous_projects_modules
end
describe 'with activity in Setting.default_projects_modules' do
before do
Setting.default_projects_modules = %w[activity wiki]
end
it "renders 'new'" do
get 'new', @params
response.should be_success
response.should render_template 'new'
end
it 'renders available modules list with activity being selected' do
get 'new', @params
response.body.should have_selector "input[@name='project[enabled_module_names][]'][@value='activity'][@checked='checked']"
response.body.should have_selector "input[@name='project[enabled_module_names][]'][@value='wiki'][@checked='checked']"
end
end
describe 'without activated activity module' do
before do
Setting.default_projects_modules = %w[wiki]
end
it "renders 'new'" do
get 'new', @params
response.should be_success
response.should render_template 'new'
end
it 'renders available modules list without activity being selected' do
get 'new', @params
response.body.should have_selector "input[@name='project[enabled_module_names][]'][@value='wiki'][@checked='checked']"
response.body.should have_selector "input[@name='project[enabled_module_names][]'][@value='activity']"
response.body.should_not have_selector "input[@name='project[enabled_module_names][]'][@value='activity'][@checked='checked']"
end
end
end
describe 'settings' do
render_views
describe 'with activity in Setting.default_projects_modules' do
before do
@project = FactoryGirl.create(:project, :enabled_module_names => %w[activity wiki])
@params[:id] = @project.id
end
it 'renders settings/modules' do
get 'settings', @params.merge(:tab => 'modules')
response.should be_success
response.should render_template 'settings'
end
it 'renders available modules list with activity being selected' do
get 'settings', @params.merge(:tab => 'modules')
response.body.should have_selector "#modules-form input[@name='enabled_module_names[]'][@value='activity'][@checked='checked']"
response.body.should have_selector "#modules-form input[@name='enabled_module_names[]'][@value='wiki'][@checked='checked']"
end
end
describe 'without activated activity module' do
before do
@project = FactoryGirl.create(:project, :enabled_module_names => %w[wiki])
@params[:id] = @project.id
end
it 'renders settings/modules' do
get 'settings', @params.merge(:tab => 'modules')
response.should be_success
response.should render_template 'settings'
end
it 'renders available modules list without activity being selected' do
get 'settings', @params.merge(:tab => 'modules')
response.body.should have_selector "#modules-form input[@name='enabled_module_names[]'][@value='wiki'][@checked='checked']"
response.body.should have_selector "#modules-form input[@name='enabled_module_names[]'][@value='activity']"
response.body.should_not have_selector "#modules-form input[@name='enabled_module_names[]'][@value='activity'][@checked='checked']"
end
end
end end
end end

@ -0,0 +1,106 @@
#-- copyright
# OpenProject is a project management system.
#
# Copyright (C) 2012-2013 the OpenProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'spec_helper'
describe SettingsController do
before :each do
@controller.stub(:set_localization)
@params = {}
@user = FactoryGirl.create(:admin)
User.stub(:current).and_return @user
end
describe 'edit' do
render_views
def clear_settings_cache
Rails.cache.clear
end
# this is the base method for get, post, etc.
def process(*args)
clear_settings_cache
result = super
clear_settings_cache
result
end
before(:all) do
@previous_projects_modules = Setting.default_projects_modules
end
after(:all) do
Setting.default_projects_modules = @previous_projects_modules
end
it 'contains a check box for the activity module on the projects tab' do
get 'edit', :tab => 'projects'
response.should be_success
response.should render_template 'edit'
response.body.should have_selector "input[@name='settings[default_projects_modules][]'][@value='activity']"
end
it 'does not store the activity in the default_projects_modules if unchecked' do
post 'edit', :tab => 'projects', :settings => {
:default_projects_modules => ['wiki']
}
response.should be_redirect
response.should redirect_to :action => 'edit', :tab => 'projects'
Setting.default_projects_modules.should == ['wiki']
end
it 'stores the activity in the default_projects_modules if checked' do
post 'edit', :tab => 'projects', :settings => {
:default_projects_modules => ['activity', 'wiki']
}
response.should be_redirect
response.should redirect_to :action => 'edit', :tab => 'projects'
Setting.default_projects_modules.should == ['activity', 'wiki']
end
describe 'with activity in Setting.default_projects_modules' do
before do
Setting.default_projects_modules = %w[activity wiki]
end
it 'contains a checked checkbox for activity' do
get 'edit', :tab => 'projects'
response.should be_success
response.should render_template 'edit'
response.body.should have_selector "input[@name='settings[default_projects_modules][]'][@value='activity'][@checked='checked']"
end
end
describe 'without activated activity module' do
before do
Setting.default_projects_modules = %w[wiki]
end
it 'contains an unchecked checkbox for activity' do
get 'edit', :tab => 'projects'
response.should be_success
response.should render_template 'edit'
response.body.should_not have_selector "input[@name='settings[default_projects_modules][]'][@value='activity'][@checked='checked']"
end
end
end
end

@ -83,3 +83,23 @@ enabled_modules_025:
name: news name: news
project_id: 2 project_id: 2
id: 25 id: 25
enabled_modules_026:
name: activity
project_id: 1
id: 26
enabled_modules_027:
name: activity
project_id: 2
id: 27
enabled_modules_028:
name: activity
project_id: 3
id: 28
enabled_modules_029:
name: activity
project_id: 4
id: 29
enabled_modules_030:
name: activity
project_id: 5
id: 30

Loading…
Cancel
Save