Revision 15242
Added by Jean-Philippe Lang over 9 years ago
tags/2.6.10/.gitignore | ||
---|---|---|
1 |
/.project |
|
2 |
/.loadpath |
|
3 |
/.powrc |
|
4 |
/.rvmrc |
|
5 |
/config/additional_environment.rb |
|
6 |
/config/configuration.yml |
|
7 |
/config/database.yml |
|
8 |
/config/email.yml |
|
9 |
/config/initializers/session_store.rb |
|
10 |
/config/initializers/secret_token.rb |
|
11 |
/coverage |
|
12 |
/db/*.db |
|
13 |
/db/*.sqlite3 |
|
14 |
/db/schema.rb |
|
15 |
/files/* |
|
16 |
/lib/redmine/scm/adapters/mercurial/redminehelper.pyc |
|
17 |
/lib/redmine/scm/adapters/mercurial/redminehelper.pyo |
|
18 |
/log/*.log* |
|
19 |
/log/mongrel_debug |
|
20 |
/plugins/* |
|
21 |
!/plugins/README |
|
22 |
/public/dispatch.* |
|
23 |
/public/plugin_assets/* |
|
24 |
/public/themes/* |
|
25 |
!/public/themes/alternate |
|
26 |
!/public/themes/classic |
|
27 |
!/public/themes/README |
|
28 |
/tmp/* |
|
29 |
/tmp/cache/* |
|
30 |
/tmp/pdf/* |
|
31 |
/tmp/sessions/* |
|
32 |
/tmp/sockets/* |
|
33 |
/tmp/test/* |
|
34 |
/tmp/thumbnails/* |
|
35 |
/vendor/cache |
|
36 |
/vendor/rails |
|
37 |
*.rbc |
|
38 |
|
|
39 |
/.bundle |
|
40 |
/Gemfile.lock |
|
41 |
/Gemfile.local |
|
42 |
|
tags/2.6.10/.hgignore | ||
---|---|---|
1 |
syntax: glob |
|
2 |
|
|
3 |
.project |
|
4 |
.loadpath |
|
5 |
.powrc |
|
6 |
.rvmrc |
|
7 |
config/additional_environment.rb |
|
8 |
config/configuration.yml |
|
9 |
config/database.yml |
|
10 |
config/email.yml |
|
11 |
config/initializers/session_store.rb |
|
12 |
config/initializers/secret_token.rb |
|
13 |
coverage |
|
14 |
db/*.db |
|
15 |
db/*.sqlite3 |
|
16 |
db/schema.rb |
|
17 |
files/* |
|
18 |
lib/redmine/scm/adapters/mercurial/redminehelper.pyc |
|
19 |
lib/redmine/scm/adapters/mercurial/redminehelper.pyo |
|
20 |
log/*.log* |
|
21 |
log/mongrel_debug |
|
22 |
public/dispatch.* |
|
23 |
public/plugin_assets/* |
|
24 |
tmp/* |
|
25 |
tmp/cache/* |
|
26 |
tmp/pdf/* |
|
27 |
tmp/sessions/* |
|
28 |
tmp/sockets/* |
|
29 |
tmp/test/* |
|
30 |
tmp/thumbnails/* |
|
31 |
vendor/cache |
|
32 |
vendor/rails |
|
33 |
*.rbc |
|
34 |
|
|
35 |
.svn/ |
|
36 |
.git/ |
|
37 |
|
|
38 |
.bundle |
|
39 |
Gemfile.lock |
|
40 |
Gemfile.local |
|
41 |
|
tags/2.6.10/CONTRIBUTING.md | ||
---|---|---|
1 |
|
|
2 |
**Do not send a pull requst to this github repository**. |
|
3 |
|
|
4 |
For more detail, please see [official website] wiki [Contribute]. |
|
5 |
|
|
6 |
[official website]: http://www.redmine.org |
|
7 |
[Contribute]: http://www.redmine.org/projects/redmine/wiki/Contribute |
|
8 |
|
|
0 | 9 |
tags/2.6.10/Gemfile | ||
---|---|---|
1 |
source 'https://rubygems.org' |
|
2 |
|
|
3 |
gem "rails", "3.2.22.2" |
|
4 |
gem "rack-cache", "1.2" if RUBY_VERSION < "1.9.3" |
|
5 |
gem "jquery-rails", "~> 3.1.4" |
|
6 |
gem "coderay", "~> 1.1.0" |
|
7 |
gem "fastercsv", "~> 1.5.0", :platforms => [:mri_18, :mingw_18, :jruby] |
|
8 |
gem "builder", ">= 3.0.4" |
|
9 |
gem "request_store", "1.0.5" |
|
10 |
gem "mime-types" |
|
11 |
gem "rbpdf", "~> 1.18.7" |
|
12 |
|
|
13 |
gem "i18n", "~> 0.6.11" |
|
14 |
|
|
15 |
# rake 11 require ruby 1.9.3 or higher |
|
16 |
if RUBY_VERSION < "1.9.3" |
|
17 |
gem "rake", "~> 10.4.2" |
|
18 |
end |
|
19 |
|
|
20 |
# Optional gem for LDAP authentication |
|
21 |
group :ldap do |
|
22 |
gem "net-ldap", "~> 0.3.1" |
|
23 |
end |
|
24 |
|
|
25 |
# Optional gem for OpenID authentication |
|
26 |
group :openid do |
|
27 |
gem "ruby-openid", "~> 2.3.0", :require => "openid" |
|
28 |
gem "rack-openid" |
|
29 |
end |
|
30 |
|
|
31 |
platforms :mri, :mingw do |
|
32 |
# Optional gem for exporting the gantt to a PNG file, not supported with jruby |
|
33 |
group :rmagick do |
|
34 |
# RMagick 2 supports ruby 1.9 |
|
35 |
# RMagick 1 would be fine for ruby 1.8 but Bundler does not support |
|
36 |
# different requirements for the same gem on different platforms |
|
37 |
gem "rmagick", (RUBY_VERSION < "1.9" ? "2.13.3" : "~> 2.13.4") |
|
38 |
end |
|
39 |
|
|
40 |
# Optional Markdown support, not for JRuby |
|
41 |
group :markdown do |
|
42 |
gem "redcarpet", (RUBY_VERSION < "1.9" ? "~> 2.3.0" : "~> 3.3.2") |
|
43 |
end |
|
44 |
end |
|
45 |
|
|
46 |
platforms :jruby do |
|
47 |
# jruby-openssl is bundled with JRuby 1.7.0 |
|
48 |
gem "jruby-openssl" if Object.const_defined?(:JRUBY_VERSION) && JRUBY_VERSION < '1.7.0' |
|
49 |
gem "activerecord-jdbc-adapter", "~> 1.3.2" |
|
50 |
end |
|
51 |
|
|
52 |
# Include database gems for the adapters found in the database |
|
53 |
# configuration file |
|
54 |
require 'erb' |
|
55 |
require 'yaml' |
|
56 |
database_file = File.join(File.dirname(__FILE__), "config/database.yml") |
|
57 |
if File.exist?(database_file) |
|
58 |
database_config = YAML::load(ERB.new(IO.read(database_file)).result) |
|
59 |
adapters = database_config.values.map {|c| c['adapter']}.compact.uniq |
|
60 |
if adapters.any? |
|
61 |
adapters.each do |adapter| |
|
62 |
case adapter |
|
63 |
when 'mysql2' |
|
64 |
gem "mysql2", "~> 0.3.11", :platforms => [:mri, :mingw] |
|
65 |
gem "activerecord-jdbcmysql-adapter", :platforms => :jruby |
|
66 |
when 'mysql' |
|
67 |
gem "mysql", "~> 2.8.1", :platforms => [:mri, :mingw] |
|
68 |
gem "activerecord-jdbcmysql-adapter", :platforms => :jruby |
|
69 |
when /postgresql/ |
|
70 |
gem "pg", "~> 0.17.1", :platforms => [:mri, :mingw] |
|
71 |
gem "activerecord-jdbcpostgresql-adapter", :platforms => :jruby |
|
72 |
when /sqlite3/ |
|
73 |
gem "sqlite3", :platforms => [:mri, :mingw] |
|
74 |
gem "jdbc-sqlite3", ">= 3.8.10.1", :platforms => :jruby |
|
75 |
gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby |
|
76 |
when /sqlserver/ |
|
77 |
gem "tiny_tds", "~> 0.6.2", :platforms => [:mri, :mingw] |
|
78 |
gem "activerecord-sqlserver-adapter", :platforms => [:mri, :mingw] |
|
79 |
else |
|
80 |
warn("Unknown database adapter `#{adapter}` found in config/database.yml, use Gemfile.local to load your own database gems") |
|
81 |
end |
|
82 |
end |
|
83 |
else |
|
84 |
warn("No adapter found in config/database.yml, please configure it first") |
|
85 |
end |
|
86 |
else |
|
87 |
warn("Please configure your config/database.yml first") |
|
88 |
end |
|
89 |
|
|
90 |
group :development do |
|
91 |
gem "rdoc", ">= 2.4.2" |
|
92 |
gem "yard" |
|
93 |
end |
|
94 |
|
|
95 |
group :test do |
|
96 |
gem "minitest" |
|
97 |
gem "test-unit", "~> 3.0" |
|
98 |
gem "shoulda", "~> 3.3.2" |
|
99 |
gem "shoulda-matchers", "1.4.1" |
|
100 |
gem "mocha", "~> 1.0.0", :require => 'mocha/api' |
|
101 |
if RUBY_VERSION >= '1.9.3' |
|
102 |
gem "capybara" |
|
103 |
# Request at least nokogiri 1.6.7.2 because of security advisories |
|
104 |
gem "nokogiri", ">= 1.6.7.2" |
|
105 |
gem "selenium-webdriver" |
|
106 |
end |
|
107 |
end |
|
108 |
|
|
109 |
local_gemfile = File.join(File.dirname(__FILE__), "Gemfile.local") |
|
110 |
if File.exists?(local_gemfile) |
|
111 |
puts "Loading Gemfile.local ..." if $DEBUG # `ruby -d` or `bundle -v` |
|
112 |
instance_eval File.read(local_gemfile) |
|
113 |
end |
|
114 |
|
|
115 |
# Load plugins' Gemfiles |
|
116 |
Dir.glob File.expand_path("../plugins/*/{Gemfile,PluginGemfile}", __FILE__) do |file| |
|
117 |
puts "Loading #{file} ..." if $DEBUG # `ruby -d` or `bundle -v` |
|
118 |
#TODO: switch to "eval_gemfile file" when bundler >= 1.2.0 will be required (rails 4) |
|
119 |
instance_eval File.read(file), file |
|
120 |
end |
|
0 | 121 |
tags/2.6.10/README.rdoc | ||
---|---|---|
1 |
= Redmine |
|
2 |
|
|
3 |
Redmine is a flexible project management web application written using Ruby on Rails framework. |
|
4 |
|
|
5 |
More details can be found in the doc directory or on the official website http://www.redmine.org |
tags/2.6.10/Rakefile | ||
---|---|---|
1 |
#!/usr/bin/env rake |
|
2 |
# Add your own tasks in files placed in lib/tasks ending in .rake, |
|
3 |
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. |
|
4 |
|
|
5 |
require File.expand_path('../config/application', __FILE__) |
|
6 |
|
|
7 |
RedmineApp::Application.load_tasks |
tags/2.6.10/app/controllers/account_controller.rb | ||
---|---|---|
1 |
# Redmine - project management software |
|
2 |
# Copyright (C) 2006-2016 Jean-Philippe Lang |
|
3 |
# |
|
4 |
# This program is free software; you can redistribute it and/or |
|
5 |
# modify it under the terms of the GNU General Public License |
|
6 |
# as published by the Free Software Foundation; either version 2 |
|
7 |
# of the License, or (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU General Public License for more details. |
|
13 |
# |
|
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 |
|
16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 |
|
|
18 |
class AccountController < ApplicationController |
|
19 |
helper :custom_fields |
|
20 |
include CustomFieldsHelper |
|
21 |
|
|
22 |
# prevents login action to be filtered by check_if_login_required application scope filter |
|
23 |
skip_before_filter :check_if_login_required, :check_password_change |
|
24 |
|
|
25 |
# Overrides ApplicationController#verify_authenticity_token to disable |
|
26 |
# token verification on openid callbacks |
|
27 |
def verify_authenticity_token |
|
28 |
unless using_open_id? |
|
29 |
super |
|
30 |
end |
|
31 |
end |
|
32 |
|
|
33 |
# Login request and validation |
|
34 |
def login |
|
35 |
if request.get? |
|
36 |
if User.current.logged? |
|
37 |
redirect_back_or_default home_url, :referer => true |
|
38 |
end |
|
39 |
else |
|
40 |
authenticate_user |
|
41 |
end |
|
42 |
rescue AuthSourceException => e |
|
43 |
logger.error "An error occured when authenticating #{params[:username]}: #{e.message}" |
|
44 |
render_error :message => e.message |
|
45 |
end |
|
46 |
|
|
47 |
# Log out current user and redirect to welcome page |
|
48 |
def logout |
|
49 |
if User.current.anonymous? |
|
50 |
redirect_to home_url |
|
51 |
elsif request.post? |
|
52 |
logout_user |
|
53 |
redirect_to home_url |
|
54 |
end |
|
55 |
# display the logout form |
|
56 |
end |
|
57 |
|
|
58 |
# Lets user choose a new password |
|
59 |
def lost_password |
|
60 |
(redirect_to(home_url); return) unless Setting.lost_password? |
|
61 |
if params[:token] |
|
62 |
@token = Token.find_token("recovery", params[:token].to_s) |
|
63 |
if @token.nil? || @token.expired? |
|
64 |
redirect_to home_url |
|
65 |
return |
|
66 |
end |
|
67 |
@user = @token.user |
|
68 |
unless @user && @user.active? |
|
69 |
redirect_to home_url |
|
70 |
return |
|
71 |
end |
|
72 |
if request.post? |
|
73 |
@user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] |
|
74 |
if @user.save |
|
75 |
@token.destroy |
|
76 |
flash[:notice] = l(:notice_account_password_updated) |
|
77 |
redirect_to signin_path |
|
78 |
return |
|
79 |
end |
|
80 |
end |
|
81 |
render :template => "account/password_recovery" |
|
82 |
return |
|
83 |
else |
|
84 |
if request.post? |
|
85 |
user = User.find_by_mail(params[:mail].to_s) |
|
86 |
# user not found |
|
87 |
unless user |
|
88 |
flash.now[:error] = l(:notice_account_unknown_email) |
|
89 |
return |
|
90 |
end |
|
91 |
unless user.active? |
|
92 |
handle_inactive_user(user, lost_password_path) |
|
93 |
return |
|
94 |
end |
|
95 |
# user cannot change its password |
|
96 |
unless user.change_password_allowed? |
|
97 |
flash.now[:error] = l(:notice_can_t_change_password) |
|
98 |
return |
|
99 |
end |
|
100 |
# create a new token for password recovery |
|
101 |
token = Token.new(:user => user, :action => "recovery") |
|
102 |
if token.save |
|
103 |
Mailer.lost_password(token).deliver |
|
104 |
flash[:notice] = l(:notice_account_lost_email_sent) |
|
105 |
redirect_to signin_path |
|
106 |
return |
|
107 |
end |
|
108 |
end |
|
109 |
end |
|
110 |
end |
|
111 |
|
|
112 |
# User self-registration |
|
113 |
def register |
|
114 |
(redirect_to(home_url); return) unless Setting.self_registration? || session[:auth_source_registration] |
|
115 |
if request.get? |
|
116 |
session[:auth_source_registration] = nil |
|
117 |
@user = User.new(:language => current_language.to_s) |
|
118 |
else |
|
119 |
user_params = params[:user] || {} |
|
120 |
@user = User.new |
|
121 |
@user.safe_attributes = user_params |
|
122 |
@user.admin = false |
|
123 |
@user.register |
|
124 |
if session[:auth_source_registration] |
|
125 |
@user.activate |
|
126 |
@user.login = session[:auth_source_registration][:login] |
|
127 |
@user.auth_source_id = session[:auth_source_registration][:auth_source_id] |
|
128 |
if @user.save |
|
129 |
session[:auth_source_registration] = nil |
|
130 |
self.logged_user = @user |
|
131 |
flash[:notice] = l(:notice_account_activated) |
|
132 |
redirect_to my_account_path |
|
133 |
end |
|
134 |
else |
|
135 |
@user.login = params[:user][:login] |
|
136 |
unless user_params[:identity_url].present? && user_params[:password].blank? && user_params[:password_confirmation].blank? |
|
137 |
@user.password, @user.password_confirmation = user_params[:password], user_params[:password_confirmation] |
|
138 |
end |
|
139 |
|
|
140 |
case Setting.self_registration |
|
141 |
when '1' |
|
142 |
register_by_email_activation(@user) |
|
143 |
when '3' |
|
144 |
register_automatically(@user) |
|
145 |
else |
|
146 |
register_manually_by_administrator(@user) |
|
147 |
end |
|
148 |
end |
|
149 |
end |
|
150 |
end |
|
151 |
|
|
152 |
# Token based account activation |
|
153 |
def activate |
|
154 |
(redirect_to(home_url); return) unless Setting.self_registration? && params[:token].present? |
|
155 |
token = Token.find_token('register', params[:token].to_s) |
|
156 |
(redirect_to(home_url); return) unless token and !token.expired? |
|
157 |
user = token.user |
|
158 |
(redirect_to(home_url); return) unless user.registered? |
|
159 |
user.activate |
|
160 |
if user.save |
|
161 |
token.destroy |
|
162 |
flash[:notice] = l(:notice_account_activated) |
|
163 |
end |
|
164 |
redirect_to signin_path |
|
165 |
end |
|
166 |
|
|
167 |
# Sends a new account activation email |
|
168 |
def activation_email |
|
169 |
if session[:registered_user_id] && Setting.self_registration == '1' |
|
170 |
user_id = session.delete(:registered_user_id).to_i |
|
171 |
user = User.find_by_id(user_id) |
|
172 |
if user && user.registered? |
|
173 |
register_by_email_activation(user) |
|
174 |
return |
|
175 |
end |
|
176 |
end |
|
177 |
redirect_to(home_url) |
|
178 |
end |
|
179 |
|
|
180 |
private |
|
181 |
|
|
182 |
def authenticate_user |
|
183 |
if Setting.openid? && using_open_id? |
|
184 |
open_id_authenticate(params[:openid_url]) |
|
185 |
else |
|
186 |
password_authentication |
|
187 |
end |
|
188 |
end |
|
189 |
|
|
190 |
def password_authentication |
|
191 |
user = User.try_to_login(params[:username], params[:password], false) |
|
192 |
|
|
193 |
if user.nil? |
|
194 |
invalid_credentials |
|
195 |
elsif user.new_record? |
|
196 |
onthefly_creation_failed(user, {:login => user.login, :auth_source_id => user.auth_source_id }) |
|
197 |
else |
|
198 |
# Valid user |
|
199 |
if user.active? |
|
200 |
successful_authentication(user) |
|
201 |
else |
|
202 |
handle_inactive_user(user) |
|
203 |
end |
|
204 |
end |
|
205 |
end |
|
206 |
|
|
207 |
def open_id_authenticate(openid_url) |
|
208 |
back_url = signin_url(:autologin => params[:autologin]) |
|
209 |
authenticate_with_open_id( |
|
210 |
openid_url, :required => [:nickname, :fullname, :email], |
|
211 |
:return_to => back_url, :method => :post |
|
212 |
) do |result, identity_url, registration| |
|
213 |
if result.successful? |
|
214 |
user = User.find_or_initialize_by_identity_url(identity_url) |
|
215 |
if user.new_record? |
|
216 |
# Self-registration off |
|
217 |
(redirect_to(home_url); return) unless Setting.self_registration? |
|
218 |
# Create on the fly |
|
219 |
user.login = registration['nickname'] unless registration['nickname'].nil? |
|
220 |
user.mail = registration['email'] unless registration['email'].nil? |
|
221 |
user.firstname, user.lastname = registration['fullname'].split(' ') unless registration['fullname'].nil? |
|
222 |
user.random_password |
|
223 |
user.register |
|
224 |
case Setting.self_registration |
|
225 |
when '1' |
|
226 |
register_by_email_activation(user) do |
|
227 |
onthefly_creation_failed(user) |
|
228 |
end |
|
229 |
when '3' |
|
230 |
register_automatically(user) do |
|
231 |
onthefly_creation_failed(user) |
|
232 |
end |
|
233 |
else |
|
234 |
register_manually_by_administrator(user) do |
|
235 |
onthefly_creation_failed(user) |
|
236 |
end |
|
237 |
end |
|
238 |
else |
|
239 |
# Existing record |
|
240 |
if user.active? |
|
241 |
successful_authentication(user) |
|
242 |
else |
|
243 |
handle_inactive_user(user) |
|
244 |
end |
|
245 |
end |
|
246 |
end |
|
247 |
end |
|
248 |
end |
|
249 |
|
|
250 |
def successful_authentication(user) |
|
251 |
logger.info "Successful authentication for '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}" |
|
252 |
# Valid user |
|
253 |
self.logged_user = user |
|
254 |
# generate a key and set cookie if autologin |
|
255 |
if params[:autologin] && Setting.autologin? |
|
256 |
set_autologin_cookie(user) |
|
257 |
end |
|
258 |
call_hook(:controller_account_success_authentication_after, {:user => user }) |
|
259 |
redirect_back_or_default my_page_path |
|
260 |
end |
|
261 |
|
|
262 |
def set_autologin_cookie(user) |
|
263 |
token = Token.create(:user => user, :action => 'autologin') |
|
264 |
cookie_options = { |
|
265 |
:value => token.value, |
|
266 |
:expires => 1.year.from_now, |
|
267 |
:path => (Redmine::Configuration['autologin_cookie_path'] || '/'), |
|
268 |
:secure => (Redmine::Configuration['autologin_cookie_secure'] ? true : false), |
|
269 |
:httponly => true |
|
270 |
} |
|
271 |
cookies[autologin_cookie_name] = cookie_options |
|
272 |
end |
|
273 |
|
|
274 |
# Onthefly creation failed, display the registration form to fill/fix attributes |
|
275 |
def onthefly_creation_failed(user, auth_source_options = { }) |
|
276 |
@user = user |
|
277 |
session[:auth_source_registration] = auth_source_options unless auth_source_options.empty? |
|
278 |
render :action => 'register' |
|
279 |
end |
|
280 |
|
|
281 |
def invalid_credentials |
|
282 |
logger.warn "Failed login for '#{params[:username]}' from #{request.remote_ip} at #{Time.now.utc}" |
|
283 |
flash.now[:error] = l(:notice_account_invalid_creditentials) |
|
284 |
end |
|
285 |
|
|
286 |
# Register a user for email activation. |
|
287 |
# |
|
288 |
# Pass a block for behavior when a user fails to save |
|
289 |
def register_by_email_activation(user, &block) |
|
290 |
token = Token.new(:user => user, :action => "register") |
|
291 |
if user.save and token.save |
|
292 |
Mailer.register(token).deliver |
|
293 |
flash[:notice] = l(:notice_account_register_done, :email => ERB::Util.h(user.mail)) |
|
294 |
redirect_to signin_path |
|
295 |
else |
|
296 |
yield if block_given? |
|
297 |
end |
|
298 |
end |
|
299 |
|
|
300 |
# Automatically register a user |
|
301 |
# |
|
302 |
# Pass a block for behavior when a user fails to save |
|
303 |
def register_automatically(user, &block) |
|
304 |
# Automatic activation |
|
305 |
user.activate |
|
306 |
user.last_login_on = Time.now |
|
307 |
if user.save |
|
308 |
self.logged_user = user |
|
309 |
flash[:notice] = l(:notice_account_activated) |
|
310 |
redirect_to my_account_path |
|
311 |
else |
|
312 |
yield if block_given? |
|
313 |
end |
|
314 |
end |
|
315 |
|
|
316 |
# Manual activation by the administrator |
|
317 |
# |
|
318 |
# Pass a block for behavior when a user fails to save |
|
319 |
def register_manually_by_administrator(user, &block) |
|
320 |
if user.save |
|
321 |
# Sends an email to the administrators |
|
322 |
Mailer.account_activation_request(user).deliver |
|
323 |
account_pending(user) |
|
324 |
else |
|
325 |
yield if block_given? |
|
326 |
end |
|
327 |
end |
|
328 |
|
|
329 |
def handle_inactive_user(user, redirect_path=signin_path) |
|
330 |
if user.registered? |
|
331 |
account_pending(user, redirect_path) |
|
332 |
else |
|
333 |
account_locked(user, redirect_path) |
|
334 |
end |
|
335 |
end |
|
336 |
|
|
337 |
def account_pending(user, redirect_path=signin_path) |
|
338 |
if Setting.self_registration == '1' |
|
339 |
flash[:error] = l(:notice_account_not_activated_yet, :url => activation_email_path) |
|
340 |
session[:registered_user_id] = user.id |
|
341 |
else |
|
342 |
flash[:error] = l(:notice_account_pending) |
|
343 |
end |
|
344 |
redirect_to redirect_path |
|
345 |
end |
|
346 |
|
|
347 |
def account_locked(user, redirect_path=signin_path) |
|
348 |
flash[:error] = l(:notice_account_locked) |
|
349 |
redirect_to redirect_path |
|
350 |
end |
|
351 |
end |
|
0 | 352 |
tags/2.6.10/app/controllers/activities_controller.rb | ||
---|---|---|
1 |
# Redmine - project management software |
|
2 |
# Copyright (C) 2006-2016 Jean-Philippe Lang |
|
3 |
# |
|
4 |
# This program is free software; you can redistribute it and/or |
|
5 |
# modify it under the terms of the GNU General Public License |
|
6 |
# as published by the Free Software Foundation; either version 2 |
|
7 |
# of the License, or (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU General Public License for more details. |
|
13 |
# |
|
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 |
|
16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 |
|
|
18 |
class ActivitiesController < ApplicationController |
|
19 |
menu_item :activity |
|
20 |
before_filter :find_optional_project |
|
21 |
accept_rss_auth :index |
|
22 |
|
|
23 |
def index |
|
24 |
@days = Setting.activity_days_default.to_i |
|
25 |
|
|
26 |
if params[:from] |
|
27 |
begin; @date_to = params[:from].to_date + 1; rescue; end |
|
28 |
end |
|
29 |
|
|
30 |
@date_to ||= Date.today + 1 |
|
31 |
@date_from = @date_to - @days |
|
32 |
@with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1') |
|
33 |
@author = (params[:user_id].blank? ? nil : User.active.find(params[:user_id])) |
|
34 |
|
|
35 |
@activity = Redmine::Activity::Fetcher.new(User.current, :project => @project, |
|
36 |
:with_subprojects => @with_subprojects, |
|
37 |
:author => @author) |
|
38 |
@activity.scope_select {|t| !params["show_#{t}"].nil?} |
|
39 |
@activity.scope = (@author.nil? ? :default : :all) if @activity.scope.empty? |
|
40 |
|
|
41 |
events = @activity.events(@date_from, @date_to) |
|
42 |
|
|
43 |
if events.empty? || stale?(:etag => [@activity.scope, @date_to, @date_from, @with_subprojects, @author, events.first, events.size, User.current, current_language]) |
|
44 |
respond_to do |format| |
|
45 |
format.html { |
|
46 |
@events_by_day = events.group_by {|event| User.current.time_to_date(event.event_datetime)} |
|
47 |
render :layout => false if request.xhr? |
|
48 |
} |
|
49 |
format.atom { |
|
50 |
title = l(:label_activity) |
|
51 |
if @author |
|
52 |
title = @author.name |
|
53 |
elsif @activity.scope.size == 1 |
|
54 |
title = l("label_#{@activity.scope.first.singularize}_plural") |
|
55 |
end |
|
56 |
render_feed(events, :title => "#{@project || Setting.app_title}: #{title}") |
|
57 |
} |
|
58 |
end |
|
59 |
end |
|
60 |
|
|
61 |
rescue ActiveRecord::RecordNotFound |
|
62 |
render_404 |
|
63 |
end |
|
64 |
|
|
65 |
private |
|
66 |
|
|
67 |
# TODO: refactor, duplicated in projects_controller |
|
68 |
def find_optional_project |
|
69 |
return true unless params[:id] |
|
70 |
@project = Project.find(params[:id]) |
|
71 |
authorize |
|
72 |
rescue ActiveRecord::RecordNotFound |
|
73 |
render_404 |
|
74 |
end |
|
75 |
end |
|
0 | 76 |
tags/2.6.10/app/controllers/admin_controller.rb | ||
---|---|---|
1 |
# Redmine - project management software |
|
2 |
# Copyright (C) 2006-2016 Jean-Philippe Lang |
|
3 |
# |
|
4 |
# This program is free software; you can redistribute it and/or |
|
5 |
# modify it under the terms of the GNU General Public License |
|
6 |
# as published by the Free Software Foundation; either version 2 |
|
7 |
# of the License, or (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU General Public License for more details. |
|
13 |
# |
|
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 |
|
16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 |
|
|
18 |
class AdminController < ApplicationController |
|
19 |
layout 'admin' |
|
20 |
menu_item :projects, :only => :projects |
|
21 |
menu_item :plugins, :only => :plugins |
|
22 |
menu_item :info, :only => :info |
|
23 |
|
|
24 |
before_filter :require_admin |
|
25 |
helper :sort |
|
26 |
include SortHelper |
|
27 |
|
|
28 |
def index |
|
29 |
@no_configuration_data = Redmine::DefaultData::Loader::no_data? |
|
30 |
end |
|
31 |
|
|
32 |
def projects |
|
33 |
@status = params[:status] || 1 |
|
34 |
|
|
35 |
scope = Project.status(@status).order('lft') |
|
36 |
scope = scope.like(params[:name]) if params[:name].present? |
|
37 |
@projects = scope.all |
|
38 |
|
|
39 |
render :action => "projects", :layout => false if request.xhr? |
|
40 |
end |
|
41 |
|
|
42 |
def plugins |
|
43 |
@plugins = Redmine::Plugin.all |
|
44 |
end |
|
45 |
|
|
46 |
# Loads the default configuration |
|
47 |
# (roles, trackers, statuses, workflow, enumerations) |
|
48 |
def default_configuration |
|
49 |
if request.post? |
|
50 |
begin |
|
51 |
Redmine::DefaultData::Loader::load(params[:lang]) |
|
52 |
flash[:notice] = l(:notice_default_data_loaded) |
|
53 |
rescue Exception => e |
|
54 |
flash[:error] = l(:error_can_t_load_default_data, ERB::Util.h(e.message)) |
|
55 |
end |
|
56 |
end |
|
57 |
redirect_to admin_path |
|
58 |
end |
|
59 |
|
|
60 |
def test_email |
|
61 |
raise_delivery_errors = ActionMailer::Base.raise_delivery_errors |
|
62 |
# Force ActionMailer to raise delivery errors so we can catch it |
|
63 |
ActionMailer::Base.raise_delivery_errors = true |
|
64 |
begin |
|
65 |
@test = Mailer.test_email(User.current).deliver |
|
66 |
flash[:notice] = l(:notice_email_sent, ERB::Util.h(User.current.mail)) |
|
67 |
rescue Exception => e |
|
68 |
flash[:error] = l(:notice_email_error, ERB::Util.h(Redmine::CodesetUtil.replace_invalid_utf8(e.message.dup))) |
|
69 |
end |
|
70 |
ActionMailer::Base.raise_delivery_errors = raise_delivery_errors |
|
71 |
redirect_to settings_path(:tab => 'notifications') |
|
72 |
end |
|
73 |
|
|
74 |
def info |
|
75 |
@db_adapter_name = ActiveRecord::Base.connection.adapter_name |
|
76 |
@checklist = [ |
|
77 |
[:text_default_administrator_account_changed, User.default_admin_account_changed?], |
|
78 |
[:text_file_repository_writable, File.writable?(Attachment.storage_path)], |
|
79 |
["#{l :text_plugin_assets_writable} (./public/plugin_assets)", File.writable?(Redmine::Plugin.public_directory)], |
|
80 |
[:text_rmagick_available, Object.const_defined?(:Magick)], |
|
81 |
[:text_convert_available, Redmine::Thumbnail.convert_available?] |
|
82 |
] |
|
83 |
end |
|
84 |
end |
|
0 | 85 |
tags/2.6.10/app/controllers/application_controller.rb | ||
---|---|---|
1 |
# Redmine - project management software |
|
2 |
# Copyright (C) 2006-2016 Jean-Philippe Lang |
|
3 |
# |
|
4 |
# This program is free software; you can redistribute it and/or |
|
5 |
# modify it under the terms of the GNU General Public License |
|
6 |
# as published by the Free Software Foundation; either version 2 |
|
7 |
# of the License, or (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU General Public License for more details. |
|
13 |
# |
|
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 |
|
16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
17 |
|
|
18 |
require 'uri' |
|
19 |
require 'cgi' |
|
20 |
|
|
21 |
class Unauthorized < Exception; end |
|
22 |
|
|
23 |
class ApplicationController < ActionController::Base |
|
24 |
include Redmine::I18n |
|
25 |
include Redmine::Pagination |
|
26 |
include RoutesHelper |
|
27 |
helper :routes |
|
28 |
|
|
29 |
class_attribute :accept_api_auth_actions |
|
30 |
class_attribute :accept_rss_auth_actions |
|
31 |
class_attribute :model_object |
|
32 |
|
|
33 |
layout 'base' |
|
34 |
|
|
35 |
protect_from_forgery |
|
36 |
|
|
37 |
def verify_authenticity_token |
|
38 |
unless api_request? |
|
39 |
super |
|
40 |
end |
|
41 |
end |
|
42 |
|
|
43 |
def handle_unverified_request |
|
44 |
unless api_request? |
|
45 |
super |
|
46 |
cookies.delete(autologin_cookie_name) |
|
47 |
self.logged_user = nil |
|
48 |
set_localization |
|
49 |
render_error :status => 422, :message => "Invalid form authenticity token." |
|
50 |
end |
|
51 |
end |
|
52 |
|
|
53 |
before_filter :session_expiration, :user_setup, :force_logout_if_password_changed, :check_if_login_required, :check_password_change, :set_localization |
|
54 |
|
|
55 |
rescue_from ::Unauthorized, :with => :deny_access |
|
56 |
rescue_from ::ActionView::MissingTemplate, :with => :missing_template |
|
57 |
|
|
58 |
include Redmine::Search::Controller |
|
59 |
include Redmine::MenuManager::MenuController |
|
60 |
helper Redmine::MenuManager::MenuHelper |
|
61 |
|
|
62 |
def session_expiration |
|
63 |
if session[:user_id] |
|
64 |
if session_expired? && !try_to_autologin |
|
65 |
set_localization(User.active.find_by_id(session[:user_id])) |
|
66 |
self.logged_user = nil |
|
67 |
flash[:error] = l(:error_session_expired) |
|
68 |
require_login |
|
69 |
else |
|
70 |
session[:atime] = Time.now.utc.to_i |
|
71 |
end |
|
72 |
end |
|
73 |
end |
|
74 |
|
|
75 |
def session_expired? |
|
76 |
if Setting.session_lifetime? |
|
77 |
unless session[:ctime] && (Time.now.utc.to_i - session[:ctime].to_i <= Setting.session_lifetime.to_i * 60) |
|
78 |
return true |
|
79 |
end |
|
80 |
end |
|
81 |
if Setting.session_timeout? |
|
82 |
unless session[:atime] && (Time.now.utc.to_i - session[:atime].to_i <= Setting.session_timeout.to_i * 60) |
|
83 |
return true |
|
84 |
end |
|
85 |
end |
|
86 |
false |
|
87 |
end |
|
88 |
|
|
89 |
def start_user_session(user) |
|
90 |
session[:user_id] = user.id |
|
91 |
session[:ctime] = Time.now.utc.to_i |
|
92 |
session[:atime] = Time.now.utc.to_i |
|
93 |
if user.must_change_password? |
|
94 |
session[:pwd] = '1' |
|
95 |
end |
|
96 |
end |
|
97 |
|
|
98 |
def user_setup |
|
99 |
# Check the settings cache for each request |
|
100 |
Setting.check_cache |
|
101 |
# Find the current user |
|
102 |
User.current = find_current_user |
|
103 |
logger.info(" Current user: " + (User.current.logged? ? "#{User.current.login} (id=#{User.current.id})" : "anonymous")) if logger |
|
104 |
end |
|
105 |
|
|
106 |
# Returns the current user or nil if no user is logged in |
|
107 |
# and starts a session if needed |
|
108 |
def find_current_user |
|
109 |
user = nil |
|
110 |
unless api_request? |
|
111 |
if session[:user_id] |
|
112 |
# existing session |
|
113 |
user = (User.active.find(session[:user_id]) rescue nil) |
|
114 |
elsif autologin_user = try_to_autologin |
|
115 |
user = autologin_user |
|
116 |
elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth? |
|
117 |
# RSS key authentication does not start a session |
|
118 |
user = User.find_by_rss_key(params[:key]) |
|
119 |
end |
|
120 |
end |
|
121 |
if user.nil? && Setting.rest_api_enabled? && accept_api_auth? |
|
122 |
if (key = api_key_from_request) |
|
123 |
# Use API key |
|
124 |
user = User.find_by_api_key(key) |
|
125 |
elsif request.authorization.to_s =~ /\ABasic /i |
|
126 |
# HTTP Basic, either username/password or API key/random |
|
127 |
authenticate_with_http_basic do |username, password| |
|
128 |
user = User.try_to_login(username, password) || User.find_by_api_key(username) |
|
129 |
end |
|
130 |
if user && user.must_change_password? |
|
131 |
render_error :message => 'You must change your password', :status => 403 |
|
132 |
return |
|
133 |
end |
|
134 |
end |
|
135 |
# Switch user if requested by an admin user |
|
136 |
if user && user.admin? && (username = api_switch_user_from_request) |
|
137 |
su = User.find_by_login(username) |
|
138 |
if su && su.active? |
|
139 |
logger.info(" User switched by: #{user.login} (id=#{user.id})") if logger |
|
140 |
user = su |
|
141 |
else |
|
142 |
render_error :message => 'Invalid X-Redmine-Switch-User header', :status => 412 |
|
143 |
end |
|
144 |
end |
|
145 |
end |
|
146 |
user |
|
147 |
end |
|
148 |
|
|
149 |
def force_logout_if_password_changed |
|
150 |
passwd_changed_on = User.current.passwd_changed_on || Time.at(0) |
|
151 |
# Make sure we force logout only for web browser sessions, not API calls |
|
152 |
# if the password was changed after the session creation. |
|
153 |
if session[:user_id] && passwd_changed_on.utc.to_i > session[:ctime].to_i |
|
154 |
reset_session |
|
155 |
set_localization |
|
156 |
flash[:error] = l(:error_session_expired) |
|
157 |
redirect_to signin_url |
|
158 |
end |
|
159 |
end |
|
160 |
|
|
161 |
def autologin_cookie_name |
|
162 |
Redmine::Configuration['autologin_cookie_name'].presence || 'autologin' |
|
163 |
end |
|
164 |
|
|
165 |
def try_to_autologin |
|
166 |
if cookies[autologin_cookie_name] && Setting.autologin? |
|
167 |
# auto-login feature starts a new session |
|
168 |
user = User.try_to_autologin(cookies[autologin_cookie_name]) |
|
169 |
if user |
|
170 |
reset_session |
|
171 |
start_user_session(user) |
|
172 |
end |
|
173 |
user |
|
174 |
end |
|
175 |
end |
|
176 |
|
|
177 |
# Sets the logged in user |
|
178 |
def logged_user=(user) |
|
179 |
reset_session |
|
180 |
if user && user.is_a?(User) |
|
181 |
User.current = user |
|
182 |
start_user_session(user) |
|
183 |
else |
|
184 |
User.current = User.anonymous |
|
185 |
end |
|
186 |
end |
|
187 |
|
|
188 |
# Logs out current user |
|
189 |
def logout_user |
|
190 |
if User.current.logged? |
|
191 |
cookies.delete(autologin_cookie_name) |
|
192 |
Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin']) |
|
193 |
self.logged_user = nil |
|
194 |
end |
|
195 |
end |
|
196 |
|
|
197 |
# check if login is globally required to access the application |
|
198 |
def check_if_login_required |
|
199 |
# no check needed if user is already logged in |
|
200 |
return true if User.current.logged? |
|
201 |
require_login if Setting.login_required? |
|
202 |
end |
|
203 |
|
|
204 |
def check_password_change |
|
205 |
if session[:pwd] |
|
206 |
if User.current.must_change_password? |
|
207 |
redirect_to my_password_path |
|
208 |
else |
|
209 |
session.delete(:pwd) |
|
210 |
end |
|
211 |
end |
|
212 |
end |
|
213 |
|
|
214 |
def set_localization(user=User.current) |
|
215 |
lang = nil |
|
216 |
if user && user.logged? |
|
217 |
lang = find_language(user.language) |
|
218 |
end |
|
219 |
if lang.nil? && !Setting.force_default_language_for_anonymous? && request.env['HTTP_ACCEPT_LANGUAGE'] |
|
220 |
accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first |
|
221 |
if !accept_lang.blank? |
|
222 |
accept_lang = accept_lang.downcase |
|
223 |
lang = find_language(accept_lang) || find_language(accept_lang.split('-').first) |
|
224 |
end |
|
225 |
end |
|
226 |
lang ||= Setting.default_language |
|
227 |
set_language_if_valid(lang) |
|
228 |
end |
|
229 |
|
|
230 |
def require_login |
|
231 |
if !User.current.logged? |
|
232 |
# Extract only the basic url parameters on non-GET requests |
|
233 |
if request.get? |
|
234 |
url = url_for(params) |
|
235 |
else |
|
236 |
url = url_for(:controller => params[:controller], :action => params[:action], :id => params[:id], :project_id => params[:project_id]) |
|
237 |
end |
|
238 |
respond_to do |format| |
|
239 |
format.html { |
|
240 |
if request.xhr? |
|
241 |
head :unauthorized |
|
242 |
else |
|
243 |
redirect_to :controller => "account", :action => "login", :back_url => url |
|
244 |
end |
|
245 |
} |
|
246 |
format.atom { redirect_to :controller => "account", :action => "login", :back_url => url } |
|
247 |
format.xml { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' } |
|
248 |
format.js { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' } |
|
249 |
format.json { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' } |
|
250 |
end |
|
251 |
return false |
|
252 |
end |
|
253 |
true |
|
254 |
end |
|
255 |
|
|
256 |
def require_admin |
|
257 |
return unless require_login |
|
258 |
if !User.current.admin? |
|
259 |
render_403 |
|
260 |
return false |
|
261 |
end |
|
262 |
true |
|
263 |
end |
|
264 |
|
|
265 |
def deny_access |
|
266 |
User.current.logged? ? render_403 : require_login |
|
267 |
end |
|
268 |
|
|
269 |
# Authorize the user for the requested action |
|
270 |
def authorize(ctrl = params[:controller], action = params[:action], global = false) |
|
271 |
allowed = User.current.allowed_to?({:controller => ctrl, :action => action}, @project || @projects, :global => global) |
|
272 |
if allowed |
|
273 |
true |
|
274 |
else |
|
275 |
if @project && @project.archived? |
|
276 |
render_403 :message => :notice_not_authorized_archived_project |
|
277 |
else |
|
278 |
deny_access |
|
279 |
end |
|
280 |
end |
|
281 |
end |
|
282 |
|
|
283 |
# Authorize the user for the requested action outside a project |
|
284 |
def authorize_global(ctrl = params[:controller], action = params[:action], global = true) |
|
285 |
authorize(ctrl, action, global) |
|
286 |
end |
|
287 |
|
|
288 |
# Find project of id params[:id] |
|
289 |
def find_project |
|
290 |
@project = Project.find(params[:id]) |
|
291 |
rescue ActiveRecord::RecordNotFound |
|
292 |
render_404 |
|
293 |
end |
|
294 |
|
|
295 |
# Find project of id params[:project_id] |
|
296 |
def find_project_by_project_id |
|
297 |
@project = Project.find(params[:project_id]) |
|
298 |
rescue ActiveRecord::RecordNotFound |
|
299 |
render_404 |
|
300 |
end |
|
301 |
|
|
302 |
# Find a project based on params[:project_id] |
|
303 |
# TODO: some subclasses override this, see about merging their logic |
|
304 |
def find_optional_project |
|
305 |
@project = Project.find(params[:project_id]) unless params[:project_id].blank? |
|
306 |
allowed = User.current.allowed_to?({:controller => params[:controller], :action => params[:action]}, @project, :global => true) |
|
307 |
allowed ? true : deny_access |
|
308 |
rescue ActiveRecord::RecordNotFound |
|
309 |
render_404 |
|
310 |
end |
|
311 |
|
|
312 |
# Finds and sets @project based on @object.project |
|
313 |
def find_project_from_association |
|
314 |
render_404 unless @object.present? |
|
315 |
|
|
316 |
@project = @object.project |
|
317 |
end |
|
318 |
|
|
319 |
def find_model_object |
|
320 |
model = self.class.model_object |
|
321 |
if model |
|
322 |
@object = model.find(params[:id]) |
|
323 |
self.instance_variable_set('@' + controller_name.singularize, @object) if @object |
|
324 |
end |
|
325 |
rescue ActiveRecord::RecordNotFound |
|
326 |
render_404 |
|
327 |
end |
|
328 |
|
|
329 |
def self.model_object(model) |
|
330 |
self.model_object = model |
|
331 |
end |
|
332 |
|
|
333 |
# Find the issue whose id is the :id parameter |
|
334 |
# Raises a Unauthorized exception if the issue is not visible |
|
335 |
def find_issue |
|
336 |
# Issue.visible.find(...) can not be used to redirect user to the login form |
|
337 |
# if the issue actually exists but requires authentication |
|
338 |
@issue = Issue.find(params[:id]) |
|
339 |
raise Unauthorized unless @issue.visible? |
|
340 |
@project = @issue.project |
|
341 |
rescue ActiveRecord::RecordNotFound |
|
342 |
render_404 |
|
343 |
end |
|
344 |
|
|
345 |
# Find issues with a single :id param or :ids array param |
|
346 |
# Raises a Unauthorized exception if one of the issues is not visible |
|
347 |
def find_issues |
|
348 |
@issues = Issue.where(:id => (params[:id] || params[:ids])).preload(:project, :status, :tracker, :priority, :author, :assigned_to, :relations_to).to_a |
|
349 |
raise ActiveRecord::RecordNotFound if @issues.empty? |
|
350 |
raise Unauthorized unless @issues.all?(&:visible?) |
|
351 |
@projects = @issues.collect(&:project).compact.uniq |
|
352 |
@project = @projects.first if @projects.size == 1 |
|
353 |
rescue ActiveRecord::RecordNotFound |
|
354 |
render_404 |
|
355 |
end |
|
356 |
|
|
357 |
def find_attachments |
|
358 |
if (attachments = params[:attachments]).present? |
|
359 |
att = attachments.values.collect do |attachment| |
|
360 |
Attachment.find_by_token( attachment[:token] ) if attachment[:token].present? |
|
361 |
end |
|
362 |
att.compact! |
|
363 |
end |
|
364 |
@attachments = att || [] |
|
365 |
end |
|
366 |
|
|
367 |
# make sure that the user is a member of the project (or admin) if project is private |
|
368 |
# used as a before_filter for actions that do not require any particular permission on the project |
|
369 |
def check_project_privacy |
|
370 |
if @project && [email protected]? |
|
371 |
if @project.visible? |
|
372 |
true |
|
373 |
else |
|
374 |
deny_access |
|
375 |
end |
|
376 |
else |
|
377 |
@project = nil |
|
378 |
render_404 |
|
379 |
false |
|
380 |
end |
|
381 |
end |
|
382 |
|
|
383 |
def back_url |
|
384 |
url = params[:back_url] |
|
385 |
if url.nil? && referer = request.env['HTTP_REFERER'] |
|
386 |
url = CGI.unescape(referer.to_s) |
|
387 |
end |
|
388 |
url |
|
389 |
end |
|
390 |
|
|
391 |
def redirect_back_or_default(default, options={}) |
|
392 |
back_url = params[:back_url].to_s |
|
393 |
if back_url.present? && valid_url = validate_back_url(back_url) |
|
394 |
redirect_to(valid_url) |
|
395 |
return |
|
396 |
elsif options[:referer] |
|
397 |
redirect_to_referer_or default |
|
398 |
return |
|
399 |
end |
|
400 |
redirect_to default |
|
401 |
false |
|
402 |
end |
|
403 |
|
|
404 |
# Returns a validated URL string if back_url is a valid url for redirection, |
|
405 |
# otherwise false |
|
406 |
def validate_back_url(back_url) |
|
407 |
if CGI.unescape(back_url).include?('..') |
|
408 |
return false |
|
409 |
end |
|
410 |
|
|
411 |
begin |
|
412 |
uri = URI.parse(back_url) |
|
413 |
rescue URI::InvalidURIError |
|
414 |
return false |
|
415 |
end |
|
416 |
|
|
417 |
[:scheme, :host, :port].each do |component| |
|
418 |
if uri.send(component).present? && uri.send(component) != request.send(component) |
|
419 |
return false |
|
420 |
end |
|
421 |
uri.send(:"#{component}=", nil) |
|
422 |
end |
|
423 |
# Always ignore basic user:password in the URL |
|
424 |
uri.userinfo = nil |
|
425 |
|
|
426 |
path = uri.to_s |
|
427 |
# Ensure that the remaining URL starts with a slash, followed by a |
|
428 |
# non-slash character or the end |
|
429 |
if path !~ %r{\A/([^/]|\z)} |
|
430 |
return false |
|
431 |
end |
|
432 |
|
|
433 |
if path.match(%r{/(login|account/register)}) |
|
434 |
return false |
|
435 |
end |
|
436 |
|
|
437 |
if relative_url_root.present? && !path.starts_with?(relative_url_root) |
|
438 |
return false |
|
439 |
end |
|
440 |
|
|
441 |
return path |
|
442 |
end |
|
443 |
private :validate_back_url |
|
444 |
|
|
445 |
def valid_back_url?(back_url) |
|
446 |
!!validate_back_url(back_url) |
|
447 |
end |
|
448 |
private :valid_back_url? |
|
449 |
|
|
450 |
# Redirects to the request referer if present, redirects to args or call block otherwise. |
|
451 |
def redirect_to_referer_or(*args, &block) |
|
452 |
redirect_to :back |
|
453 |
rescue ::ActionController::RedirectBackError |
|
454 |
if args.any? |
|
455 |
redirect_to *args |
|
456 |
elsif block_given? |
|
457 |
block.call |
|
458 |
else |
|
459 |
raise "#redirect_to_referer_or takes arguments or a block" |
|
460 |
end |
|
461 |
end |
|
462 |
|
|
463 |
def render_403(options={}) |
|
464 |
@project = nil |
|
465 |
render_error({:message => :notice_not_authorized, :status => 403}.merge(options)) |
|
466 |
return false |
|
467 |
end |
|
468 |
|
|
469 |
def render_404(options={}) |
|
470 |
render_error({:message => :notice_file_not_found, :status => 404}.merge(options)) |
|
471 |
return false |
|
472 |
end |
|
473 |
|
|
474 |
# Renders an error response |
|
475 |
def render_error(arg) |
|
476 |
arg = {:message => arg} unless arg.is_a?(Hash) |
|
477 |
|
|
478 |
@message = arg[:message] |
|
479 |
@message = l(@message) if @message.is_a?(Symbol) |
|
480 |
@status = arg[:status] || 500 |
|
481 |
|
|
482 |
respond_to do |format| |
|
483 |
format.html { |
|
484 |
render :template => 'common/error', :layout => use_layout, :status => @status |
|
485 |
} |
|
486 |
format.any { head @status } |
|
487 |
end |
|
488 |
end |
|
489 |
|
|
490 |
# Handler for ActionView::MissingTemplate exception |
|
491 |
def missing_template |
|
492 |
logger.warn "Missing template, responding with 404" |
|
493 |
@project = nil |
|
494 |
render_404 |
|
495 |
end |
|
496 |
|
|
497 |
# Filter for actions that provide an API response |
|
498 |
# but have no HTML representation for non admin users |
|
499 |
def require_admin_or_api_request |
|
500 |
return true if api_request? |
|
501 |
if User.current.admin? |
|
502 |
true |
|
503 |
elsif User.current.logged? |
|
504 |
render_error(:status => 406) |
|
505 |
else |
|
506 |
deny_access |
|
507 |
end |
|
508 |
end |
|
509 |
|
|
510 |
# Picks which layout to use based on the request |
|
511 |
# |
|
512 |
# @return [boolean, string] name of the layout to use or false for no layout |
|
513 |
def use_layout |
|
514 |
request.xhr? ? false : 'base' |
|
515 |
end |
|
516 |
|
|
517 |
def render_feed(items, options={}) |
|
518 |
@items = items || [] |
|
519 |
@items.sort! {|x,y| y.event_datetime <=> x.event_datetime } |
|
520 |
@items = @items.slice(0, Setting.feeds_limit.to_i) |
|
521 |
@title = options[:title] || Setting.app_title |
|
522 |
render :template => "common/feed", :formats => [:atom], :layout => false, |
|
523 |
:content_type => 'application/atom+xml' |
|
524 |
end |
|
525 |
|
|
526 |
def self.accept_rss_auth(*actions) |
|
527 |
if actions.any? |
|
528 |
self.accept_rss_auth_actions = actions |
|
529 |
else |
|
530 |
self.accept_rss_auth_actions || [] |
|
531 |
end |
|
532 |
end |
|
533 |
|
|
534 |
def accept_rss_auth?(action=action_name) |
|
535 |
self.class.accept_rss_auth.include?(action.to_sym) |
|
536 |
end |
|
537 |
|
|
538 |
def self.accept_api_auth(*actions) |
|
539 |
if actions.any? |
|
540 |
self.accept_api_auth_actions = actions |
|
541 |
else |
|
542 |
self.accept_api_auth_actions || [] |
|
543 |
end |
|
544 |
end |
|
545 |
|
|
546 |
def accept_api_auth?(action=action_name) |
|
547 |
self.class.accept_api_auth.include?(action.to_sym) |
|
548 |
end |
|
549 |
|
|
550 |
# Returns the number of objects that should be displayed |
|
551 |
# on the paginated list |
|
552 |
def per_page_option |
|
553 |
per_page = nil |
|
554 |
if params[:per_page] && Setting.per_page_options_array.include?(params[:per_page].to_s.to_i) |
|
555 |
per_page = params[:per_page].to_s.to_i |
|
556 |
session[:per_page] = per_page |
|
557 |
elsif session[:per_page] |
|
558 |
per_page = session[:per_page] |
|
559 |
else |
|
560 |
per_page = Setting.per_page_options_array.first || 25 |
|
561 |
end |
|
562 |
per_page |
|
563 |
end |
|
564 |
|
|
565 |
# Returns offset and limit used to retrieve objects |
|
566 |
# for an API response based on offset, limit and page parameters |
|
567 |
def api_offset_and_limit(options=params) |
|
568 |
if options[:offset].present? |
|
569 |
offset = options[:offset].to_i |
|
570 |
if offset < 0 |
|
571 |
offset = 0 |
|
572 |
end |
|
573 |
end |
|
574 |
limit = options[:limit].to_i |
|
575 |
if limit < 1 |
|
576 |
limit = 25 |
|
577 |
elsif limit > 100 |
|
578 |
limit = 100 |
|
579 |
end |
|
580 |
if offset.nil? && options[:page].present? |
|
581 |
offset = (options[:page].to_i - 1) * limit |
|
582 |
offset = 0 if offset < 0 |
|
583 |
end |
|
584 |
offset ||= 0 |
|
585 |
|
|
586 |
[offset, limit] |
|
587 |
end |
|
588 |
|
|
589 |
# qvalues http header parser |
|
590 |
# code taken from webrick |
|
591 |
def parse_qvalues(value) |
|
592 |
tmp = [] |
|
593 |
if value |
|
594 |
parts = value.split(/,\s*/) |
|
595 |
parts.each {|part| |
|
596 |
if m = %r{^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$}.match(part) |
|
597 |
val = m[1] |
|
598 |
q = (m[2] or 1).to_f |
|
599 |
tmp.push([val, q]) |
|
600 |
end |
|
601 |
} |
|
602 |
tmp = tmp.sort_by{|val, q| -q} |
|
603 |
tmp.collect!{|val, q| val} |
|
604 |
end |
|
605 |
return tmp |
|
606 |
rescue |
|
607 |
nil |
|
608 |
end |
|
609 |
|
|
610 |
# Returns a string that can be used as filename value in Content-Disposition header |
|
611 |
def filename_for_content_disposition(name) |
|
612 |
request.env['HTTP_USER_AGENT'] =~ %r{(MSIE|Trident|Edge)} ? ERB::Util.url_encode(name) : name |
|
613 |
end |
|
614 |
|
|
615 |
def api_request? |
|
616 |
%w(xml json).include? params[:format] |
|
617 |
end |
|
618 |
|
|
619 |
# Returns the API key present in the request |
|
620 |
def api_key_from_request |
|
621 |
if params[:key].present? |
|
622 |
params[:key].to_s |
|
623 |
elsif request.headers["X-Redmine-API-Key"].present? |
|
624 |
request.headers["X-Redmine-API-Key"].to_s |
|
625 |
end |
|
626 |
end |
|
627 |
|
|
628 |
# Returns the API 'switch user' value if present |
|
629 |
def api_switch_user_from_request |
|
630 |
request.headers["X-Redmine-Switch-User"].to_s.presence |
|
631 |
end |
|
632 |
|
|
633 |
# Renders a warning flash if obj has unsaved attachments |
|
634 |
def render_attachment_warning_if_needed(obj) |
|
635 |
flash[:warning] = l(:warning_attachments_not_saved, obj.unsaved_attachments.size) if obj.unsaved_attachments.present? |
|
636 |
end |
|
637 |
|
|
638 |
# Rescues an invalid query statement. Just in case... |
|
639 |
def query_statement_invalid(exception) |
|
640 |
logger.error "Query::StatementInvalid: #{exception.message}" if logger |
|
641 |
session.delete(:query) |
|
642 |
sort_clear if respond_to?(:sort_clear) |
|
643 |
render_error "An error occurred while executing the query and has been logged. Please report this error to your Redmine administrator." |
|
644 |
end |
|
645 |
|
|
646 |
# Renders a 200 response for successfull updates or deletions via the API |
|
647 |
def render_api_ok |
|
648 |
render_api_head :ok |
|
649 |
end |
|
650 |
|
|
651 |
# Renders a head API response |
|
652 |
def render_api_head(status) |
|
653 |
# #head would return a response body with one space |
|
654 |
render :text => '', :status => status, :layout => nil |
|
655 |
end |
|
656 |
|
|
657 |
# Renders API response on validation failure |
|
658 |
# for an object or an array of objects |
|
659 |
def render_validation_errors(objects) |
|
660 |
messages = Array.wrap(objects).map {|object| object.errors.full_messages}.flatten |
|
661 |
render_api_errors(messages) |
|
662 |
end |
|
663 |
|
|
664 |
def render_api_errors(*messages) |
|
665 |
@error_messages = messages.flatten |
|
666 |
render :template => 'common/error_messages.api', :status => :unprocessable_entity, :layout => nil |
|
667 |
end |
|
668 |
|
|
669 |
# Overrides #_include_layout? so that #render with no arguments |
|
670 |
# doesn't use the layout for api requests |
|
671 |
def _include_layout?(*args) |
|
672 |
api_request? ? false : super |
|
673 |
end |
|
674 |
end |
|
0 | 675 |
Also available in: Unified diff
tagged version 2.6.10