application_controller.rb
252 lines
| 7.6 KiB
| text/x-ruby
|
RubyLexer
|
r330 | # redMine - project management software | ||
# Copyright (C) 2006-2007 Jean-Philippe Lang | ||||
# | ||||
# This program is free software; you can redistribute it and/or | ||||
# modify it under the terms of the GNU General Public License | ||||
# as published by the Free Software Foundation; either version 2 | ||||
# of the License, or (at your option) any later version. | ||||
# | ||||
# This program is distributed in the hope that it will be useful, | ||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
# GNU General Public License for more details. | ||||
# | ||||
# You should have received a copy of the GNU General Public License | ||||
# along with this program; if not, write to the Free Software | ||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
|
r1686 | require 'uri' | ||
|
r1891 | require 'cgi' | ||
|
r1686 | |||
|
r330 | class ApplicationController < ActionController::Base | ||
|
r2430 | include Redmine::I18n | ||
|
r2773 | |||
|
r1726 | layout 'base' | ||
|
r663 | before_filter :user_setup, :check_if_login_required, :set_localization | ||
|
r330 | filter_parameter_logging :password | ||
|
r2829 | include Redmine::Search::Controller | ||
|
r1062 | include Redmine::MenuManager::MenuController | ||
helper Redmine::MenuManager::MenuHelper | ||||
|
r558 | REDMINE_SUPPORTED_SCM.each do |scm| | ||
require_dependency "repository/#{scm.underscore}" | ||||
end | ||||
|
r663 | def user_setup | ||
|
r1016 | # Check the settings cache for each request | ||
|
r674 | Setting.check_cache | ||
|
r1016 | # Find the current user | ||
|
r2679 | User.current = find_current_user | ||
|
r1016 | end | ||
# Returns the current user or nil if no user is logged in | ||||
|
r2679 | # and starts a session if needed | ||
|
r1016 | def find_current_user | ||
|
r330 | if session[:user_id] | ||
|
r663 | # existing session | ||
|
r2077 | (User.active.find(session[:user_id]) rescue nil) | ||
|
r663 | elsif cookies[:autologin] && Setting.autologin? | ||
|
r2679 | # auto-login feature starts a new session | ||
user = User.try_to_autologin(cookies[: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 | ||||
|
r1016 | User.find_by_rss_key(params[:key]) | ||
|
r330 | end | ||
end | ||||
|
r2460 | # Sets the logged in user | ||
def logged_user=(user) | ||||
if user && user.is_a?(User) | ||||
User.current = user | ||||
session[:user_id] = user.id | ||||
else | ||||
User.current = User.anonymous | ||||
session[:user_id] = nil | ||||
end | ||||
end | ||||
|
r330 | # check if login is globally required to access the application | ||
def check_if_login_required | ||||
|
r511 | # no check needed if user is already logged in | ||
|
r663 | return true if User.current.logged? | ||
|
r330 | require_login if Setting.login_required? | ||
end | ||||
def set_localization | ||||
|
r2430 | 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.downcase | ||||
if !accept_lang.blank? | ||||
lang = find_language(accept_lang) || find_language(accept_lang.split('-').first) | ||||
|
r330 | end | ||
|
r2430 | end | ||
lang ||= Setting.default_language | ||||
set_language_if_valid(lang) | ||||
|
r330 | end | ||
def require_login | ||||
|
r663 | if !User.current.logged? | ||
|
r1903 | redirect_to :controller => "account", :action => "login", :back_url => url_for(params) | ||
|
r330 | return false | ||
end | ||||
true | ||||
end | ||||
def require_admin | ||||
return unless require_login | ||||
|
r663 | if !User.current.admin? | ||
|
r492 | render_403 | ||
|
r330 | return false | ||
end | ||||
true | ||||
end | ||||
|
r1777 | |||
def deny_access | ||||
User.current.logged? ? render_403 : require_login | ||||
end | ||||
|
r330 | |||
|
r663 | # Authorize the user for the requested action | ||
|
r2651 | def authorize(ctrl = params[:controller], action = params[:action], global = false) | ||
allowed = User.current.allowed_to?({:controller => ctrl, :action => action}, @project, :global => global) | ||||
|
r1777 | allowed ? true : deny_access | ||
|
r330 | end | ||
|
r2651 | |||
# Authorize the user for the requested action outside a project | ||||
def authorize_global(ctrl = params[:controller], action = params[:action], global = true) | ||||
authorize(ctrl, action, global) | ||||
end | ||||
|
r330 | |||
# 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 | ||||
def check_project_privacy | ||||
|
r1223 | 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 | ||||
|
r546 | @project = nil | ||
render_404 | ||||
|
r1223 | false | ||
|
r546 | end | ||
|
r330 | end | ||
|
r5 | def redirect_back_or_default(default) | ||
|
r1891 | back_url = CGI.unescape(params[:back_url].to_s) | ||
|
r1686 | if !back_url.blank? | ||
|
r2124 | 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) and return | ||||
end | ||||
rescue URI::InvalidURIError | ||||
# redirect to default | ||||
|
r1686 | end | ||
|
r5 | end | ||
|
r1686 | redirect_to default | ||
|
r5 | end | ||
|
r330 | |||
|
r492 | def render_403 | ||
@project = nil | ||||
|
r861 | render :template => "common/403", :layout => !request.xhr?, :status => 403 | ||
|
r492 | return false | ||
end | ||||
|
r330 | def render_404 | ||
|
r861 | render :template => "common/404", :layout => !request.xhr?, :status => 404 | ||
|
r330 | return false | ||
end | ||||
|
r663 | |||
|
r1080 | def render_error(msg) | ||
flash.now[:error] = msg | ||||
|
r2430 | render :text => '', :layout => !request.xhr?, :status => 500 | ||
|
r1080 | end | ||
|
r675 | def render_feed(items, options={}) | ||
@items = items || [] | ||||
@items.sort! {|x,y| y.event_datetime <=> x.event_datetime } | ||||
|
r1295 | @items = @items.slice(0, Setting.feeds_limit.to_i) | ||
|
r663 | @title = options[:title] || Setting.app_title | ||
render :template => "common/feed.atom.rxml", :layout => false, :content_type => 'application/atom+xml' | ||||
end | ||||
def self.accept_key_auth(*actions) | ||||
actions = actions.flatten.map(&:to_s) | ||||
write_inheritable_attribute('accept_key_auth_actions', actions) | ||||
end | ||||
def accept_key_auth_actions | ||||
self.class.read_inheritable_attribute('accept_key_auth_actions') || [] | ||||
end | ||||
|
r977 | |||
# TODO: move to model | ||||
|
r1166 | def attach_files(obj, attachments) | ||
attached = [] | ||||
|
r2222 | unsaved = [] | ||
|
r1166 | if attachments && attachments.is_a?(Hash) | ||
attachments.each_value do |attachment| | ||||
file = attachment['file'] | ||||
next unless file && file.size > 0 | ||||
a = Attachment.create(:container => obj, | ||||
:file => file, | ||||
:description => attachment['description'].to_s.strip, | ||||
:author => User.current) | ||||
|
r2222 | a.new_record? ? (unsaved << a) : (attached << a) | ||
end | ||||
if unsaved.any? | ||||
flash[:warning] = l(:warning_attachments_not_saved, unsaved.size) | ||||
|
r977 | end | ||
end | ||||
|
r1166 | attached | ||
|
r977 | end | ||
|
r330 | |||
|
r1013 | # Returns the number of objects that should be displayed | ||
# on the paginated list | ||||
def per_page_option | ||||
per_page = nil | ||||
if params[:per_page] && Setting.per_page_options_array.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.per_page_options_array.first || 25 | ||||
end | ||||
per_page | ||||
end | ||||
|
r330 | # qvalues http header parser | ||
# code taken from webrick | ||||
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 | ||||
|
r2430 | rescue | ||
nil | ||||
|
r330 | end | ||
|
r1039 | |||
# Returns a string that can be used as filename value in Content-Disposition header | ||||
def filename_for_content_disposition(name) | ||||
request.env['HTTP_USER_AGENT'] =~ %r{MSIE} ? ERB::Util.url_encode(name) : name | ||||
end | ||||
|
r663 | end | ||