##// END OF EJS Templates
Changed ProjectsController#destroy to DELETE only....
Jean-Philippe Lang -
r8032:467503fd4b5a
parent child
Show More
@@ -1,272 +1,269
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 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 ProjectsController < ApplicationController
18 class ProjectsController < ApplicationController
19 menu_item :overview
19 menu_item :overview
20 menu_item :roadmap, :only => :roadmap
20 menu_item :roadmap, :only => :roadmap
21 menu_item :settings, :only => :settings
21 menu_item :settings, :only => :settings
22
22
23 before_filter :find_project, :except => [ :index, :list, :new, :create, :copy ]
23 before_filter :find_project, :except => [ :index, :list, :new, :create, :copy ]
24 before_filter :authorize, :except => [ :index, :list, :new, :create, :copy, :archive, :unarchive, :destroy]
24 before_filter :authorize, :except => [ :index, :list, :new, :create, :copy, :archive, :unarchive, :destroy]
25 before_filter :authorize_global, :only => [:new, :create]
25 before_filter :authorize_global, :only => [:new, :create]
26 before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ]
26 before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ]
27 accept_rss_auth :index
27 accept_rss_auth :index
28 accept_api_auth :index, :show, :create, :update, :destroy
28 accept_api_auth :index, :show, :create, :update, :destroy
29
29
30 after_filter :only => [:create, :edit, :update, :archive, :unarchive, :destroy] do |controller|
30 after_filter :only => [:create, :edit, :update, :archive, :unarchive, :destroy] do |controller|
31 if controller.request.post?
31 if controller.request.post?
32 controller.send :expire_action, :controller => 'welcome', :action => 'robots.txt'
32 controller.send :expire_action, :controller => 'welcome', :action => 'robots.txt'
33 end
33 end
34 end
34 end
35
35
36 helper :sort
36 helper :sort
37 include SortHelper
37 include SortHelper
38 helper :custom_fields
38 helper :custom_fields
39 include CustomFieldsHelper
39 include CustomFieldsHelper
40 helper :issues
40 helper :issues
41 helper :queries
41 helper :queries
42 include QueriesHelper
42 include QueriesHelper
43 helper :repositories
43 helper :repositories
44 include RepositoriesHelper
44 include RepositoriesHelper
45 include ProjectsHelper
45 include ProjectsHelper
46
46
47 # Lists visible projects
47 # Lists visible projects
48 def index
48 def index
49 respond_to do |format|
49 respond_to do |format|
50 format.html {
50 format.html {
51 @projects = Project.visible.find(:all, :order => 'lft')
51 @projects = Project.visible.find(:all, :order => 'lft')
52 }
52 }
53 format.api {
53 format.api {
54 @offset, @limit = api_offset_and_limit
54 @offset, @limit = api_offset_and_limit
55 @project_count = Project.visible.count
55 @project_count = Project.visible.count
56 @projects = Project.visible.all(:offset => @offset, :limit => @limit, :order => 'lft')
56 @projects = Project.visible.all(:offset => @offset, :limit => @limit, :order => 'lft')
57 }
57 }
58 format.atom {
58 format.atom {
59 projects = Project.visible.find(:all, :order => 'created_on DESC',
59 projects = Project.visible.find(:all, :order => 'created_on DESC',
60 :limit => Setting.feeds_limit.to_i)
60 :limit => Setting.feeds_limit.to_i)
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 def new
66 def new
67 @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
67 @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
68 @trackers = Tracker.all
68 @trackers = Tracker.all
69 @project = Project.new(params[:project])
69 @project = Project.new(params[:project])
70 end
70 end
71
71
72 verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
72 verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
73 def create
73 def create
74 @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
74 @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
75 @trackers = Tracker.all
75 @trackers = Tracker.all
76 @project = Project.new
76 @project = Project.new
77 @project.safe_attributes = params[:project]
77 @project.safe_attributes = params[:project]
78
78
79 if validate_parent_id && @project.save
79 if validate_parent_id && @project.save
80 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
80 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
81 # Add current user as a project member if he is not admin
81 # Add current user as a project member if he is not admin
82 unless User.current.admin?
82 unless User.current.admin?
83 r = Role.givable.find_by_id(Setting.new_project_user_role_id.to_i) || Role.givable.first
83 r = Role.givable.find_by_id(Setting.new_project_user_role_id.to_i) || Role.givable.first
84 m = Member.new(:user => User.current, :roles => [r])
84 m = Member.new(:user => User.current, :roles => [r])
85 @project.members << m
85 @project.members << m
86 end
86 end
87 respond_to do |format|
87 respond_to do |format|
88 format.html {
88 format.html {
89 flash[:notice] = l(:notice_successful_create)
89 flash[:notice] = l(:notice_successful_create)
90 redirect_to(params[:continue] ?
90 redirect_to(params[:continue] ?
91 {:controller => 'projects', :action => 'new', :project => {:parent_id => @project.parent_id}.reject {|k,v| v.nil?}} :
91 {:controller => 'projects', :action => 'new', :project => {:parent_id => @project.parent_id}.reject {|k,v| v.nil?}} :
92 {:controller => 'projects', :action => 'settings', :id => @project}
92 {:controller => 'projects', :action => 'settings', :id => @project}
93 )
93 )
94 }
94 }
95 format.api { render :action => 'show', :status => :created, :location => url_for(:controller => 'projects', :action => 'show', :id => @project.id) }
95 format.api { render :action => 'show', :status => :created, :location => url_for(:controller => 'projects', :action => 'show', :id => @project.id) }
96 end
96 end
97 else
97 else
98 respond_to do |format|
98 respond_to do |format|
99 format.html { render :action => 'new' }
99 format.html { render :action => 'new' }
100 format.api { render_validation_errors(@project) }
100 format.api { render_validation_errors(@project) }
101 end
101 end
102 end
102 end
103
103
104 end
104 end
105
105
106 def copy
106 def copy
107 @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
107 @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
108 @trackers = Tracker.all
108 @trackers = Tracker.all
109 @root_projects = Project.find(:all,
109 @root_projects = Project.find(:all,
110 :conditions => "parent_id IS NULL AND status = #{Project::STATUS_ACTIVE}",
110 :conditions => "parent_id IS NULL AND status = #{Project::STATUS_ACTIVE}",
111 :order => 'name')
111 :order => 'name')
112 @source_project = Project.find(params[:id])
112 @source_project = Project.find(params[:id])
113 if request.get?
113 if request.get?
114 @project = Project.copy_from(@source_project)
114 @project = Project.copy_from(@source_project)
115 if @project
115 if @project
116 @project.identifier = Project.next_identifier if Setting.sequential_project_identifiers?
116 @project.identifier = Project.next_identifier if Setting.sequential_project_identifiers?
117 else
117 else
118 redirect_to :controller => 'admin', :action => 'projects'
118 redirect_to :controller => 'admin', :action => 'projects'
119 end
119 end
120 else
120 else
121 Mailer.with_deliveries(params[:notifications] == '1') do
121 Mailer.with_deliveries(params[:notifications] == '1') do
122 @project = Project.new
122 @project = Project.new
123 @project.safe_attributes = params[:project]
123 @project.safe_attributes = params[:project]
124 if validate_parent_id && @project.copy(@source_project, :only => params[:only])
124 if validate_parent_id && @project.copy(@source_project, :only => params[:only])
125 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
125 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
126 flash[:notice] = l(:notice_successful_create)
126 flash[:notice] = l(:notice_successful_create)
127 redirect_to :controller => 'projects', :action => 'settings', :id => @project
127 redirect_to :controller => 'projects', :action => 'settings', :id => @project
128 elsif !@project.new_record?
128 elsif !@project.new_record?
129 # Project was created
129 # Project was created
130 # But some objects were not copied due to validation failures
130 # But some objects were not copied due to validation failures
131 # (eg. issues from disabled trackers)
131 # (eg. issues from disabled trackers)
132 # TODO: inform about that
132 # TODO: inform about that
133 redirect_to :controller => 'projects', :action => 'settings', :id => @project
133 redirect_to :controller => 'projects', :action => 'settings', :id => @project
134 end
134 end
135 end
135 end
136 end
136 end
137 rescue ActiveRecord::RecordNotFound
137 rescue ActiveRecord::RecordNotFound
138 redirect_to :controller => 'admin', :action => 'projects'
138 redirect_to :controller => 'admin', :action => 'projects'
139 end
139 end
140
140
141 # Show @project
141 # Show @project
142 def show
142 def show
143 if params[:jump]
143 if params[:jump]
144 # try to redirect to the requested menu item
144 # try to redirect to the requested menu item
145 redirect_to_project_menu_item(@project, params[:jump]) && return
145 redirect_to_project_menu_item(@project, params[:jump]) && return
146 end
146 end
147
147
148 @users_by_role = @project.users_by_role
148 @users_by_role = @project.users_by_role
149 @subprojects = @project.children.visible.all
149 @subprojects = @project.children.visible.all
150 @news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
150 @news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
151 @trackers = @project.rolled_up_trackers
151 @trackers = @project.rolled_up_trackers
152
152
153 cond = @project.project_condition(Setting.display_subprojects_issues?)
153 cond = @project.project_condition(Setting.display_subprojects_issues?)
154
154
155 @open_issues_by_tracker = Issue.visible.count(:group => :tracker,
155 @open_issues_by_tracker = Issue.visible.count(:group => :tracker,
156 :include => [:project, :status, :tracker],
156 :include => [:project, :status, :tracker],
157 :conditions => ["(#{cond}) AND #{IssueStatus.table_name}.is_closed=?", false])
157 :conditions => ["(#{cond}) AND #{IssueStatus.table_name}.is_closed=?", false])
158 @total_issues_by_tracker = Issue.visible.count(:group => :tracker,
158 @total_issues_by_tracker = Issue.visible.count(:group => :tracker,
159 :include => [:project, :status, :tracker],
159 :include => [:project, :status, :tracker],
160 :conditions => cond)
160 :conditions => cond)
161
161
162 if User.current.allowed_to?(:view_time_entries, @project)
162 if User.current.allowed_to?(:view_time_entries, @project)
163 @total_hours = TimeEntry.visible.sum(:hours, :include => :project, :conditions => cond).to_f
163 @total_hours = TimeEntry.visible.sum(:hours, :include => :project, :conditions => cond).to_f
164 end
164 end
165
165
166 @key = User.current.rss_key
166 @key = User.current.rss_key
167
167
168 respond_to do |format|
168 respond_to do |format|
169 format.html
169 format.html
170 format.api
170 format.api
171 end
171 end
172 end
172 end
173
173
174 def settings
174 def settings
175 @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
175 @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
176 @issue_category ||= IssueCategory.new
176 @issue_category ||= IssueCategory.new
177 @member ||= @project.members.new
177 @member ||= @project.members.new
178 @trackers = Tracker.all
178 @trackers = Tracker.all
179 @repository ||= @project.repository
179 @repository ||= @project.repository
180 @wiki ||= @project.wiki
180 @wiki ||= @project.wiki
181 end
181 end
182
182
183 def edit
183 def edit
184 end
184 end
185
185
186 # TODO: convert to PUT only
186 # TODO: convert to PUT only
187 verify :method => [:post, :put], :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
187 verify :method => [:post, :put], :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
188 def update
188 def update
189 @project.safe_attributes = params[:project]
189 @project.safe_attributes = params[:project]
190 if validate_parent_id && @project.save
190 if validate_parent_id && @project.save
191 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
191 @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
192 respond_to do |format|
192 respond_to do |format|
193 format.html {
193 format.html {
194 flash[:notice] = l(:notice_successful_update)
194 flash[:notice] = l(:notice_successful_update)
195 redirect_to :action => 'settings', :id => @project
195 redirect_to :action => 'settings', :id => @project
196 }
196 }
197 format.api { head :ok }
197 format.api { head :ok }
198 end
198 end
199 else
199 else
200 respond_to do |format|
200 respond_to do |format|
201 format.html {
201 format.html {
202 settings
202 settings
203 render :action => 'settings'
203 render :action => 'settings'
204 }
204 }
205 format.api { render_validation_errors(@project) }
205 format.api { render_validation_errors(@project) }
206 end
206 end
207 end
207 end
208 end
208 end
209
209
210 verify :method => :post, :only => :modules, :render => {:nothing => true, :status => :method_not_allowed }
210 verify :method => :post, :only => :modules, :render => {:nothing => true, :status => :method_not_allowed }
211 def modules
211 def modules
212 @project.enabled_module_names = params[:enabled_module_names]
212 @project.enabled_module_names = params[:enabled_module_names]
213 flash[:notice] = l(:notice_successful_update)
213 flash[:notice] = l(:notice_successful_update)
214 redirect_to :action => 'settings', :id => @project, :tab => 'modules'
214 redirect_to :action => 'settings', :id => @project, :tab => 'modules'
215 end
215 end
216
216
217 def archive
217 def archive
218 if request.post?
218 if request.post?
219 unless @project.archive
219 unless @project.archive
220 flash[:error] = l(:error_can_not_archive_project)
220 flash[:error] = l(:error_can_not_archive_project)
221 end
221 end
222 end
222 end
223 redirect_to(url_for(:controller => 'admin', :action => 'projects', :status => params[:status]))
223 redirect_to(url_for(:controller => 'admin', :action => 'projects', :status => params[:status]))
224 end
224 end
225
225
226 def unarchive
226 def unarchive
227 @project.unarchive if request.post? && !@project.active?
227 @project.unarchive if request.post? && !@project.active?
228 redirect_to(url_for(:controller => 'admin', :action => 'projects', :status => params[:status]))
228 redirect_to(url_for(:controller => 'admin', :action => 'projects', :status => params[:status]))
229 end
229 end
230
230
231 verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed }
231 # Delete @project
232 # Delete @project
232 def destroy
233 def destroy
233 @project_to_destroy = @project
234 @project_to_destroy = @project
234 if request.get?
235 if api_request? || params[:confirm]
235 # display confirmation view
236 @project_to_destroy.destroy
236 else
237 respond_to do |format|
237 if api_request? || params[:confirm]
238 format.html { redirect_to :controller => 'admin', :action => 'projects' }
238 @project_to_destroy.destroy
239 format.api { head :ok }
239 respond_to do |format|
240 format.html { redirect_to :controller => 'admin', :action => 'projects' }
241 format.api { head :ok }
242 end
243 end
240 end
244 end
241 end
245 # hide project in layout
242 # hide project in layout
246 @project = nil
243 @project = nil
247 end
244 end
248
245
249 private
246 private
250 def find_optional_project
247 def find_optional_project
251 return true unless params[:id]
248 return true unless params[:id]
252 @project = Project.find(params[:id])
249 @project = Project.find(params[:id])
253 authorize
250 authorize
254 rescue ActiveRecord::RecordNotFound
251 rescue ActiveRecord::RecordNotFound
255 render_404
252 render_404
256 end
253 end
257
254
258 # Validates parent_id param according to user's permissions
255 # Validates parent_id param according to user's permissions
259 # TODO: move it to Project model in a validation that depends on User.current
256 # TODO: move it to Project model in a validation that depends on User.current
260 def validate_parent_id
257 def validate_parent_id
261 return true if User.current.admin?
258 return true if User.current.admin?
262 parent_id = params[:project] && params[:project][:parent_id]
259 parent_id = params[:project] && params[:project][:parent_id]
263 if parent_id || @project.new_record?
260 if parent_id || @project.new_record?
264 parent = parent_id.blank? ? nil : Project.find_by_id(parent_id.to_i)
261 parent = parent_id.blank? ? nil : Project.find_by_id(parent_id.to_i)
265 unless @project.allowed_parents.include?(parent)
262 unless @project.allowed_parents.include?(parent)
266 @project.errors.add :parent_id, :invalid
263 @project.errors.add :parent_id, :invalid
267 return false
264 return false
268 end
265 end
269 end
266 end
270 true
267 true
271 end
268 end
272 end
269 end
@@ -1,45 +1,45
1 <div class="contextual">
1 <div class="contextual">
2 <%= link_to l(:label_project_new), {:controller => 'projects', :action => 'new'}, :class => 'icon icon-add' %>
2 <%= link_to l(:label_project_new), {:controller => 'projects', :action => 'new'}, :class => 'icon icon-add' %>
3 </div>
3 </div>
4
4
5 <h2><%=l(:label_project_plural)%></h2>
5 <h2><%=l(:label_project_plural)%></h2>
6
6
7 <% form_tag({}, :method => :get) do %>
7 <% form_tag({}, :method => :get) do %>
8 <fieldset><legend><%= l(:label_filter_plural) %></legend>
8 <fieldset><legend><%= l(:label_filter_plural) %></legend>
9 <label for='status'><%= l(:field_status) %> :</label>
9 <label for='status'><%= l(:field_status) %> :</label>
10 <%= select_tag 'status', project_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;" %>
10 <%= select_tag 'status', project_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;" %>
11 <label for='name'><%= l(:label_project) %>:</label>
11 <label for='name'><%= l(:label_project) %>:</label>
12 <%= text_field_tag 'name', params[:name], :size => 30 %>
12 <%= text_field_tag 'name', params[:name], :size => 30 %>
13 <%= submit_tag l(:button_apply), :class => "small", :name => nil %>
13 <%= submit_tag l(:button_apply), :class => "small", :name => nil %>
14 <%= link_to l(:button_clear), {:controller => 'admin', :action => 'projects'}, :class => 'icon icon-reload' %>
14 <%= link_to l(:button_clear), {:controller => 'admin', :action => 'projects'}, :class => 'icon icon-reload' %>
15 </fieldset>
15 </fieldset>
16 <% end %>
16 <% end %>
17 &nbsp;
17 &nbsp;
18
18
19 <div class="autoscroll">
19 <div class="autoscroll">
20 <table class="list">
20 <table class="list">
21 <thead><tr>
21 <thead><tr>
22 <th><%=l(:label_project)%></th>
22 <th><%=l(:label_project)%></th>
23 <th><%=l(:field_is_public)%></th>
23 <th><%=l(:field_is_public)%></th>
24 <th><%=l(:field_created_on)%></th>
24 <th><%=l(:field_created_on)%></th>
25 <th></th>
25 <th></th>
26 </tr></thead>
26 </tr></thead>
27 <tbody>
27 <tbody>
28 <% project_tree(@projects) do |project, level| %>
28 <% project_tree(@projects) do |project, level| %>
29 <tr class="<%= cycle("odd", "even") %> <%= project.css_classes %> <%= level > 0 ? "idnt idnt-#{level}" : nil %>">
29 <tr class="<%= cycle("odd", "even") %> <%= project.css_classes %> <%= level > 0 ? "idnt idnt-#{level}" : nil %>">
30 <td class="name"><span><%= link_to_project(project, {:action => 'settings'}, :title => project.short_description) %></span></td>
30 <td class="name"><span><%= link_to_project(project, {:action => 'settings'}, :title => project.short_description) %></span></td>
31 <td align="center"><%= checked_image project.is_public? %></td>
31 <td align="center"><%= checked_image project.is_public? %></td>
32 <td align="center"><%= format_date(project.created_on) %></td>
32 <td align="center"><%= format_date(project.created_on) %></td>
33 <td class="buttons">
33 <td class="buttons">
34 <%= link_to(l(:button_archive), { :controller => 'projects', :action => 'archive', :id => project, :status => params[:status] }, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-lock') if project.active? %>
34 <%= link_to(l(:button_archive), { :controller => 'projects', :action => 'archive', :id => project, :status => params[:status] }, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-lock') if project.active? %>
35 <%= link_to(l(:button_unarchive), { :controller => 'projects', :action => 'unarchive', :id => project, :status => params[:status] }, :method => :post, :class => 'icon icon-unlock') if !project.active? && (project.parent.nil? || project.parent.active?) %>
35 <%= link_to(l(:button_unarchive), { :controller => 'projects', :action => 'unarchive', :id => project, :status => params[:status] }, :method => :post, :class => 'icon icon-unlock') if !project.active? && (project.parent.nil? || project.parent.active?) %>
36 <%= link_to(l(:button_copy), { :controller => 'projects', :action => 'copy', :id => project }, :class => 'icon icon-copy') %>
36 <%= link_to(l(:button_copy), { :controller => 'projects', :action => 'copy', :id => project }, :class => 'icon icon-copy') %>
37 <%= link_to(l(:button_delete), project_destroy_confirm_path(project), :class => 'icon icon-del') %>
37 <%= link_to(l(:button_delete), project_path(project), :method => :delete, :class => 'icon icon-del') %>
38 </td>
38 </td>
39 </tr>
39 </tr>
40 <% end %>
40 <% end %>
41 </tbody>
41 </tbody>
42 </table>
42 </table>
43 </div>
43 </div>
44
44
45 <% html_title(l(:label_project_plural)) -%>
45 <% html_title(l(:label_project_plural)) -%>
@@ -1,203 +1,200
1 ActionController::Routing::Routes.draw do |map|
1 ActionController::Routing::Routes.draw do |map|
2 # Add your own custom routes here.
2 # Add your own custom routes here.
3 # The priority is based upon order of creation: first created -> highest priority.
3 # The priority is based upon order of creation: first created -> highest priority.
4
4
5 # Here's a sample route:
5 # Here's a sample route:
6 # map.connect 'products/:id', :controller => 'catalog', :action => 'view'
6 # map.connect 'products/:id', :controller => 'catalog', :action => 'view'
7 # Keep in mind you can assign values other than :controller and :action
7 # Keep in mind you can assign values other than :controller and :action
8
8
9 map.home '', :controller => 'welcome'
9 map.home '', :controller => 'welcome'
10
10
11 map.signin 'login', :controller => 'account', :action => 'login'
11 map.signin 'login', :controller => 'account', :action => 'login'
12 map.signout 'logout', :controller => 'account', :action => 'logout'
12 map.signout 'logout', :controller => 'account', :action => 'logout'
13
13
14 map.connect 'roles/workflow/:id/:role_id/:tracker_id', :controller => 'roles', :action => 'workflow'
14 map.connect 'roles/workflow/:id/:role_id/:tracker_id', :controller => 'roles', :action => 'workflow'
15 map.connect 'help/:ctrl/:page', :controller => 'help'
15 map.connect 'help/:ctrl/:page', :controller => 'help'
16
16
17 map.time_entries_context_menu '/time_entries/context_menu',
17 map.time_entries_context_menu '/time_entries/context_menu',
18 :controller => 'context_menus', :action => 'time_entries'
18 :controller => 'context_menus', :action => 'time_entries'
19
19
20 map.resources :time_entries, :controller => 'timelog', :collection => {:report => :get, :bulk_edit => :get, :bulk_update => :post}
20 map.resources :time_entries, :controller => 'timelog', :collection => {:report => :get, :bulk_edit => :get, :bulk_update => :post}
21
21
22 map.connect 'projects/:id/wiki', :controller => 'wikis', :action => 'edit', :conditions => {:method => :post}
22 map.connect 'projects/:id/wiki', :controller => 'wikis', :action => 'edit', :conditions => {:method => :post}
23 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :get}
23 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :get}
24 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :post}
24 map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :post}
25
25
26 map.with_options :controller => 'messages' do |messages_routes|
26 map.with_options :controller => 'messages' do |messages_routes|
27 messages_routes.with_options :conditions => {:method => :get} do |messages_views|
27 messages_routes.with_options :conditions => {:method => :get} do |messages_views|
28 messages_views.connect 'boards/:board_id/topics/new', :action => 'new'
28 messages_views.connect 'boards/:board_id/topics/new', :action => 'new'
29 messages_views.connect 'boards/:board_id/topics/:id', :action => 'show'
29 messages_views.connect 'boards/:board_id/topics/:id', :action => 'show'
30 messages_views.connect 'boards/:board_id/topics/:id/edit', :action => 'edit'
30 messages_views.connect 'boards/:board_id/topics/:id/edit', :action => 'edit'
31 end
31 end
32 messages_routes.with_options :conditions => {:method => :post} do |messages_actions|
32 messages_routes.with_options :conditions => {:method => :post} do |messages_actions|
33 messages_actions.connect 'boards/:board_id/topics/new', :action => 'new'
33 messages_actions.connect 'boards/:board_id/topics/new', :action => 'new'
34 messages_actions.connect 'boards/:board_id/topics/:id/replies', :action => 'reply'
34 messages_actions.connect 'boards/:board_id/topics/:id/replies', :action => 'reply'
35 messages_actions.connect 'boards/:board_id/topics/:id/:action', :action => /edit|destroy/
35 messages_actions.connect 'boards/:board_id/topics/:id/:action', :action => /edit|destroy/
36 end
36 end
37 end
37 end
38
38
39 map.resources :issue_moves, :only => [:new, :create], :path_prefix => '/issues', :as => 'move'
39 map.resources :issue_moves, :only => [:new, :create], :path_prefix => '/issues', :as => 'move'
40 map.resources :queries, :except => [:show]
40 map.resources :queries, :except => [:show]
41
41
42 # Misc issue routes. TODO: move into resources
42 # Misc issue routes. TODO: move into resources
43 map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes', :action => 'issues', :conditions => { :method => :get }
43 map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes', :action => 'issues', :conditions => { :method => :get }
44 map.preview_issue '/issues/preview/:id', :controller => 'previews', :action => 'issue' # TODO: would look nicer as /issues/:id/preview
44 map.preview_issue '/issues/preview/:id', :controller => 'previews', :action => 'issue' # TODO: would look nicer as /issues/:id/preview
45 map.issues_context_menu '/issues/context_menu', :controller => 'context_menus', :action => 'issues'
45 map.issues_context_menu '/issues/context_menu', :controller => 'context_menus', :action => 'issues'
46 map.issue_changes '/issues/changes', :controller => 'journals', :action => 'index'
46 map.issue_changes '/issues/changes', :controller => 'journals', :action => 'index'
47 map.quoted_issue '/issues/:id/quoted', :controller => 'journals', :action => 'new', :id => /\d+/, :conditions => { :method => :post }
47 map.quoted_issue '/issues/:id/quoted', :controller => 'journals', :action => 'new', :id => /\d+/, :conditions => { :method => :post }
48
48
49 map.with_options :controller => 'gantts', :action => 'show' do |gantts_routes|
49 map.with_options :controller => 'gantts', :action => 'show' do |gantts_routes|
50 gantts_routes.connect '/projects/:project_id/issues/gantt'
50 gantts_routes.connect '/projects/:project_id/issues/gantt'
51 gantts_routes.connect '/projects/:project_id/issues/gantt.:format'
51 gantts_routes.connect '/projects/:project_id/issues/gantt.:format'
52 gantts_routes.connect '/issues/gantt.:format'
52 gantts_routes.connect '/issues/gantt.:format'
53 end
53 end
54
54
55 map.with_options :controller => 'calendars', :action => 'show' do |calendars_routes|
55 map.with_options :controller => 'calendars', :action => 'show' do |calendars_routes|
56 calendars_routes.connect '/projects/:project_id/issues/calendar'
56 calendars_routes.connect '/projects/:project_id/issues/calendar'
57 calendars_routes.connect '/issues/calendar'
57 calendars_routes.connect '/issues/calendar'
58 end
58 end
59
59
60 map.with_options :controller => 'reports', :conditions => {:method => :get} do |reports|
60 map.with_options :controller => 'reports', :conditions => {:method => :get} do |reports|
61 reports.connect 'projects/:id/issues/report', :action => 'issue_report'
61 reports.connect 'projects/:id/issues/report', :action => 'issue_report'
62 reports.connect 'projects/:id/issues/report/:detail', :action => 'issue_report_details'
62 reports.connect 'projects/:id/issues/report/:detail', :action => 'issue_report_details'
63 end
63 end
64
64
65 map.resources :issues, :collection => {:bulk_edit => :get, :bulk_update => :post} do |issues|
65 map.resources :issues, :collection => {:bulk_edit => :get, :bulk_update => :post} do |issues|
66 issues.resources :time_entries, :controller => 'timelog', :collection => {:report => :get}
66 issues.resources :time_entries, :controller => 'timelog', :collection => {:report => :get}
67 issues.resources :relations, :shallow => true, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
67 issues.resources :relations, :shallow => true, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
68 end
68 end
69 # Bulk deletion
69 # Bulk deletion
70 map.connect '/issues', :controller => 'issues', :action => 'destroy', :conditions => {:method => :delete}
70 map.connect '/issues', :controller => 'issues', :action => 'destroy', :conditions => {:method => :delete}
71
71
72 map.connect 'projects/:id/members/new', :controller => 'members', :action => 'new'
72 map.connect 'projects/:id/members/new', :controller => 'members', :action => 'new'
73
73
74 map.resources :users
74 map.resources :users
75 map.with_options :controller => 'users' do |users|
75 map.with_options :controller => 'users' do |users|
76 users.user_memberships 'users/:id/memberships', :action => 'edit_membership', :conditions => {:method => :post}
76 users.user_memberships 'users/:id/memberships', :action => 'edit_membership', :conditions => {:method => :post}
77 users.user_membership 'users/:id/memberships/:membership_id', :action => 'edit_membership', :conditions => {:method => :put}
77 users.user_membership 'users/:id/memberships/:membership_id', :action => 'edit_membership', :conditions => {:method => :put}
78 users.connect 'users/:id/memberships/:membership_id', :action => 'destroy_membership', :conditions => {:method => :delete}
78 users.connect 'users/:id/memberships/:membership_id', :action => 'destroy_membership', :conditions => {:method => :delete}
79 end
79 end
80
80
81 # For nice "roadmap" in the url for the index action
81 # For nice "roadmap" in the url for the index action
82 map.connect 'projects/:project_id/roadmap', :controller => 'versions', :action => 'index'
82 map.connect 'projects/:project_id/roadmap', :controller => 'versions', :action => 'index'
83
83
84 map.all_news 'news', :controller => 'news', :action => 'index'
84 map.all_news 'news', :controller => 'news', :action => 'index'
85 map.formatted_all_news 'news.:format', :controller => 'news', :action => 'index'
85 map.formatted_all_news 'news.:format', :controller => 'news', :action => 'index'
86 map.preview_news '/news/preview', :controller => 'previews', :action => 'news'
86 map.preview_news '/news/preview', :controller => 'previews', :action => 'news'
87 map.connect 'news/:id/comments', :controller => 'comments', :action => 'create', :conditions => {:method => :post}
87 map.connect 'news/:id/comments', :controller => 'comments', :action => 'create', :conditions => {:method => :post}
88 map.connect 'news/:id/comments/:comment_id', :controller => 'comments', :action => 'destroy', :conditions => {:method => :delete}
88 map.connect 'news/:id/comments/:comment_id', :controller => 'comments', :action => 'destroy', :conditions => {:method => :delete}
89
89
90 map.resources :projects, :member => {
90 map.resources :projects, :member => {
91 :copy => [:get, :post],
91 :copy => [:get, :post],
92 :settings => :get,
92 :settings => :get,
93 :modules => :post,
93 :modules => :post,
94 :archive => :post,
94 :archive => :post,
95 :unarchive => :post
95 :unarchive => :post
96 } do |project|
96 } do |project|
97 project.resource :project_enumerations, :as => 'enumerations', :only => [:update, :destroy]
97 project.resource :project_enumerations, :as => 'enumerations', :only => [:update, :destroy]
98 project.resources :issues, :only => [:index, :new, :create] do |issues|
98 project.resources :issues, :only => [:index, :new, :create] do |issues|
99 issues.resources :time_entries, :controller => 'timelog', :collection => {:report => :get}
99 issues.resources :time_entries, :controller => 'timelog', :collection => {:report => :get}
100 end
100 end
101 project.resources :files, :only => [:index, :new, :create]
101 project.resources :files, :only => [:index, :new, :create]
102 project.resources :versions, :shallow => true, :collection => {:close_completed => :put}, :member => {:status_by => :post}
102 project.resources :versions, :shallow => true, :collection => {:close_completed => :put}, :member => {:status_by => :post}
103 project.resources :news, :shallow => true
103 project.resources :news, :shallow => true
104 project.resources :time_entries, :controller => 'timelog', :path_prefix => 'projects/:project_id', :collection => {:report => :get}
104 project.resources :time_entries, :controller => 'timelog', :path_prefix => 'projects/:project_id', :collection => {:report => :get}
105 project.resources :queries, :only => [:new, :create]
105 project.resources :queries, :only => [:new, :create]
106 project.resources :issue_categories, :shallow => true
106 project.resources :issue_categories, :shallow => true
107 project.resources :documents, :shallow => true, :member => {:add_attachment => :post}
107 project.resources :documents, :shallow => true, :member => {:add_attachment => :post}
108 project.resources :boards
108 project.resources :boards
109
109
110 project.wiki_start_page 'wiki', :controller => 'wiki', :action => 'show', :conditions => {:method => :get}
110 project.wiki_start_page 'wiki', :controller => 'wiki', :action => 'show', :conditions => {:method => :get}
111 project.wiki_index 'wiki/index', :controller => 'wiki', :action => 'index', :conditions => {:method => :get}
111 project.wiki_index 'wiki/index', :controller => 'wiki', :action => 'index', :conditions => {:method => :get}
112 project.wiki_diff 'wiki/:id/diff/:version', :controller => 'wiki', :action => 'diff', :version => nil
112 project.wiki_diff 'wiki/:id/diff/:version', :controller => 'wiki', :action => 'diff', :version => nil
113 project.wiki_diff 'wiki/:id/diff/:version/vs/:version_from', :controller => 'wiki', :action => 'diff'
113 project.wiki_diff 'wiki/:id/diff/:version/vs/:version_from', :controller => 'wiki', :action => 'diff'
114 project.wiki_annotate 'wiki/:id/annotate/:version', :controller => 'wiki', :action => 'annotate'
114 project.wiki_annotate 'wiki/:id/annotate/:version', :controller => 'wiki', :action => 'annotate'
115 project.resources :wiki, :except => [:new, :create], :member => {
115 project.resources :wiki, :except => [:new, :create], :member => {
116 :rename => [:get, :post],
116 :rename => [:get, :post],
117 :history => :get,
117 :history => :get,
118 :preview => :any,
118 :preview => :any,
119 :protect => :post,
119 :protect => :post,
120 :add_attachment => :post
120 :add_attachment => :post
121 }, :collection => {
121 }, :collection => {
122 :export => :get,
122 :export => :get,
123 :date_index => :get
123 :date_index => :get
124 }
124 }
125
125
126 end
126 end
127
127
128 # Destroy uses a get request to prompt the user before the actual DELETE request
129 map.project_destroy_confirm 'projects/:id/destroy', :controller => 'projects', :action => 'destroy', :conditions => {:method => :get}
130
131 # TODO: port to be part of the resources route(s)
128 # TODO: port to be part of the resources route(s)
132 map.with_options :controller => 'projects' do |project_mapper|
129 map.with_options :controller => 'projects' do |project_mapper|
133 project_mapper.with_options :conditions => {:method => :get} do |project_views|
130 project_mapper.with_options :conditions => {:method => :get} do |project_views|
134 project_views.connect 'projects/:id/settings/:tab', :controller => 'projects', :action => 'settings'
131 project_views.connect 'projects/:id/settings/:tab', :controller => 'projects', :action => 'settings'
135 project_views.connect 'projects/:project_id/issues/:copy_from/copy', :controller => 'issues', :action => 'new'
132 project_views.connect 'projects/:project_id/issues/:copy_from/copy', :controller => 'issues', :action => 'new'
136 end
133 end
137 end
134 end
138
135
139 map.with_options :controller => 'activities', :action => 'index', :conditions => {:method => :get} do |activity|
136 map.with_options :controller => 'activities', :action => 'index', :conditions => {:method => :get} do |activity|
140 activity.connect 'projects/:id/activity'
137 activity.connect 'projects/:id/activity'
141 activity.connect 'projects/:id/activity.:format'
138 activity.connect 'projects/:id/activity.:format'
142 activity.connect 'activity', :id => nil
139 activity.connect 'activity', :id => nil
143 activity.connect 'activity.:format', :id => nil
140 activity.connect 'activity.:format', :id => nil
144 end
141 end
145
142
146 map.with_options :controller => 'repositories' do |repositories|
143 map.with_options :controller => 'repositories' do |repositories|
147 repositories.with_options :conditions => {:method => :get} do |repository_views|
144 repositories.with_options :conditions => {:method => :get} do |repository_views|
148 repository_views.connect 'projects/:id/repository', :action => 'show'
145 repository_views.connect 'projects/:id/repository', :action => 'show'
149 repository_views.connect 'projects/:id/repository/edit', :action => 'edit'
146 repository_views.connect 'projects/:id/repository/edit', :action => 'edit'
150 repository_views.connect 'projects/:id/repository/statistics', :action => 'stats'
147 repository_views.connect 'projects/:id/repository/statistics', :action => 'stats'
151 repository_views.connect 'projects/:id/repository/revisions', :action => 'revisions'
148 repository_views.connect 'projects/:id/repository/revisions', :action => 'revisions'
152 repository_views.connect 'projects/:id/repository/revisions.:format', :action => 'revisions'
149 repository_views.connect 'projects/:id/repository/revisions.:format', :action => 'revisions'
153 repository_views.connect 'projects/:id/repository/revisions/:rev', :action => 'revision'
150 repository_views.connect 'projects/:id/repository/revisions/:rev', :action => 'revision'
154 repository_views.connect 'projects/:id/repository/revisions/:rev/diff', :action => 'diff'
151 repository_views.connect 'projects/:id/repository/revisions/:rev/diff', :action => 'diff'
155 repository_views.connect 'projects/:id/repository/revisions/:rev/diff.:format', :action => 'diff'
152 repository_views.connect 'projects/:id/repository/revisions/:rev/diff.:format', :action => 'diff'
156 repository_views.connect 'projects/:id/repository/revisions/:rev/raw/*path', :action => 'entry', :format => 'raw', :requirements => { :rev => /[a-z0-9\.\-_]+/ }
153 repository_views.connect 'projects/:id/repository/revisions/:rev/raw/*path', :action => 'entry', :format => 'raw', :requirements => { :rev => /[a-z0-9\.\-_]+/ }
157 repository_views.connect 'projects/:id/repository/revisions/:rev/:action/*path', :requirements => { :rev => /[a-z0-9\.\-_]+/ }
154 repository_views.connect 'projects/:id/repository/revisions/:rev/:action/*path', :requirements => { :rev => /[a-z0-9\.\-_]+/ }
158 repository_views.connect 'projects/:id/repository/raw/*path', :action => 'entry', :format => 'raw'
155 repository_views.connect 'projects/:id/repository/raw/*path', :action => 'entry', :format => 'raw'
159 # TODO: why the following route is required?
156 # TODO: why the following route is required?
160 repository_views.connect 'projects/:id/repository/entry/*path', :action => 'entry'
157 repository_views.connect 'projects/:id/repository/entry/*path', :action => 'entry'
161 repository_views.connect 'projects/:id/repository/:action/*path'
158 repository_views.connect 'projects/:id/repository/:action/*path'
162 end
159 end
163
160
164 repositories.connect 'projects/:id/repository/:action', :conditions => {:method => :post}
161 repositories.connect 'projects/:id/repository/:action', :conditions => {:method => :post}
165 end
162 end
166
163
167 map.resources :attachments, :only => [:show, :destroy]
164 map.resources :attachments, :only => [:show, :destroy]
168 # additional routes for having the file name at the end of url
165 # additional routes for having the file name at the end of url
169 map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/
166 map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/
170 map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/
167 map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/
171
168
172 map.resources :groups, :member => {:autocomplete_for_user => :get}
169 map.resources :groups, :member => {:autocomplete_for_user => :get}
173 map.group_users 'groups/:id/users', :controller => 'groups', :action => 'add_users', :id => /\d+/, :conditions => {:method => :post}
170 map.group_users 'groups/:id/users', :controller => 'groups', :action => 'add_users', :id => /\d+/, :conditions => {:method => :post}
174 map.group_user 'groups/:id/users/:user_id', :controller => 'groups', :action => 'remove_user', :id => /\d+/, :conditions => {:method => :delete}
171 map.group_user 'groups/:id/users/:user_id', :controller => 'groups', :action => 'remove_user', :id => /\d+/, :conditions => {:method => :delete}
175
172
176 map.resources :trackers, :except => :show
173 map.resources :trackers, :except => :show
177 map.resources :issue_statuses, :except => :show, :collection => {:update_issue_done_ratio => :post}
174 map.resources :issue_statuses, :except => :show, :collection => {:update_issue_done_ratio => :post}
178 map.resources :custom_fields, :except => :show
175 map.resources :custom_fields, :except => :show
179 map.resources :roles, :except => :show, :collection => {:permissions => [:get, :post]}
176 map.resources :roles, :except => :show, :collection => {:permissions => [:get, :post]}
180
177
181 #left old routes at the bottom for backwards compat
178 #left old routes at the bottom for backwards compat
182 map.connect 'boards/:board_id/topics/:action/:id', :controller => 'messages'
179 map.connect 'boards/:board_id/topics/:action/:id', :controller => 'messages'
183 map.connect 'wiki/:id/:page/:action', :page => nil, :controller => 'wiki'
180 map.connect 'wiki/:id/:page/:action', :page => nil, :controller => 'wiki'
184 map.with_options :controller => 'repositories' do |omap|
181 map.with_options :controller => 'repositories' do |omap|
185 omap.repositories_show 'repositories/browse/:id/*path', :action => 'browse'
182 omap.repositories_show 'repositories/browse/:id/*path', :action => 'browse'
186 omap.repositories_changes 'repositories/changes/:id/*path', :action => 'changes'
183 omap.repositories_changes 'repositories/changes/:id/*path', :action => 'changes'
187 omap.repositories_diff 'repositories/diff/:id/*path', :action => 'diff'
184 omap.repositories_diff 'repositories/diff/:id/*path', :action => 'diff'
188 omap.repositories_entry 'repositories/entry/:id/*path', :action => 'entry'
185 omap.repositories_entry 'repositories/entry/:id/*path', :action => 'entry'
189 omap.repositories_entry 'repositories/annotate/:id/*path', :action => 'annotate'
186 omap.repositories_entry 'repositories/annotate/:id/*path', :action => 'annotate'
190 omap.connect 'repositories/revision/:id/:rev', :action => 'revision'
187 omap.connect 'repositories/revision/:id/:rev', :action => 'revision'
191 end
188 end
192
189
193 map.with_options :controller => 'sys' do |sys|
190 map.with_options :controller => 'sys' do |sys|
194 sys.connect 'sys/projects.:format', :action => 'projects', :conditions => {:method => :get}
191 sys.connect 'sys/projects.:format', :action => 'projects', :conditions => {:method => :get}
195 sys.connect 'sys/projects/:id/repository.:format', :action => 'create_project_repository', :conditions => {:method => :post}
192 sys.connect 'sys/projects/:id/repository.:format', :action => 'create_project_repository', :conditions => {:method => :post}
196 end
193 end
197
194
198 # Install the default route as the lowest priority.
195 # Install the default route as the lowest priority.
199 map.connect ':controller/:action/:id'
196 map.connect ':controller/:action/:id'
200 map.connect 'robots.txt', :controller => 'welcome', :action => 'robots'
197 map.connect 'robots.txt', :controller => 'welcome', :action => 'robots'
201 # Used for OpenID
198 # Used for OpenID
202 map.root :controller => 'account', :action => 'login'
199 map.root :controller => 'account', :action => 'login'
203 end
200 end
@@ -1,545 +1,545
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2011 Jean-Philippe Lang
2 # Copyright (C) 2006-2011 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.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19 require 'projects_controller'
19 require 'projects_controller'
20
20
21 # Re-raise errors caught by the controller.
21 # Re-raise errors caught by the controller.
22 class ProjectsController; def rescue_action(e) raise e end; end
22 class ProjectsController; def rescue_action(e) raise e end; end
23
23
24 class ProjectsControllerTest < ActionController::TestCase
24 class ProjectsControllerTest < ActionController::TestCase
25 fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details,
25 fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details,
26 :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages,
26 :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages,
27 :attachments, :custom_fields, :custom_values, :time_entries
27 :attachments, :custom_fields, :custom_values, :time_entries
28
28
29 def setup
29 def setup
30 @controller = ProjectsController.new
30 @controller = ProjectsController.new
31 @request = ActionController::TestRequest.new
31 @request = ActionController::TestRequest.new
32 @response = ActionController::TestResponse.new
32 @response = ActionController::TestResponse.new
33 @request.session[:user_id] = nil
33 @request.session[:user_id] = nil
34 Setting.default_language = 'en'
34 Setting.default_language = 'en'
35 end
35 end
36
36
37 def test_index
37 def test_index
38 get :index
38 get :index
39 assert_response :success
39 assert_response :success
40 assert_template 'index'
40 assert_template 'index'
41 assert_not_nil assigns(:projects)
41 assert_not_nil assigns(:projects)
42
42
43 assert_tag :ul, :child => {:tag => 'li',
43 assert_tag :ul, :child => {:tag => 'li',
44 :descendant => {:tag => 'a', :content => 'eCookbook'},
44 :descendant => {:tag => 'a', :content => 'eCookbook'},
45 :child => { :tag => 'ul',
45 :child => { :tag => 'ul',
46 :descendant => { :tag => 'a',
46 :descendant => { :tag => 'a',
47 :content => 'Child of private child'
47 :content => 'Child of private child'
48 }
48 }
49 }
49 }
50 }
50 }
51
51
52 assert_no_tag :a, :content => /Private child of eCookbook/
52 assert_no_tag :a, :content => /Private child of eCookbook/
53 end
53 end
54
54
55 def test_index_atom
55 def test_index_atom
56 get :index, :format => 'atom'
56 get :index, :format => 'atom'
57 assert_response :success
57 assert_response :success
58 assert_template 'common/feed.atom'
58 assert_template 'common/feed.atom'
59 assert_select 'feed>title', :text => 'Redmine: Latest projects'
59 assert_select 'feed>title', :text => 'Redmine: Latest projects'
60 assert_select 'feed>entry', :count => Project.count(:conditions => Project.visible_condition(User.current))
60 assert_select 'feed>entry', :count => Project.count(:conditions => Project.visible_condition(User.current))
61 end
61 end
62
62
63 context "#index" do
63 context "#index" do
64 context "by non-admin user with view_time_entries permission" do
64 context "by non-admin user with view_time_entries permission" do
65 setup do
65 setup do
66 @request.session[:user_id] = 3
66 @request.session[:user_id] = 3
67 end
67 end
68 should "show overall spent time link" do
68 should "show overall spent time link" do
69 get :index
69 get :index
70 assert_template 'index'
70 assert_template 'index'
71 assert_tag :a, :attributes => {:href => '/time_entries'}
71 assert_tag :a, :attributes => {:href => '/time_entries'}
72 end
72 end
73 end
73 end
74
74
75 context "by non-admin user without view_time_entries permission" do
75 context "by non-admin user without view_time_entries permission" do
76 setup do
76 setup do
77 Role.find(2).remove_permission! :view_time_entries
77 Role.find(2).remove_permission! :view_time_entries
78 Role.non_member.remove_permission! :view_time_entries
78 Role.non_member.remove_permission! :view_time_entries
79 Role.anonymous.remove_permission! :view_time_entries
79 Role.anonymous.remove_permission! :view_time_entries
80 @request.session[:user_id] = 3
80 @request.session[:user_id] = 3
81 end
81 end
82 should "not show overall spent time link" do
82 should "not show overall spent time link" do
83 get :index
83 get :index
84 assert_template 'index'
84 assert_template 'index'
85 assert_no_tag :a, :attributes => {:href => '/time_entries'}
85 assert_no_tag :a, :attributes => {:href => '/time_entries'}
86 end
86 end
87 end
87 end
88 end
88 end
89
89
90 context "#new" do
90 context "#new" do
91 context "by admin user" do
91 context "by admin user" do
92 setup do
92 setup do
93 @request.session[:user_id] = 1
93 @request.session[:user_id] = 1
94 end
94 end
95
95
96 should "accept get" do
96 should "accept get" do
97 get :new
97 get :new
98 assert_response :success
98 assert_response :success
99 assert_template 'new'
99 assert_template 'new'
100 end
100 end
101
101
102 end
102 end
103
103
104 context "by non-admin user with add_project permission" do
104 context "by non-admin user with add_project permission" do
105 setup do
105 setup do
106 Role.non_member.add_permission! :add_project
106 Role.non_member.add_permission! :add_project
107 @request.session[:user_id] = 9
107 @request.session[:user_id] = 9
108 end
108 end
109
109
110 should "accept get" do
110 should "accept get" do
111 get :new
111 get :new
112 assert_response :success
112 assert_response :success
113 assert_template 'new'
113 assert_template 'new'
114 assert_no_tag :select, :attributes => {:name => 'project[parent_id]'}
114 assert_no_tag :select, :attributes => {:name => 'project[parent_id]'}
115 end
115 end
116 end
116 end
117
117
118 context "by non-admin user with add_subprojects permission" do
118 context "by non-admin user with add_subprojects permission" do
119 setup do
119 setup do
120 Role.find(1).remove_permission! :add_project
120 Role.find(1).remove_permission! :add_project
121 Role.find(1).add_permission! :add_subprojects
121 Role.find(1).add_permission! :add_subprojects
122 @request.session[:user_id] = 2
122 @request.session[:user_id] = 2
123 end
123 end
124
124
125 should "accept get" do
125 should "accept get" do
126 get :new, :parent_id => 'ecookbook'
126 get :new, :parent_id => 'ecookbook'
127 assert_response :success
127 assert_response :success
128 assert_template 'new'
128 assert_template 'new'
129 # parent project selected
129 # parent project selected
130 assert_tag :select, :attributes => {:name => 'project[parent_id]'},
130 assert_tag :select, :attributes => {:name => 'project[parent_id]'},
131 :child => {:tag => 'option', :attributes => {:value => '1', :selected => 'selected'}}
131 :child => {:tag => 'option', :attributes => {:value => '1', :selected => 'selected'}}
132 # no empty value
132 # no empty value
133 assert_no_tag :select, :attributes => {:name => 'project[parent_id]'},
133 assert_no_tag :select, :attributes => {:name => 'project[parent_id]'},
134 :child => {:tag => 'option', :attributes => {:value => ''}}
134 :child => {:tag => 'option', :attributes => {:value => ''}}
135 end
135 end
136 end
136 end
137
137
138 end
138 end
139
139
140 context "POST :create" do
140 context "POST :create" do
141 context "by admin user" do
141 context "by admin user" do
142 setup do
142 setup do
143 @request.session[:user_id] = 1
143 @request.session[:user_id] = 1
144 end
144 end
145
145
146 should "create a new project" do
146 should "create a new project" do
147 post :create,
147 post :create,
148 :project => {
148 :project => {
149 :name => "blog",
149 :name => "blog",
150 :description => "weblog",
150 :description => "weblog",
151 :homepage => 'http://weblog',
151 :homepage => 'http://weblog',
152 :identifier => "blog",
152 :identifier => "blog",
153 :is_public => 1,
153 :is_public => 1,
154 :custom_field_values => { '3' => 'Beta' },
154 :custom_field_values => { '3' => 'Beta' },
155 :tracker_ids => ['1', '3'],
155 :tracker_ids => ['1', '3'],
156 # an issue custom field that is not for all project
156 # an issue custom field that is not for all project
157 :issue_custom_field_ids => ['9'],
157 :issue_custom_field_ids => ['9'],
158 :enabled_module_names => ['issue_tracking', 'news', 'repository']
158 :enabled_module_names => ['issue_tracking', 'news', 'repository']
159 }
159 }
160 assert_redirected_to '/projects/blog/settings'
160 assert_redirected_to '/projects/blog/settings'
161
161
162 project = Project.find_by_name('blog')
162 project = Project.find_by_name('blog')
163 assert_kind_of Project, project
163 assert_kind_of Project, project
164 assert project.active?
164 assert project.active?
165 assert_equal 'weblog', project.description
165 assert_equal 'weblog', project.description
166 assert_equal 'http://weblog', project.homepage
166 assert_equal 'http://weblog', project.homepage
167 assert_equal true, project.is_public?
167 assert_equal true, project.is_public?
168 assert_nil project.parent
168 assert_nil project.parent
169 assert_equal 'Beta', project.custom_value_for(3).value
169 assert_equal 'Beta', project.custom_value_for(3).value
170 assert_equal [1, 3], project.trackers.map(&:id).sort
170 assert_equal [1, 3], project.trackers.map(&:id).sort
171 assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
171 assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
172 assert project.issue_custom_fields.include?(IssueCustomField.find(9))
172 assert project.issue_custom_fields.include?(IssueCustomField.find(9))
173 end
173 end
174
174
175 should "create a new subproject" do
175 should "create a new subproject" do
176 post :create, :project => { :name => "blog",
176 post :create, :project => { :name => "blog",
177 :description => "weblog",
177 :description => "weblog",
178 :identifier => "blog",
178 :identifier => "blog",
179 :is_public => 1,
179 :is_public => 1,
180 :custom_field_values => { '3' => 'Beta' },
180 :custom_field_values => { '3' => 'Beta' },
181 :parent_id => 1
181 :parent_id => 1
182 }
182 }
183 assert_redirected_to '/projects/blog/settings'
183 assert_redirected_to '/projects/blog/settings'
184
184
185 project = Project.find_by_name('blog')
185 project = Project.find_by_name('blog')
186 assert_kind_of Project, project
186 assert_kind_of Project, project
187 assert_equal Project.find(1), project.parent
187 assert_equal Project.find(1), project.parent
188 end
188 end
189
189
190 should "continue" do
190 should "continue" do
191 assert_difference 'Project.count' do
191 assert_difference 'Project.count' do
192 post :create, :project => {:name => "blog", :identifier => "blog"}, :continue => 'Create and continue'
192 post :create, :project => {:name => "blog", :identifier => "blog"}, :continue => 'Create and continue'
193 end
193 end
194 assert_redirected_to '/projects/new?'
194 assert_redirected_to '/projects/new?'
195 end
195 end
196 end
196 end
197
197
198 context "by non-admin user with add_project permission" do
198 context "by non-admin user with add_project permission" do
199 setup do
199 setup do
200 Role.non_member.add_permission! :add_project
200 Role.non_member.add_permission! :add_project
201 @request.session[:user_id] = 9
201 @request.session[:user_id] = 9
202 end
202 end
203
203
204 should "accept create a Project" do
204 should "accept create a Project" do
205 post :create, :project => { :name => "blog",
205 post :create, :project => { :name => "blog",
206 :description => "weblog",
206 :description => "weblog",
207 :identifier => "blog",
207 :identifier => "blog",
208 :is_public => 1,
208 :is_public => 1,
209 :custom_field_values => { '3' => 'Beta' },
209 :custom_field_values => { '3' => 'Beta' },
210 :tracker_ids => ['1', '3'],
210 :tracker_ids => ['1', '3'],
211 :enabled_module_names => ['issue_tracking', 'news', 'repository']
211 :enabled_module_names => ['issue_tracking', 'news', 'repository']
212 }
212 }
213
213
214 assert_redirected_to '/projects/blog/settings'
214 assert_redirected_to '/projects/blog/settings'
215
215
216 project = Project.find_by_name('blog')
216 project = Project.find_by_name('blog')
217 assert_kind_of Project, project
217 assert_kind_of Project, project
218 assert_equal 'weblog', project.description
218 assert_equal 'weblog', project.description
219 assert_equal true, project.is_public?
219 assert_equal true, project.is_public?
220 assert_equal [1, 3], project.trackers.map(&:id).sort
220 assert_equal [1, 3], project.trackers.map(&:id).sort
221 assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
221 assert_equal ['issue_tracking', 'news', 'repository'], project.enabled_module_names.sort
222
222
223 # User should be added as a project member
223 # User should be added as a project member
224 assert User.find(9).member_of?(project)
224 assert User.find(9).member_of?(project)
225 assert_equal 1, project.members.size
225 assert_equal 1, project.members.size
226 end
226 end
227
227
228 should "fail with parent_id" do
228 should "fail with parent_id" do
229 assert_no_difference 'Project.count' do
229 assert_no_difference 'Project.count' do
230 post :create, :project => { :name => "blog",
230 post :create, :project => { :name => "blog",
231 :description => "weblog",
231 :description => "weblog",
232 :identifier => "blog",
232 :identifier => "blog",
233 :is_public => 1,
233 :is_public => 1,
234 :custom_field_values => { '3' => 'Beta' },
234 :custom_field_values => { '3' => 'Beta' },
235 :parent_id => 1
235 :parent_id => 1
236 }
236 }
237 end
237 end
238 assert_response :success
238 assert_response :success
239 project = assigns(:project)
239 project = assigns(:project)
240 assert_kind_of Project, project
240 assert_kind_of Project, project
241 assert_not_nil project.errors[:parent_id]
241 assert_not_nil project.errors[:parent_id]
242 end
242 end
243 end
243 end
244
244
245 context "by non-admin user with add_subprojects permission" do
245 context "by non-admin user with add_subprojects permission" do
246 setup do
246 setup do
247 Role.find(1).remove_permission! :add_project
247 Role.find(1).remove_permission! :add_project
248 Role.find(1).add_permission! :add_subprojects
248 Role.find(1).add_permission! :add_subprojects
249 @request.session[:user_id] = 2
249 @request.session[:user_id] = 2
250 end
250 end
251
251
252 should "create a project with a parent_id" do
252 should "create a project with a parent_id" do
253 post :create, :project => { :name => "blog",
253 post :create, :project => { :name => "blog",
254 :description => "weblog",
254 :description => "weblog",
255 :identifier => "blog",
255 :identifier => "blog",
256 :is_public => 1,
256 :is_public => 1,
257 :custom_field_values => { '3' => 'Beta' },
257 :custom_field_values => { '3' => 'Beta' },
258 :parent_id => 1
258 :parent_id => 1
259 }
259 }
260 assert_redirected_to '/projects/blog/settings'
260 assert_redirected_to '/projects/blog/settings'
261 project = Project.find_by_name('blog')
261 project = Project.find_by_name('blog')
262 end
262 end
263
263
264 should "fail without parent_id" do
264 should "fail without parent_id" do
265 assert_no_difference 'Project.count' do
265 assert_no_difference 'Project.count' do
266 post :create, :project => { :name => "blog",
266 post :create, :project => { :name => "blog",
267 :description => "weblog",
267 :description => "weblog",
268 :identifier => "blog",
268 :identifier => "blog",
269 :is_public => 1,
269 :is_public => 1,
270 :custom_field_values => { '3' => 'Beta' }
270 :custom_field_values => { '3' => 'Beta' }
271 }
271 }
272 end
272 end
273 assert_response :success
273 assert_response :success
274 project = assigns(:project)
274 project = assigns(:project)
275 assert_kind_of Project, project
275 assert_kind_of Project, project
276 assert_not_nil project.errors[:parent_id]
276 assert_not_nil project.errors[:parent_id]
277 end
277 end
278
278
279 should "fail with unauthorized parent_id" do
279 should "fail with unauthorized parent_id" do
280 assert !User.find(2).member_of?(Project.find(6))
280 assert !User.find(2).member_of?(Project.find(6))
281 assert_no_difference 'Project.count' do
281 assert_no_difference 'Project.count' do
282 post :create, :project => { :name => "blog",
282 post :create, :project => { :name => "blog",
283 :description => "weblog",
283 :description => "weblog",
284 :identifier => "blog",
284 :identifier => "blog",
285 :is_public => 1,
285 :is_public => 1,
286 :custom_field_values => { '3' => 'Beta' },
286 :custom_field_values => { '3' => 'Beta' },
287 :parent_id => 6
287 :parent_id => 6
288 }
288 }
289 end
289 end
290 assert_response :success
290 assert_response :success
291 project = assigns(:project)
291 project = assigns(:project)
292 assert_kind_of Project, project
292 assert_kind_of Project, project
293 assert_not_nil project.errors[:parent_id]
293 assert_not_nil project.errors[:parent_id]
294 end
294 end
295 end
295 end
296 end
296 end
297
297
298 def test_create_should_preserve_modules_on_validation_failure
298 def test_create_should_preserve_modules_on_validation_failure
299 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
299 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
300 @request.session[:user_id] = 1
300 @request.session[:user_id] = 1
301 assert_no_difference 'Project.count' do
301 assert_no_difference 'Project.count' do
302 post :create, :project => {
302 post :create, :project => {
303 :name => "blog",
303 :name => "blog",
304 :identifier => "",
304 :identifier => "",
305 :enabled_module_names => %w(issue_tracking news)
305 :enabled_module_names => %w(issue_tracking news)
306 }
306 }
307 end
307 end
308 assert_response :success
308 assert_response :success
309 project = assigns(:project)
309 project = assigns(:project)
310 assert_equal %w(issue_tracking news), project.enabled_module_names.sort
310 assert_equal %w(issue_tracking news), project.enabled_module_names.sort
311 end
311 end
312 end
312 end
313
313
314 def test_create_should_not_accept_get
314 def test_create_should_not_accept_get
315 @request.session[:user_id] = 1
315 @request.session[:user_id] = 1
316 get :create
316 get :create
317 assert_response :method_not_allowed
317 assert_response :method_not_allowed
318 end
318 end
319
319
320 def test_show_by_id
320 def test_show_by_id
321 get :show, :id => 1
321 get :show, :id => 1
322 assert_response :success
322 assert_response :success
323 assert_template 'show'
323 assert_template 'show'
324 assert_not_nil assigns(:project)
324 assert_not_nil assigns(:project)
325 end
325 end
326
326
327 def test_show_by_identifier
327 def test_show_by_identifier
328 get :show, :id => 'ecookbook'
328 get :show, :id => 'ecookbook'
329 assert_response :success
329 assert_response :success
330 assert_template 'show'
330 assert_template 'show'
331 assert_not_nil assigns(:project)
331 assert_not_nil assigns(:project)
332 assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
332 assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
333
333
334 assert_tag 'li', :content => /Development status/
334 assert_tag 'li', :content => /Development status/
335 end
335 end
336
336
337 def test_show_should_not_display_hidden_custom_fields
337 def test_show_should_not_display_hidden_custom_fields
338 ProjectCustomField.find_by_name('Development status').update_attribute :visible, false
338 ProjectCustomField.find_by_name('Development status').update_attribute :visible, false
339 get :show, :id => 'ecookbook'
339 get :show, :id => 'ecookbook'
340 assert_response :success
340 assert_response :success
341 assert_template 'show'
341 assert_template 'show'
342 assert_not_nil assigns(:project)
342 assert_not_nil assigns(:project)
343
343
344 assert_no_tag 'li', :content => /Development status/
344 assert_no_tag 'li', :content => /Development status/
345 end
345 end
346
346
347 def test_show_should_not_fail_when_custom_values_are_nil
347 def test_show_should_not_fail_when_custom_values_are_nil
348 project = Project.find_by_identifier('ecookbook')
348 project = Project.find_by_identifier('ecookbook')
349 project.custom_values.first.update_attribute(:value, nil)
349 project.custom_values.first.update_attribute(:value, nil)
350 get :show, :id => 'ecookbook'
350 get :show, :id => 'ecookbook'
351 assert_response :success
351 assert_response :success
352 assert_template 'show'
352 assert_template 'show'
353 assert_not_nil assigns(:project)
353 assert_not_nil assigns(:project)
354 assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
354 assert_equal Project.find_by_identifier('ecookbook'), assigns(:project)
355 end
355 end
356
356
357 def show_archived_project_should_be_denied
357 def show_archived_project_should_be_denied
358 project = Project.find_by_identifier('ecookbook')
358 project = Project.find_by_identifier('ecookbook')
359 project.archive!
359 project.archive!
360
360
361 get :show, :id => 'ecookbook'
361 get :show, :id => 'ecookbook'
362 assert_response 403
362 assert_response 403
363 assert_nil assigns(:project)
363 assert_nil assigns(:project)
364 assert_tag :tag => 'p', :content => /archived/
364 assert_tag :tag => 'p', :content => /archived/
365 end
365 end
366
366
367 def test_private_subprojects_hidden
367 def test_private_subprojects_hidden
368 get :show, :id => 'ecookbook'
368 get :show, :id => 'ecookbook'
369 assert_response :success
369 assert_response :success
370 assert_template 'show'
370 assert_template 'show'
371 assert_no_tag :tag => 'a', :content => /Private child/
371 assert_no_tag :tag => 'a', :content => /Private child/
372 end
372 end
373
373
374 def test_private_subprojects_visible
374 def test_private_subprojects_visible
375 @request.session[:user_id] = 2 # manager who is a member of the private subproject
375 @request.session[:user_id] = 2 # manager who is a member of the private subproject
376 get :show, :id => 'ecookbook'
376 get :show, :id => 'ecookbook'
377 assert_response :success
377 assert_response :success
378 assert_template 'show'
378 assert_template 'show'
379 assert_tag :tag => 'a', :content => /Private child/
379 assert_tag :tag => 'a', :content => /Private child/
380 end
380 end
381
381
382 def test_settings
382 def test_settings
383 @request.session[:user_id] = 2 # manager
383 @request.session[:user_id] = 2 # manager
384 get :settings, :id => 1
384 get :settings, :id => 1
385 assert_response :success
385 assert_response :success
386 assert_template 'settings'
386 assert_template 'settings'
387 end
387 end
388
388
389 def test_update
389 def test_update
390 @request.session[:user_id] = 2 # manager
390 @request.session[:user_id] = 2 # manager
391 post :update, :id => 1, :project => {:name => 'Test changed name',
391 post :update, :id => 1, :project => {:name => 'Test changed name',
392 :issue_custom_field_ids => ['']}
392 :issue_custom_field_ids => ['']}
393 assert_redirected_to '/projects/ecookbook/settings'
393 assert_redirected_to '/projects/ecookbook/settings'
394 project = Project.find(1)
394 project = Project.find(1)
395 assert_equal 'Test changed name', project.name
395 assert_equal 'Test changed name', project.name
396 end
396 end
397
397
398 def test_modules
398 def test_modules
399 @request.session[:user_id] = 2
399 @request.session[:user_id] = 2
400 Project.find(1).enabled_module_names = ['issue_tracking', 'news']
400 Project.find(1).enabled_module_names = ['issue_tracking', 'news']
401
401
402 post :modules, :id => 1, :enabled_module_names => ['issue_tracking', 'repository', 'documents']
402 post :modules, :id => 1, :enabled_module_names => ['issue_tracking', 'repository', 'documents']
403 assert_redirected_to '/projects/ecookbook/settings/modules'
403 assert_redirected_to '/projects/ecookbook/settings/modules'
404 assert_equal ['documents', 'issue_tracking', 'repository'], Project.find(1).enabled_module_names.sort
404 assert_equal ['documents', 'issue_tracking', 'repository'], Project.find(1).enabled_module_names.sort
405 end
405 end
406
406
407 def test_modules_should_not_allow_get
407 def test_modules_should_not_allow_get
408 @request.session[:user_id] = 1
408 @request.session[:user_id] = 1
409 get :modules, :id => 1
409 get :modules, :id => 1
410 assert_response :method_not_allowed
410 assert_response :method_not_allowed
411 end
411 end
412
412
413 def test_get_destroy
413 def test_destroy_without_confirmation
414 @request.session[:user_id] = 1 # admin
414 @request.session[:user_id] = 1 # admin
415 get :destroy, :id => 1
415 delete :destroy, :id => 1
416 assert_response :success
416 assert_response :success
417 assert_template 'destroy'
417 assert_template 'destroy'
418 assert_not_nil Project.find_by_id(1)
418 assert_not_nil Project.find_by_id(1)
419 end
419 end
420
420
421 def test_post_destroy
421 def test_destroy
422 @request.session[:user_id] = 1 # admin
422 @request.session[:user_id] = 1 # admin
423 post :destroy, :id => 1, :confirm => 1
423 delete :destroy, :id => 1, :confirm => 1
424 assert_redirected_to '/admin/projects'
424 assert_redirected_to '/admin/projects'
425 assert_nil Project.find_by_id(1)
425 assert_nil Project.find_by_id(1)
426 end
426 end
427
427
428 def test_archive
428 def test_archive
429 @request.session[:user_id] = 1 # admin
429 @request.session[:user_id] = 1 # admin
430 post :archive, :id => 1
430 post :archive, :id => 1
431 assert_redirected_to '/admin/projects'
431 assert_redirected_to '/admin/projects'
432 assert !Project.find(1).active?
432 assert !Project.find(1).active?
433 end
433 end
434
434
435 def test_unarchive
435 def test_unarchive
436 @request.session[:user_id] = 1 # admin
436 @request.session[:user_id] = 1 # admin
437 Project.find(1).archive
437 Project.find(1).archive
438 post :unarchive, :id => 1
438 post :unarchive, :id => 1
439 assert_redirected_to '/admin/projects'
439 assert_redirected_to '/admin/projects'
440 assert Project.find(1).active?
440 assert Project.find(1).active?
441 end
441 end
442
442
443 def test_project_breadcrumbs_should_be_limited_to_3_ancestors
443 def test_project_breadcrumbs_should_be_limited_to_3_ancestors
444 CustomField.delete_all
444 CustomField.delete_all
445 parent = nil
445 parent = nil
446 6.times do |i|
446 6.times do |i|
447 p = Project.create!(:name => "Breadcrumbs #{i}", :identifier => "breadcrumbs-#{i}")
447 p = Project.create!(:name => "Breadcrumbs #{i}", :identifier => "breadcrumbs-#{i}")
448 p.set_parent!(parent)
448 p.set_parent!(parent)
449 get :show, :id => p
449 get :show, :id => p
450 assert_tag :h1, :parent => { :attributes => {:id => 'header'}},
450 assert_tag :h1, :parent => { :attributes => {:id => 'header'}},
451 :children => { :count => [i, 3].min,
451 :children => { :count => [i, 3].min,
452 :only => { :tag => 'a' } }
452 :only => { :tag => 'a' } }
453
453
454 parent = p
454 parent = p
455 end
455 end
456 end
456 end
457
457
458 def test_get_copy
458 def test_get_copy
459 @request.session[:user_id] = 1 # admin
459 @request.session[:user_id] = 1 # admin
460 get :copy, :id => 1
460 get :copy, :id => 1
461 assert_response :success
461 assert_response :success
462 assert_template 'copy'
462 assert_template 'copy'
463 assert assigns(:project)
463 assert assigns(:project)
464 assert_equal Project.find(1).description, assigns(:project).description
464 assert_equal Project.find(1).description, assigns(:project).description
465 assert_nil assigns(:project).id
465 assert_nil assigns(:project).id
466
466
467 assert_tag :tag => 'input',
467 assert_tag :tag => 'input',
468 :attributes => {:name => 'project[enabled_module_names][]', :value => 'issue_tracking'}
468 :attributes => {:name => 'project[enabled_module_names][]', :value => 'issue_tracking'}
469 end
469 end
470
470
471 def test_get_copy_without_project
471 def test_get_copy_without_project
472 @request.session[:user_id] = 1 # admin
472 @request.session[:user_id] = 1 # admin
473 get :copy
473 get :copy
474 assert_response :redirect
474 assert_response :redirect
475 assert_redirected_to :controller => 'admin', :action => 'projects'
475 assert_redirected_to :controller => 'admin', :action => 'projects'
476 end
476 end
477
477
478 def test_post_copy_should_copy_requested_items
478 def test_post_copy_should_copy_requested_items
479 @request.session[:user_id] = 1 # admin
479 @request.session[:user_id] = 1 # admin
480 CustomField.delete_all
480 CustomField.delete_all
481
481
482 assert_difference 'Project.count' do
482 assert_difference 'Project.count' do
483 post :copy, :id => 1,
483 post :copy, :id => 1,
484 :project => {
484 :project => {
485 :name => 'Copy',
485 :name => 'Copy',
486 :identifier => 'unique-copy',
486 :identifier => 'unique-copy',
487 :tracker_ids => ['1', '2', '3', ''],
487 :tracker_ids => ['1', '2', '3', ''],
488 :enabled_module_names => %w(issue_tracking time_tracking)
488 :enabled_module_names => %w(issue_tracking time_tracking)
489 },
489 },
490 :only => %w(issues versions)
490 :only => %w(issues versions)
491 end
491 end
492 project = Project.find('unique-copy')
492 project = Project.find('unique-copy')
493 source = Project.find(1)
493 source = Project.find(1)
494 assert_equal %w(issue_tracking time_tracking), project.enabled_module_names.sort
494 assert_equal %w(issue_tracking time_tracking), project.enabled_module_names.sort
495
495
496 assert_equal source.versions.count, project.versions.count, "All versions were not copied"
496 assert_equal source.versions.count, project.versions.count, "All versions were not copied"
497 # issues assigned to a closed version won't be copied
497 # issues assigned to a closed version won't be copied
498 assert_equal source.issues.select {|i| i.fixed_version.nil? || i.fixed_version.open?}.size,
498 assert_equal source.issues.select {|i| i.fixed_version.nil? || i.fixed_version.open?}.size,
499 project.issues.count, "All issues were not copied"
499 project.issues.count, "All issues were not copied"
500 assert_equal 0, project.members.count
500 assert_equal 0, project.members.count
501 end
501 end
502
502
503 def test_post_copy_should_redirect_to_settings_when_successful
503 def test_post_copy_should_redirect_to_settings_when_successful
504 @request.session[:user_id] = 1 # admin
504 @request.session[:user_id] = 1 # admin
505 post :copy, :id => 1, :project => {:name => 'Copy', :identifier => 'unique-copy'}
505 post :copy, :id => 1, :project => {:name => 'Copy', :identifier => 'unique-copy'}
506 assert_response :redirect
506 assert_response :redirect
507 assert_redirected_to :controller => 'projects', :action => 'settings', :id => 'unique-copy'
507 assert_redirected_to :controller => 'projects', :action => 'settings', :id => 'unique-copy'
508 end
508 end
509
509
510 def test_jump_should_redirect_to_active_tab
510 def test_jump_should_redirect_to_active_tab
511 get :show, :id => 1, :jump => 'issues'
511 get :show, :id => 1, :jump => 'issues'
512 assert_redirected_to '/projects/ecookbook/issues'
512 assert_redirected_to '/projects/ecookbook/issues'
513 end
513 end
514
514
515 def test_jump_should_not_redirect_to_inactive_tab
515 def test_jump_should_not_redirect_to_inactive_tab
516 get :show, :id => 3, :jump => 'documents'
516 get :show, :id => 3, :jump => 'documents'
517 assert_response :success
517 assert_response :success
518 assert_template 'show'
518 assert_template 'show'
519 end
519 end
520
520
521 def test_jump_should_not_redirect_to_unknown_tab
521 def test_jump_should_not_redirect_to_unknown_tab
522 get :show, :id => 3, :jump => 'foobar'
522 get :show, :id => 3, :jump => 'foobar'
523 assert_response :success
523 assert_response :success
524 assert_template 'show'
524 assert_template 'show'
525 end
525 end
526
526
527 # A hook that is manually registered later
527 # A hook that is manually registered later
528 class ProjectBasedTemplate < Redmine::Hook::ViewListener
528 class ProjectBasedTemplate < Redmine::Hook::ViewListener
529 def view_layouts_base_html_head(context)
529 def view_layouts_base_html_head(context)
530 # Adds a project stylesheet
530 # Adds a project stylesheet
531 stylesheet_link_tag(context[:project].identifier) if context[:project]
531 stylesheet_link_tag(context[:project].identifier) if context[:project]
532 end
532 end
533 end
533 end
534 # Don't use this hook now
534 # Don't use this hook now
535 Redmine::Hook.clear_listeners
535 Redmine::Hook.clear_listeners
536
536
537 def test_hook_response
537 def test_hook_response
538 Redmine::Hook.add_listener(ProjectBasedTemplate)
538 Redmine::Hook.add_listener(ProjectBasedTemplate)
539 get :show, :id => 1
539 get :show, :id => 1
540 assert_tag :tag => 'link', :attributes => {:href => '/stylesheets/ecookbook.css'},
540 assert_tag :tag => 'link', :attributes => {:href => '/stylesheets/ecookbook.css'},
541 :parent => {:tag => 'head'}
541 :parent => {:tag => 'head'}
542
542
543 Redmine::Hook.clear_listeners
543 Redmine::Hook.clear_listeners
544 end
544 end
545 end
545 end
General Comments 0
You need to be logged in to leave comments. Login now