application.rb
230 lines
| 7.1 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 | ||
|
r1726 | layout 'base' | ||
|
r663 | before_filter :user_setup, :check_if_login_required, :set_localization | ||
|
r330 | filter_parameter_logging :password | ||
|
r1062 | include Redmine::MenuManager::MenuController | ||
helper Redmine::MenuManager::MenuHelper | ||||
|
r558 | REDMINE_SUPPORTED_SCM.each do |scm| | ||
require_dependency "repository/#{scm.underscore}" | ||||
end | ||||
|
r663 | def current_role | ||
@current_role ||= User.current.role_for_project(@project) | ||||
end | ||||
def user_setup | ||||
|
r1016 | # Check the settings cache for each request | ||
|
r674 | Setting.check_cache | ||
|
r1016 | # Find the current user | ||
User.current = find_current_user | ||||
end | ||||
# Returns the current user or nil if no user is logged in | ||||
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? | ||
# auto-login feature | ||||
|
r1016 | User.find_by_autologin_key(cookies[:autologin]) | ||
|
r663 | elsif params[:key] && accept_key_auth_actions.include?(params[:action]) | ||
# RSS key authentication | ||||
|
r1016 | User.find_by_rss_key(params[:key]) | ||
|
r330 | end | ||
end | ||||
# 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 | ||||
|
r1130 | User.current.language = nil unless User.current.logged? | ||
|
r330 | lang = begin | ||
|
r1467 | if !User.current.language.blank? && GLoc.valid_language?(User.current.language) | ||
|
r663 | User.current.language | ||
|
r330 | elsif request.env['HTTP_ACCEPT_LANGUAGE'] | ||
|
r1467 | accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first.downcase | ||
if !accept_lang.blank? && (GLoc.valid_language?(accept_lang) || GLoc.valid_language?(accept_lang = accept_lang.split('-').first)) | ||||
|
r1117 | User.current.language = accept_lang | ||
|
r330 | end | ||
end | ||||
rescue | ||||
nil | ||||
end || Setting.default_language | ||||
set_language_if_valid(lang) | ||||
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 | ||
|
r330 | def authorize(ctrl = params[:controller], action = params[:action]) | ||
|
r663 | allowed = User.current.allowed_to?({:controller => ctrl, :action => action}, @project) | ||
|
r1777 | allowed ? true : deny_access | ||
|
r330 | end | ||
# 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 | ||||
render :nothing => true, :layout => !request.xhr?, :status => 500 | ||||
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 = [] | ||||
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) | ||||
attached << a unless a.new_record? | ||||
|
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 | ||||
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 | ||