##// END OF EJS Templates
Refactor: Change the different find_object filters to share a common method....
Eric Davis -
r3483:194dab8e96f6
parent child
Show More
@@ -1,318 +1,332
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require 'uri'
18 require 'uri'
19 require 'cgi'
19 require 'cgi'
20
20
21 class ApplicationController < ActionController::Base
21 class ApplicationController < ActionController::Base
22 include Redmine::I18n
22 include Redmine::I18n
23
23
24 layout 'base'
24 layout 'base'
25 exempt_from_layout 'builder'
25 exempt_from_layout 'builder'
26
26
27 # Remove broken cookie after upgrade from 0.8.x (#4292)
27 # Remove broken cookie after upgrade from 0.8.x (#4292)
28 # See https://rails.lighthouseapp.com/projects/8994/tickets/3360
28 # See https://rails.lighthouseapp.com/projects/8994/tickets/3360
29 # TODO: remove it when Rails is fixed
29 # TODO: remove it when Rails is fixed
30 before_filter :delete_broken_cookies
30 before_filter :delete_broken_cookies
31 def delete_broken_cookies
31 def delete_broken_cookies
32 if cookies['_redmine_session'] && cookies['_redmine_session'] !~ /--/
32 if cookies['_redmine_session'] && cookies['_redmine_session'] !~ /--/
33 cookies.delete '_redmine_session'
33 cookies.delete '_redmine_session'
34 redirect_to home_path
34 redirect_to home_path
35 return false
35 return false
36 end
36 end
37 end
37 end
38
38
39 before_filter :user_setup, :check_if_login_required, :set_localization
39 before_filter :user_setup, :check_if_login_required, :set_localization
40 filter_parameter_logging :password
40 filter_parameter_logging :password
41 protect_from_forgery
41 protect_from_forgery
42
42
43 rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token
43 rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token
44
44
45 include Redmine::Search::Controller
45 include Redmine::Search::Controller
46 include Redmine::MenuManager::MenuController
46 include Redmine::MenuManager::MenuController
47 helper Redmine::MenuManager::MenuHelper
47 helper Redmine::MenuManager::MenuHelper
48
48
49 Redmine::Scm::Base.all.each do |scm|
49 Redmine::Scm::Base.all.each do |scm|
50 require_dependency "repository/#{scm.underscore}"
50 require_dependency "repository/#{scm.underscore}"
51 end
51 end
52
52
53 def user_setup
53 def user_setup
54 # Check the settings cache for each request
54 # Check the settings cache for each request
55 Setting.check_cache
55 Setting.check_cache
56 # Find the current user
56 # Find the current user
57 User.current = find_current_user
57 User.current = find_current_user
58 end
58 end
59
59
60 # Returns the current user or nil if no user is logged in
60 # Returns the current user or nil if no user is logged in
61 # and starts a session if needed
61 # and starts a session if needed
62 def find_current_user
62 def find_current_user
63 if session[:user_id]
63 if session[:user_id]
64 # existing session
64 # existing session
65 (User.active.find(session[:user_id]) rescue nil)
65 (User.active.find(session[:user_id]) rescue nil)
66 elsif cookies[:autologin] && Setting.autologin?
66 elsif cookies[:autologin] && Setting.autologin?
67 # auto-login feature starts a new session
67 # auto-login feature starts a new session
68 user = User.try_to_autologin(cookies[:autologin])
68 user = User.try_to_autologin(cookies[:autologin])
69 session[:user_id] = user.id if user
69 session[:user_id] = user.id if user
70 user
70 user
71 elsif params[:format] == 'atom' && params[:key] && accept_key_auth_actions.include?(params[:action])
71 elsif params[:format] == 'atom' && params[:key] && accept_key_auth_actions.include?(params[:action])
72 # RSS key authentication does not start a session
72 # RSS key authentication does not start a session
73 User.find_by_rss_key(params[:key])
73 User.find_by_rss_key(params[:key])
74 elsif Setting.rest_api_enabled? && ['xml', 'json'].include?(params[:format])
74 elsif Setting.rest_api_enabled? && ['xml', 'json'].include?(params[:format])
75 if params[:key].present? && accept_key_auth_actions.include?(params[:action])
75 if params[:key].present? && accept_key_auth_actions.include?(params[:action])
76 # Use API key
76 # Use API key
77 User.find_by_api_key(params[:key])
77 User.find_by_api_key(params[:key])
78 else
78 else
79 # HTTP Basic, either username/password or API key/random
79 # HTTP Basic, either username/password or API key/random
80 authenticate_with_http_basic do |username, password|
80 authenticate_with_http_basic do |username, password|
81 User.try_to_login(username, password) || User.find_by_api_key(username)
81 User.try_to_login(username, password) || User.find_by_api_key(username)
82 end
82 end
83 end
83 end
84 end
84 end
85 end
85 end
86
86
87 # Sets the logged in user
87 # Sets the logged in user
88 def logged_user=(user)
88 def logged_user=(user)
89 reset_session
89 reset_session
90 if user && user.is_a?(User)
90 if user && user.is_a?(User)
91 User.current = user
91 User.current = user
92 session[:user_id] = user.id
92 session[:user_id] = user.id
93 else
93 else
94 User.current = User.anonymous
94 User.current = User.anonymous
95 end
95 end
96 end
96 end
97
97
98 # check if login is globally required to access the application
98 # check if login is globally required to access the application
99 def check_if_login_required
99 def check_if_login_required
100 # no check needed if user is already logged in
100 # no check needed if user is already logged in
101 return true if User.current.logged?
101 return true if User.current.logged?
102 require_login if Setting.login_required?
102 require_login if Setting.login_required?
103 end
103 end
104
104
105 def set_localization
105 def set_localization
106 lang = nil
106 lang = nil
107 if User.current.logged?
107 if User.current.logged?
108 lang = find_language(User.current.language)
108 lang = find_language(User.current.language)
109 end
109 end
110 if lang.nil? && request.env['HTTP_ACCEPT_LANGUAGE']
110 if lang.nil? && request.env['HTTP_ACCEPT_LANGUAGE']
111 accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first.downcase
111 accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first.downcase
112 if !accept_lang.blank?
112 if !accept_lang.blank?
113 lang = find_language(accept_lang) || find_language(accept_lang.split('-').first)
113 lang = find_language(accept_lang) || find_language(accept_lang.split('-').first)
114 end
114 end
115 end
115 end
116 lang ||= Setting.default_language
116 lang ||= Setting.default_language
117 set_language_if_valid(lang)
117 set_language_if_valid(lang)
118 end
118 end
119
119
120 def require_login
120 def require_login
121 if !User.current.logged?
121 if !User.current.logged?
122 # Extract only the basic url parameters on non-GET requests
122 # Extract only the basic url parameters on non-GET requests
123 if request.get?
123 if request.get?
124 url = url_for(params)
124 url = url_for(params)
125 else
125 else
126 url = url_for(:controller => params[:controller], :action => params[:action], :id => params[:id], :project_id => params[:project_id])
126 url = url_for(:controller => params[:controller], :action => params[:action], :id => params[:id], :project_id => params[:project_id])
127 end
127 end
128 respond_to do |format|
128 respond_to do |format|
129 format.html { redirect_to :controller => "account", :action => "login", :back_url => url }
129 format.html { redirect_to :controller => "account", :action => "login", :back_url => url }
130 format.atom { redirect_to :controller => "account", :action => "login", :back_url => url }
130 format.atom { redirect_to :controller => "account", :action => "login", :back_url => url }
131 format.xml { head :unauthorized }
131 format.xml { head :unauthorized }
132 format.json { head :unauthorized }
132 format.json { head :unauthorized }
133 end
133 end
134 return false
134 return false
135 end
135 end
136 true
136 true
137 end
137 end
138
138
139 def require_admin
139 def require_admin
140 return unless require_login
140 return unless require_login
141 if !User.current.admin?
141 if !User.current.admin?
142 render_403
142 render_403
143 return false
143 return false
144 end
144 end
145 true
145 true
146 end
146 end
147
147
148 def deny_access
148 def deny_access
149 User.current.logged? ? render_403 : require_login
149 User.current.logged? ? render_403 : require_login
150 end
150 end
151
151
152 # Authorize the user for the requested action
152 # Authorize the user for the requested action
153 def authorize(ctrl = params[:controller], action = params[:action], global = false)
153 def authorize(ctrl = params[:controller], action = params[:action], global = false)
154 allowed = User.current.allowed_to?({:controller => ctrl, :action => action}, @project, :global => global)
154 allowed = User.current.allowed_to?({:controller => ctrl, :action => action}, @project, :global => global)
155 allowed ? true : deny_access
155 allowed ? true : deny_access
156 end
156 end
157
157
158 # Authorize the user for the requested action outside a project
158 # Authorize the user for the requested action outside a project
159 def authorize_global(ctrl = params[:controller], action = params[:action], global = true)
159 def authorize_global(ctrl = params[:controller], action = params[:action], global = true)
160 authorize(ctrl, action, global)
160 authorize(ctrl, action, global)
161 end
161 end
162
162
163 # Find project of id params[:id]
163 # Find project of id params[:id]
164 def find_project
164 def find_project
165 @project = Project.find(params[:id])
165 @project = Project.find(params[:id])
166 rescue ActiveRecord::RecordNotFound
166 rescue ActiveRecord::RecordNotFound
167 render_404
167 render_404
168 end
168 end
169
169
170 # Finds and sets @project based on @object.project
170 # Finds and sets @project based on @object.project
171 def find_project_from_association
171 def find_project_from_association
172 render_404 unless @object.present?
172 render_404 unless @object.present?
173
173
174 @project = @object.project
174 @project = @object.project
175 rescue ActiveRecord::RecordNotFound
175 rescue ActiveRecord::RecordNotFound
176 render_404
176 render_404
177 end
177 end
178
178
179 def find_model_object
180 model = self.class.read_inheritable_attribute('model_object')
181 if model
182 @object = model.find(params[:id])
183 self.instance_variable_set('@' + controller_name.singularize, @object) if @object
184 end
185 rescue ActiveRecord::RecordNotFound
186 render_404
187 end
188
189 def self.model_object(model)
190 write_inheritable_attribute('model_object', model)
191 end
192
179 # make sure that the user is a member of the project (or admin) if project is private
193 # make sure that the user is a member of the project (or admin) if project is private
180 # used as a before_filter for actions that do not require any particular permission on the project
194 # used as a before_filter for actions that do not require any particular permission on the project
181 def check_project_privacy
195 def check_project_privacy
182 if @project && @project.active?
196 if @project && @project.active?
183 if @project.is_public? || User.current.member_of?(@project) || User.current.admin?
197 if @project.is_public? || User.current.member_of?(@project) || User.current.admin?
184 true
198 true
185 else
199 else
186 User.current.logged? ? render_403 : require_login
200 User.current.logged? ? render_403 : require_login
187 end
201 end
188 else
202 else
189 @project = nil
203 @project = nil
190 render_404
204 render_404
191 false
205 false
192 end
206 end
193 end
207 end
194
208
195 def redirect_back_or_default(default)
209 def redirect_back_or_default(default)
196 back_url = CGI.unescape(params[:back_url].to_s)
210 back_url = CGI.unescape(params[:back_url].to_s)
197 if !back_url.blank?
211 if !back_url.blank?
198 begin
212 begin
199 uri = URI.parse(back_url)
213 uri = URI.parse(back_url)
200 # do not redirect user to another host or to the login or register page
214 # do not redirect user to another host or to the login or register page
201 if (uri.relative? || (uri.host == request.host)) && !uri.path.match(%r{/(login|account/register)})
215 if (uri.relative? || (uri.host == request.host)) && !uri.path.match(%r{/(login|account/register)})
202 redirect_to(back_url)
216 redirect_to(back_url)
203 return
217 return
204 end
218 end
205 rescue URI::InvalidURIError
219 rescue URI::InvalidURIError
206 # redirect to default
220 # redirect to default
207 end
221 end
208 end
222 end
209 redirect_to default
223 redirect_to default
210 end
224 end
211
225
212 def render_403
226 def render_403
213 @project = nil
227 @project = nil
214 respond_to do |format|
228 respond_to do |format|
215 format.html { render :template => "common/403", :layout => (request.xhr? ? false : 'base'), :status => 403 }
229 format.html { render :template => "common/403", :layout => (request.xhr? ? false : 'base'), :status => 403 }
216 format.atom { head 403 }
230 format.atom { head 403 }
217 format.xml { head 403 }
231 format.xml { head 403 }
218 format.json { head 403 }
232 format.json { head 403 }
219 end
233 end
220 return false
234 return false
221 end
235 end
222
236
223 def render_404
237 def render_404
224 respond_to do |format|
238 respond_to do |format|
225 format.html { render :template => "common/404", :layout => !request.xhr?, :status => 404 }
239 format.html { render :template => "common/404", :layout => !request.xhr?, :status => 404 }
226 format.atom { head 404 }
240 format.atom { head 404 }
227 format.xml { head 404 }
241 format.xml { head 404 }
228 format.json { head 404 }
242 format.json { head 404 }
229 end
243 end
230 return false
244 return false
231 end
245 end
232
246
233 def render_error(msg)
247 def render_error(msg)
234 respond_to do |format|
248 respond_to do |format|
235 format.html {
249 format.html {
236 flash.now[:error] = msg
250 flash.now[:error] = msg
237 render :text => '', :layout => !request.xhr?, :status => 500
251 render :text => '', :layout => !request.xhr?, :status => 500
238 }
252 }
239 format.atom { head 500 }
253 format.atom { head 500 }
240 format.xml { head 500 }
254 format.xml { head 500 }
241 format.json { head 500 }
255 format.json { head 500 }
242 end
256 end
243 end
257 end
244
258
245 def invalid_authenticity_token
259 def invalid_authenticity_token
246 if api_request?
260 if api_request?
247 logger.error "Form authenticity token is missing or is invalid. API calls must include a proper Content-type header (text/xml or text/json)."
261 logger.error "Form authenticity token is missing or is invalid. API calls must include a proper Content-type header (text/xml or text/json)."
248 end
262 end
249 render_error "Invalid form authenticity token."
263 render_error "Invalid form authenticity token."
250 end
264 end
251
265
252 def render_feed(items, options={})
266 def render_feed(items, options={})
253 @items = items || []
267 @items = items || []
254 @items.sort! {|x,y| y.event_datetime <=> x.event_datetime }
268 @items.sort! {|x,y| y.event_datetime <=> x.event_datetime }
255 @items = @items.slice(0, Setting.feeds_limit.to_i)
269 @items = @items.slice(0, Setting.feeds_limit.to_i)
256 @title = options[:title] || Setting.app_title
270 @title = options[:title] || Setting.app_title
257 render :template => "common/feed.atom.rxml", :layout => false, :content_type => 'application/atom+xml'
271 render :template => "common/feed.atom.rxml", :layout => false, :content_type => 'application/atom+xml'
258 end
272 end
259
273
260 def self.accept_key_auth(*actions)
274 def self.accept_key_auth(*actions)
261 actions = actions.flatten.map(&:to_s)
275 actions = actions.flatten.map(&:to_s)
262 write_inheritable_attribute('accept_key_auth_actions', actions)
276 write_inheritable_attribute('accept_key_auth_actions', actions)
263 end
277 end
264
278
265 def accept_key_auth_actions
279 def accept_key_auth_actions
266 self.class.read_inheritable_attribute('accept_key_auth_actions') || []
280 self.class.read_inheritable_attribute('accept_key_auth_actions') || []
267 end
281 end
268
282
269 # Returns the number of objects that should be displayed
283 # Returns the number of objects that should be displayed
270 # on the paginated list
284 # on the paginated list
271 def per_page_option
285 def per_page_option
272 per_page = nil
286 per_page = nil
273 if params[:per_page] && Setting.per_page_options_array.include?(params[:per_page].to_s.to_i)
287 if params[:per_page] && Setting.per_page_options_array.include?(params[:per_page].to_s.to_i)
274 per_page = params[:per_page].to_s.to_i
288 per_page = params[:per_page].to_s.to_i
275 session[:per_page] = per_page
289 session[:per_page] = per_page
276 elsif session[:per_page]
290 elsif session[:per_page]
277 per_page = session[:per_page]
291 per_page = session[:per_page]
278 else
292 else
279 per_page = Setting.per_page_options_array.first || 25
293 per_page = Setting.per_page_options_array.first || 25
280 end
294 end
281 per_page
295 per_page
282 end
296 end
283
297
284 # qvalues http header parser
298 # qvalues http header parser
285 # code taken from webrick
299 # code taken from webrick
286 def parse_qvalues(value)
300 def parse_qvalues(value)
287 tmp = []
301 tmp = []
288 if value
302 if value
289 parts = value.split(/,\s*/)
303 parts = value.split(/,\s*/)
290 parts.each {|part|
304 parts.each {|part|
291 if m = %r{^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$}.match(part)
305 if m = %r{^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$}.match(part)
292 val = m[1]
306 val = m[1]
293 q = (m[2] or 1).to_f
307 q = (m[2] or 1).to_f
294 tmp.push([val, q])
308 tmp.push([val, q])
295 end
309 end
296 }
310 }
297 tmp = tmp.sort_by{|val, q| -q}
311 tmp = tmp.sort_by{|val, q| -q}
298 tmp.collect!{|val, q| val}
312 tmp.collect!{|val, q| val}
299 end
313 end
300 return tmp
314 return tmp
301 rescue
315 rescue
302 nil
316 nil
303 end
317 end
304
318
305 # Returns a string that can be used as filename value in Content-Disposition header
319 # Returns a string that can be used as filename value in Content-Disposition header
306 def filename_for_content_disposition(name)
320 def filename_for_content_disposition(name)
307 request.env['HTTP_USER_AGENT'] =~ %r{MSIE} ? ERB::Util.url_encode(name) : name
321 request.env['HTTP_USER_AGENT'] =~ %r{MSIE} ? ERB::Util.url_encode(name) : name
308 end
322 end
309
323
310 def api_request?
324 def api_request?
311 %w(xml json).include? params[:format]
325 %w(xml json).include? params[:format]
312 end
326 end
313
327
314 # Renders a warning flash if obj has unsaved attachments
328 # Renders a warning flash if obj has unsaved attachments
315 def render_attachment_warning_if_needed(obj)
329 def render_attachment_warning_if_needed(obj)
316 flash[:warning] = l(:warning_attachments_not_saved, obj.unsaved_attachments.size) if obj.unsaved_attachments.present?
330 flash[:warning] = l(:warning_attachments_not_saved, obj.unsaved_attachments.size) if obj.unsaved_attachments.present?
317 end
331 end
318 end
332 end
@@ -1,91 +1,86
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class DocumentsController < ApplicationController
18 class DocumentsController < ApplicationController
19 default_search_scope :documents
19 default_search_scope :documents
20 model_object Document
20 before_filter :find_project, :only => [:index, :new]
21 before_filter :find_project, :only => [:index, :new]
21 before_filter :find_document, :except => [:index, :new]
22 before_filter :find_model_object, :except => [:index, :new]
22 before_filter :find_project_from_association, :except => [:index, :new]
23 before_filter :find_project_from_association, :except => [:index, :new]
23 before_filter :authorize
24 before_filter :authorize
24
25
25 helper :attachments
26 helper :attachments
26
27
27 def index
28 def index
28 @sort_by = %w(category date title author).include?(params[:sort_by]) ? params[:sort_by] : 'category'
29 @sort_by = %w(category date title author).include?(params[:sort_by]) ? params[:sort_by] : 'category'
29 documents = @project.documents.find :all, :include => [:attachments, :category]
30 documents = @project.documents.find :all, :include => [:attachments, :category]
30 case @sort_by
31 case @sort_by
31 when 'date'
32 when 'date'
32 @grouped = documents.group_by {|d| d.updated_on.to_date }
33 @grouped = documents.group_by {|d| d.updated_on.to_date }
33 when 'title'
34 when 'title'
34 @grouped = documents.group_by {|d| d.title.first.upcase}
35 @grouped = documents.group_by {|d| d.title.first.upcase}
35 when 'author'
36 when 'author'
36 @grouped = documents.select{|d| d.attachments.any?}.group_by {|d| d.attachments.last.author}
37 @grouped = documents.select{|d| d.attachments.any?}.group_by {|d| d.attachments.last.author}
37 else
38 else
38 @grouped = documents.group_by(&:category)
39 @grouped = documents.group_by(&:category)
39 end
40 end
40 @document = @project.documents.build
41 @document = @project.documents.build
41 render :layout => false if request.xhr?
42 render :layout => false if request.xhr?
42 end
43 end
43
44
44 def show
45 def show
45 @attachments = @document.attachments.find(:all, :order => "created_on DESC")
46 @attachments = @document.attachments.find(:all, :order => "created_on DESC")
46 end
47 end
47
48
48 def new
49 def new
49 @document = @project.documents.build(params[:document])
50 @document = @project.documents.build(params[:document])
50 if request.post? and @document.save
51 if request.post? and @document.save
51 attachments = Attachment.attach_files(@document, params[:attachments])
52 attachments = Attachment.attach_files(@document, params[:attachments])
52 render_attachment_warning_if_needed(@document)
53 render_attachment_warning_if_needed(@document)
53 flash[:notice] = l(:notice_successful_create)
54 flash[:notice] = l(:notice_successful_create)
54 redirect_to :action => 'index', :project_id => @project
55 redirect_to :action => 'index', :project_id => @project
55 end
56 end
56 end
57 end
57
58
58 def edit
59 def edit
59 @categories = DocumentCategory.all
60 @categories = DocumentCategory.all
60 if request.post? and @document.update_attributes(params[:document])
61 if request.post? and @document.update_attributes(params[:document])
61 flash[:notice] = l(:notice_successful_update)
62 flash[:notice] = l(:notice_successful_update)
62 redirect_to :action => 'show', :id => @document
63 redirect_to :action => 'show', :id => @document
63 end
64 end
64 end
65 end
65
66
66 def destroy
67 def destroy
67 @document.destroy
68 @document.destroy
68 redirect_to :controller => 'documents', :action => 'index', :project_id => @project
69 redirect_to :controller => 'documents', :action => 'index', :project_id => @project
69 end
70 end
70
71
71 def add_attachment
72 def add_attachment
72 attachments = Attachment.attach_files(@document, params[:attachments])
73 attachments = Attachment.attach_files(@document, params[:attachments])
73 render_attachment_warning_if_needed(@document)
74 render_attachment_warning_if_needed(@document)
74
75
75 Mailer.deliver_attachments_added(attachments[:files]) if attachments.present? && attachments[:files].present? && Setting.notified_events.include?('document_added')
76 Mailer.deliver_attachments_added(attachments[:files]) if attachments.present? && attachments[:files].present? && Setting.notified_events.include?('document_added')
76 redirect_to :action => 'show', :id => @document
77 redirect_to :action => 'show', :id => @document
77 end
78 end
78
79
79 private
80 private
80 def find_project
81 def find_project
81 @project = Project.find(params[:project_id])
82 @project = Project.find(params[:project_id])
82 rescue ActiveRecord::RecordNotFound
83 rescue ActiveRecord::RecordNotFound
83 render_404
84 render_404
84 end
85 end
85
86 def find_document
87 @document = @object = Document.find(params[:id])
88 rescue ActiveRecord::RecordNotFound
89 render_404
90 end
91 end
86 end
@@ -1,87 +1,89
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class IssueCategoriesController < ApplicationController
18 class IssueCategoriesController < ApplicationController
19 menu_item :settings
19 menu_item :settings
20 before_filter :find_category, :except => :new
20 model_object IssueCategory
21 before_filter :find_model_object, :except => :new
21 before_filter :find_project_from_association, :except => :new
22 before_filter :find_project_from_association, :except => :new
22 before_filter :find_project, :only => :new
23 before_filter :find_project, :only => :new
23 before_filter :authorize
24 before_filter :authorize
24
25
25 verify :method => :post, :only => :destroy
26 verify :method => :post, :only => :destroy
26
27
27 def new
28 def new
28 @category = @project.issue_categories.build(params[:category])
29 @category = @project.issue_categories.build(params[:category])
29 if request.post?
30 if request.post?
30 if @category.save
31 if @category.save
31 respond_to do |format|
32 respond_to do |format|
32 format.html do
33 format.html do
33 flash[:notice] = l(:notice_successful_create)
34 flash[:notice] = l(:notice_successful_create)
34 redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
35 redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
35 end
36 end
36 format.js do
37 format.js do
37 # IE doesn't support the replace_html rjs method for select box options
38 # IE doesn't support the replace_html rjs method for select box options
38 render(:update) {|page| page.replace "issue_category_id",
39 render(:update) {|page| page.replace "issue_category_id",
39 content_tag('select', '<option></option>' + options_from_collection_for_select(@project.issue_categories, 'id', 'name', @category.id), :id => 'issue_category_id', :name => 'issue[category_id]')
40 content_tag('select', '<option></option>' + options_from_collection_for_select(@project.issue_categories, 'id', 'name', @category.id), :id => 'issue_category_id', :name => 'issue[category_id]')
40 }
41 }
41 end
42 end
42 end
43 end
43 else
44 else
44 respond_to do |format|
45 respond_to do |format|
45 format.html
46 format.html
46 format.js do
47 format.js do
47 render(:update) {|page| page.alert(@category.errors.full_messages.join('\n')) }
48 render(:update) {|page| page.alert(@category.errors.full_messages.join('\n')) }
48 end
49 end
49 end
50 end
50 end
51 end
51 end
52 end
52 end
53 end
53
54
54 def edit
55 def edit
55 if request.post? and @category.update_attributes(params[:category])
56 if request.post? and @category.update_attributes(params[:category])
56 flash[:notice] = l(:notice_successful_update)
57 flash[:notice] = l(:notice_successful_update)
57 redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
58 redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
58 end
59 end
59 end
60 end
60
61
61 def destroy
62 def destroy
62 @issue_count = @category.issues.size
63 @issue_count = @category.issues.size
63 if @issue_count == 0
64 if @issue_count == 0
64 # No issue assigned to this category
65 # No issue assigned to this category
65 @category.destroy
66 @category.destroy
66 redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories'
67 redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories'
67 elsif params[:todo]
68 elsif params[:todo]
68 reassign_to = @project.issue_categories.find_by_id(params[:reassign_to_id]) if params[:todo] == 'reassign'
69 reassign_to = @project.issue_categories.find_by_id(params[:reassign_to_id]) if params[:todo] == 'reassign'
69 @category.destroy(reassign_to)
70 @category.destroy(reassign_to)
70 redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories'
71 redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories'
71 end
72 end
72 @categories = @project.issue_categories - [@category]
73 @categories = @project.issue_categories - [@category]
73 end
74 end
74
75
75 private
76 private
76 def find_category
77 # Wrap ApplicationController's find_model_object method to set
77 @category = @object = IssueCategory.find(params[:id])
78 # @category instead of just @issue_category
78 rescue ActiveRecord::RecordNotFound
79 def find_model_object
79 render_404
80 super
81 @category = @object
80 end
82 end
81
83
82 def find_project
84 def find_project
83 @project = Project.find(params[:project_id])
85 @project = Project.find(params[:project_id])
84 rescue ActiveRecord::RecordNotFound
86 rescue ActiveRecord::RecordNotFound
85 render_404
87 render_404
86 end
88 end
87 end
89 end
@@ -1,83 +1,78
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class MembersController < ApplicationController
18 class MembersController < ApplicationController
19 before_filter :find_member, :except => [:new, :autocomplete_for_member]
19 model_object Member
20 before_filter :find_model_object, :except => [:new, :autocomplete_for_member]
20 before_filter :find_project_from_association, :except => [:new, :autocomplete_for_member]
21 before_filter :find_project_from_association, :except => [:new, :autocomplete_for_member]
21 before_filter :find_project, :only => [:new, :autocomplete_for_member]
22 before_filter :find_project, :only => [:new, :autocomplete_for_member]
22 before_filter :authorize
23 before_filter :authorize
23
24
24 def new
25 def new
25 members = []
26 members = []
26 if params[:member] && request.post?
27 if params[:member] && request.post?
27 attrs = params[:member].dup
28 attrs = params[:member].dup
28 if (user_ids = attrs.delete(:user_ids))
29 if (user_ids = attrs.delete(:user_ids))
29 user_ids.each do |user_id|
30 user_ids.each do |user_id|
30 members << Member.new(attrs.merge(:user_id => user_id))
31 members << Member.new(attrs.merge(:user_id => user_id))
31 end
32 end
32 else
33 else
33 members << Member.new(attrs)
34 members << Member.new(attrs)
34 end
35 end
35 @project.members << members
36 @project.members << members
36 end
37 end
37 respond_to do |format|
38 respond_to do |format|
38 format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
39 format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
39 format.js {
40 format.js {
40 render(:update) {|page|
41 render(:update) {|page|
41 page.replace_html "tab-content-members", :partial => 'projects/settings/members'
42 page.replace_html "tab-content-members", :partial => 'projects/settings/members'
42 members.each {|member| page.visual_effect(:highlight, "member-#{member.id}") }
43 members.each {|member| page.visual_effect(:highlight, "member-#{member.id}") }
43 }
44 }
44 }
45 }
45 end
46 end
46 end
47 end
47
48
48 def edit
49 def edit
49 if request.post? and @member.update_attributes(params[:member])
50 if request.post? and @member.update_attributes(params[:member])
50 respond_to do |format|
51 respond_to do |format|
51 format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
52 format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
52 format.js {
53 format.js {
53 render(:update) {|page|
54 render(:update) {|page|
54 page.replace_html "tab-content-members", :partial => 'projects/settings/members'
55 page.replace_html "tab-content-members", :partial => 'projects/settings/members'
55 page.visual_effect(:highlight, "member-#{@member.id}")
56 page.visual_effect(:highlight, "member-#{@member.id}")
56 }
57 }
57 }
58 }
58 end
59 end
59 end
60 end
60 end
61 end
61
62
62 def destroy
63 def destroy
63 if request.post? && @member.deletable?
64 if request.post? && @member.deletable?
64 @member.destroy
65 @member.destroy
65 end
66 end
66 respond_to do |format|
67 respond_to do |format|
67 format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
68 format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
68 format.js { render(:update) {|page| page.replace_html "tab-content-members", :partial => 'projects/settings/members'} }
69 format.js { render(:update) {|page| page.replace_html "tab-content-members", :partial => 'projects/settings/members'} }
69 end
70 end
70 end
71 end
71
72
72 def autocomplete_for_member
73 def autocomplete_for_member
73 @principals = Principal.active.like(params[:q]).find(:all, :limit => 100) - @project.principals
74 @principals = Principal.active.like(params[:q]).find(:all, :limit => 100) - @project.principals
74 render :layout => false
75 render :layout => false
75 end
76 end
76
77
77 private
78 def find_member
79 @member = @object = Member.find(params[:id])
80 rescue ActiveRecord::RecordNotFound
81 render_404
82 end
83 end
78 end
@@ -1,111 +1,106
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class NewsController < ApplicationController
18 class NewsController < ApplicationController
19 default_search_scope :news
19 default_search_scope :news
20 before_filter :find_news, :except => [:new, :index, :preview]
20 model_object News
21 before_filter :find_model_object, :except => [:new, :index, :preview]
21 before_filter :find_project_from_association, :except => [:new, :index, :preview]
22 before_filter :find_project_from_association, :except => [:new, :index, :preview]
22 before_filter :find_project, :only => [:new, :preview]
23 before_filter :find_project, :only => [:new, :preview]
23 before_filter :authorize, :except => [:index, :preview]
24 before_filter :authorize, :except => [:index, :preview]
24 before_filter :find_optional_project, :only => :index
25 before_filter :find_optional_project, :only => :index
25 accept_key_auth :index
26 accept_key_auth :index
26
27
27 def index
28 def index
28 @news_pages, @newss = paginate :news,
29 @news_pages, @newss = paginate :news,
29 :per_page => 10,
30 :per_page => 10,
30 :conditions => Project.allowed_to_condition(User.current, :view_news, :project => @project),
31 :conditions => Project.allowed_to_condition(User.current, :view_news, :project => @project),
31 :include => [:author, :project],
32 :include => [:author, :project],
32 :order => "#{News.table_name}.created_on DESC"
33 :order => "#{News.table_name}.created_on DESC"
33 respond_to do |format|
34 respond_to do |format|
34 format.html { render :layout => false if request.xhr? }
35 format.html { render :layout => false if request.xhr? }
35 format.xml { render :xml => @newss.to_xml }
36 format.xml { render :xml => @newss.to_xml }
36 format.json { render :json => @newss.to_json }
37 format.json { render :json => @newss.to_json }
37 format.atom { render_feed(@newss, :title => (@project ? @project.name : Setting.app_title) + ": #{l(:label_news_plural)}") }
38 format.atom { render_feed(@newss, :title => (@project ? @project.name : Setting.app_title) + ": #{l(:label_news_plural)}") }
38 end
39 end
39 end
40 end
40
41
41 def show
42 def show
42 @comments = @news.comments
43 @comments = @news.comments
43 @comments.reverse! if User.current.wants_comments_in_reverse_order?
44 @comments.reverse! if User.current.wants_comments_in_reverse_order?
44 end
45 end
45
46
46 def new
47 def new
47 @news = News.new(:project => @project, :author => User.current)
48 @news = News.new(:project => @project, :author => User.current)
48 if request.post?
49 if request.post?
49 @news.attributes = params[:news]
50 @news.attributes = params[:news]
50 if @news.save
51 if @news.save
51 flash[:notice] = l(:notice_successful_create)
52 flash[:notice] = l(:notice_successful_create)
52 redirect_to :controller => 'news', :action => 'index', :project_id => @project
53 redirect_to :controller => 'news', :action => 'index', :project_id => @project
53 end
54 end
54 end
55 end
55 end
56 end
56
57
57 def edit
58 def edit
58 if request.post? and @news.update_attributes(params[:news])
59 if request.post? and @news.update_attributes(params[:news])
59 flash[:notice] = l(:notice_successful_update)
60 flash[:notice] = l(:notice_successful_update)
60 redirect_to :action => 'show', :id => @news
61 redirect_to :action => 'show', :id => @news
61 end
62 end
62 end
63 end
63
64
64 def add_comment
65 def add_comment
65 @comment = Comment.new(params[:comment])
66 @comment = Comment.new(params[:comment])
66 @comment.author = User.current
67 @comment.author = User.current
67 if @news.comments << @comment
68 if @news.comments << @comment
68 flash[:notice] = l(:label_comment_added)
69 flash[:notice] = l(:label_comment_added)
69 redirect_to :action => 'show', :id => @news
70 redirect_to :action => 'show', :id => @news
70 else
71 else
71 show
72 show
72 render :action => 'show'
73 render :action => 'show'
73 end
74 end
74 end
75 end
75
76
76 def destroy_comment
77 def destroy_comment
77 @news.comments.find(params[:comment_id]).destroy
78 @news.comments.find(params[:comment_id]).destroy
78 redirect_to :action => 'show', :id => @news
79 redirect_to :action => 'show', :id => @news
79 end
80 end
80
81
81 def destroy
82 def destroy
82 @news.destroy
83 @news.destroy
83 redirect_to :action => 'index', :project_id => @project
84 redirect_to :action => 'index', :project_id => @project
84 end
85 end
85
86
86 def preview
87 def preview
87 @text = (params[:news] ? params[:news][:description] : nil)
88 @text = (params[:news] ? params[:news][:description] : nil)
88 render :partial => 'common/preview'
89 render :partial => 'common/preview'
89 end
90 end
90
91
91 private
92 private
92 def find_news
93 @news = @object = News.find(params[:id])
94 rescue ActiveRecord::RecordNotFound
95 render_404
96 end
97
98 def find_project
93 def find_project
99 @project = Project.find(params[:project_id])
94 @project = Project.find(params[:project_id])
100 rescue ActiveRecord::RecordNotFound
95 rescue ActiveRecord::RecordNotFound
101 render_404
96 render_404
102 end
97 end
103
98
104 def find_optional_project
99 def find_optional_project
105 return true unless params[:project_id]
100 return true unless params[:project_id]
106 @project = Project.find(params[:project_id])
101 @project = Project.find(params[:project_id])
107 authorize
102 authorize
108 rescue ActiveRecord::RecordNotFound
103 rescue ActiveRecord::RecordNotFound
109 render_404
104 render_404
110 end
105 end
111 end
106 end
@@ -1,108 +1,103
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class VersionsController < ApplicationController
18 class VersionsController < ApplicationController
19 menu_item :roadmap
19 menu_item :roadmap
20 before_filter :find_version, :except => [:new, :close_completed]
20 model_object Version
21 before_filter :find_model_object, :except => [:new, :close_completed]
21 before_filter :find_project_from_association, :except => [:new, :close_completed]
22 before_filter :find_project_from_association, :except => [:new, :close_completed]
22 before_filter :find_project, :only => [:new, :close_completed]
23 before_filter :find_project, :only => [:new, :close_completed]
23 before_filter :authorize
24 before_filter :authorize
24
25
25 helper :custom_fields
26 helper :custom_fields
26 helper :projects
27 helper :projects
27
28
28 def show
29 def show
29 end
30 end
30
31
31 def new
32 def new
32 @version = @project.versions.build
33 @version = @project.versions.build
33 if params[:version]
34 if params[:version]
34 attributes = params[:version].dup
35 attributes = params[:version].dup
35 attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing'])
36 attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing'])
36 @version.attributes = attributes
37 @version.attributes = attributes
37 end
38 end
38 if request.post?
39 if request.post?
39 if @version.save
40 if @version.save
40 respond_to do |format|
41 respond_to do |format|
41 format.html do
42 format.html do
42 flash[:notice] = l(:notice_successful_create)
43 flash[:notice] = l(:notice_successful_create)
43 redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
44 redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
44 end
45 end
45 format.js do
46 format.js do
46 # IE doesn't support the replace_html rjs method for select box options
47 # IE doesn't support the replace_html rjs method for select box options
47 render(:update) {|page| page.replace "issue_fixed_version_id",
48 render(:update) {|page| page.replace "issue_fixed_version_id",
48 content_tag('select', '<option></option>' + version_options_for_select(@project.shared_versions.open, @version), :id => 'issue_fixed_version_id', :name => 'issue[fixed_version_id]')
49 content_tag('select', '<option></option>' + version_options_for_select(@project.shared_versions.open, @version), :id => 'issue_fixed_version_id', :name => 'issue[fixed_version_id]')
49 }
50 }
50 end
51 end
51 end
52 end
52 else
53 else
53 respond_to do |format|
54 respond_to do |format|
54 format.html
55 format.html
55 format.js do
56 format.js do
56 render(:update) {|page| page.alert(@version.errors.full_messages.join('\n')) }
57 render(:update) {|page| page.alert(@version.errors.full_messages.join('\n')) }
57 end
58 end
58 end
59 end
59 end
60 end
60 end
61 end
61 end
62 end
62
63
63 def edit
64 def edit
64 if request.post? && params[:version]
65 if request.post? && params[:version]
65 attributes = params[:version].dup
66 attributes = params[:version].dup
66 attributes.delete('sharing') unless @version.allowed_sharings.include?(attributes['sharing'])
67 attributes.delete('sharing') unless @version.allowed_sharings.include?(attributes['sharing'])
67 if @version.update_attributes(attributes)
68 if @version.update_attributes(attributes)
68 flash[:notice] = l(:notice_successful_update)
69 flash[:notice] = l(:notice_successful_update)
69 redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
70 redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
70 end
71 end
71 end
72 end
72 end
73 end
73
74
74 def close_completed
75 def close_completed
75 if request.post?
76 if request.post?
76 @project.close_completed_versions
77 @project.close_completed_versions
77 end
78 end
78 redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
79 redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
79 end
80 end
80
81
81 def destroy
82 def destroy
82 @version.destroy
83 @version.destroy
83 redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
84 redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
84 rescue
85 rescue
85 flash[:error] = l(:notice_unable_delete_version)
86 flash[:error] = l(:notice_unable_delete_version)
86 redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
87 redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
87 end
88 end
88
89
89 def status_by
90 def status_by
90 respond_to do |format|
91 respond_to do |format|
91 format.html { render :action => 'show' }
92 format.html { render :action => 'show' }
92 format.js { render(:update) {|page| page.replace_html 'status_by', render_issue_status_by(@version, params[:status_by])} }
93 format.js { render(:update) {|page| page.replace_html 'status_by', render_issue_status_by(@version, params[:status_by])} }
93 end
94 end
94 end
95 end
95
96
96 private
97 private
97 def find_version
98 @version = @object = Version.find(params[:id])
99 rescue ActiveRecord::RecordNotFound
100 render_404
101 end
102
103 def find_project
98 def find_project
104 @project = Project.find(params[:project_id])
99 @project = Project.find(params[:project_id])
105 rescue ActiveRecord::RecordNotFound
100 rescue ActiveRecord::RecordNotFound
106 render_404
101 render_404
107 end
102 end
108 end
103 end
General Comments 0
You need to be logged in to leave comments. Login now