##// END OF EJS Templates
Removes #move_to= (#12909)....
Jean-Philippe Lang -
r14957:39ff11ba06a7
parent child
Show More
@@ -1,134 +1,118
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 module Redmine
19 19 module Acts
20 20 module Positioned
21 21 def self.included(base)
22 22 base.extend ClassMethods
23 23 end
24 24
25 25 # This extension provides the capabilities for reordering objects in a list.
26 26 # The class needs to have a +position+ column defined as an integer on the
27 27 # mapped database table.
28 28 module ClassMethods
29 29 # Configuration options are:
30 30 #
31 31 # * +scope+ - restricts what is to be considered a list. Must be a symbol
32 32 # or an array of symbols
33 33 def acts_as_positioned(options = {})
34 34 class_attribute :positioned_options
35 35 self.positioned_options = {:scope => Array(options[:scope])}
36 36
37 37 send :include, Redmine::Acts::Positioned::InstanceMethods
38 38
39 39 before_save :set_default_position
40 40 after_save :update_position
41 41 after_destroy :remove_position
42 42 end
43 43 end
44 44
45 45 module InstanceMethods
46 46 def self.included(base)
47 47 base.extend ClassMethods
48 48 end
49 49
50 # Move to the given position
51 # For compatibility with the previous way of sorting items
52 def move_to=(pos)
53 case pos.to_s
54 when 'highest'
55 self.position = 1
56 when 'higher'
57 self.position -= 1 if position > 1
58 when 'lower'
59 self.position += 1
60 when 'lowest'
61 self.position = nil
62 set_default_position
63 end
64 end
65
66 50 private
67 51
68 52 def position_scope
69 53 build_position_scope {|c| send(c)}
70 54 end
71 55
72 56 def position_scope_was
73 57 build_position_scope {|c| send("#{c}_was")}
74 58 end
75 59
76 60 def build_position_scope
77 61 condition_hash = self.class.positioned_options[:scope].inject({}) do |h, column|
78 62 h[column] = yield(column)
79 63 h
80 64 end
81 65 self.class.where(condition_hash)
82 66 end
83 67
84 68 def set_default_position
85 69 if position.nil?
86 70 self.position = position_scope.maximum(:position).to_i + (new_record? ? 1 : 0)
87 71 end
88 72 end
89 73
90 74 def update_position
91 75 if !new_record? && position_scope_changed?
92 76 remove_position
93 77 insert_position
94 78 elsif position_changed?
95 79 if position_was.nil?
96 80 insert_position
97 81 else
98 82 shift_positions
99 83 end
100 84 end
101 85 end
102 86
103 87 def insert_position
104 88 position_scope.where("position >= ? AND id <> ?", position, id).update_all("position = position + 1")
105 89 end
106 90
107 91 def remove_position
108 92 position_scope_was.where("position >= ? AND id <> ?", position_was, id).update_all("position = position - 1")
109 93 end
110 94
111 95 def position_scope_changed?
112 96 (changed & self.class.positioned_options[:scope].map(&:to_s)).any?
113 97 end
114 98
115 99 def shift_positions
116 100 offset = position_was <=> position
117 101 min, max = [position, position_was].sort
118 102 r = position_scope.where("id <> ? AND position BETWEEN ? AND ?", id, min, max).update_all("position = position + #{offset}")
119 103 if r != max - min
120 104 reset_positions_in_list
121 105 end
122 106 end
123 107
124 108 def reset_positions_in_list
125 109 position_scope.reorder(:position, :id).pluck(:id).each_with_index do |record_id, p|
126 110 self.class.where(:id => record_id).update_all(:position => p+1)
127 111 end
128 112 end
129 113 end
130 114 end
131 115 end
132 116 end
133 117
134 118 ActiveRecord::Base.send :include, Redmine::Acts::Positioned
@@ -1,208 +1,208
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../test_helper', __FILE__)
19 19
20 20 class RolesControllerTest < ActionController::TestCase
21 21 fixtures :roles, :users, :members, :member_roles, :workflows, :trackers
22 22
23 23 def setup
24 24 User.current = nil
25 25 @request.session[:user_id] = 1 # admin
26 26 end
27 27
28 28 def test_index
29 29 get :index
30 30 assert_response :success
31 31 assert_template 'index'
32 32
33 33 assert_not_nil assigns(:roles)
34 34 assert_equal Role.order('builtin, position').to_a, assigns(:roles)
35 35
36 36 assert_select 'a[href="/roles/1/edit"]', :text => 'Manager'
37 37 end
38 38
39 39 def test_new
40 40 get :new
41 41 assert_response :success
42 42 assert_template 'new'
43 43 end
44 44
45 45 def test_new_with_copy
46 46 copy_from = Role.find(2)
47 47
48 48 get :new, :copy => copy_from.id.to_s
49 49 assert_response :success
50 50 assert_template 'new'
51 51
52 52 role = assigns(:role)
53 53 assert_equal copy_from.permissions, role.permissions
54 54
55 55 assert_select 'form' do
56 56 # blank name
57 57 assert_select 'input[name=?][value=""]', 'role[name]'
58 58 # edit_project permission checked
59 59 assert_select 'input[type=checkbox][name=?][value=edit_project][checked=checked]', 'role[permissions][]'
60 60 # add_project permission not checked
61 61 assert_select 'input[type=checkbox][name=?][value=add_project]', 'role[permissions][]'
62 62 assert_select 'input[type=checkbox][name=?][value=add_project][checked=checked]', 'role[permissions][]', 0
63 63 # workflow copy selected
64 64 assert_select 'select[name=?]', 'copy_workflow_from' do
65 65 assert_select 'option[value="2"][selected=selected]'
66 66 end
67 67 end
68 68 end
69 69
70 70 def test_create_with_validaton_failure
71 71 post :create, :role => {:name => '',
72 72 :permissions => ['add_issues', 'edit_issues', 'log_time', ''],
73 73 :assignable => '0'}
74 74
75 75 assert_response :success
76 76 assert_template 'new'
77 77 assert_select 'div#errorExplanation'
78 78 end
79 79
80 80 def test_create_without_workflow_copy
81 81 post :create, :role => {:name => 'RoleWithoutWorkflowCopy',
82 82 :permissions => ['add_issues', 'edit_issues', 'log_time', ''],
83 83 :assignable => '0'}
84 84
85 85 assert_redirected_to '/roles'
86 86 role = Role.find_by_name('RoleWithoutWorkflowCopy')
87 87 assert_not_nil role
88 88 assert_equal [:add_issues, :edit_issues, :log_time], role.permissions
89 89 assert !role.assignable?
90 90 end
91 91
92 92 def test_create_with_workflow_copy
93 93 post :create, :role => {:name => 'RoleWithWorkflowCopy',
94 94 :permissions => ['add_issues', 'edit_issues', 'log_time', ''],
95 95 :assignable => '0'},
96 96 :copy_workflow_from => '1'
97 97
98 98 assert_redirected_to '/roles'
99 99 role = Role.find_by_name('RoleWithWorkflowCopy')
100 100 assert_not_nil role
101 101 assert_equal Role.find(1).workflow_rules.size, role.workflow_rules.size
102 102 end
103 103
104 104 def test_edit
105 105 get :edit, :id => 1
106 106 assert_response :success
107 107 assert_template 'edit'
108 108 assert_equal Role.find(1), assigns(:role)
109 109 assert_select 'select[name=?]', 'role[issues_visibility]'
110 110 end
111 111
112 112 def test_edit_anonymous
113 113 get :edit, :id => Role.anonymous.id
114 114 assert_response :success
115 115 assert_template 'edit'
116 116 assert_select 'select[name=?]', 'role[issues_visibility]', 0
117 117 end
118 118
119 119 def test_edit_invalid_should_respond_with_404
120 120 get :edit, :id => 999
121 121 assert_response 404
122 122 end
123 123
124 124 def test_update
125 125 put :update, :id => 1,
126 126 :role => {:name => 'Manager',
127 127 :permissions => ['edit_project', ''],
128 128 :assignable => '0'}
129 129
130 130 assert_redirected_to '/roles'
131 131 role = Role.find(1)
132 132 assert_equal [:edit_project], role.permissions
133 133 end
134 134
135 135 def test_update_with_failure
136 136 put :update, :id => 1, :role => {:name => ''}
137 137 assert_response :success
138 138 assert_template 'edit'
139 139 end
140 140
141 141 def test_destroy
142 142 r = Role.create!(:name => 'ToBeDestroyed', :permissions => [:view_wiki_pages])
143 143
144 144 delete :destroy, :id => r
145 145 assert_redirected_to '/roles'
146 146 assert_nil Role.find_by_id(r.id)
147 147 end
148 148
149 149 def test_destroy_role_in_use
150 150 delete :destroy, :id => 1
151 151 assert_redirected_to '/roles'
152 152 assert_equal 'This role is in use and cannot be deleted.', flash[:error]
153 153 assert_not_nil Role.find_by_id(1)
154 154 end
155 155
156 156 def test_get_permissions
157 157 get :permissions
158 158 assert_response :success
159 159 assert_template 'permissions'
160 160
161 161 assert_not_nil assigns(:roles)
162 162 assert_equal Role.order('builtin, position').to_a, assigns(:roles)
163 163
164 164 assert_select 'input[name=?][type=checkbox][value=add_issues][checked=checked]', 'permissions[3][]'
165 165 assert_select 'input[name=?][type=checkbox][value=delete_issues]:not([checked])', 'permissions[3][]'
166 166 end
167 167
168 168 def test_post_permissions
169 169 post :permissions, :permissions => { '0' => '', '1' => ['edit_issues'], '3' => ['add_issues', 'delete_issues']}
170 170 assert_redirected_to '/roles'
171 171
172 172 assert_equal [:edit_issues], Role.find(1).permissions
173 173 assert_equal [:add_issues, :delete_issues], Role.find(3).permissions
174 174 assert Role.find(2).permissions.empty?
175 175 end
176 176
177 177 def test_clear_all_permissions
178 178 post :permissions, :permissions => { '0' => '' }
179 179 assert_redirected_to '/roles'
180 180 assert Role.find(1).permissions.empty?
181 181 end
182 182
183 183 def test_move_highest
184 put :update, :id => 3, :role => {:move_to => 'highest'}
184 put :update, :id => 3, :role => {:position => 1}
185 185 assert_redirected_to '/roles'
186 186 assert_equal 1, Role.find(3).position
187 187 end
188 188
189 189 def test_move_higher
190 190 position = Role.find(3).position
191 put :update, :id => 3, :role => {:move_to => 'higher'}
191 put :update, :id => 3, :role => {:position => position - 1}
192 192 assert_redirected_to '/roles'
193 193 assert_equal position - 1, Role.find(3).position
194 194 end
195 195
196 196 def test_move_lower
197 197 position = Role.find(2).position
198 put :update, :id => 2, :role => {:move_to => 'lower'}
198 put :update, :id => 2, :role => {:position => position + 1}
199 199 assert_redirected_to '/roles'
200 200 assert_equal position + 1, Role.find(2).position
201 201 end
202 202
203 203 def test_move_lowest
204 put :update, :id => 2, :role => {:move_to => 'lowest'}
204 put :update, :id => 2, :role => {:position => Role.givable.count}
205 205 assert_redirected_to '/roles'
206 206 assert_equal Role.givable.count, Role.find(2).position
207 207 end
208 208 end
@@ -1,175 +1,175
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../test_helper', __FILE__)
19 19
20 20 class EnumerationTest < ActiveSupport::TestCase
21 21 fixtures :enumerations, :issues, :custom_fields, :custom_values
22 22
23 23 def test_objects_count
24 24 # low priority
25 25 assert_equal 6, Enumeration.find(4).objects_count
26 26 # urgent
27 27 assert_equal 0, Enumeration.find(7).objects_count
28 28 end
29 29
30 30 def test_in_use
31 31 # low priority
32 32 assert Enumeration.find(4).in_use?
33 33 # urgent
34 34 assert !Enumeration.find(7).in_use?
35 35 end
36 36
37 37 def test_default
38 38 e = Enumeration.default
39 39 assert e.is_a?(Enumeration)
40 40 assert e.is_default?
41 41 assert e.active?
42 42 assert_equal 'Default Enumeration', e.name
43 43 end
44 44
45 45 def test_default_non_active
46 46 e = Enumeration.find(12)
47 47 assert e.is_a?(Enumeration)
48 48 assert e.is_default?
49 49 assert e.active?
50 50 e.update_attributes(:active => false)
51 51 assert e.is_default?
52 52 assert !e.active?
53 53 end
54 54
55 55 def test_create
56 56 e = Enumeration.new(:name => 'Not default', :is_default => false)
57 57 e.type = 'Enumeration'
58 58 assert e.save
59 59 assert_equal 'Default Enumeration', Enumeration.default.name
60 60 end
61 61
62 62 def test_create_as_default
63 63 e = Enumeration.new(:name => 'Very urgent', :is_default => true)
64 64 e.type = 'Enumeration'
65 65 assert e.save
66 66 assert_equal e, Enumeration.default
67 67 end
68 68
69 69 def test_update_default
70 70 e = Enumeration.default
71 71 e.update_attributes(:name => 'Changed', :is_default => true)
72 72 assert_equal e, Enumeration.default
73 73 end
74 74
75 75 def test_update_default_to_non_default
76 76 e = Enumeration.default
77 77 e.update_attributes(:name => 'Changed', :is_default => false)
78 78 assert_nil Enumeration.default
79 79 end
80 80
81 81 def test_change_default
82 82 e = Enumeration.find_by_name('Default Enumeration')
83 83 e.update_attributes(:name => 'Changed Enumeration', :is_default => true)
84 84 assert_equal e, Enumeration.default
85 85 end
86 86
87 87 def test_destroy_with_reassign
88 88 Enumeration.find(4).destroy(Enumeration.find(6))
89 89 assert_nil Issue.where(:priority_id => 4).first
90 90 assert_equal 6, Enumeration.find(6).objects_count
91 91 end
92 92
93 93 def test_should_be_customizable
94 94 assert Enumeration.included_modules.include?(Redmine::Acts::Customizable::InstanceMethods)
95 95 end
96 96
97 97 def test_should_belong_to_a_project
98 98 association = Enumeration.reflect_on_association(:project)
99 99 assert association, "No Project association found"
100 100 assert_equal :belongs_to, association.macro
101 101 end
102 102
103 103 def test_should_act_as_tree
104 104 enumeration = Enumeration.find(4)
105 105
106 106 assert enumeration.respond_to?(:parent)
107 107 assert enumeration.respond_to?(:children)
108 108 end
109 109
110 110 def test_is_override
111 111 # Defaults to off
112 112 enumeration = Enumeration.find(4)
113 113 assert !enumeration.is_override?
114 114
115 115 # Setup as an override
116 116 enumeration.parent = Enumeration.find(5)
117 117 assert enumeration.is_override?
118 118 end
119 119
120 120 def test_get_subclasses
121 121 classes = Enumeration.get_subclasses
122 122 assert_include IssuePriority, classes
123 123 assert_include DocumentCategory, classes
124 124 assert_include TimeEntryActivity, classes
125 125
126 126 classes.each do |klass|
127 127 assert_equal Enumeration, klass.superclass
128 128 end
129 129 end
130 130
131 131 def test_list_should_be_scoped_for_each_type
132 132 Enumeration.delete_all
133 133
134 134 a = IssuePriority.create!(:name => 'A')
135 135 b = IssuePriority.create!(:name => 'B')
136 136 c = DocumentCategory.create!(:name => 'C')
137 137
138 138 assert_equal [1, 2, 1], [a, b, c].map(&:reload).map(&:position)
139 139 end
140 140
141 141 def test_override_should_be_created_with_same_position_as_parent
142 142 Enumeration.delete_all
143 143
144 144 a = IssuePriority.create!(:name => 'A')
145 145 b = IssuePriority.create!(:name => 'B')
146 146 override = IssuePriority.create!(:name => 'BB', :parent_id => b.id)
147 147
148 148 assert_equal [1, 2, 2], [a, b, override].map(&:reload).map(&:position)
149 149 end
150 150
151 151 def test_override_position_should_be_updated_with_parent_position
152 152 Enumeration.delete_all
153 153
154 154 a = IssuePriority.create!(:name => 'A')
155 155 b = IssuePriority.create!(:name => 'B')
156 156 override = IssuePriority.create!(:name => 'BB', :parent_id => b.id)
157 b.move_to = 'higher'
157 b.position -= 1
158 158 b.save!
159 159
160 160 assert_equal [2, 1, 1], [a, b, override].map(&:reload).map(&:position)
161 161 end
162 162
163 163 def test_destroying_override_should_not_update_positions
164 164 Enumeration.delete_all
165 165
166 166 a = IssuePriority.create!(:name => 'A')
167 167 b = IssuePriority.create!(:name => 'B')
168 168 c = IssuePriority.create!(:name => 'C')
169 169 override = IssuePriority.create!(:name => 'BB', :parent_id => b.id)
170 170 assert_equal [1, 2, 3, 2], [a, b, c, override].map(&:reload).map(&:position)
171 171
172 172 override.destroy
173 173 assert_equal [1, 2, 3], [a, b, c].map(&:reload).map(&:position)
174 174 end
175 175 end
@@ -1,102 +1,102
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 3 #
4 4 # This program is free software; you can redistribute it and/or
5 5 # modify it under the terms of the GNU General Public License
6 6 # as published by the Free Software Foundation; either version 2
7 7 # of the License, or (at your option) any later version.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU General Public License
15 15 # along with this program; if not, write to the Free Software
16 16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 17
18 18 require File.expand_path('../../test_helper', __FILE__)
19 19
20 20 class IssuePriorityTest < ActiveSupport::TestCase
21 21 fixtures :enumerations, :issues
22 22
23 23 def test_named_scope
24 24 assert_equal Enumeration.find_by_name('Normal'), Enumeration.named('normal').first
25 25 end
26 26
27 27 def test_default_should_return_the_default_priority
28 28 assert_equal Enumeration.find_by_name('Normal'), IssuePriority.default
29 29 end
30 30
31 31 def test_default_should_return_nil_when_no_default_priority
32 32 IssuePriority.update_all :is_default => false
33 33 assert_nil IssuePriority.default
34 34 end
35 35
36 36 def test_should_be_an_enumeration
37 37 assert IssuePriority.ancestors.include?(Enumeration)
38 38 end
39 39
40 40 def test_objects_count
41 41 # low priority
42 42 assert_equal 6, IssuePriority.find(4).objects_count
43 43 # urgent
44 44 assert_equal 0, IssuePriority.find(7).objects_count
45 45 end
46 46
47 47 def test_option_name
48 48 assert_equal :enumeration_issue_priorities, IssuePriority.new.option_name
49 49 end
50 50
51 51 def test_should_be_created_at_last_position
52 52 IssuePriority.delete_all
53 53
54 54 priorities = [1, 2, 3].map {|i| IssuePriority.create!(:name => "P#{i}")}
55 55 assert_equal [1, 2, 3], priorities.map(&:position)
56 56 end
57 57
58 58 def test_clear_position_names_should_set_position_names_to_nil
59 59 IssuePriority.clear_position_names
60 60 assert IssuePriority.all.all? {|priority| priority.position_name.nil?}
61 61 end
62 62
63 63 def test_compute_position_names_with_default_priority
64 64 IssuePriority.clear_position_names
65 65
66 66 IssuePriority.compute_position_names
67 67 assert_equal %w(lowest default high3 high2 highest), IssuePriority.active.to_a.sort.map(&:position_name)
68 68 end
69 69
70 70 def test_compute_position_names_without_default_priority_should_split_priorities
71 71 IssuePriority.clear_position_names
72 72 IssuePriority.update_all :is_default => false
73 73
74 74 IssuePriority.compute_position_names
75 75 assert_equal %w(lowest low2 default high2 highest), IssuePriority.active.to_a.sort.map(&:position_name)
76 76 end
77 77
78 78 def test_adding_a_priority_should_update_position_names
79 79 priority = IssuePriority.create!(:name => 'New')
80 80 assert_equal %w(lowest default high4 high3 high2 highest), IssuePriority.active.to_a.sort.map(&:position_name)
81 81 end
82 82
83 83 def test_moving_a_priority_should_update_position_names
84 84 prio = IssuePriority.first
85 prio.move_to = 'lowest'
85 prio.position = IssuePriority.count
86 86 prio.save!
87 87 prio.reload
88 88 assert_equal 'highest', prio.position_name
89 89 end
90 90
91 91 def test_deactivating_a_priority_should_update_position_names
92 92 prio = IssuePriority.active.order(:position).last
93 93 prio.active = false
94 94 prio.save
95 95 assert_equal 'highest', IssuePriority.active.order(:position).last.position_name
96 96 end
97 97
98 98 def test_destroying_a_priority_should_update_position_names
99 99 IssuePriority.find_by_position_name('highest').destroy
100 100 assert_equal %w(lowest default high2 highest), IssuePriority.active.to_a.sort.map(&:position_name)
101 101 end
102 102 end
General Comments 0
You need to be logged in to leave comments. Login now