##// END OF EJS Templates
Ability to add a new version from the issue form (#4315)....
Jean-Philippe Lang -
r3012:a2b4bb0dfb93
parent child
Show More
@@ -1,406 +1,425
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2009 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 class ProjectsController < ApplicationController
19 19 menu_item :overview
20 20 menu_item :activity, :only => :activity
21 21 menu_item :roadmap, :only => :roadmap
22 22 menu_item :files, :only => [:list_files, :add_file]
23 23 menu_item :settings, :only => :settings
24 24 menu_item :issues, :only => [:changelog]
25 25
26 26 before_filter :find_project, :except => [ :index, :list, :add, :copy, :activity ]
27 27 before_filter :find_optional_project, :only => :activity
28 28 before_filter :authorize, :except => [ :index, :list, :add, :copy, :archive, :unarchive, :destroy, :activity ]
29 29 before_filter :authorize_global, :only => :add
30 30 before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ]
31 31 accept_key_auth :activity
32 32
33 33 after_filter :only => [:add, :edit, :archive, :unarchive, :destroy] do |controller|
34 34 if controller.request.post?
35 35 controller.send :expire_action, :controller => 'welcome', :action => 'robots.txt'
36 36 end
37 37 end
38 38
39 39 helper :sort
40 40 include SortHelper
41 41 helper :custom_fields
42 42 include CustomFieldsHelper
43 43 helper :issues
44 44 helper IssuesHelper
45 45 helper :queries
46 46 include QueriesHelper
47 47 helper :repositories
48 48 include RepositoriesHelper
49 49 include ProjectsHelper
50 50
51 51 # Lists visible projects
52 52 def index
53 53 respond_to do |format|
54 54 format.html {
55 55 @projects = Project.visible.find(:all, :order => 'lft')
56 56 }
57 57 format.atom {
58 58 projects = Project.visible.find(:all, :order => 'created_on DESC',
59 59 :limit => Setting.feeds_limit.to_i)
60 60 render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}")
61 61 }
62 62 end
63 63 end
64 64
65 65 # Add a new project
66 66 def add
67 67 @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
68 68 @trackers = Tracker.all
69 69 @project = Project.new(params[:project])
70 70 if request.get?
71 71 @project.identifier = Project.next_identifier if Setting.sequential_project_identifiers?
72 72 @project.trackers = Tracker.all
73 73 @project.is_public = Setting.default_projects_public?
74 74 @project.enabled_module_names = Setting.default_projects_modules
75 75 else
76 76 @project.enabled_module_names = params[:enabled_modules]
77 77 if @project.save
78 78 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
79 79 # Add current user as a project member if he is not admin
80 80 unless User.current.admin?
81 81 r = Role.givable.find_by_id(Setting.new_project_user_role_id.to_i) || Role.givable.first
82 82 m = Member.new(:user => User.current, :roles => [r])
83 83 @project.members << m
84 84 end
85 85 flash[:notice] = l(:notice_successful_create)
86 86 redirect_to :controller => 'projects', :action => 'settings', :id => @project
87 87 end
88 88 end
89 89 end
90 90
91 91 def copy
92 92 @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
93 93 @trackers = Tracker.all
94 94 @root_projects = Project.find(:all,
95 95 :conditions => "parent_id IS NULL AND status = #{Project::STATUS_ACTIVE}",
96 96 :order => 'name')
97 97 @source_project = Project.find(params[:id])
98 98 if request.get?
99 99 @project = Project.copy_from(@source_project)
100 100 if @project
101 101 @project.identifier = Project.next_identifier if Setting.sequential_project_identifiers?
102 102 else
103 103 redirect_to :controller => 'admin', :action => 'projects'
104 104 end
105 105 else
106 106 @project = Project.new(params[:project])
107 107 @project.enabled_module_names = params[:enabled_modules]
108 108 if @project.copy(@source_project, :only => params[:only])
109 109 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
110 110 flash[:notice] = l(:notice_successful_create)
111 111 redirect_to :controller => 'admin', :action => 'projects'
112 112 end
113 113 end
114 114 rescue ActiveRecord::RecordNotFound
115 115 redirect_to :controller => 'admin', :action => 'projects'
116 116 end
117 117
118 118 # Show @project
119 119 def show
120 120 if params[:jump]
121 121 # try to redirect to the requested menu item
122 122 redirect_to_project_menu_item(@project, params[:jump]) && return
123 123 end
124 124
125 125 @users_by_role = @project.users_by_role
126 126 @subprojects = @project.children.visible
127 127 @news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
128 128 @trackers = @project.rolled_up_trackers
129 129
130 130 cond = @project.project_condition(Setting.display_subprojects_issues?)
131 131
132 132 @open_issues_by_tracker = Issue.visible.count(:group => :tracker,
133 133 :include => [:project, :status, :tracker],
134 134 :conditions => ["(#{cond}) AND #{IssueStatus.table_name}.is_closed=?", false])
135 135 @total_issues_by_tracker = Issue.visible.count(:group => :tracker,
136 136 :include => [:project, :status, :tracker],
137 137 :conditions => cond)
138 138
139 139 TimeEntry.visible_by(User.current) do
140 140 @total_hours = TimeEntry.sum(:hours,
141 141 :include => :project,
142 142 :conditions => cond).to_f
143 143 end
144 144 @key = User.current.rss_key
145 145 end
146 146
147 147 def settings
148 148 @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
149 149 @issue_category ||= IssueCategory.new
150 150 @member ||= @project.members.new
151 151 @trackers = Tracker.all
152 152 @repository ||= @project.repository
153 153 @wiki ||= @project.wiki
154 154 end
155 155
156 156 # Edit @project
157 157 def edit
158 158 if request.post?
159 159 @project.attributes = params[:project]
160 160 if @project.save
161 161 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
162 162 flash[:notice] = l(:notice_successful_update)
163 163 redirect_to :action => 'settings', :id => @project
164 164 else
165 165 settings
166 166 render :action => 'settings'
167 167 end
168 168 end
169 169 end
170 170
171 171 def modules
172 172 @project.enabled_module_names = params[:enabled_modules]
173 173 redirect_to :action => 'settings', :id => @project, :tab => 'modules'
174 174 end
175 175
176 176 def archive
177 177 if request.post?
178 178 unless @project.archive
179 179 flash[:error] = l(:error_can_not_archive_project)
180 180 end
181 181 end
182 182 redirect_to(url_for(:controller => 'admin', :action => 'projects', :status => params[:status]))
183 183 end
184 184
185 185 def unarchive
186 186 @project.unarchive if request.post? && !@project.active?
187 187 redirect_to(url_for(:controller => 'admin', :action => 'projects', :status => params[:status]))
188 188 end
189 189
190 190 # Delete @project
191 191 def destroy
192 192 @project_to_destroy = @project
193 193 if request.post? and params[:confirm]
194 194 @project_to_destroy.destroy
195 195 redirect_to :controller => 'admin', :action => 'projects'
196 196 end
197 197 # hide project in layout
198 198 @project = nil
199 199 end
200 200
201 201 # Add a new issue category to @project
202 202 def add_issue_category
203 203 @category = @project.issue_categories.build(params[:category])
204 204 if request.post?
205 205 if @category.save
206 206 respond_to do |format|
207 207 format.html do
208 208 flash[:notice] = l(:notice_successful_create)
209 209 redirect_to :action => 'settings', :tab => 'categories', :id => @project
210 210 end
211 211 format.js do
212 212 # IE doesn't support the replace_html rjs method for select box options
213 213 render(:update) {|page| page.replace "issue_category_id",
214 214 content_tag('select', '<option></option>' + options_from_collection_for_select(@project.issue_categories, 'id', 'name', @category.id), :id => 'issue_category_id', :name => 'issue[category_id]')
215 215 }
216 216 end
217 217 end
218 218 else
219 219 respond_to do |format|
220 220 format.html
221 221 format.js do
222 222 render(:update) {|page| page.alert(@category.errors.full_messages.join('\n')) }
223 223 end
224 224 end
225 225 end
226 226 end
227 227 end
228 228
229 229 # Add a new version to @project
230 230 def add_version
231 231 @version = @project.versions.build
232 232 if params[:version]
233 233 attributes = params[:version].dup
234 234 attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing'])
235 235 @version.attributes = attributes
236 236 end
237 if request.post? and @version.save
238 flash[:notice] = l(:notice_successful_create)
239 redirect_to :action => 'settings', :tab => 'versions', :id => @project
237 if request.post?
238 if @version.save
239 respond_to do |format|
240 format.html do
241 flash[:notice] = l(:notice_successful_create)
242 redirect_to :action => 'settings', :tab => 'versions', :id => @project
243 end
244 format.js do
245 # IE doesn't support the replace_html rjs method for select box options
246 render(:update) {|page| page.replace "issue_fixed_version_id",
247 content_tag('select', '<option></option>' + version_options_for_select(@project.shared_versions.open, @version), :id => 'issue_fixed_version_id', :name => 'issue[fixed_version_id]')
248 }
249 end
250 end
251 else
252 respond_to do |format|
253 format.html
254 format.js do
255 render(:update) {|page| page.alert(@version.errors.full_messages.join('\n')) }
256 end
257 end
258 end
240 259 end
241 260 end
242 261
243 262 def add_file
244 263 if request.post?
245 264 container = (params[:version_id].blank? ? @project : @project.versions.find_by_id(params[:version_id]))
246 265 attachments = attach_files(container, params[:attachments])
247 266 if !attachments.empty? && Setting.notified_events.include?('file_added')
248 267 Mailer.deliver_attachments_added(attachments)
249 268 end
250 269 redirect_to :controller => 'projects', :action => 'list_files', :id => @project
251 270 return
252 271 end
253 272 @versions = @project.versions.sort
254 273 end
255 274
256 275 def save_activities
257 276 if request.post? && params[:enumerations]
258 277 Project.transaction do
259 278 params[:enumerations].each do |id, activity|
260 279 @project.update_or_create_time_entry_activity(id, activity)
261 280 end
262 281 end
263 282 end
264 283
265 284 redirect_to :controller => 'projects', :action => 'settings', :tab => 'activities', :id => @project
266 285 end
267 286
268 287 def reset_activities
269 288 @project.time_entry_activities.each do |time_entry_activity|
270 289 time_entry_activity.destroy(time_entry_activity.parent)
271 290 end
272 291 redirect_to :controller => 'projects', :action => 'settings', :tab => 'activities', :id => @project
273 292 end
274 293
275 294 def list_files
276 295 sort_init 'filename', 'asc'
277 296 sort_update 'filename' => "#{Attachment.table_name}.filename",
278 297 'created_on' => "#{Attachment.table_name}.created_on",
279 298 'size' => "#{Attachment.table_name}.filesize",
280 299 'downloads' => "#{Attachment.table_name}.downloads"
281 300
282 301 @containers = [ Project.find(@project.id, :include => :attachments, :order => sort_clause)]
283 302 @containers += @project.versions.find(:all, :include => :attachments, :order => sort_clause).sort.reverse
284 303 render :layout => !request.xhr?
285 304 end
286 305
287 306 # Show changelog for @project
288 307 def changelog
289 308 @trackers = @project.trackers.find(:all, :conditions => ["is_in_chlog=?", true], :order => 'position')
290 309 retrieve_selected_tracker_ids(@trackers)
291 310 @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
292 311 project_ids = @with_subprojects ? @project.self_and_descendants.collect(&:id) : [@project.id]
293 312
294 313 @versions = @project.shared_versions.sort
295 314
296 315 @issues_by_version = {}
297 316 unless @selected_tracker_ids.empty?
298 317 @versions.each do |version|
299 318 conditions = {:tracker_id => @selected_tracker_ids, "#{IssueStatus.table_name}.is_closed" => true}
300 319 if !@project.versions.include?(version)
301 320 conditions.merge!(:project_id => project_ids)
302 321 end
303 322 issues = version.fixed_issues.visible.find(:all,
304 323 :include => [:status, :tracker, :priority],
305 324 :conditions => conditions,
306 325 :order => "#{Tracker.table_name}.position, #{Issue.table_name}.id")
307 326 @issues_by_version[version] = issues
308 327 end
309 328 end
310 329 @versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].empty?}
311 330 end
312 331
313 332 def roadmap
314 333 @trackers = @project.trackers.find(:all, :conditions => ["is_in_roadmap=?", true], :order => 'position')
315 334 retrieve_selected_tracker_ids(@trackers)
316 335 @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
317 336 project_ids = @with_subprojects ? @project.self_and_descendants.collect(&:id) : [@project.id]
318 337
319 338 @versions = @project.shared_versions.sort
320 339 @versions.reject! {|version| version.closed? || version.completed? } unless params[:completed]
321 340
322 341 @issues_by_version = {}
323 342 unless @selected_tracker_ids.empty?
324 343 @versions.each do |version|
325 344 conditions = {:tracker_id => @selected_tracker_ids}
326 345 if !@project.versions.include?(version)
327 346 conditions.merge!(:project_id => project_ids)
328 347 end
329 348 issues = version.fixed_issues.visible.find(:all,
330 349 :include => [:status, :tracker, :priority],
331 350 :conditions => conditions,
332 351 :order => "#{Tracker.table_name}.position, #{Issue.table_name}.id")
333 352 @issues_by_version[version] = issues
334 353 end
335 354 end
336 355 @versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].empty?}
337 356 end
338 357
339 358 def activity
340 359 @days = Setting.activity_days_default.to_i
341 360
342 361 if params[:from]
343 362 begin; @date_to = params[:from].to_date + 1; rescue; end
344 363 end
345 364
346 365 @date_to ||= Date.today + 1
347 366 @date_from = @date_to - @days
348 367 @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
349 368 @author = (params[:user_id].blank? ? nil : User.active.find(params[:user_id]))
350 369
351 370 @activity = Redmine::Activity::Fetcher.new(User.current, :project => @project,
352 371 :with_subprojects => @with_subprojects,
353 372 :author => @author)
354 373 @activity.scope_select {|t| !params["show_#{t}"].nil?}
355 374 @activity.scope = (@author.nil? ? :default : :all) if @activity.scope.empty?
356 375
357 376 events = @activity.events(@date_from, @date_to)
358 377
359 378 if events.empty? || stale?(:etag => [events.first, User.current])
360 379 respond_to do |format|
361 380 format.html {
362 381 @events_by_day = events.group_by(&:event_date)
363 382 render :layout => false if request.xhr?
364 383 }
365 384 format.atom {
366 385 title = l(:label_activity)
367 386 if @author
368 387 title = @author.name
369 388 elsif @activity.scope.size == 1
370 389 title = l("label_#{@activity.scope.first.singularize}_plural")
371 390 end
372 391 render_feed(events, :title => "#{@project || Setting.app_title}: #{title}")
373 392 }
374 393 end
375 394 end
376 395
377 396 rescue ActiveRecord::RecordNotFound
378 397 render_404
379 398 end
380 399
381 400 private
382 401 # Find project of id params[:id]
383 402 # if not found, redirect to project list
384 403 # Used as a before_filter
385 404 def find_project
386 405 @project = Project.find(params[:id])
387 406 rescue ActiveRecord::RecordNotFound
388 407 render_404
389 408 end
390 409
391 410 def find_optional_project
392 411 return true unless params[:id]
393 412 @project = Project.find(params[:id])
394 413 authorize
395 414 rescue ActiveRecord::RecordNotFound
396 415 render_404
397 416 end
398 417
399 418 def retrieve_selected_tracker_ids(selectable_trackers)
400 419 if ids = params[:tracker_ids]
401 420 @selected_tracker_ids = (ids.is_a? Array) ? ids.collect { |id| id.to_i.to_s } : ids.split('/').collect { |id| id.to_i.to_s }
402 421 else
403 422 @selected_tracker_ids = selectable_trackers.collect {|t| t.id.to_s }
404 423 end
405 424 end
406 425 end
@@ -1,36 +1,43
1 1 <% fields_for :issue, @issue, :builder => TabularFormBuilder do |f| %>
2 2
3 3 <div class="splitcontentleft">
4 4 <% if @issue.new_record? || @allowed_statuses.any? %>
5 5 <p><%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %></p>
6 6 <% else %>
7 7 <p><label><%= l(:field_status) %></label> <%= @issue.status.name %></p>
8 8 <% end %>
9 9
10 10 <p><%= f.select :priority_id, (@priorities.collect {|p| [p.name, p.id]}), :required => true %></p>
11 11 <p><%= f.select :assigned_to_id, (@issue.assignable_users.collect {|m| [m.name, m.id]}), :include_blank => true %></p>
12 12 <% unless @project.issue_categories.empty? %>
13 13 <p><%= f.select :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %>
14 14 <%= prompt_to_remote(image_tag('add.png', :style => 'vertical-align: middle;'),
15 15 l(:label_issue_category_new),
16 16 'category[name]',
17 17 {:controller => 'projects', :action => 'add_issue_category', :id => @project},
18 18 :title => l(:label_issue_category_new),
19 19 :tabindex => 199) if authorize_for('projects', 'add_issue_category') %></p>
20 20 <% end %>
21 21 <% unless @issue.assignable_versions.empty? %>
22 <p><%= f.select :fixed_version_id, version_options_for_select(@issue.assignable_versions, @issue.fixed_version), :include_blank => true %></p>
22 <p><%= f.select :fixed_version_id, version_options_for_select(@issue.assignable_versions, @issue.fixed_version), :include_blank => true %>
23 <%= prompt_to_remote(image_tag('add.png', :style => 'vertical-align: middle;'),
24 l(:label_version_new),
25 'version[name]',
26 {:controller => 'projects', :action => 'add_version', :id => @project},
27 :title => l(:label_version_new),
28 :tabindex => 200) if authorize_for('projects', 'add_version') %>
29 </p>
23 30 <% end %>
24 31 </div>
25 32
26 33 <div class="splitcontentright">
27 34 <p><%= f.text_field :start_date, :size => 10 %><%= calendar_for('issue_start_date') %></p>
28 35 <p><%= f.text_field :due_date, :size => 10 %><%= calendar_for('issue_due_date') %></p>
29 36 <p><%= f.text_field :estimated_hours, :size => 3 %> <%= l(:field_hours) %></p>
30 37 <p><%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %></p>
31 38 </div>
32 39
33 40 <div style="clear:both;"> </div>
34 41 <%= render :partial => 'form_custom_fields' %>
35 42
36 43 <% end %>
@@ -1,800 +1,823
1 1 # Redmine - project management software
2 2 # Copyright (C) 2006-2008 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.dirname(__FILE__) + '/../test_helper'
19 19 require 'projects_controller'
20 20
21 21 # Re-raise errors caught by the controller.
22 22 class ProjectsController; def rescue_action(e) raise e end; end
23 23
24 24 class ProjectsControllerTest < ActionController::TestCase
25 25 fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details,
26 26 :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages,
27 27 :attachments, :custom_fields, :custom_values, :time_entries
28 28
29 29 def setup
30 30 @controller = ProjectsController.new
31 31 @request = ActionController::TestRequest.new
32 32 @response = ActionController::TestResponse.new
33 33 @request.session[:user_id] = nil
34 34 Setting.default_language = 'en'
35 35 end
36 36
37 37 def test_index_routing
38 38 assert_routing(
39 39 {:method => :get, :path => '/projects'},
40 40 :controller => 'projects', :action => 'index'
41 41 )
42 42 end
43 43
44 44 def test_index
45 45 get :index
46 46 assert_response :success
47 47 assert_template 'index'
48 48 assert_not_nil assigns(:projects)
49 49
50 50 assert_tag :ul, :child => {:tag => 'li',
51 51 :descendant => {:tag => 'a', :content => 'eCookbook'},
52 52 :child => { :tag => 'ul',
53 53 :descendant => { :tag => 'a',
54 54 :content => 'Child of private child'
55 55 }
56 56 }
57 57 }
58 58
59 59 assert_no_tag :a, :content => /Private child of eCookbook/
60 60 end
61 61
62 62 def test_index_atom_routing
63 63 assert_routing(
64 64 {:method => :get, :path => '/projects.atom'},
65 65 :controller => 'projects', :action => 'index', :format => 'atom'
66 66 )
67 67 end
68 68
69 69 def test_index_atom
70 70 get :index, :format => 'atom'
71 71 assert_response :success
72 72 assert_template 'common/feed.atom.rxml'
73 73 assert_select 'feed>title', :text => 'Redmine: Latest projects'
74 74 assert_select 'feed>entry', :count => Project.count(:conditions => Project.visible_by(User.current))
75 75 end
76 76
77 77 def test_add_routing
78 78 assert_routing(
79 79 {:method => :get, :path => '/projects/new'},
80 80 :controller => 'projects', :action => 'add'
81 81 )
82 82 assert_recognizes(
83 83 {:controller => 'projects', :action => 'add'},
84 84 {:method => :post, :path => '/projects/new'}
85 85 )
86 86 assert_recognizes(
87 87 {:controller => 'projects', :action => 'add'},
88 88 {:method => :post, :path => '/projects'}
89 89 )
90 90 end
91 91
92 92 def test_get_add
93 93 @request.session[:user_id] = 1
94 94 get :add
95 95 assert_response :success
96 96 assert_template 'add'
97 97 end
98 98
99 99 def test_get_add_by_non_admin
100 100 @request.session[:user_id] = 2
101 101 get :add
102 102 assert_response :success
103 103 assert_template 'add'
104 104 end
105 105
106 106 def test_post_add
107 107 @request.session[:user_id] = 1
108 108 post :add, :project => { :name => "blog",
109 109 :description => "weblog",
110 110 :identifier => "blog",
111 111 :is_public => 1,
112 112 :custom_field_values => { '3' => 'Beta' }
113 113 }
114 114 assert_redirected_to '/projects/blog/settings'
115 115
116 116 project = Project.find_by_name('blog')
117 117 assert_kind_of Project, project
118 118 assert_equal 'weblog', project.description
119 119 assert_equal true, project.is_public?
120 120 assert_nil project.parent
121 121 end
122 122
123 123 def test_post_add_subproject
124 124 @request.session[:user_id] = 1
125 125 post :add, :project => { :name => "blog",
126 126 :description => "weblog",
127 127 :identifier => "blog",
128 128 :is_public => 1,
129 129 :custom_field_values => { '3' => 'Beta' },
130 130 :parent_id => 1
131 131 }
132 132 assert_redirected_to '/projects/blog/settings'
133 133
134 134 project = Project.find_by_name('blog')
135 135 assert_kind_of Project, project
136 136 assert_equal Project.find(1), project.parent
137 137 end
138 138
139 139 def test_post_add_by_non_admin
140 140 @request.session[:user_id] = 2
141 141 post :add, :project => { :name => "blog",
142 142 :description => "weblog",
143 143 :identifier => "blog",
144 144 :is_public => 1,
145 145 :custom_field_values => { '3' => 'Beta' }
146 146 }
147 147 assert_redirected_to '/projects/blog/settings'
148 148
149 149 project = Project.find_by_name('blog')
150 150 assert_kind_of Project, project
151 151 assert_equal 'weblog', project.description
152 152 assert_equal true, project.is_public?
153 153
154 154 # User should be added as a project member
155 155 assert User.find(2).member_of?(project)
156 156 assert_equal 1, project.members.size
157 157 end
158 158
159 159 def test_show_routing
160 160 assert_routing(
161 161 {:method => :get, :path => '/projects/test'},
162 162 :controller => 'projects', :action => 'show', :id => 'test'
163 163 )
164 164 end
165 165
166 166 def test_show_by_id
167 167 get :show, :id => 1
168 168 assert_response :success
169 169 assert_template 'show'
170 170 assert_not_nil assigns(:project)
171 171 end
172 172
173 173 def test_show_by_identifier
174 174 get :show, :id => 'ecookbook'
175 175 assert_response :success
176 176 assert_template 'show'
177 177 assert_not_nil assigns(:project)
178 178 assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
179 179 end
180 180
181 181 def test_show_should_not_fail_when_custom_values_are_nil
182 182 project = Project.find_by_identifier('ecookbook')
183 183 project.custom_values.first.update_attribute(:value, nil)
184 184 get :show, :id => 'ecookbook'
185 185 assert_response :success
186 186 assert_template 'show'
187 187 assert_not_nil assigns(:project)
188 188 assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
189 189 end
190 190
191 191 def test_private_subprojects_hidden
192 192 get :show, :id => 'ecookbook'
193 193 assert_response :success
194 194 assert_template 'show'
195 195 assert_no_tag :tag => 'a', :content => /Private child/
196 196 end
197 197
198 198 def test_private_subprojects_visible
199 199 @request.session[:user_id] = 2 # manager who is a member of the private subproject
200 200 get :show, :id => 'ecookbook'
201 201 assert_response :success
202 202 assert_template 'show'
203 203 assert_tag :tag => 'a', :content => /Private child/
204 204 end
205 205
206 206 def test_settings_routing
207 207 assert_routing(
208 208 {:method => :get, :path => '/projects/4223/settings'},
209 209 :controller => 'projects', :action => 'settings', :id => '4223'
210 210 )
211 211 assert_routing(
212 212 {:method => :get, :path => '/projects/4223/settings/members'},
213 213 :controller => 'projects', :action => 'settings', :id => '4223', :tab => 'members'
214 214 )
215 215 end
216 216
217 217 def test_settings
218 218 @request.session[:user_id] = 2 # manager
219 219 get :settings, :id => 1
220 220 assert_response :success
221 221 assert_template 'settings'
222 222 end
223 223
224 224 def test_edit
225 225 @request.session[:user_id] = 2 # manager
226 226 post :edit, :id => 1, :project => {:name => 'Test changed name',
227 227 :issue_custom_field_ids => ['']}
228 228 assert_redirected_to 'projects/ecookbook/settings'
229 229 project = Project.find(1)
230 230 assert_equal 'Test changed name', project.name
231 231 end
232 232
233 233 def test_add_version_routing
234 234 assert_routing(
235 235 {:method => :get, :path => 'projects/64/versions/new'},
236 236 :controller => 'projects', :action => 'add_version', :id => '64'
237 237 )
238 238 assert_routing(
239 239 #TODO: use PUT
240 240 {:method => :post, :path => 'projects/64/versions/new'},
241 241 :controller => 'projects', :action => 'add_version', :id => '64'
242 242 )
243 243 end
244 244
245 def test_add_version
246 @request.session[:user_id] = 2 # manager
247 assert_difference 'Version.count' do
248 post :add_version, :id => '1', :version => {:name => 'test_add_version'}
249 end
250 assert_redirected_to '/projects/ecookbook/settings/versions'
251 version = Version.find_by_name('test_add_version')
252 assert_not_nil version
253 assert_equal 1, version.project_id
254 end
255
256 def test_add_version_from_issue_form
257 @request.session[:user_id] = 2 # manager
258 assert_difference 'Version.count' do
259 xhr :post, :add_version, :id => '1', :version => {:name => 'test_add_version_from_issue_form'}
260 end
261 assert_response :success
262 assert_select_rjs :replace, 'issue_fixed_version_id'
263 version = Version.find_by_name('test_add_version_from_issue_form')
264 assert_not_nil version
265 assert_equal 1, version.project_id
266 end
267
245 268 def test_add_issue_category_routing
246 269 assert_routing(
247 270 {:method => :get, :path => 'projects/test/categories/new'},
248 271 :controller => 'projects', :action => 'add_issue_category', :id => 'test'
249 272 )
250 273 assert_routing(
251 274 #TODO: use PUT and update form
252 275 {:method => :post, :path => 'projects/64/categories/new'},
253 276 :controller => 'projects', :action => 'add_issue_category', :id => '64'
254 277 )
255 278 end
256 279
257 280 def test_destroy_routing
258 281 assert_routing(
259 282 {:method => :get, :path => '/projects/567/destroy'},
260 283 :controller => 'projects', :action => 'destroy', :id => '567'
261 284 )
262 285 assert_routing(
263 286 #TODO: use DELETE and update form
264 287 {:method => :post, :path => 'projects/64/destroy'},
265 288 :controller => 'projects', :action => 'destroy', :id => '64'
266 289 )
267 290 end
268 291
269 292 def test_get_destroy
270 293 @request.session[:user_id] = 1 # admin
271 294 get :destroy, :id => 1
272 295 assert_response :success
273 296 assert_template 'destroy'
274 297 assert_not_nil Project.find_by_id(1)
275 298 end
276 299
277 300 def test_post_destroy
278 301 @request.session[:user_id] = 1 # admin
279 302 post :destroy, :id => 1, :confirm => 1
280 303 assert_redirected_to 'admin/projects'
281 304 assert_nil Project.find_by_id(1)
282 305 end
283 306
284 307 def test_add_file
285 308 set_tmp_attachments_directory
286 309 @request.session[:user_id] = 2
287 310 Setting.notified_events = ['file_added']
288 311 ActionMailer::Base.deliveries.clear
289 312
290 313 assert_difference 'Attachment.count' do
291 314 post :add_file, :id => 1, :version_id => '',
292 315 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
293 316 end
294 317 assert_redirected_to 'projects/ecookbook/files'
295 318 a = Attachment.find(:first, :order => 'created_on DESC')
296 319 assert_equal 'testfile.txt', a.filename
297 320 assert_equal Project.find(1), a.container
298 321
299 322 mail = ActionMailer::Base.deliveries.last
300 323 assert_kind_of TMail::Mail, mail
301 324 assert_equal "[eCookbook] New file", mail.subject
302 325 assert mail.body.include?('testfile.txt')
303 326 end
304 327
305 328 def test_add_file_routing
306 329 assert_routing(
307 330 {:method => :get, :path => '/projects/33/files/new'},
308 331 :controller => 'projects', :action => 'add_file', :id => '33'
309 332 )
310 333 assert_routing(
311 334 {:method => :post, :path => '/projects/33/files/new'},
312 335 :controller => 'projects', :action => 'add_file', :id => '33'
313 336 )
314 337 end
315 338
316 339 def test_add_version_file
317 340 set_tmp_attachments_directory
318 341 @request.session[:user_id] = 2
319 342 Setting.notified_events = ['file_added']
320 343
321 344 assert_difference 'Attachment.count' do
322 345 post :add_file, :id => 1, :version_id => '2',
323 346 :attachments => {'1' => {'file' => uploaded_test_file('testfile.txt', 'text/plain')}}
324 347 end
325 348 assert_redirected_to 'projects/ecookbook/files'
326 349 a = Attachment.find(:first, :order => 'created_on DESC')
327 350 assert_equal 'testfile.txt', a.filename
328 351 assert_equal Version.find(2), a.container
329 352 end
330 353
331 354 def test_list_files
332 355 get :list_files, :id => 1
333 356 assert_response :success
334 357 assert_template 'list_files'
335 358 assert_not_nil assigns(:containers)
336 359
337 360 # file attached to the project
338 361 assert_tag :a, :content => 'project_file.zip',
339 362 :attributes => { :href => '/attachments/download/8/project_file.zip' }
340 363
341 364 # file attached to a project's version
342 365 assert_tag :a, :content => 'version_file.zip',
343 366 :attributes => { :href => '/attachments/download/9/version_file.zip' }
344 367 end
345 368
346 369 def test_list_files_routing
347 370 assert_routing(
348 371 {:method => :get, :path => '/projects/33/files'},
349 372 :controller => 'projects', :action => 'list_files', :id => '33'
350 373 )
351 374 end
352 375
353 376 def test_changelog_routing
354 377 assert_routing(
355 378 {:method => :get, :path => '/projects/44/changelog'},
356 379 :controller => 'projects', :action => 'changelog', :id => '44'
357 380 )
358 381 end
359 382
360 383 def test_changelog
361 384 get :changelog, :id => 1
362 385 assert_response :success
363 386 assert_template 'changelog'
364 387 assert_not_nil assigns(:versions)
365 388 end
366 389
367 390 def test_changelog_showing_subprojects_versions
368 391 get :changelog, :id => 1, :with_subprojects => 1
369 392 assert_response :success
370 393 assert_template 'changelog'
371 394 assert_not_nil assigns(:versions)
372 395 # Version on subproject appears
373 396 assert assigns(:versions).include?(Version.find(4))
374 397 end
375 398
376 399 def test_roadmap_routing
377 400 assert_routing(
378 401 {:method => :get, :path => 'projects/33/roadmap'},
379 402 :controller => 'projects', :action => 'roadmap', :id => '33'
380 403 )
381 404 end
382 405
383 406 def test_roadmap
384 407 get :roadmap, :id => 1
385 408 assert_response :success
386 409 assert_template 'roadmap'
387 410 assert_not_nil assigns(:versions)
388 411 # Version with no date set appears
389 412 assert assigns(:versions).include?(Version.find(3))
390 413 # Completed version doesn't appear
391 414 assert !assigns(:versions).include?(Version.find(1))
392 415 end
393 416
394 417 def test_roadmap_with_completed_versions
395 418 get :roadmap, :id => 1, :completed => 1
396 419 assert_response :success
397 420 assert_template 'roadmap'
398 421 assert_not_nil assigns(:versions)
399 422 # Version with no date set appears
400 423 assert assigns(:versions).include?(Version.find(3))
401 424 # Completed version appears
402 425 assert assigns(:versions).include?(Version.find(1))
403 426 end
404 427
405 428 def test_roadmap_showing_subprojects_versions
406 429 get :roadmap, :id => 1, :with_subprojects => 1
407 430 assert_response :success
408 431 assert_template 'roadmap'
409 432 assert_not_nil assigns(:versions)
410 433 # Version on subproject appears
411 434 assert assigns(:versions).include?(Version.find(4))
412 435 end
413 436
414 437 def test_project_activity_routing
415 438 assert_routing(
416 439 {:method => :get, :path => '/projects/1/activity'},
417 440 :controller => 'projects', :action => 'activity', :id => '1'
418 441 )
419 442 end
420 443
421 444 def test_project_activity_atom_routing
422 445 assert_routing(
423 446 {:method => :get, :path => '/projects/1/activity.atom'},
424 447 :controller => 'projects', :action => 'activity', :id => '1', :format => 'atom'
425 448 )
426 449 end
427 450
428 451 def test_project_activity
429 452 get :activity, :id => 1, :with_subprojects => 0
430 453 assert_response :success
431 454 assert_template 'activity'
432 455 assert_not_nil assigns(:events_by_day)
433 456
434 457 assert_tag :tag => "h3",
435 458 :content => /#{2.days.ago.to_date.day}/,
436 459 :sibling => { :tag => "dl",
437 460 :child => { :tag => "dt",
438 461 :attributes => { :class => /issue-edit/ },
439 462 :child => { :tag => "a",
440 463 :content => /(#{IssueStatus.find(2).name})/,
441 464 }
442 465 }
443 466 }
444 467 end
445 468
446 469 def test_previous_project_activity
447 470 get :activity, :id => 1, :from => 3.days.ago.to_date
448 471 assert_response :success
449 472 assert_template 'activity'
450 473 assert_not_nil assigns(:events_by_day)
451 474
452 475 assert_tag :tag => "h3",
453 476 :content => /#{3.day.ago.to_date.day}/,
454 477 :sibling => { :tag => "dl",
455 478 :child => { :tag => "dt",
456 479 :attributes => { :class => /issue/ },
457 480 :child => { :tag => "a",
458 481 :content => /#{Issue.find(1).subject}/,
459 482 }
460 483 }
461 484 }
462 485 end
463 486
464 487 def test_global_activity_routing
465 488 assert_routing({:method => :get, :path => '/activity'}, :controller => 'projects', :action => 'activity', :id => nil)
466 489 end
467 490
468 491 def test_global_activity
469 492 get :activity
470 493 assert_response :success
471 494 assert_template 'activity'
472 495 assert_not_nil assigns(:events_by_day)
473 496
474 497 assert_tag :tag => "h3",
475 498 :content => /#{5.day.ago.to_date.day}/,
476 499 :sibling => { :tag => "dl",
477 500 :child => { :tag => "dt",
478 501 :attributes => { :class => /issue/ },
479 502 :child => { :tag => "a",
480 503 :content => /#{Issue.find(5).subject}/,
481 504 }
482 505 }
483 506 }
484 507 end
485 508
486 509 def test_user_activity
487 510 get :activity, :user_id => 2
488 511 assert_response :success
489 512 assert_template 'activity'
490 513 assert_not_nil assigns(:events_by_day)
491 514
492 515 assert_tag :tag => "h3",
493 516 :content => /#{3.day.ago.to_date.day}/,
494 517 :sibling => { :tag => "dl",
495 518 :child => { :tag => "dt",
496 519 :attributes => { :class => /issue/ },
497 520 :child => { :tag => "a",
498 521 :content => /#{Issue.find(1).subject}/,
499 522 }
500 523 }
501 524 }
502 525 end
503 526
504 527 def test_global_activity_atom_routing
505 528 assert_routing({:method => :get, :path => '/activity.atom'}, :controller => 'projects', :action => 'activity', :id => nil, :format => 'atom')
506 529 end
507 530
508 531 def test_activity_atom_feed
509 532 get :activity, :format => 'atom'
510 533 assert_response :success
511 534 assert_template 'common/feed.atom.rxml'
512 535 end
513 536
514 537 def test_archive_routing
515 538 assert_routing(
516 539 #TODO: use PUT to project path and modify form
517 540 {:method => :post, :path => 'projects/64/archive'},
518 541 :controller => 'projects', :action => 'archive', :id => '64'
519 542 )
520 543 end
521 544
522 545 def test_archive
523 546 @request.session[:user_id] = 1 # admin
524 547 post :archive, :id => 1
525 548 assert_redirected_to 'admin/projects'
526 549 assert !Project.find(1).active?
527 550 end
528 551
529 552 def test_unarchive_routing
530 553 assert_routing(
531 554 #TODO: use PUT to project path and modify form
532 555 {:method => :post, :path => '/projects/567/unarchive'},
533 556 :controller => 'projects', :action => 'unarchive', :id => '567'
534 557 )
535 558 end
536 559
537 560 def test_unarchive
538 561 @request.session[:user_id] = 1 # admin
539 562 Project.find(1).archive
540 563 post :unarchive, :id => 1
541 564 assert_redirected_to 'admin/projects'
542 565 assert Project.find(1).active?
543 566 end
544 567
545 568 def test_project_breadcrumbs_should_be_limited_to_3_ancestors
546 569 CustomField.delete_all
547 570 parent = nil
548 571 6.times do |i|
549 572 p = Project.create!(:name => "Breadcrumbs #{i}", :identifier => "breadcrumbs-#{i}")
550 573 p.set_parent!(parent)
551 574 get :show, :id => p
552 575 assert_tag :h1, :parent => { :attributes => {:id => 'header'}},
553 576 :children => { :count => [i, 3].min,
554 577 :only => { :tag => 'a' } }
555 578
556 579 parent = p
557 580 end
558 581 end
559 582
560 583 def test_copy_with_project
561 584 @request.session[:user_id] = 1 # admin
562 585 get :copy, :id => 1
563 586 assert_response :success
564 587 assert_template 'copy'
565 588 assert assigns(:project)
566 589 assert_equal Project.find(1).description, assigns(:project).description
567 590 assert_nil assigns(:project).id
568 591 end
569 592
570 593 def test_copy_without_project
571 594 @request.session[:user_id] = 1 # admin
572 595 get :copy
573 596 assert_response :redirect
574 597 assert_redirected_to :controller => 'admin', :action => 'projects'
575 598 end
576 599
577 600 def test_jump_should_redirect_to_active_tab
578 601 get :show, :id => 1, :jump => 'issues'
579 602 assert_redirected_to 'projects/ecookbook/issues'
580 603 end
581 604
582 605 def test_jump_should_not_redirect_to_inactive_tab
583 606 get :show, :id => 3, :jump => 'documents'
584 607 assert_response :success
585 608 assert_template 'show'
586 609 end
587 610
588 611 def test_jump_should_not_redirect_to_unknown_tab
589 612 get :show, :id => 3, :jump => 'foobar'
590 613 assert_response :success
591 614 assert_template 'show'
592 615 end
593 616
594 617 def test_reset_activities_routing
595 618 assert_routing({:method => :delete, :path => 'projects/64/reset_activities'},
596 619 :controller => 'projects', :action => 'reset_activities', :id => '64')
597 620 end
598 621
599 622 def test_reset_activities
600 623 @request.session[:user_id] = 2 # manager
601 624 project_activity = TimeEntryActivity.new({
602 625 :name => 'Project Specific',
603 626 :parent => TimeEntryActivity.find(:first),
604 627 :project => Project.find(1),
605 628 :active => true
606 629 })
607 630 assert project_activity.save
608 631 project_activity_two = TimeEntryActivity.new({
609 632 :name => 'Project Specific Two',
610 633 :parent => TimeEntryActivity.find(:last),
611 634 :project => Project.find(1),
612 635 :active => true
613 636 })
614 637 assert project_activity_two.save
615 638
616 639 delete :reset_activities, :id => 1
617 640 assert_response :redirect
618 641 assert_redirected_to 'projects/ecookbook/settings/activities'
619 642
620 643 assert_nil TimeEntryActivity.find_by_id(project_activity.id)
621 644 assert_nil TimeEntryActivity.find_by_id(project_activity_two.id)
622 645 end
623 646
624 647 def test_reset_activities_should_reassign_time_entries_back_to_the_system_activity
625 648 @request.session[:user_id] = 2 # manager
626 649 project_activity = TimeEntryActivity.new({
627 650 :name => 'Project Specific Design',
628 651 :parent => TimeEntryActivity.find(9),
629 652 :project => Project.find(1),
630 653 :active => true
631 654 })
632 655 assert project_activity.save
633 656 assert TimeEntry.update_all("activity_id = '#{project_activity.id}'", ["project_id = ? AND activity_id = ?", 1, 9])
634 657 assert 3, TimeEntry.find_all_by_activity_id_and_project_id(project_activity.id, 1).size
635 658
636 659 delete :reset_activities, :id => 1
637 660 assert_response :redirect
638 661 assert_redirected_to 'projects/ecookbook/settings/activities'
639 662
640 663 assert_nil TimeEntryActivity.find_by_id(project_activity.id)
641 664 assert_equal 0, TimeEntry.find_all_by_activity_id_and_project_id(project_activity.id, 1).size, "TimeEntries still assigned to project specific activity"
642 665 assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(9, 1).size, "TimeEntries still assigned to project specific activity"
643 666 end
644 667
645 668 def test_save_activities_routing
646 669 assert_routing({:method => :post, :path => 'projects/64/activities/save'},
647 670 :controller => 'projects', :action => 'save_activities', :id => '64')
648 671 end
649 672
650 673 def test_save_activities_to_override_system_activities
651 674 @request.session[:user_id] = 2 # manager
652 675 billable_field = TimeEntryActivityCustomField.find_by_name("Billable")
653 676
654 677 post :save_activities, :id => 1, :enumerations => {
655 678 "9"=> {"parent_id"=>"9", "custom_field_values"=>{"7" => "1"}, "active"=>"0"}, # Design, De-activate
656 679 "10"=> {"parent_id"=>"10", "custom_field_values"=>{"7"=>"0"}, "active"=>"1"}, # Development, Change custom value
657 680 "14"=>{"parent_id"=>"14", "custom_field_values"=>{"7"=>"1"}, "active"=>"1"}, # Inactive Activity, Activate with custom value
658 681 "11"=>{"parent_id"=>"11", "custom_field_values"=>{"7"=>"1"}, "active"=>"1"} # QA, no changes
659 682 }
660 683
661 684 assert_response :redirect
662 685 assert_redirected_to 'projects/ecookbook/settings/activities'
663 686
664 687 # Created project specific activities...
665 688 project = Project.find('ecookbook')
666 689
667 690 # ... Design
668 691 design = project.time_entry_activities.find_by_name("Design")
669 692 assert design, "Project activity not found"
670 693
671 694 assert_equal 9, design.parent_id # Relate to the system activity
672 695 assert_not_equal design.parent.id, design.id # Different records
673 696 assert_equal design.parent.name, design.name # Same name
674 697 assert !design.active?
675 698
676 699 # ... Development
677 700 development = project.time_entry_activities.find_by_name("Development")
678 701 assert development, "Project activity not found"
679 702
680 703 assert_equal 10, development.parent_id # Relate to the system activity
681 704 assert_not_equal development.parent.id, development.id # Different records
682 705 assert_equal development.parent.name, development.name # Same name
683 706 assert development.active?
684 707 assert_equal "0", development.custom_value_for(billable_field).value
685 708
686 709 # ... Inactive Activity
687 710 previously_inactive = project.time_entry_activities.find_by_name("Inactive Activity")
688 711 assert previously_inactive, "Project activity not found"
689 712
690 713 assert_equal 14, previously_inactive.parent_id # Relate to the system activity
691 714 assert_not_equal previously_inactive.parent.id, previously_inactive.id # Different records
692 715 assert_equal previously_inactive.parent.name, previously_inactive.name # Same name
693 716 assert previously_inactive.active?
694 717 assert_equal "1", previously_inactive.custom_value_for(billable_field).value
695 718
696 719 # ... QA
697 720 assert_equal nil, project.time_entry_activities.find_by_name("QA"), "Custom QA activity created when it wasn't modified"
698 721 end
699 722
700 723 def test_save_activities_will_update_project_specific_activities
701 724 @request.session[:user_id] = 2 # manager
702 725
703 726 project_activity = TimeEntryActivity.new({
704 727 :name => 'Project Specific',
705 728 :parent => TimeEntryActivity.find(:first),
706 729 :project => Project.find(1),
707 730 :active => true
708 731 })
709 732 assert project_activity.save
710 733 project_activity_two = TimeEntryActivity.new({
711 734 :name => 'Project Specific Two',
712 735 :parent => TimeEntryActivity.find(:last),
713 736 :project => Project.find(1),
714 737 :active => true
715 738 })
716 739 assert project_activity_two.save
717 740
718 741
719 742 post :save_activities, :id => 1, :enumerations => {
720 743 project_activity.id => {"custom_field_values"=>{"7" => "1"}, "active"=>"0"}, # De-activate
721 744 project_activity_two.id => {"custom_field_values"=>{"7" => "1"}, "active"=>"0"} # De-activate
722 745 }
723 746
724 747 assert_response :redirect
725 748 assert_redirected_to 'projects/ecookbook/settings/activities'
726 749
727 750 # Created project specific activities...
728 751 project = Project.find('ecookbook')
729 752 assert_equal 2, project.time_entry_activities.count
730 753
731 754 activity_one = project.time_entry_activities.find_by_name(project_activity.name)
732 755 assert activity_one, "Project activity not found"
733 756 assert_equal project_activity.id, activity_one.id
734 757 assert !activity_one.active?
735 758
736 759 activity_two = project.time_entry_activities.find_by_name(project_activity_two.name)
737 760 assert activity_two, "Project activity not found"
738 761 assert_equal project_activity_two.id, activity_two.id
739 762 assert !activity_two.active?
740 763 end
741 764
742 765 def test_save_activities_when_creating_new_activities_will_convert_existing_data
743 766 assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(9, 1).size
744 767
745 768 @request.session[:user_id] = 2 # manager
746 769 post :save_activities, :id => 1, :enumerations => {
747 770 "9"=> {"parent_id"=>"9", "custom_field_values"=>{"7" => "1"}, "active"=>"0"} # Design, De-activate
748 771 }
749 772 assert_response :redirect
750 773
751 774 # No more TimeEntries using the system activity
752 775 assert_equal 0, TimeEntry.find_all_by_activity_id_and_project_id(9, 1).size, "Time Entries still assigned to system activities"
753 776 # All TimeEntries using project activity
754 777 project_specific_activity = TimeEntryActivity.find_by_parent_id_and_project_id(9, 1)
755 778 assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(project_specific_activity.id, 1).size, "No Time Entries assigned to the project activity"
756 779 end
757 780
758 781 def test_save_activities_when_creating_new_activities_will_not_convert_existing_data_if_an_exception_is_raised
759 782 # TODO: Need to cause an exception on create but these tests
760 783 # aren't setup for mocking. Just create a record now so the
761 784 # second one is a dupicate
762 785 parent = TimeEntryActivity.find(9)
763 786 TimeEntryActivity.create!({:name => parent.name, :project_id => 1, :position => parent.position, :active => true})
764 787 TimeEntry.create!({:project_id => 1, :hours => 1.0, :user => User.find(1), :issue_id => 3, :activity_id => 10, :spent_on => '2009-01-01'})
765 788
766 789 assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(9, 1).size
767 790 assert_equal 1, TimeEntry.find_all_by_activity_id_and_project_id(10, 1).size
768 791
769 792 @request.session[:user_id] = 2 # manager
770 793 post :save_activities, :id => 1, :enumerations => {
771 794 "9"=> {"parent_id"=>"9", "custom_field_values"=>{"7" => "1"}, "active"=>"0"}, # Design
772 795 "10"=> {"parent_id"=>"10", "custom_field_values"=>{"7"=>"0"}, "active"=>"1"} # Development, Change custom value
773 796 }
774 797 assert_response :redirect
775 798
776 799 # TimeEntries shouldn't have been reassigned on the failed record
777 800 assert_equal 3, TimeEntry.find_all_by_activity_id_and_project_id(9, 1).size, "Time Entries are not assigned to system activities"
778 801 # TimeEntries shouldn't have been reassigned on the saved record either
779 802 assert_equal 1, TimeEntry.find_all_by_activity_id_and_project_id(10, 1).size, "Time Entries are not assigned to system activities"
780 803 end
781 804
782 805 # A hook that is manually registered later
783 806 class ProjectBasedTemplate < Redmine::Hook::ViewListener
784 807 def view_layouts_base_html_head(context)
785 808 # Adds a project stylesheet
786 809 stylesheet_link_tag(context[:project].identifier) if context[:project]
787 810 end
788 811 end
789 812 # Don't use this hook now
790 813 Redmine::Hook.clear_listeners
791 814
792 815 def test_hook_response
793 816 Redmine::Hook.add_listener(ProjectBasedTemplate)
794 817 get :show, :id => 1
795 818 assert_tag :tag => 'link', :attributes => {:href => '/stylesheets/ecookbook.css'},
796 819 :parent => {:tag => 'head'}
797 820
798 821 Redmine::Hook.clear_listeners
799 822 end
800 823 end
General Comments 0
You need to be logged in to leave comments. Login now