##// END OF EJS Templates
Fixed: Boards are not deleted when project is deleted (closes #963)....
Jean-Philippe Lang -
r1301:80a5ad7ff344
parent child
Show More
@@ -1,254 +1,254
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
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
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.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class Project < ActiveRecord::Base
18 class Project < ActiveRecord::Base
19 # Project statuses
19 # Project statuses
20 STATUS_ACTIVE = 1
20 STATUS_ACTIVE = 1
21 STATUS_ARCHIVED = 9
21 STATUS_ARCHIVED = 9
22
22
23 has_many :members, :include => :user, :conditions => "#{User.table_name}.status=#{User::STATUS_ACTIVE}"
23 has_many :members, :include => :user, :conditions => "#{User.table_name}.status=#{User::STATUS_ACTIVE}"
24 has_many :users, :through => :members
24 has_many :users, :through => :members
25 has_many :custom_values, :dependent => :delete_all, :as => :customized
25 has_many :custom_values, :dependent => :delete_all, :as => :customized
26 has_many :enabled_modules, :dependent => :delete_all
26 has_many :enabled_modules, :dependent => :delete_all
27 has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position"
27 has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position"
28 has_many :issues, :dependent => :destroy, :order => "#{Issue.table_name}.created_on DESC", :include => [:status, :tracker]
28 has_many :issues, :dependent => :destroy, :order => "#{Issue.table_name}.created_on DESC", :include => [:status, :tracker]
29 has_many :issue_changes, :through => :issues, :source => :journals
29 has_many :issue_changes, :through => :issues, :source => :journals
30 has_many :versions, :dependent => :destroy, :order => "#{Version.table_name}.effective_date DESC, #{Version.table_name}.name DESC"
30 has_many :versions, :dependent => :destroy, :order => "#{Version.table_name}.effective_date DESC, #{Version.table_name}.name DESC"
31 has_many :time_entries, :dependent => :delete_all
31 has_many :time_entries, :dependent => :delete_all
32 has_many :queries, :dependent => :delete_all
32 has_many :queries, :dependent => :delete_all
33 has_many :documents, :dependent => :destroy
33 has_many :documents, :dependent => :destroy
34 has_many :news, :dependent => :delete_all, :include => :author
34 has_many :news, :dependent => :delete_all, :include => :author
35 has_many :issue_categories, :dependent => :delete_all, :order => "#{IssueCategory.table_name}.name"
35 has_many :issue_categories, :dependent => :delete_all, :order => "#{IssueCategory.table_name}.name"
36 has_many :boards, :order => "position ASC"
36 has_many :boards, :dependent => :destroy, :order => "position ASC"
37 has_one :repository, :dependent => :destroy
37 has_one :repository, :dependent => :destroy
38 has_many :changesets, :through => :repository
38 has_many :changesets, :through => :repository
39 has_one :wiki, :dependent => :destroy
39 has_one :wiki, :dependent => :destroy
40 # Custom field for the project issues
40 # Custom field for the project issues
41 has_and_belongs_to_many :custom_fields,
41 has_and_belongs_to_many :custom_fields,
42 :class_name => 'IssueCustomField',
42 :class_name => 'IssueCustomField',
43 :order => "#{CustomField.table_name}.position",
43 :order => "#{CustomField.table_name}.position",
44 :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}",
44 :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}",
45 :association_foreign_key => 'custom_field_id'
45 :association_foreign_key => 'custom_field_id'
46
46
47 acts_as_tree :order => "name", :counter_cache => true
47 acts_as_tree :order => "name", :counter_cache => true
48
48
49 acts_as_searchable :columns => ['name', 'description'], :project_key => 'id'
49 acts_as_searchable :columns => ['name', 'description'], :project_key => 'id'
50 acts_as_event :title => Proc.new {|o| "#{l(:label_project)}: #{o.name}"},
50 acts_as_event :title => Proc.new {|o| "#{l(:label_project)}: #{o.name}"},
51 :url => Proc.new {|o| {:controller => 'projects', :action => 'show', :id => o.id}}
51 :url => Proc.new {|o| {:controller => 'projects', :action => 'show', :id => o.id}}
52
52
53 attr_protected :status, :enabled_module_names
53 attr_protected :status, :enabled_module_names
54
54
55 validates_presence_of :name, :identifier
55 validates_presence_of :name, :identifier
56 validates_uniqueness_of :name, :identifier
56 validates_uniqueness_of :name, :identifier
57 validates_associated :custom_values, :on => :update
57 validates_associated :custom_values, :on => :update
58 validates_associated :repository, :wiki
58 validates_associated :repository, :wiki
59 validates_length_of :name, :maximum => 30
59 validates_length_of :name, :maximum => 30
60 validates_length_of :homepage, :maximum => 60
60 validates_length_of :homepage, :maximum => 60
61 validates_length_of :identifier, :in => 3..20
61 validates_length_of :identifier, :in => 3..20
62 validates_format_of :identifier, :with => /^[a-z0-9\-]*$/
62 validates_format_of :identifier, :with => /^[a-z0-9\-]*$/
63
63
64 before_destroy :delete_all_members
64 before_destroy :delete_all_members
65
65
66 def identifier=(identifier)
66 def identifier=(identifier)
67 super unless identifier_frozen?
67 super unless identifier_frozen?
68 end
68 end
69
69
70 def identifier_frozen?
70 def identifier_frozen?
71 errors[:identifier].nil? && !(new_record? || identifier.blank?)
71 errors[:identifier].nil? && !(new_record? || identifier.blank?)
72 end
72 end
73
73
74 def issues_with_subprojects(include_subprojects=false)
74 def issues_with_subprojects(include_subprojects=false)
75 conditions = nil
75 conditions = nil
76 if include_subprojects && !active_children.empty?
76 if include_subprojects && !active_children.empty?
77 ids = [id] + active_children.collect {|c| c.id}
77 ids = [id] + active_children.collect {|c| c.id}
78 conditions = ["#{Issue.table_name}.project_id IN (#{ids.join(',')})"]
78 conditions = ["#{Issue.table_name}.project_id IN (#{ids.join(',')})"]
79 end
79 end
80 conditions ||= ["#{Issue.table_name}.project_id = ?", id]
80 conditions ||= ["#{Issue.table_name}.project_id = ?", id]
81 # Quick and dirty fix for Rails 2 compatibility
81 # Quick and dirty fix for Rails 2 compatibility
82 Issue.send(:with_scope, :find => { :conditions => conditions }) do
82 Issue.send(:with_scope, :find => { :conditions => conditions }) do
83 yield
83 yield
84 end
84 end
85 end
85 end
86
86
87 # returns latest created projects
87 # returns latest created projects
88 # non public projects will be returned only if user is a member of those
88 # non public projects will be returned only if user is a member of those
89 def self.latest(user=nil, count=5)
89 def self.latest(user=nil, count=5)
90 find(:all, :limit => count, :conditions => visible_by(user), :order => "created_on DESC")
90 find(:all, :limit => count, :conditions => visible_by(user), :order => "created_on DESC")
91 end
91 end
92
92
93 def self.visible_by(user=nil)
93 def self.visible_by(user=nil)
94 if user && user.admin?
94 if user && user.admin?
95 return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}"
95 return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}"
96 elsif user && user.memberships.any?
96 elsif user && user.memberships.any?
97 return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND (#{Project.table_name}.is_public = #{connection.quoted_true} or #{Project.table_name}.id IN (#{user.memberships.collect{|m| m.project_id}.join(',')}))"
97 return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND (#{Project.table_name}.is_public = #{connection.quoted_true} or #{Project.table_name}.id IN (#{user.memberships.collect{|m| m.project_id}.join(',')}))"
98 else
98 else
99 return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND #{Project.table_name}.is_public = #{connection.quoted_true}"
99 return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND #{Project.table_name}.is_public = #{connection.quoted_true}"
100 end
100 end
101 end
101 end
102
102
103 def self.allowed_to_condition(user, permission, options={})
103 def self.allowed_to_condition(user, permission, options={})
104 statements = []
104 statements = []
105 base_statement = "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}"
105 base_statement = "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}"
106 if options[:project]
106 if options[:project]
107 project_statement = "#{Project.table_name}.id = #{options[:project].id}"
107 project_statement = "#{Project.table_name}.id = #{options[:project].id}"
108 project_statement << " OR #{Project.table_name}.parent_id = #{options[:project].id}" if options[:with_subprojects]
108 project_statement << " OR #{Project.table_name}.parent_id = #{options[:project].id}" if options[:with_subprojects]
109 base_statement = "(#{project_statement}) AND (#{base_statement})"
109 base_statement = "(#{project_statement}) AND (#{base_statement})"
110 end
110 end
111 if user.admin?
111 if user.admin?
112 # no restriction
112 # no restriction
113 elsif user.logged?
113 elsif user.logged?
114 statements << "#{Project.table_name}.is_public = #{connection.quoted_true}" if Role.non_member.allowed_to?(permission)
114 statements << "#{Project.table_name}.is_public = #{connection.quoted_true}" if Role.non_member.allowed_to?(permission)
115 allowed_project_ids = user.memberships.select {|m| m.role.allowed_to?(permission)}.collect {|m| m.project_id}
115 allowed_project_ids = user.memberships.select {|m| m.role.allowed_to?(permission)}.collect {|m| m.project_id}
116 statements << "#{Project.table_name}.id IN (#{allowed_project_ids.join(',')})" if allowed_project_ids.any?
116 statements << "#{Project.table_name}.id IN (#{allowed_project_ids.join(',')})" if allowed_project_ids.any?
117 elsif Role.anonymous.allowed_to?(permission)
117 elsif Role.anonymous.allowed_to?(permission)
118 # anonymous user allowed on public project
118 # anonymous user allowed on public project
119 statements << "#{Project.table_name}.is_public = #{connection.quoted_true}"
119 statements << "#{Project.table_name}.is_public = #{connection.quoted_true}"
120 else
120 else
121 # anonymous user is not authorized
121 # anonymous user is not authorized
122 statements << "1=0"
122 statements << "1=0"
123 end
123 end
124 statements.empty? ? base_statement : "((#{base_statement}) AND (#{statements.join(' OR ')}))"
124 statements.empty? ? base_statement : "((#{base_statement}) AND (#{statements.join(' OR ')}))"
125 end
125 end
126
126
127 def project_condition(with_subprojects)
127 def project_condition(with_subprojects)
128 cond = "#{Project.table_name}.id = #{id}"
128 cond = "#{Project.table_name}.id = #{id}"
129 cond = "(#{cond} OR #{Project.table_name}.parent_id = #{id})" if with_subprojects
129 cond = "(#{cond} OR #{Project.table_name}.parent_id = #{id})" if with_subprojects
130 cond
130 cond
131 end
131 end
132
132
133 def self.find(*args)
133 def self.find(*args)
134 if args.first && args.first.is_a?(String) && !args.first.match(/^\d*$/)
134 if args.first && args.first.is_a?(String) && !args.first.match(/^\d*$/)
135 project = find_by_identifier(*args)
135 project = find_by_identifier(*args)
136 raise ActiveRecord::RecordNotFound, "Couldn't find Project with identifier=#{args.first}" if project.nil?
136 raise ActiveRecord::RecordNotFound, "Couldn't find Project with identifier=#{args.first}" if project.nil?
137 project
137 project
138 else
138 else
139 super
139 super
140 end
140 end
141 end
141 end
142
142
143 def to_param
143 def to_param
144 identifier
144 identifier
145 end
145 end
146
146
147 def active?
147 def active?
148 self.status == STATUS_ACTIVE
148 self.status == STATUS_ACTIVE
149 end
149 end
150
150
151 def archive
151 def archive
152 # Archive subprojects if any
152 # Archive subprojects if any
153 children.each do |subproject|
153 children.each do |subproject|
154 subproject.archive
154 subproject.archive
155 end
155 end
156 update_attribute :status, STATUS_ARCHIVED
156 update_attribute :status, STATUS_ARCHIVED
157 end
157 end
158
158
159 def unarchive
159 def unarchive
160 return false if parent && !parent.active?
160 return false if parent && !parent.active?
161 update_attribute :status, STATUS_ACTIVE
161 update_attribute :status, STATUS_ACTIVE
162 end
162 end
163
163
164 def active_children
164 def active_children
165 children.select {|child| child.active?}
165 children.select {|child| child.active?}
166 end
166 end
167
167
168 # Returns an array of the trackers used by the project and its sub projects
168 # Returns an array of the trackers used by the project and its sub projects
169 def rolled_up_trackers
169 def rolled_up_trackers
170 @rolled_up_trackers ||=
170 @rolled_up_trackers ||=
171 Tracker.find(:all, :include => :projects,
171 Tracker.find(:all, :include => :projects,
172 :select => "DISTINCT #{Tracker.table_name}.*",
172 :select => "DISTINCT #{Tracker.table_name}.*",
173 :conditions => ["#{Project.table_name}.id = ? OR #{Project.table_name}.parent_id = ?", id, id],
173 :conditions => ["#{Project.table_name}.id = ? OR #{Project.table_name}.parent_id = ?", id, id],
174 :order => "#{Tracker.table_name}.position")
174 :order => "#{Tracker.table_name}.position")
175 end
175 end
176
176
177 # Deletes all project's members
177 # Deletes all project's members
178 def delete_all_members
178 def delete_all_members
179 Member.delete_all(['project_id = ?', id])
179 Member.delete_all(['project_id = ?', id])
180 end
180 end
181
181
182 # Users issues can be assigned to
182 # Users issues can be assigned to
183 def assignable_users
183 def assignable_users
184 members.select {|m| m.role.assignable?}.collect {|m| m.user}.sort
184 members.select {|m| m.role.assignable?}.collect {|m| m.user}.sort
185 end
185 end
186
186
187 # Returns the mail adresses of users that should be always notified on project events
187 # Returns the mail adresses of users that should be always notified on project events
188 def recipients
188 def recipients
189 members.select {|m| m.mail_notification? || m.user.mail_notification?}.collect {|m| m.user.mail}
189 members.select {|m| m.mail_notification? || m.user.mail_notification?}.collect {|m| m.user.mail}
190 end
190 end
191
191
192 # Returns an array of all custom fields enabled for project issues
192 # Returns an array of all custom fields enabled for project issues
193 # (explictly associated custom fields and custom fields enabled for all projects)
193 # (explictly associated custom fields and custom fields enabled for all projects)
194 def custom_fields_for_issues(tracker)
194 def custom_fields_for_issues(tracker)
195 all_custom_fields.select {|c| tracker.custom_fields.include? c }
195 all_custom_fields.select {|c| tracker.custom_fields.include? c }
196 end
196 end
197
197
198 def all_custom_fields
198 def all_custom_fields
199 @all_custom_fields ||= (IssueCustomField.for_all + custom_fields).uniq
199 @all_custom_fields ||= (IssueCustomField.for_all + custom_fields).uniq
200 end
200 end
201
201
202 def <=>(project)
202 def <=>(project)
203 name.downcase <=> project.name.downcase
203 name.downcase <=> project.name.downcase
204 end
204 end
205
205
206 def to_s
206 def to_s
207 name
207 name
208 end
208 end
209
209
210 # Returns a short description of the projects (first lines)
210 # Returns a short description of the projects (first lines)
211 def short_description(length = 255)
211 def short_description(length = 255)
212 description.gsub(/^(.{#{length}}[^\n]*).*$/m, '\1').strip if description
212 description.gsub(/^(.{#{length}}[^\n]*).*$/m, '\1').strip if description
213 end
213 end
214
214
215 def allows_to?(action)
215 def allows_to?(action)
216 if action.is_a? Hash
216 if action.is_a? Hash
217 allowed_actions.include? "#{action[:controller]}/#{action[:action]}"
217 allowed_actions.include? "#{action[:controller]}/#{action[:action]}"
218 else
218 else
219 allowed_permissions.include? action
219 allowed_permissions.include? action
220 end
220 end
221 end
221 end
222
222
223 def module_enabled?(module_name)
223 def module_enabled?(module_name)
224 module_name = module_name.to_s
224 module_name = module_name.to_s
225 enabled_modules.detect {|m| m.name == module_name}
225 enabled_modules.detect {|m| m.name == module_name}
226 end
226 end
227
227
228 def enabled_module_names=(module_names)
228 def enabled_module_names=(module_names)
229 enabled_modules.clear
229 enabled_modules.clear
230 module_names = [] unless module_names && module_names.is_a?(Array)
230 module_names = [] unless module_names && module_names.is_a?(Array)
231 module_names.each do |name|
231 module_names.each do |name|
232 enabled_modules << EnabledModule.new(:name => name.to_s)
232 enabled_modules << EnabledModule.new(:name => name.to_s)
233 end
233 end
234 end
234 end
235
235
236 protected
236 protected
237 def validate
237 def validate
238 errors.add(parent_id, " must be a root project") if parent and parent.parent
238 errors.add(parent_id, " must be a root project") if parent and parent.parent
239 errors.add_to_base("A project with subprojects can't be a subproject") if parent and children.size > 0
239 errors.add_to_base("A project with subprojects can't be a subproject") if parent and children.size > 0
240 errors.add(:identifier, :activerecord_error_invalid) if !identifier.blank? && identifier.match(/^\d*$/)
240 errors.add(:identifier, :activerecord_error_invalid) if !identifier.blank? && identifier.match(/^\d*$/)
241 end
241 end
242
242
243 private
243 private
244 def allowed_permissions
244 def allowed_permissions
245 @allowed_permissions ||= begin
245 @allowed_permissions ||= begin
246 module_names = enabled_modules.collect {|m| m.name}
246 module_names = enabled_modules.collect {|m| m.name}
247 Redmine::AccessControl.modules_permissions(module_names).collect {|p| p.name}
247 Redmine::AccessControl.modules_permissions(module_names).collect {|p| p.name}
248 end
248 end
249 end
249 end
250
250
251 def allowed_actions
251 def allowed_actions
252 @actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten
252 @actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten
253 end
253 end
254 end
254 end
@@ -1,129 +1,132
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
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
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.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.dirname(__FILE__) + '/../test_helper'
18 require File.dirname(__FILE__) + '/../test_helper'
19
19
20 class ProjectTest < Test::Unit::TestCase
20 class ProjectTest < Test::Unit::TestCase
21 fixtures :projects, :issues, :issue_statuses, :journals, :journal_details, :users, :members, :roles, :projects_trackers, :trackers
21 fixtures :projects, :issues, :issue_statuses, :journals, :journal_details, :users, :members, :roles, :projects_trackers, :trackers, :boards
22
22
23 def setup
23 def setup
24 @ecookbook = Project.find(1)
24 @ecookbook = Project.find(1)
25 @ecookbook_sub1 = Project.find(3)
25 @ecookbook_sub1 = Project.find(3)
26 end
26 end
27
27
28 def test_truth
28 def test_truth
29 assert_kind_of Project, @ecookbook
29 assert_kind_of Project, @ecookbook
30 assert_equal "eCookbook", @ecookbook.name
30 assert_equal "eCookbook", @ecookbook.name
31 end
31 end
32
32
33 def test_update
33 def test_update
34 assert_equal "eCookbook", @ecookbook.name
34 assert_equal "eCookbook", @ecookbook.name
35 @ecookbook.name = "eCook"
35 @ecookbook.name = "eCook"
36 assert @ecookbook.save, @ecookbook.errors.full_messages.join("; ")
36 assert @ecookbook.save, @ecookbook.errors.full_messages.join("; ")
37 @ecookbook.reload
37 @ecookbook.reload
38 assert_equal "eCook", @ecookbook.name
38 assert_equal "eCook", @ecookbook.name
39 end
39 end
40
40
41 def test_validate
41 def test_validate
42 @ecookbook.name = ""
42 @ecookbook.name = ""
43 assert !@ecookbook.save
43 assert !@ecookbook.save
44 assert_equal 1, @ecookbook.errors.count
44 assert_equal 1, @ecookbook.errors.count
45 assert_equal "activerecord_error_blank", @ecookbook.errors.on(:name)
45 assert_equal "activerecord_error_blank", @ecookbook.errors.on(:name)
46 end
46 end
47
47
48 def test_public_projects
48 def test_public_projects
49 public_projects = Project.find(:all, :conditions => ["is_public=?", true])
49 public_projects = Project.find(:all, :conditions => ["is_public=?", true])
50 assert_equal 3, public_projects.length
50 assert_equal 3, public_projects.length
51 assert_equal true, public_projects[0].is_public?
51 assert_equal true, public_projects[0].is_public?
52 end
52 end
53
53
54 def test_archive
54 def test_archive
55 user = @ecookbook.members.first.user
55 user = @ecookbook.members.first.user
56 @ecookbook.archive
56 @ecookbook.archive
57 @ecookbook.reload
57 @ecookbook.reload
58
58
59 assert !@ecookbook.active?
59 assert !@ecookbook.active?
60 assert !user.projects.include?(@ecookbook)
60 assert !user.projects.include?(@ecookbook)
61 # Subproject are also archived
61 # Subproject are also archived
62 assert !@ecookbook.children.empty?
62 assert !@ecookbook.children.empty?
63 assert @ecookbook.active_children.empty?
63 assert @ecookbook.active_children.empty?
64 end
64 end
65
65
66 def test_unarchive
66 def test_unarchive
67 user = @ecookbook.members.first.user
67 user = @ecookbook.members.first.user
68 @ecookbook.archive
68 @ecookbook.archive
69 # A subproject of an archived project can not be unarchived
69 # A subproject of an archived project can not be unarchived
70 assert !@ecookbook_sub1.unarchive
70 assert !@ecookbook_sub1.unarchive
71
71
72 # Unarchive project
72 # Unarchive project
73 assert @ecookbook.unarchive
73 assert @ecookbook.unarchive
74 @ecookbook.reload
74 @ecookbook.reload
75 assert @ecookbook.active?
75 assert @ecookbook.active?
76 assert user.projects.include?(@ecookbook)
76 assert user.projects.include?(@ecookbook)
77 # Subproject can now be unarchived
77 # Subproject can now be unarchived
78 @ecookbook_sub1.reload
78 @ecookbook_sub1.reload
79 assert @ecookbook_sub1.unarchive
79 assert @ecookbook_sub1.unarchive
80 end
80 end
81
81
82 def test_destroy
82 def test_destroy
83 # 2 active members
83 # 2 active members
84 assert_equal 2, @ecookbook.members.size
84 assert_equal 2, @ecookbook.members.size
85 # and 1 is locked
85 # and 1 is locked
86 assert_equal 3, Member.find(:all, :conditions => ['project_id = ?', @ecookbook.id]).size
86 assert_equal 3, Member.find(:all, :conditions => ['project_id = ?', @ecookbook.id]).size
87 # some boards
88 assert @ecookbook.boards.any?
87
89
88 @ecookbook.destroy
90 @ecookbook.destroy
89 # make sure that the project non longer exists
91 # make sure that the project non longer exists
90 assert_raise(ActiveRecord::RecordNotFound) { Project.find(@ecookbook.id) }
92 assert_raise(ActiveRecord::RecordNotFound) { Project.find(@ecookbook.id) }
91 # make sure all members have been removed
93 # make sure related data was removed
92 assert_equal 0, Member.find(:all, :conditions => ['project_id = ?', @ecookbook.id]).size
94 assert Member.find(:all, :conditions => ['project_id = ?', @ecookbook.id]).empty?
95 assert Board.find(:all, :conditions => ['project_id = ?', @ecookbook.id]).empty?
93 end
96 end
94
97
95 def test_subproject_ok
98 def test_subproject_ok
96 sub = Project.find(2)
99 sub = Project.find(2)
97 sub.parent = @ecookbook
100 sub.parent = @ecookbook
98 assert sub.save
101 assert sub.save
99 assert_equal @ecookbook.id, sub.parent.id
102 assert_equal @ecookbook.id, sub.parent.id
100 @ecookbook.reload
103 @ecookbook.reload
101 assert_equal 3, @ecookbook.children.size
104 assert_equal 3, @ecookbook.children.size
102 end
105 end
103
106
104 def test_subproject_invalid
107 def test_subproject_invalid
105 sub = Project.find(2)
108 sub = Project.find(2)
106 sub.parent = @ecookbook_sub1
109 sub.parent = @ecookbook_sub1
107 assert !sub.save
110 assert !sub.save
108 end
111 end
109
112
110 def test_subproject_invalid_2
113 def test_subproject_invalid_2
111 sub = @ecookbook
114 sub = @ecookbook
112 sub.parent = Project.find(2)
115 sub.parent = Project.find(2)
113 assert !sub.save
116 assert !sub.save
114 end
117 end
115
118
116 def test_rolled_up_trackers
119 def test_rolled_up_trackers
117 parent = Project.find(1)
120 parent = Project.find(1)
118 child = parent.children.find(3)
121 child = parent.children.find(3)
119
122
120 assert_equal [1, 2], parent.tracker_ids
123 assert_equal [1, 2], parent.tracker_ids
121 assert_equal [2, 3], child.tracker_ids
124 assert_equal [2, 3], child.tracker_ids
122
125
123 assert_kind_of Tracker, parent.rolled_up_trackers.first
126 assert_kind_of Tracker, parent.rolled_up_trackers.first
124 assert_equal Tracker.find(1), parent.rolled_up_trackers.first
127 assert_equal Tracker.find(1), parent.rolled_up_trackers.first
125
128
126 assert_equal [1, 2, 3], parent.rolled_up_trackers.collect(&:id)
129 assert_equal [1, 2, 3], parent.rolled_up_trackers.collect(&:id)
127 assert_equal [2, 3], child.rolled_up_trackers.collect(&:id)
130 assert_equal [2, 3], child.rolled_up_trackers.collect(&:id)
128 end
131 end
129 end
132 end
General Comments 0
You need to be logged in to leave comments. Login now