Class: ApplicationController
- Inherits:
-
ActionController::Base
- Object
- ActionController::Base
- ApplicationController
- Defined in:
- app/controllers/application_controller.rb
Direct Known Subclasses
AccountController, ActivitiesController, AdminController, AttachmentsController, AuthSourcesController, AutoCompletesController, BoardsController, CalendarsController, CommentsController, ContextMenusController, CustomFieldsController, DocumentsController, EnumerationsController, FilesController, GanttsController, GroupsController, IssueCategoriesController, IssueMovesController, IssueRelationsController, IssueStatusesController, IssuesController, JournalsController, MembersController, MessagesController, MyController, NewsController, PreviewsController, ProjectEnumerationsController, ProjectsController, QueriesController, ReportsController, RepositoriesController, RolesController, SearchController, SettingsController, TimeEntryReportsController, TimelogController, TrackersController, UsersController, VersionsController, WatchersController, WelcomeController, WikiController, WikisController, WorkflowsController
Class Method Summary collapse
Instance Method Summary collapse
- #accept_key_auth_actions ⇒ Object
-
#api_key_from_request ⇒ Object
Returns the API key present in the request.
-
#api_offset_and_limit(options = params) ⇒ Object
Returns offset and limit used to retrieve objects for an API response based on offset, limit and page parameters.
- #api_request? ⇒ Boolean
-
#authorize(ctrl = , action = , global = false) ⇒ Object
Authorize the user for the requested action.
-
#authorize_global(ctrl = , action = , global = true) ⇒ Object
Authorize the user for the requested action outside a project.
- #back_url ⇒ Object
-
#check_if_login_required ⇒ Object
check if login is globally required to access the application.
-
#check_project_privacy ⇒ Object
make sure that the user is a member of the project (or admin) if project is private used as a before_filter for actions that do not require any particular permission on the project.
-
#check_project_uniqueness ⇒ Object
Check if project is unique before bulk operations.
-
#default_template(action_name = self.action_name) ⇒ Object
Overrides #default_template so that the api template is used automatically if it exists.
- #delete_broken_cookies ⇒ Object
- #deny_access ⇒ Object
-
#filename_for_content_disposition(name) ⇒ Object
Returns a string that can be used as filename value in Content-Disposition header.
-
#find_current_user ⇒ Object
Returns the current user or nil if no user is logged in and starts a session if needed.
-
#find_issues ⇒ Object
Filter for bulk issue operations.
- #find_model_object ⇒ Object
-
#find_optional_project ⇒ Object
Find a project based on params TODO: some subclasses override this, see about merging their logic.
-
#find_project ⇒ Object
Find project of id params.
-
#find_project_by_project_id ⇒ Object
Find project of id params.
-
#find_project_from_association ⇒ Object
Finds and sets @project based on @object.project.
- #invalid_authenticity_token ⇒ Object
-
#logged_user=(user) ⇒ Object
Sets the logged in user.
-
#object_errors_to_json(object) ⇒ Object
Converts the errors on an ActiveRecord object into a common JSON format.
-
#parse_qvalues(value) ⇒ Object
qvalues http header parser code taken from webrick.
-
#per_page_option ⇒ Object
Returns the number of objects that should be displayed on the paginated list.
-
#pick_layout(*args) ⇒ Object
Overrides #pick_layout so that #render with no arguments doesn’t use the layout for api requests.
-
#query_statement_invalid(exception) ⇒ Object
Rescues an invalid query statement.
- #redirect_back_or_default(default) ⇒ Object
- #render_403(options = {}) ⇒ Object
- #render_404(options = {}) ⇒ Object
-
#render_attachment_warning_if_needed(obj) ⇒ Object
Renders a warning flash if obj has unsaved attachments.
-
#render_error(arg) ⇒ Object
Renders an error response.
- #render_feed(items, options = {}) ⇒ Object
-
#render_validation_errors(object) ⇒ Object
Renders API response on validation failure.
- #require_admin ⇒ Object
- #require_login ⇒ Object
-
#set_flash_from_bulk_issue_save(issues, unsaved_issue_ids) ⇒ Object
Sets the ‘flash` notice or error based the number of issues that did not save.
- #set_localization ⇒ Object
-
#use_layout ⇒ boolean, string
Picks which layout to use based on the request.
- #user_setup ⇒ Object
Methods included from Redmine::MenuManager::MenuController
#current_menu_item, included, #menu_items, #redirect_to_project_menu_item
Methods included from Redmine::Search::Controller
#default_search_scope, #default_search_scopes, included
Methods included from Redmine::I18n
#current_language, #day_name, #find_language, #format_date, #format_time, included, #l, #l_hours, #l_or_humanize, #ll, #month_name, #set_language_if_valid, #valid_languages
Class Method Details
.accept_key_auth(*actions) ⇒ Object
328 329 330 331 |
# File 'app/controllers/application_controller.rb', line 328 def self.accept_key_auth(*actions) actions = actions.flatten.map(&:to_s) write_inheritable_attribute('accept_key_auth_actions', actions) end |
.model_object(model) ⇒ Object
216 217 218 |
# File 'app/controllers/application_controller.rb', line 216 def self.model_object(model) write_inheritable_attribute('model_object', model) end |
Instance Method Details
#accept_key_auth_actions ⇒ Object
333 334 335 |
# File 'app/controllers/application_controller.rb', line 333 def accept_key_auth_actions self.class.read_inheritable_attribute('accept_key_auth_actions') || [] end |
#api_key_from_request ⇒ Object
Returns the API key present in the request
407 408 409 410 411 412 413 |
# File 'app/controllers/application_controller.rb', line 407 def api_key_from_request if params[:key].present? params[:key] elsif request.headers["X-Redmine-API-Key"].present? request.headers["X-Redmine-API-Key"] end end |
#api_offset_and_limit(options = params) ⇒ Object
Returns offset and limit used to retrieve objects for an API response based on offset, limit and page parameters
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 |
# File 'app/controllers/application_controller.rb', line 354 def api_offset_and_limit(=params) if [:offset].present? offset = [:offset].to_i if offset < 0 offset = 0 end end limit = [:limit].to_i if limit < 1 limit = 25 elsif limit > 100 limit = 100 end if offset.nil? && [:page].present? offset = ([:page].to_i - 1) * limit offset = 0 if offset < 0 end offset ||= 0 [offset, limit] end |
#api_request? ⇒ Boolean
402 403 404 |
# File 'app/controllers/application_controller.rb', line 402 def api_request? %w(xml json).include? params[:format] end |
#authorize(ctrl = , action = , global = false) ⇒ Object
Authorize the user for the requested action
155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'app/controllers/application_controller.rb', line 155 def (ctrl = params[:controller], action = params[:action], global = false) allowed = User.current.allowed_to?({:controller => ctrl, :action => action}, @project || @projects, :global => global) if allowed true else if @project && @project.archived? render_403 :message => :notice_not_authorized_archived_project else deny_access end end end |
#authorize_global(ctrl = , action = , global = true) ⇒ Object
Authorize the user for the requested action outside a project
169 170 171 |
# File 'app/controllers/application_controller.rb', line 169 def (ctrl = params[:controller], action = params[:action], global = true) (ctrl, action, global) end |
#back_url ⇒ Object
255 256 257 |
# File 'app/controllers/application_controller.rb', line 255 def back_url params[:back_url] || request.env['HTTP_REFERER'] end |
#check_if_login_required ⇒ Object
check if login is globally required to access the application
99 100 101 102 103 |
# File 'app/controllers/application_controller.rb', line 99 def check_if_login_required # no check needed if user is already logged in return true if User.current.logged? require_login if Setting.login_required? end |
#check_project_privacy ⇒ Object
make sure that the user is a member of the project (or admin) if project is private used as a before_filter for actions that do not require any particular permission on the project
241 242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'app/controllers/application_controller.rb', line 241 def check_project_privacy if @project && @project.active? if @project.is_public? || User.current.member_of?(@project) || User.current.admin? true else User.current.logged? ? render_403 : require_login end else @project = nil render_404 false end end |
#check_project_uniqueness ⇒ Object
Check if project is unique before bulk operations
231 232 233 234 235 236 237 |
# File 'app/controllers/application_controller.rb', line 231 def check_project_uniqueness unless @project # TODO: let users bulk edit/move/destroy issues from different projects render_error 'Can not bulk edit/move/destroy issues from different projects' return false end end |
#default_template(action_name = self.action_name) ⇒ Object
Overrides #default_template so that the api template is used automatically if it exists
465 466 467 468 469 470 471 472 473 474 475 |
# File 'app/controllers/application_controller.rb', line 465 def default_template(action_name = self.action_name) if api_request? begin return self.view_paths.find_template(default_template_name(action_name), 'api') rescue ::ActionView::MissingTemplate # the api template was not found # fallback to the default behaviour end end super end |
#delete_broken_cookies ⇒ Object
31 32 33 34 35 36 37 |
# File 'app/controllers/application_controller.rb', line 31 def if ['_redmine_session'] && ['_redmine_session'] !~ /--/ .delete '_redmine_session' redirect_to home_path return false end end |
#deny_access ⇒ Object
150 151 152 |
# File 'app/controllers/application_controller.rb', line 150 def deny_access User.current.logged? ? render_403 : require_login end |
#filename_for_content_disposition(name) ⇒ Object
Returns a string that can be used as filename value in Content-Disposition header
398 399 400 |
# File 'app/controllers/application_controller.rb', line 398 def filename_for_content_disposition(name) request.env['HTTP_USER_AGENT'] =~ %r{MSIE} ? ERB::Util.url_encode(name) : name end |
#find_current_user ⇒ Object
Returns the current user or nil if no user is logged in and starts a session if needed
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'app/controllers/application_controller.rb', line 62 def find_current_user if session[:user_id] # existing session (User.active.find(session[:user_id]) rescue nil) elsif [:autologin] && Setting.autologin? # auto-login feature starts a new session user = User.try_to_autologin([:autologin]) session[:user_id] = user.id if user user elsif params[:format] == 'atom' && params[:key] && accept_key_auth_actions.include?(params[:action]) # RSS key authentication does not start a session User.find_by_rss_key(params[:key]) elsif Setting.rest_api_enabled? && api_request? if (key = api_key_from_request) && accept_key_auth_actions.include?(params[:action]) # Use API key User.find_by_api_key(key) else # HTTP Basic, either username/password or API key/random authenticate_with_http_basic do |username, password| User.try_to_login(username, password) || User.find_by_api_key(username) end end end end |
#find_issues ⇒ Object
Filter for bulk issue operations
221 222 223 224 225 226 227 228 |
# File 'app/controllers/application_controller.rb', line 221 def find_issues @issues = Issue.find_all_by_id(params[:id] || params[:ids]) raise ActiveRecord::RecordNotFound if @issues.empty? @projects = @issues.collect(&:project).compact.uniq @project = @projects.first if @projects.size == 1 rescue ActiveRecord::RecordNotFound render_404 end |
#find_model_object ⇒ Object
206 207 208 209 210 211 212 213 214 |
# File 'app/controllers/application_controller.rb', line 206 def find_model_object model = self.class.read_inheritable_attribute('model_object') if model @object = model.find(params[:id]) self.instance_variable_set('@' + controller_name.singularize, @object) if @object end rescue ActiveRecord::RecordNotFound render_404 end |
#find_optional_project ⇒ Object
Find a project based on params TODO: some subclasses override this, see about merging their logic
189 190 191 192 193 194 195 |
# File 'app/controllers/application_controller.rb', line 189 def find_optional_project @project = Project.find(params[:project_id]) unless params[:project_id].blank? allowed = User.current.allowed_to?({:controller => params[:controller], :action => params[:action]}, @project, :global => true) allowed ? true : deny_access rescue ActiveRecord::RecordNotFound render_404 end |
#find_project ⇒ Object
Find project of id params
174 175 176 177 178 |
# File 'app/controllers/application_controller.rb', line 174 def find_project @project = Project.find(params[:id]) rescue ActiveRecord::RecordNotFound render_404 end |
#find_project_by_project_id ⇒ Object
Find project of id params
181 182 183 184 185 |
# File 'app/controllers/application_controller.rb', line 181 def find_project_by_project_id @project = Project.find(params[:project_id]) rescue ActiveRecord::RecordNotFound render_404 end |
#find_project_from_association ⇒ Object
Finds and sets @project based on @object.project
198 199 200 201 202 203 204 |
# File 'app/controllers/application_controller.rb', line 198 def find_project_from_association render_404 unless @object.present? @project = @object.project rescue ActiveRecord::RecordNotFound render_404 end |
#invalid_authenticity_token ⇒ Object
313 314 315 316 317 318 |
# File 'app/controllers/application_controller.rb', line 313 def invalid_authenticity_token if api_request? logger.error "Form authenticity token is missing or is invalid. API calls must include a proper Content-type header (text/xml or text/json)." end render_error "Invalid form authenticity token." end |
#logged_user=(user) ⇒ Object
Sets the logged in user
88 89 90 91 92 93 94 95 96 |
# File 'app/controllers/application_controller.rb', line 88 def logged_user=(user) reset_session if user && user.is_a?(User) User.current = user session[:user_id] = user.id else User.current = User.anonymous end end |
#object_errors_to_json(object) ⇒ Object
Converts the errors on an ActiveRecord object into a common JSON format
444 445 446 447 448 |
# File 'app/controllers/application_controller.rb', line 444 def object_errors_to_json(object) object.errors.collect do |attribute, error| { attribute => error } end.to_json end |
#parse_qvalues(value) ⇒ Object
qvalues http header parser code taken from webrick
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 |
# File 'app/controllers/application_controller.rb', line 378 def parse_qvalues(value) tmp = [] if value parts = value.split(/,\s*/) parts.each {|part| if m = %r{^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$}.match(part) val = m[1] q = (m[2] or 1).to_f tmp.push([val, q]) end } tmp = tmp.sort_by{|val, q| -q} tmp.collect!{|val, q| val} end return tmp rescue nil end |
#per_page_option ⇒ Object
Returns the number of objects that should be displayed on the paginated list
339 340 341 342 343 344 345 346 347 348 349 350 |
# File 'app/controllers/application_controller.rb', line 339 def per_page_option per_page = nil if params[:per_page] && Setting..include?(params[:per_page].to_s.to_i) per_page = params[:per_page].to_s.to_i session[:per_page] = per_page elsif session[:per_page] per_page = session[:per_page] else per_page = Setting..first || 25 end per_page end |
#pick_layout(*args) ⇒ Object
Overrides #pick_layout so that #render with no arguments doesn’t use the layout for api requests
479 480 481 |
# File 'app/controllers/application_controller.rb', line 479 def pick_layout(*args) api_request? ? nil : super end |
#query_statement_invalid(exception) ⇒ Object
Rescues an invalid query statement. Just in case…
436 437 438 439 440 441 |
# File 'app/controllers/application_controller.rb', line 436 def query_statement_invalid(exception) logger.error "Query::StatementInvalid: #{exception.}" if logger session.delete(:query) sort_clear if respond_to?(:sort_clear) render_error "An error occurred while executing the query and has been logged. Please report this error to your Redmine administrator." end |
#redirect_back_or_default(default) ⇒ Object
259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
# File 'app/controllers/application_controller.rb', line 259 def redirect_back_or_default(default) back_url = CGI.unescape(params[:back_url].to_s) if !back_url.blank? begin uri = URI.parse(back_url) # do not redirect user to another host or to the login or register page if (uri.relative? || (uri.host == request.host)) && !uri.path.match(%r{/(login|account/register)}) redirect_to(back_url) return end rescue URI::InvalidURIError # redirect to default end end redirect_to default end |
#render_403(options = {}) ⇒ Object
276 277 278 279 280 |
# File 'app/controllers/application_controller.rb', line 276 def render_403(={}) @project = nil render_error({:message => :notice_not_authorized, :status => 403}.merge()) return false end |
#render_404(options = {}) ⇒ Object
282 283 284 285 |
# File 'app/controllers/application_controller.rb', line 282 def render_404(={}) render_error({:message => :notice_file_not_found, :status => 404}.merge()) return false end |
#render_attachment_warning_if_needed(obj) ⇒ Object
Renders a warning flash if obj has unsaved attachments
416 417 418 |
# File 'app/controllers/application_controller.rb', line 416 def (obj) flash[:warning] = l(:warning_attachments_not_saved, obj..size) if obj..present? end |
#render_error(arg) ⇒ Object
Renders an error response
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 |
# File 'app/controllers/application_controller.rb', line 288 def render_error(arg) arg = {:message => arg} unless arg.is_a?(Hash) @message = arg[:message] @message = l(@message) if @message.is_a?(Symbol) @status = arg[:status] || 500 respond_to do |format| format.html { render :template => 'common/error', :layout => use_layout, :status => @status } format.atom { head @status } format.xml { head @status } format.js { head @status } format.json { head @status } end end |
#render_feed(items, options = {}) ⇒ Object
320 321 322 323 324 325 326 |
# File 'app/controllers/application_controller.rb', line 320 def render_feed(items, ={}) @items = items || [] @items.sort! {|x,y| y.event_datetime <=> x.event_datetime } @items = @items.slice(0, Setting.feeds_limit.to_i) @title = [:title] || Setting.app_title render :template => "common/feed.atom.rxml", :layout => false, :content_type => 'application/atom+xml' end |
#render_validation_errors(object) ⇒ Object
Renders API response on validation failure
451 452 453 454 455 456 457 458 459 460 461 |
# File 'app/controllers/application_controller.rb', line 451 def render_validation_errors(object) = { :status => :unprocessable_entity, :layout => false } .merge!(case params[:format] when 'xml'; { :xml => object.errors } when 'json'; { :json => {'errors' => object.errors} } # ActiveResource client compliance else raise "Unknown format #{params[:format]} in #render_validation_errors" end ) render end |
#require_admin ⇒ Object
141 142 143 144 145 146 147 148 |
# File 'app/controllers/application_controller.rb', line 141 def require_admin return unless require_login if !User.current.admin? render_403 return false end true end |
#require_login ⇒ Object
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'app/controllers/application_controller.rb', line 121 def require_login if !User.current.logged? # Extract only the basic url parameters on non-GET requests if request.get? url = url_for(params) else url = url_for(:controller => params[:controller], :action => params[:action], :id => params[:id], :project_id => params[:project_id]) end respond_to do |format| format.html { redirect_to :controller => "account", :action => "login", :back_url => url } format.atom { redirect_to :controller => "account", :action => "login", :back_url => url } format.xml { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' } format.js { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' } format.json { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' } end return false end true end |
#set_flash_from_bulk_issue_save(issues, unsaved_issue_ids) ⇒ Object
Sets the ‘flash` notice or error based the number of issues that did not save
424 425 426 427 428 429 430 431 432 433 |
# File 'app/controllers/application_controller.rb', line 424 def set_flash_from_bulk_issue_save(issues, unsaved_issue_ids) if unsaved_issue_ids.empty? flash[:notice] = l(:notice_successful_update) unless issues.empty? else flash[:error] = l(:notice_failed_to_save_issues, :count => unsaved_issue_ids.size, :total => issues.size, :ids => '#' + unsaved_issue_ids.join(', #')) end end |
#set_localization ⇒ Object
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'app/controllers/application_controller.rb', line 105 def set_localization lang = nil if User.current.logged? lang = find_language(User.current.language) end if lang.nil? && request.env['HTTP_ACCEPT_LANGUAGE'] accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first if !accept_lang.blank? accept_lang = accept_lang.downcase lang = find_language(accept_lang) || find_language(accept_lang.split('-').first) end end lang ||= Setting.default_language set_language_if_valid(lang) end |
#use_layout ⇒ boolean, string
Picks which layout to use based on the request
309 310 311 |
# File 'app/controllers/application_controller.rb', line 309 def use_layout request.xhr? ? false : 'base' end |
#user_setup ⇒ Object
53 54 55 56 57 58 |
# File 'app/controllers/application_controller.rb', line 53 def user_setup # Check the settings cache for each request Setting.check_cache # Find the current user User.current = find_current_user end |