comparison app/controllers/projects_controller.rb @ 22:40f7cfd4df19

* Update to SVN trunk rev 4173
author Chris Cannam <chris.cannam@soundsoftware.ac.uk>
date Fri, 24 Sep 2010 14:06:04 +0100
parents 513646585e45
children 94944d00e43c
comparison
equal deleted inserted replaced
14:1d32c0a0efbf 22:40f7cfd4df19
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 ProjectsController < ApplicationController 18 class ProjectsController < ApplicationController
19 menu_item :overview 19 menu_item :overview
20 menu_item :activity, :only => :activity
21 menu_item :roadmap, :only => :roadmap 20 menu_item :roadmap, :only => :roadmap
22 menu_item :files, :only => [:list_files, :add_file]
23 menu_item :settings, :only => :settings 21 menu_item :settings, :only => :settings
24 22
25 before_filter :find_project, :except => [ :index, :list, :add, :copy, :activity ] 23 before_filter :find_project, :except => [ :index, :list, :new, :create, :copy ]
26 before_filter :find_optional_project, :only => :activity 24 before_filter :authorize, :except => [ :index, :list, :new, :create, :copy, :archive, :unarchive, :destroy]
27 before_filter :authorize, :except => [ :index, :list, :add, :copy, :archive, :unarchive, :destroy, :activity ] 25 before_filter :authorize_global, :only => [:new, :create]
28 before_filter :authorize_global, :only => :add
29 before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ] 26 before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ]
30 accept_key_auth :activity, :index 27 accept_key_auth :index
31 28
32 after_filter :only => [:add, :edit, :archive, :unarchive, :destroy] do |controller| 29 after_filter :only => [:create, :edit, :update, :archive, :unarchive, :destroy] do |controller|
33 if controller.request.post? 30 if controller.request.post?
34 controller.send :expire_action, :controller => 'welcome', :action => 'robots.txt' 31 controller.send :expire_action, :controller => 'welcome', :action => 'robots.txt'
35 end 32 end
36 end 33 end
37 34
35 # TODO: convert to PUT only
36 verify :method => [:post, :put], :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
37
38 helper :sort 38 helper :sort
39 include SortHelper 39 include SortHelper
40 helper :custom_fields 40 helper :custom_fields
41 include CustomFieldsHelper 41 include CustomFieldsHelper
42 helper :issues 42 helper :issues
61 render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}") 61 render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}")
62 } 62 }
63 end 63 end
64 end 64 end
65 65
66 # Add a new project 66 def new
67 def add
68 @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position") 67 @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
69 @trackers = Tracker.all 68 @trackers = Tracker.all
70 @project = Project.new(params[:project]) 69 @project = Project.new(params[:project])
71 if request.get? 70
72 @project.identifier = Project.next_identifier if Setting.sequential_project_identifiers? 71 @project.identifier = Project.next_identifier if Setting.sequential_project_identifiers?
73 @project.trackers = Tracker.all 72 @project.trackers = Tracker.all
74 @project.is_public = Setting.default_projects_public? 73 @project.is_public = Setting.default_projects_public?
75 @project.enabled_module_names = Setting.default_projects_modules 74 @project.enabled_module_names = Setting.default_projects_modules
76 else 75 end
77 @project.enabled_module_names = params[:enabled_modules] 76
78 if validate_parent_id && @project.save 77 def create
79 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id') 78 @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
80 # Add current user as a project member if he is not admin 79 @trackers = Tracker.all
81 unless User.current.admin? 80 @project = Project.new(params[:project])
82 r = Role.givable.find_by_id(Setting.new_project_user_role_id.to_i) || Role.givable.first 81
83 m = Member.new(:user => User.current, :roles => [r]) 82 @project.enabled_module_names = params[:enabled_modules]
84 @project.members << m 83 if validate_parent_id && @project.save
85 end 84 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
86 respond_to do |format| 85 # Add current user as a project member if he is not admin
87 format.html { 86 unless User.current.admin?
88 flash[:notice] = l(:notice_successful_create) 87 r = Role.givable.find_by_id(Setting.new_project_user_role_id.to_i) || Role.givable.first
89 redirect_to :controller => 'projects', :action => 'settings', :id => @project 88 m = Member.new(:user => User.current, :roles => [r])
90 } 89 @project.members << m
91 format.xml { head :created, :location => url_for(:controller => 'projects', :action => 'show', :id => @project.id) } 90 end
92 end 91 respond_to do |format|
93 else 92 format.html {
94 respond_to do |format| 93 flash[:notice] = l(:notice_successful_create)
95 format.html 94 redirect_to :controller => 'projects', :action => 'settings', :id => @project
96 format.xml { render :xml => @project.errors, :status => :unprocessable_entity } 95 }
97 end 96 format.xml { head :created, :location => url_for(:controller => 'projects', :action => 'show', :id => @project.id) }
98 end 97 end
99 end 98 else
99 respond_to do |format|
100 format.html { render :action => 'new' }
101 format.xml { render :xml => @project.errors, :status => :unprocessable_entity }
102 end
103 end
104
100 end 105 end
101 106
102 def copy 107 def copy
103 @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position") 108 @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
104 @trackers = Tracker.all 109 @trackers = Tracker.all
175 @trackers = Tracker.all 180 @trackers = Tracker.all
176 @repository ||= @project.repository 181 @repository ||= @project.repository
177 @wiki ||= @project.wiki 182 @wiki ||= @project.wiki
178 end 183 end
179 184
180 # Edit @project
181 def edit 185 def edit
182 if request.get? 186 end
183 else 187
184 @project.attributes = params[:project] 188 def update
185 if validate_parent_id && @project.save 189 @project.attributes = params[:project]
186 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id') 190 if validate_parent_id && @project.save
187 respond_to do |format| 191 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
188 format.html { 192 respond_to do |format|
189 flash[:notice] = l(:notice_successful_update) 193 format.html {
190 redirect_to :action => 'settings', :id => @project 194 flash[:notice] = l(:notice_successful_update)
191 } 195 redirect_to :action => 'settings', :id => @project
192 format.xml { head :ok } 196 }
193 end 197 format.xml { head :ok }
194 else 198 end
195 respond_to do |format| 199 else
196 format.html { 200 respond_to do |format|
197 settings 201 format.html {
198 render :action => 'settings' 202 settings
199 } 203 render :action => 'settings'
200 format.xml { render :xml => @project.errors, :status => :unprocessable_entity } 204 }
201 end 205 format.xml { render :xml => @project.errors, :status => :unprocessable_entity }
202 end 206 end
203 end 207 end
204 end 208 end
205 209
206 def modules 210 def modules
239 end 243 end
240 # hide project in layout 244 # hide project in layout
241 @project = nil 245 @project = nil
242 end 246 end
243 247
244 def add_file
245 if request.post?
246 container = (params[:version_id].blank? ? @project : @project.versions.find_by_id(params[:version_id]))
247 attachments = Attachment.attach_files(container, params[:attachments])
248 render_attachment_warning_if_needed(container)
249
250 if !attachments.empty? && Setting.notified_events.include?('file_added')
251 Mailer.deliver_attachments_added(attachments[:files])
252 end
253 redirect_to :controller => 'projects', :action => 'list_files', :id => @project
254 return
255 end
256 @versions = @project.versions.sort
257 end
258
259 def save_activities
260 if request.post? && params[:enumerations]
261 Project.transaction do
262 params[:enumerations].each do |id, activity|
263 @project.update_or_create_time_entry_activity(id, activity)
264 end
265 end
266 flash[:notice] = l(:notice_successful_update)
267 end
268
269 redirect_to :controller => 'projects', :action => 'settings', :tab => 'activities', :id => @project
270 end
271
272 def reset_activities
273 @project.time_entry_activities.each do |time_entry_activity|
274 time_entry_activity.destroy(time_entry_activity.parent)
275 end
276 flash[:notice] = l(:notice_successful_update)
277 redirect_to :controller => 'projects', :action => 'settings', :tab => 'activities', :id => @project
278 end
279
280 def list_files
281 sort_init 'filename', 'asc'
282 sort_update 'filename' => "#{Attachment.table_name}.filename",
283 'created_on' => "#{Attachment.table_name}.created_on",
284 'size' => "#{Attachment.table_name}.filesize",
285 'downloads' => "#{Attachment.table_name}.downloads"
286
287 @containers = [ Project.find(@project.id, :include => :attachments, :order => sort_clause)]
288 @containers += @project.versions.find(:all, :include => :attachments, :order => sort_clause).sort.reverse
289 render :layout => !request.xhr?
290 end
291
292 def roadmap
293 @trackers = @project.trackers.find(:all, :order => 'position')
294 retrieve_selected_tracker_ids(@trackers, @trackers.select {|t| t.is_in_roadmap?})
295 @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
296 project_ids = @with_subprojects ? @project.self_and_descendants.collect(&:id) : [@project.id]
297
298 @versions = @project.shared_versions || []
299 @versions += @project.rolled_up_versions.visible if @with_subprojects
300 @versions = @versions.uniq.sort
301 @versions.reject! {|version| version.closed? || version.completed? } unless params[:completed]
302
303 @issues_by_version = {}
304 unless @selected_tracker_ids.empty?
305 @versions.each do |version|
306 issues = version.fixed_issues.visible.find(:all,
307 :include => [:project, :status, :tracker, :priority],
308 :conditions => {:tracker_id => @selected_tracker_ids, :project_id => project_ids},
309 :order => "#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id")
310 @issues_by_version[version] = issues
311 end
312 end
313 @versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?}
314 end
315
316 def activity
317 @days = Setting.activity_days_default.to_i
318
319 if params[:from]
320 begin; @date_to = params[:from].to_date + 1; rescue; end
321 end
322
323 @date_to ||= Date.today + 1
324 @date_from = @date_to - @days
325 @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
326 @author = (params[:user_id].blank? ? nil : User.active.find(params[:user_id]))
327
328 @activity = Redmine::Activity::Fetcher.new(User.current, :project => @project,
329 :with_subprojects => @with_subprojects,
330 :author => @author)
331 @activity.scope_select {|t| !params["show_#{t}"].nil?}
332 @activity.scope = (@author.nil? ? :default : :all) if @activity.scope.empty?
333
334 events = @activity.events(@date_from, @date_to)
335
336 if events.empty? || stale?(:etag => [events.first, User.current])
337 respond_to do |format|
338 format.html {
339 @events_by_day = events.group_by(&:event_date)
340 render :layout => false if request.xhr?
341 }
342 format.atom {
343 title = l(:label_activity)
344 if @author
345 title = @author.name
346 elsif @activity.scope.size == 1
347 title = l("label_#{@activity.scope.first.singularize}_plural")
348 end
349 render_feed(events, :title => "#{@project || Setting.app_title}: #{title}")
350 }
351 end
352 end
353
354 rescue ActiveRecord::RecordNotFound
355 render_404
356 end
357
358 private 248 private
359 def find_optional_project 249 def find_optional_project
360 return true unless params[:id] 250 return true unless params[:id]
361 @project = Project.find(params[:id]) 251 @project = Project.find(params[:id])
362 authorize 252 authorize
363 rescue ActiveRecord::RecordNotFound 253 rescue ActiveRecord::RecordNotFound
364 render_404 254 render_404
365 end 255 end
366 256
367 def retrieve_selected_tracker_ids(selectable_trackers, default_trackers=nil)
368 if ids = params[:tracker_ids]
369 @selected_tracker_ids = (ids.is_a? Array) ? ids.collect { |id| id.to_i.to_s } : ids.split('/').collect { |id| id.to_i.to_s }
370 else
371 @selected_tracker_ids = (default_trackers || selectable_trackers).collect {|t| t.id.to_s }
372 end
373 end
374
375 # Validates parent_id param according to user's permissions 257 # Validates parent_id param according to user's permissions
376 # TODO: move it to Project model in a validation that depends on User.current 258 # TODO: move it to Project model in a validation that depends on User.current
377 def validate_parent_id 259 def validate_parent_id
378 return true if User.current.admin? 260 return true if User.current.admin?
379 parent_id = params[:project] && params[:project][:parent_id] 261 parent_id = params[:project] && params[:project][:parent_id]