@@ -0,0 +1,56 | |||||
|
1 | # Redmine - project management software | |||
|
2 | # Copyright (C) 2006-2009 Jean-Philippe Lang | |||
|
3 | # | |||
|
4 | # This program is free software; you can redistribute it and/or | |||
|
5 | # modify it under the terms of the GNU General Public License | |||
|
6 | # as published by the Free Software Foundation; either version 2 | |||
|
7 | # of the License, or (at your option) any later version. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU General Public License | |||
|
15 | # along with this program; if not, write to the Free Software | |||
|
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
|
17 | ||||
|
18 | require File.dirname(__FILE__) + '/../../test_helper' | |||
|
19 | ||||
|
20 | class TimelogHelperTest < HelperTestCase | |||
|
21 | include TimelogHelper | |||
|
22 | include ActionView::Helpers::TextHelper | |||
|
23 | include ActionView::Helpers::DateHelper | |||
|
24 | ||||
|
25 | fixtures :projects, :roles, :enabled_modules, :users, | |||
|
26 | :repositories, :changesets, | |||
|
27 | :trackers, :issue_statuses, :issues, :versions, :documents, | |||
|
28 | :wikis, :wiki_pages, :wiki_contents, | |||
|
29 | :boards, :messages, | |||
|
30 | :attachments, | |||
|
31 | :enumerations | |||
|
32 | ||||
|
33 | def setup | |||
|
34 | super | |||
|
35 | end | |||
|
36 | ||||
|
37 | def test_activities_collection_for_select_options_should_return_array_of_activity_names_and_ids | |||
|
38 | activities = activity_collection_for_select_options | |||
|
39 | assert activities.include?(["Design", 9]) | |||
|
40 | assert activities.include?(["Development", 10]) | |||
|
41 | end | |||
|
42 | ||||
|
43 | def test_activities_collection_for_select_options_should_not_include_inactive_activities | |||
|
44 | activities = activity_collection_for_select_options | |||
|
45 | assert !activities.include?(["Inactive Activity", 14]) | |||
|
46 | end | |||
|
47 | ||||
|
48 | def test_activities_collection_for_select_options_should_use_the_projects_override | |||
|
49 | project = Project.find(1) | |||
|
50 | override_activity = TimeEntryActivity.create!({:name => "Design override", :parent => TimeEntryActivity.find_by_name("Design"), :project => project}) | |||
|
51 | ||||
|
52 | activities = activity_collection_for_select_options(nil, project) | |||
|
53 | assert !activities.include?(["Design", 9]), "System activity found in: " + activities.inspect | |||
|
54 | assert activities.include?(["Design override", override_activity.id]), "Override activity not found in: " + activities.inspect | |||
|
55 | end | |||
|
56 | end |
@@ -29,10 +29,16 module TimelogHelper | |||||
29 | # Returns a collection of activities for a select field. time_entry |
|
29 | # Returns a collection of activities for a select field. time_entry | |
30 | # is optional and will be used to check if the selected TimeEntryActivity |
|
30 | # is optional and will be used to check if the selected TimeEntryActivity | |
31 | # is active. |
|
31 | # is active. | |
32 | def activity_collection_for_select_options(time_entry=nil) |
|
32 | def activity_collection_for_select_options(time_entry=nil, project=nil) | |
33 | activities = TimeEntryActivity.active |
|
33 | project ||= @project | |
|
34 | if project.nil? | |||
|
35 | activities = TimeEntryActivity.active | |||
|
36 | else | |||
|
37 | activities = project.activities | |||
|
38 | end | |||
|
39 | ||||
34 | collection = [] |
|
40 | collection = [] | |
35 | if time_entry && !time_entry.activity.active? |
|
41 | if time_entry && time_entry.activity && !time_entry.activity.active? | |
36 | collection << [ "--- #{l(:actionview_instancetag_blank_option)} ---", '' ] |
|
42 | collection << [ "--- #{l(:actionview_instancetag_blank_option)} ---", '' ] | |
37 | else |
|
43 | else | |
38 | collection << [ "--- #{l(:actionview_instancetag_blank_option)} ---", '' ] unless activities.detect(&:is_default) |
|
44 | collection << [ "--- #{l(:actionview_instancetag_blank_option)} ---", '' ] unless activities.detect(&:is_default) |
@@ -62,7 +62,7 class Enumeration < ActiveRecord::Base | |||||
62 |
|
62 | |||
63 | named_scope :active, lambda { |
|
63 | named_scope :active, lambda { | |
64 | { |
|
64 | { | |
65 | :conditions => {:active => true}, |
|
65 | :conditions => {:active => true, :project_id => nil}, | |
66 | :order => 'position' |
|
66 | :order => 'position' | |
67 | } |
|
67 | } | |
68 | } |
|
68 | } |
@@ -20,6 +20,7 class Project < ActiveRecord::Base | |||||
20 | STATUS_ACTIVE = 1 |
|
20 | STATUS_ACTIVE = 1 | |
21 | STATUS_ARCHIVED = 9 |
|
21 | STATUS_ARCHIVED = 9 | |
22 |
|
22 | |||
|
23 | has_many :time_entry_activities, :conditions => {:active => true } # Specific overidden Activities | |||
23 | has_many :members, :include => :user, :conditions => "#{User.table_name}.type='User' AND #{User.table_name}.status=#{User::STATUS_ACTIVE}" |
|
24 | has_many :members, :include => :user, :conditions => "#{User.table_name}.type='User' AND #{User.table_name}.status=#{User::STATUS_ACTIVE}" | |
24 | has_many :member_principals, :class_name => 'Member', |
|
25 | has_many :member_principals, :class_name => 'Member', | |
25 | :include => :principal, |
|
26 | :include => :principal, | |
@@ -155,6 +156,17 class Project < ActiveRecord::Base | |||||
155 | statements.empty? ? base_statement : "((#{base_statement}) AND (#{statements.join(' OR ')}))" |
|
156 | statements.empty? ? base_statement : "((#{base_statement}) AND (#{statements.join(' OR ')}))" | |
156 | end |
|
157 | end | |
157 |
|
158 | |||
|
159 | # Returns all the Systemwide and project specific activities | |||
|
160 | def activities | |||
|
161 | overridden_activity_ids = self.time_entry_activities.collect(&:parent_id) | |||
|
162 | ||||
|
163 | if overridden_activity_ids.empty? | |||
|
164 | return TimeEntryActivity.active | |||
|
165 | else | |||
|
166 | return system_activities_and_project_overrides | |||
|
167 | end | |||
|
168 | end | |||
|
169 | ||||
158 | # Returns a :conditions SQL string that can be used to find the issues associated with this project. |
|
170 | # Returns a :conditions SQL string that can be used to find the issues associated with this project. | |
159 | # |
|
171 | # | |
160 | # Examples: |
|
172 | # Examples: | |
@@ -446,4 +458,12 private | |||||
446 | def allowed_actions |
|
458 | def allowed_actions | |
447 | @actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten |
|
459 | @actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten | |
448 | end |
|
460 | end | |
|
461 | ||||
|
462 | # Returns the systemwide activities merged with the project specific overrides | |||
|
463 | def system_activities_and_project_overrides | |||
|
464 | return TimeEntryActivity.active. | |||
|
465 | find(:all, | |||
|
466 | :conditions => ["id NOT IN (?)", self.time_entry_activities.collect(&:parent_id)]) + | |||
|
467 | self.time_entry_activities | |||
|
468 | end | |||
449 | end |
|
469 | end |
@@ -313,6 +313,53 class ProjectTest < ActiveSupport::TestCase | |||||
313 | assert_equal 1, copied_project.status |
|
313 | assert_equal 1, copied_project.status | |
314 | end |
|
314 | end | |
315 |
|
315 | |||
|
316 | def test_activities_should_use_the_system_activities | |||
|
317 | project = Project.find(1) | |||
|
318 | assert_equal project.activities, TimeEntryActivity.find(:all, :conditions => {:active => true} ) | |||
|
319 | end | |||
|
320 | ||||
|
321 | ||||
|
322 | def test_activities_should_use_the_project_specific_activities | |||
|
323 | project = Project.find(1) | |||
|
324 | overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project}) | |||
|
325 | assert overridden_activity.save! | |||
|
326 | ||||
|
327 | assert project.activities.include?(overridden_activity), "Project specific Activity not found" | |||
|
328 | end | |||
|
329 | ||||
|
330 | def test_activities_should_not_include_the_inactive_project_specific_activities | |||
|
331 | project = Project.find(1) | |||
|
332 | overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => TimeEntryActivity.find(:first), :active => false}) | |||
|
333 | assert overridden_activity.save! | |||
|
334 | ||||
|
335 | assert !project.activities.include?(overridden_activity), "Inactive Project specific Activity found" | |||
|
336 | end | |||
|
337 | ||||
|
338 | def test_activities_should_not_include_project_specific_activities_from_other_projects | |||
|
339 | project = Project.find(1) | |||
|
340 | overridden_activity = TimeEntryActivity.new({:name => "Project", :project => Project.find(2)}) | |||
|
341 | assert overridden_activity.save! | |||
|
342 | ||||
|
343 | assert !project.activities.include?(overridden_activity), "Project specific Activity found on a different project" | |||
|
344 | end | |||
|
345 | ||||
|
346 | def test_activities_should_handle_nils | |||
|
347 | TimeEntryActivity.delete_all | |||
|
348 | ||||
|
349 | project = Project.find(1) | |||
|
350 | assert project.activities.empty? | |||
|
351 | end | |||
|
352 | ||||
|
353 | def test_activities_should_override_system_activities_with_project_activities | |||
|
354 | project = Project.find(1) | |||
|
355 | parent_activity = TimeEntryActivity.find(:first) | |||
|
356 | overridden_activity = TimeEntryActivity.new({:name => "Project", :project => project, :parent => parent_activity}) | |||
|
357 | assert overridden_activity.save! | |||
|
358 | ||||
|
359 | assert project.activities.include?(overridden_activity), "Project specific Activity not found" | |||
|
360 | assert !project.activities.include?(parent_activity), "System Activity found when it should have been overridden" | |||
|
361 | end | |||
|
362 | ||||
316 | context "Project#copy" do |
|
363 | context "Project#copy" do | |
317 | setup do |
|
364 | setup do | |
318 | ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests |
|
365 | ProjectCustomField.destroy_all # Custom values are a mess to isolate in tests |
General Comments 0
You need to be logged in to leave comments.
Login now