Compare commits

..

52 Commits
2.3.3 ... 2.2.3

Author SHA1 Message Date
Jean-Philippe Lang
689d533049 tagged version 2.2.3
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/tags/2.2.3@11368 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 19:52:36 +00:00
Jean-Philippe Lang
d094dea0ec Merged r11366 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11367 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 18:08:38 +00:00
Jean-Philippe Lang
3a98a14250 Merged r11350 from trunk (#13126).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11365 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 18:04:49 +00:00
Jean-Philippe Lang
ecef96a6b9 Merged r11332 from trunk (#13097).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11364 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 18:03:16 +00:00
Jean-Philippe Lang
0951522247 Merged r11331 and r11333 from trunk (#13075).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11363 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 18:01:15 +00:00
Jean-Philippe Lang
42cc2d322a Merged r11281 from trunk (#12979).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11362 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 17:57:46 +00:00
Jean-Philippe Lang
0367c323de Merged r11258 from trunk (#12930).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11361 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 17:56:39 +00:00
Toshi MARUYAMA
80be82ae50 Merged r11353 from trunk to 2.2-stable
upgrade Rails to 3.2.12.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11358 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 06:28:11 +00:00
Toshi MARUYAMA
ebed927de5 2.2-stable: svn propset svn:eol-style native SVG source files (#12971)
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11357 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 03:52:41 +00:00
Toshi MARUYAMA
cbd069118a 2.2-stable: backout r11355 (back to Rails 3.2.11)
jruby-1.6.7 tests fail on CI server.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11356 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 02:49:25 +00:00
Toshi MARUYAMA
a211d1be7d Merged r11353 from trunk to 2.2-stable
upgrade Rails to 3.2.12.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11355 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-12 01:46:21 +00:00
Toshi MARUYAMA
0a8e0a3bed Merged r11306 from trunk to 2.2-stable (#11987)
pdf: fix broken new line in table.

Contributed by Jun NAITOH.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11308 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-02-03 06:53:18 +00:00
Toshi MARUYAMA
58cf34dea5 Merged r11263 from trunk to 2.2-stable (#12987)
Russian translation for 2.2-stable updated.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11266 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-26 00:40:21 +00:00
Toshi MARUYAMA
594a7bde95 Merged r11246 from trunk to 2.2-stable (#12926, #12928)
Bulgarian translation for 2.2-stable updated by Ivan Cenov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11251 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-21 13:54:49 +00:00
Toshi MARUYAMA
c5e257d82b Merged r11243 from trunk to 2.2-stable (#12922)
Spanish translation for 2.2-stable updated by Jorge López.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11245 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-21 11:50:27 +00:00
Jean-Philippe Lang
56b12b289f Merged r11239 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11240 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-20 18:24:43 +00:00
Jean-Philippe Lang
c99eef1aff Merged r11228 from trunk (#12851).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11236 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-20 17:09:36 +00:00
Jean-Philippe Lang
ed891e2733 Merged r11227 from trunk (#9842).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11235 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-20 17:06:46 +00:00
Jean-Philippe Lang
4620b8b8db Backported r11233 from trunk (#12833).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11234 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-20 17:03:40 +00:00
Jean-Philippe Lang
98eb2edd25 Merged r11225 from trunk (#12838).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11232 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-20 17:01:03 +00:00
Jean-Philippe Lang
ed7318fb8d Backported r11157 and r11158 from trunk (#12801).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11231 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-20 16:59:42 +00:00
Jean-Philippe Lang
5a1a2f5855 Merged r11159 from trunk (#12799).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11230 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-20 16:56:50 +00:00
Jean-Philippe Lang
f1314278d5 Backported r11196 from trunk (#7510).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11229 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-20 16:55:37 +00:00
Toshi MARUYAMA
3a8b872a09 Merged r11170 from trunk to 2.2-stable (#12818)
Swedish translation updated by Nicklas Holm.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11172 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-12 12:43:51 +00:00
Toshi MARUYAMA
56290979fc Merged r11163 from trunk to 2.2-stable (#12809)
Swedish translation updated by Nicklas Holm.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11165 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-11 13:19:18 +00:00
Toshi MARUYAMA
6e0fb415a7 Merged r11160 from trunk to 2.2-stable (#12800)
Serbian translation updated by Miodrag Milic.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11162 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-11 08:31:14 +00:00
Jean-Philippe Lang
f26654b29f Merged r11146 from trunk: Changes for 2.2.1 release.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11147 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-09 13:33:24 +00:00
Jean-Philippe Lang
5c62c1cf95 Merged r11126 from trunk (#12744).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11145 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-09 13:31:05 +00:00
Jean-Philippe Lang
2d6adbd7ff Merged r11088 from trunk (#12691).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11144 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-09 13:29:59 +00:00
Jean-Philippe Lang
b0ccaffe1b Merged r11064 from trunk (#12652).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11143 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-09 13:29:08 +00:00
Toshi MARUYAMA
2c37617973 Merged r11140 from trunk to 2.2-stable.
Upgrade to Rails 3.2.11.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11142 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-08 23:57:13 +00:00
Toshi MARUYAMA
567eb70fdb Merged r11128 from trunk to 2.2-stable.
Test fails when run at the beginning of the day.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11141 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-08 23:14:03 +00:00
Toshi MARUYAMA
de63102925 Merged r11109 from trunk to 2.2-stable
Upgrade to Rails 3.2.10.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11111 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-04 02:05:44 +00:00
Toshi MARUYAMA
a8fcf9389e Merged r11091 from trunk (#12711, #11290)
fix incorrect min_x_value of lib/SVG/Graph/TimeSeries.rb by r10439.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11093 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-01-03 00:15:32 +00:00
Toshi MARUYAMA
3e4b36de83 Merged r11051 from trunk to 2.2-stable (#12630)
Russian "x_hours" translation updated by Mikhail Velkin.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11054 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-19 00:00:04 +00:00
Jean-Philippe Lang
edd584d59e Merged r11041 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11042 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-18 12:24:17 +00:00
Toshi MARUYAMA
e2b27ab696 Merged r11036 from trunk to 2.2-stable (#12615, #12619)
Russian translation changed by Kirill Bezrukov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11040 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-18 00:04:49 +00:00
Toshi MARUYAMA
1968d039ee Merged r11035 from trunk to 2.2-stable (#12615)
Russian translation updated by Kirill Bezrukov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11037 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-17 23:24:31 +00:00
Toshi MARUYAMA
fddc33cd45 Merged r11022 from trunk to 2.2-stable (#12614)
Dutch translation updated.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11023 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-17 12:43:15 +00:00
Toshi MARUYAMA
29518ba0cf Merged r11015 from trunk to 2.2-stable (#12605, #12608)
Norwegian translation changed by Ketil Mehl.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11018 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-16 07:34:34 +00:00
Toshi MARUYAMA
acd27b9eb1 Merged r11014 from trunk to 2.2-stable (#12605)
Norwegian translation for 1.4-stable updated by Ketil Mehl.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11017 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-16 07:34:09 +00:00
Toshi MARUYAMA
6445b5997c Merged r11012 from trunk to 2.2-stable (#12607)
Japanese translation for 2.2-stable updated.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11016 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-16 07:33:39 +00:00
Jean-Philippe Lang
416d33973f Merged r10991 from trunk (#12568).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11009 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-15 07:55:50 +00:00
Jean-Philippe Lang
82c7dc11d2 Merged r10992 from trunk (#12400).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11006 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-15 07:52:39 +00:00
Jean-Philippe Lang
d22f782d3f Merged r10956 from trunk (#12513).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11004 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-15 07:51:12 +00:00
Jean-Philippe Lang
3717fdfa79 Merged r10975 from trunk (#12566).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11002 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-15 07:49:31 +00:00
Toshi MARUYAMA
9d3d932703 Merged r10999 from trunk (#12602)
Korean translation updated by Jongwook Choi.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@11000 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-15 01:32:43 +00:00
Jean-Philippe Lang
3a379ce4b9 Merged r10948 into 2.2-stable (#3447).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@10952 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-08 08:41:59 +00:00
Toshi MARUYAMA
daa77f0109 Merged r10946 from trunk to 2.2-stable (#12514)
Lithuanian translation updated by Egidijus Zideckas.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@10947 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-06 06:30:05 +00:00
Toshi MARUYAMA
c0d66d626b Merged r10940 from trunk to 2.2-stable (#12494)
Bulgarian "button_submit" translation changed by Ivan Cenov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@10942 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-04 05:43:41 +00:00
Jean-Philippe Lang
bf02b76ca3 Sets stable branch.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@10908 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-02 18:01:48 +00:00
Jean-Philippe Lang
75e02ca486 branch 2.2-stable added
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/2.2-stable@10907 e93f8b46-1217-0410-a6f0-8f06a7374b81
2012-12-02 17:58:22 +00:00
749 changed files with 10881 additions and 14943 deletions

91
Gemfile
View File

@@ -1,9 +1,9 @@
source 'https://rubygems.org'
source 'http://rubygems.org'
gem "rails", "3.2.13"
gem 'rails', '3.2.12'
gem "jquery-rails", "~> 2.0.2"
gem "i18n", "~> 0.6.0"
gem "coderay", "~> 1.0.9"
gem "coderay", "~> 1.0.6"
gem "fastercsv", "~> 1.5.0", :platforms => [:mri_18, :mingw_18, :jruby]
gem "builder", "3.0.0"
@@ -14,7 +14,7 @@ end
# Optional gem for OpenID authentication
group :openid do
gem "ruby-openid", "~> 2.2.3", :require => "openid"
gem "ruby-openid", "~> 2.1.4", :require => "openid"
gem "rack-openid"
end
@@ -28,47 +28,43 @@ platforms :mri, :mingw do
end
end
platforms :jruby do
# jruby-openssl is bundled with JRuby 1.7.0
gem "jruby-openssl" if Object.const_defined?(:JRUBY_VERSION) && JRUBY_VERSION < '1.7.0'
gem "activerecord-jdbc-adapter", "1.2.5"
# Database gems
platforms :mri, :mingw do
group :postgresql do
gem "pg", ">= 0.11.0"
end
group :sqlite do
gem "sqlite3"
end
end
# Include database gems for the adapters found in the database
# configuration file
require 'erb'
require 'yaml'
database_file = File.join(File.dirname(__FILE__), "config/database.yml")
if File.exist?(database_file)
database_config = YAML::load(ERB.new(IO.read(database_file)).result)
adapters = database_config.values.map {|c| c['adapter']}.compact.uniq
if adapters.any?
adapters.each do |adapter|
case adapter
when 'mysql2'
gem "mysql2", "~> 0.3.11", :platforms => [:mri, :mingw]
gem "activerecord-jdbcmysql-adapter", :platforms => :jruby
when 'mysql'
gem "mysql", "~> 2.8.1", :platforms => [:mri, :mingw]
gem "activerecord-jdbcmysql-adapter", :platforms => :jruby
when /postgresql/
gem "pg", ">= 0.11.0", :platforms => [:mri, :mingw]
gem "activerecord-jdbcpostgresql-adapter", :platforms => :jruby
when /sqlite3/
gem "sqlite3", :platforms => [:mri, :mingw]
gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
when /sqlserver/
gem "tiny_tds", "~> 0.5.1", :platforms => [:mri, :mingw]
gem "activerecord-sqlserver-adapter", :platforms => [:mri, :mingw]
else
warn("Unknown database adapter `#{adapter}` found in config/database.yml, use Gemfile.local to load your own database gems")
end
end
else
warn("No adapter found in config/database.yml, please configure it first")
platforms :mri_18, :mingw_18 do
group :mysql do
gem "mysql", "~> 2.8.1"
end
end
platforms :mri_19, :mingw_19 do
group :mysql do
gem "mysql2", "~> 0.3.11"
end
end
platforms :jruby do
gem "jruby-openssl"
group :mysql do
gem "activerecord-jdbcmysql-adapter"
end
group :postgresql do
gem "activerecord-jdbcpostgresql-adapter"
end
group :sqlite do
gem "activerecord-jdbcsqlite3-adapter"
end
else
warn("Please configure your config/database.yml first")
end
group :development do
@@ -77,10 +73,13 @@ group :development do
end
group :test do
gem "shoulda", "~> 3.3.2"
gem "mocha", "~> 0.13.3"
gem 'capybara', '~> 2.0.0'
gem 'nokogiri', '< 1.6.0'
gem "shoulda", "~> 2.11"
# Shoulda does not work nice on Ruby 1.9.3 and JRuby 1.7.
# It seems to need test-unit explicitely.
platforms = [:mri_19]
platforms << :jruby if defined?(JRUBY_VERSION) && JRUBY_VERSION >= "1.7"
gem "test-unit", :platforms => platforms
gem "mocha", "0.12.3"
end
local_gemfile = File.join(File.dirname(__FILE__), "Gemfile.local")

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -25,9 +25,7 @@ class AccountController < ApplicationController
# Login request and validation
def login
if request.get?
if User.current.logged?
redirect_to home_url
end
logout_user
else
authenticate_user
end
@@ -38,20 +36,15 @@ class AccountController < ApplicationController
# Log out current user and redirect to welcome page
def logout
if User.current.anonymous?
redirect_to home_url
elsif request.post?
logout_user
redirect_to home_url
end
# display the logout form
logout_user
redirect_to home_url
end
# Lets user choose a new password
def lost_password
(redirect_to(home_url); return) unless Setting.lost_password?
redirect_to(home_url) && return unless Setting.lost_password?
if params[:token]
@token = Token.find_token("recovery", params[:token].to_s)
@token = Token.find_by_action_and_value("recovery", params[:token].to_s)
if @token.nil? || @token.expired?
redirect_to home_url
return
@@ -99,10 +92,10 @@ class AccountController < ApplicationController
# User self-registration
def register
(redirect_to(home_url); return) unless Setting.self_registration? || session[:auth_source_registration]
redirect_to(home_url) && return unless Setting.self_registration? || session[:auth_source_registration]
if request.get?
session[:auth_source_registration] = nil
@user = User.new(:language => current_language.to_s)
@user = User.new(:language => Setting.default_language)
else
user_params = params[:user] || {}
@user = User.new
@@ -117,7 +110,7 @@ class AccountController < ApplicationController
session[:auth_source_registration] = nil
self.logged_user = @user
flash[:notice] = l(:notice_account_activated)
redirect_to my_account_path
redirect_to :controller => 'my', :action => 'account'
end
else
@user.login = params[:user][:login]
@@ -139,11 +132,11 @@ class AccountController < ApplicationController
# Token based account activation
def activate
(redirect_to(home_url); return) unless Setting.self_registration? && params[:token].present?
token = Token.find_token('register', params[:token].to_s)
(redirect_to(home_url); return) unless token and !token.expired?
redirect_to(home_url) && return unless Setting.self_registration? && params[:token]
token = Token.find_by_action_and_value('register', params[:token])
redirect_to(home_url) && return unless token and !token.expired?
user = token.user
(redirect_to(home_url); return) unless user.registered?
redirect_to(home_url) && return unless user.registered?
user.activate
if user.save
token.destroy
@@ -176,14 +169,12 @@ class AccountController < ApplicationController
end
def open_id_authenticate(openid_url)
back_url = signin_url(:autologin => params[:autologin])
authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => back_url, :method => :post) do |result, identity_url, registration|
authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => signin_url, :method => :post) do |result, identity_url, registration|
if result.successful?
user = User.find_or_initialize_by_identity_url(identity_url)
if user.new_record?
# Self-registration off
(redirect_to(home_url); return) unless Setting.self_registration?
redirect_to(home_url) && return unless Setting.self_registration?
# Create on the fly
user.login = registration['nickname'] unless registration['nickname'].nil?
@@ -227,11 +218,12 @@ class AccountController < ApplicationController
set_autologin_cookie(user)
end
call_hook(:controller_account_success_authentication_after, {:user => user })
redirect_back_or_default my_page_path
redirect_back_or_default :controller => 'my', :action => 'page'
end
def set_autologin_cookie(user)
token = Token.create(:user => user, :action => 'autologin')
cookie_name = Redmine::Configuration['autologin_cookie_name'] || 'autologin'
cookie_options = {
:value => token.value,
:expires => 1.year.from_now,
@@ -239,7 +231,7 @@ class AccountController < ApplicationController
:secure => (Redmine::Configuration['autologin_cookie_secure'] ? true : false),
:httponly => true
}
cookies[autologin_cookie_name] = cookie_options
cookies[cookie_name] = cookie_options
end
# Onthefly creation failed, display the registration form to fill/fix attributes
@@ -278,7 +270,7 @@ class AccountController < ApplicationController
if user.save
self.logged_user = user
flash[:notice] = l(:notice_account_activated)
redirect_to my_account_path
redirect_to :controller => 'my', :action => 'account'
else
yield if block_given?
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -23,18 +23,19 @@ class AdminController < ApplicationController
before_filter :require_admin
helper :sort
include SortHelper
include SortHelper
def index
@no_configuration_data = Redmine::DefaultData::Loader::no_data?
end
def projects
@status = params[:status] || 1
scope = Project.status(@status).order('lft')
scope = Project.status(@status)
scope = scope.like(params[:name]) if params[:name].present?
@projects = scope.all
@projects = scope.all(:order => 'lft')
render :action => "projects", :layout => false if request.xhr?
end
@@ -54,7 +55,7 @@ class AdminController < ApplicationController
flash[:error] = l(:error_can_t_load_default_data, e.message)
end
end
redirect_to admin_path
redirect_to :action => 'index'
end
def test_email
@@ -68,7 +69,7 @@ class AdminController < ApplicationController
flash[:error] = l(:notice_email_error, e.message)
end
ActionMailer::Base.raise_delivery_errors = raise_delivery_errors
redirect_to settings_path(:tab => 'notifications')
redirect_to :controller => 'settings', :action => 'edit', :tab => 'notifications'
end
def info

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -22,9 +22,6 @@ class Unauthorized < Exception; end
class ApplicationController < ActionController::Base
include Redmine::I18n
include Redmine::Pagination
include RoutesHelper
helper :routes
class_attribute :accept_api_auth_actions
class_attribute :accept_rss_auth_actions
@@ -35,7 +32,7 @@ class ApplicationController < ActionController::Base
protect_from_forgery
def handle_unverified_request
super
cookies.delete(autologin_cookie_name)
cookies.delete(:autologin)
end
before_filter :session_expiration, :user_setup, :check_if_login_required, :set_localization
@@ -127,14 +124,10 @@ class ApplicationController < ActionController::Base
user
end
def autologin_cookie_name
Redmine::Configuration['autologin_cookie_name'].presence || 'autologin'
end
def try_to_autologin
if cookies[autologin_cookie_name] && Setting.autologin?
if cookies[:autologin] && Setting.autologin?
# auto-login feature starts a new session
user = User.try_to_autologin(cookies[autologin_cookie_name])
user = User.try_to_autologin(cookies[:autologin])
if user
reset_session
start_user_session(user)
@@ -157,7 +150,7 @@ class ApplicationController < ActionController::Base
# Logs out current user
def logout_user
if User.current.logged?
cookies.delete(autologin_cookie_name)
cookies.delete :autologin
Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin'])
self.logged_user = nil
end
@@ -307,16 +300,6 @@ class ApplicationController < ActionController::Base
render_404
end
def find_attachments
if (attachments = params[:attachments]).present?
att = attachments.values.collect do |attachment|
Attachment.find_by_token( attachment[:token] ) if attachment[:token].present?
end
att.compact!
end
@attachments = att || []
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

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -85,17 +85,15 @@ class AttachmentsController < ApplicationController
@attachment = Attachment.new(:file => request.raw_post)
@attachment.author = User.current
@attachment.filename = params[:filename].presence || Redmine::Utils.random_hex(16)
saved = @attachment.save
respond_to do |format|
format.js
format.api {
if saved
render :action => 'upload', :status => :created
else
render_validation_errors(@attachment)
end
}
if @attachment.save
respond_to do |format|
format.api { render :action => 'upload', :status => :created }
end
else
respond_to do |format|
format.api { render_validation_errors(@attachment) }
end
end
end
@@ -103,17 +101,9 @@ class AttachmentsController < ApplicationController
if @attachment.container.respond_to?(:init_journal)
@attachment.container.init_journal(User.current)
end
if @attachment.container
# Make sure association callbacks are called
@attachment.container.attachments.delete(@attachment)
else
@attachment.destroy
end
respond_to do |format|
format.html { redirect_to_referer_or project_path(@project) }
format.js
end
# Make sure association callbacks are called
@attachment.container.attachments.delete(@attachment)
redirect_to_referer_or project_path(@project)
end
private
@@ -128,12 +118,7 @@ private
# Checks that the file exists and is readable
def file_readable
if @attachment.readable?
true
else
logger.error "Cannot send attachment, #{@attachment.diskfile} does not exist or is unreadable."
render_404
end
@attachment.readable? ? true : render_404
end
def read_authorize

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -20,77 +20,57 @@ class AuthSourcesController < ApplicationController
menu_item :ldap_authentication
before_filter :require_admin
before_filter :find_auth_source, :only => [:edit, :update, :test_connection, :destroy]
def index
@auth_source_pages, @auth_sources = paginate AuthSource, :per_page => 25
@auth_source_pages, @auth_sources = paginate AuthSource, :per_page => 10
end
def new
klass_name = params[:type] || 'AuthSourceLdap'
@auth_source = AuthSource.new_subclass_instance(klass_name, params[:auth_source])
render_404 unless @auth_source
end
def create
@auth_source = AuthSource.new_subclass_instance(params[:type], params[:auth_source])
if @auth_source.save
flash[:notice] = l(:notice_successful_create)
redirect_to auth_sources_path
redirect_to :action => 'index'
else
render :action => 'new'
end
end
def edit
@auth_source = AuthSource.find(params[:id])
end
def update
@auth_source = AuthSource.find(params[:id])
if @auth_source.update_attributes(params[:auth_source])
flash[:notice] = l(:notice_successful_update)
redirect_to auth_sources_path
redirect_to :action => 'index'
else
render :action => 'edit'
end
end
def test_connection
@auth_source = AuthSource.find(params[:id])
begin
@auth_source.test_connection
flash[:notice] = l(:notice_successful_connection)
rescue Exception => e
flash[:error] = l(:error_unable_to_connect, e.message)
end
redirect_to auth_sources_path
redirect_to :action => 'index'
end
def destroy
unless @auth_source.users.exists?
@auth_source = AuthSource.find(params[:id])
unless @auth_source.users.find(:first)
@auth_source.destroy
flash[:notice] = l(:notice_successful_delete)
end
redirect_to auth_sources_path
end
def autocomplete_for_new_user
results = AuthSource.search(params[:term])
render :json => results.map {|result| {
'value' => result[:login],
'label' => "#{result[:login]} (#{result[:firstname]} #{result[:lastname]})",
'login' => result[:login].to_s,
'firstname' => result[:firstname].to_s,
'lastname' => result[:lastname].to_s,
'mail' => result[:mail].to_s,
'auth_source_id' => result[:auth_source_id].to_s
}}
end
private
def find_auth_source
@auth_source = AuthSource.find(params[:id])
rescue ActiveRecord::RecordNotFound
render_404
redirect_to :action => 'index'
end
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -23,10 +23,10 @@ class AutoCompletesController < ApplicationController
q = (params[:q] || params[:term]).to_s.strip
if q.present?
scope = (params[:scope] == "all" || @project.nil? ? Issue : @project.issues).visible
if q.match(/\A#?(\d+)\z/)
@issues << scope.find_by_id($1.to_i)
if q.match(/^\d+$/)
@issues << scope.find_by_id(q.to_i)
end
@issues += scope.where("LOWER(#{Issue.table_name}.subject) LIKE LOWER(?)", "%#{q}%").order("#{Issue.table_name}.id DESC").limit(10).all
@issues += scope.where("LOWER(#{Issue.table_name}.subject) LIKE ?", "%#{q.downcase}%").order("#{Issue.table_name}.id DESC").limit(10).all
@issues.compact!
end
render :layout => false

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -37,29 +37,23 @@ class BoardsController < ApplicationController
respond_to do |format|
format.html {
sort_init 'updated_on', 'desc'
sort_update 'created_on' => "#{Message.table_name}.created_on",
sort_update 'created_on' => "#{Message.table_name}.created_on",
'replies' => "#{Message.table_name}.replies_count",
'updated_on' => "COALESCE(last_replies_messages.created_on, #{Message.table_name}.created_on)"
'updated_on' => "#{Message.table_name}.updated_on"
@topic_count = @board.topics.count
@topic_pages = Paginator.new @topic_count, per_page_option, params['page']
@topics = @board.topics.
reorder("#{Message.table_name}.sticky DESC").
includes(:last_reply).
limit(@topic_pages.per_page).
offset(@topic_pages.offset).
order(sort_clause).
preload(:author, {:last_reply => :author}).
all
@topic_pages = Paginator.new self, @topic_count, per_page_option, params['page']
@topics = @board.topics.reorder("#{Message.table_name}.sticky DESC").order(sort_clause).all(
:include => [:author, {:last_reply => :author}],
:limit => @topic_pages.items_per_page,
:offset => @topic_pages.current.offset)
@message = Message.new(:board => @board)
render :action => 'show', :layout => !request.xhr?
}
format.atom {
@messages = @board.messages.
reorder('created_on DESC').
includes(:author, :board).
limit(Setting.feeds_limit.to_i).
all
@messages = @board.messages.find :all, :order => 'created_on DESC',
:include => [:author, :board],
:limit => Setting.feeds_limit.to_i
render_feed(@messages, :title => "#{@project}: #{@board}")
}
end
@@ -100,7 +94,7 @@ class BoardsController < ApplicationController
private
def redirect_to_settings_in_projects
redirect_to settings_project_path(@project, :tab => 'boards')
redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'boards'
end
def find_board_if_available

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -32,12 +32,12 @@ class CommentsController < ApplicationController
flash[:notice] = l(:label_comment_added)
end
redirect_to news_path(@news)
redirect_to :controller => 'news', :action => 'show', :id => @news
end
def destroy
@news.comments.find(params[:comment_id]).destroy
redirect_to news_path(@news)
redirect_to :controller => 'news', :action => 'show', :id => @news
end
private

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -21,7 +21,6 @@ class ContextMenusController < ApplicationController
def issues
@issues = Issue.visible.all(:conditions => {:id => params[:ids]}, :include => :project)
(render_404; return) unless @issues.present?
if (@issues.size == 1)
@issue = @issues.first
end
@@ -75,8 +74,6 @@ class ContextMenusController < ApplicationController
def time_entries
@time_entries = TimeEntry.all(
:conditions => {:id => params[:ids]}, :include => :project)
(render_404; return) unless @time_entries.present?
@projects = @time_entries.collect(&:project).compact.uniq
@project = @projects.first if @projects.size == 1
@activities = TimeEntryActivity.shared.active

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -23,7 +23,7 @@ class CustomFieldsController < ApplicationController
before_filter :find_custom_field, :only => [:edit, :update, :destroy]
def index
@custom_fields_by_type = CustomField.all.group_by {|f| f.class.name }
@custom_fields_by_type = CustomField.find(:all).group_by {|f| f.class.name }
@tab = params[:tab] || 'IssueCustomField'
end
@@ -31,10 +31,10 @@ class CustomFieldsController < ApplicationController
end
def create
if @custom_field.save
if request.post? and @custom_field.save
flash[:notice] = l(:notice_successful_create)
call_hook(:controller_custom_fields_new_after_save, :params => params, :custom_field => @custom_field)
redirect_to custom_fields_path(:tab => @custom_field.class.name)
redirect_to :action => 'index', :tab => @custom_field.class.name
else
render :action => 'new'
end
@@ -44,22 +44,21 @@ class CustomFieldsController < ApplicationController
end
def update
if @custom_field.update_attributes(params[:custom_field])
if request.put? and @custom_field.update_attributes(params[:custom_field])
flash[:notice] = l(:notice_successful_update)
call_hook(:controller_custom_fields_edit_after_save, :params => params, :custom_field => @custom_field)
redirect_to custom_fields_path(:tab => @custom_field.class.name)
redirect_to :action => 'index', :tab => @custom_field.class.name
else
render :action => 'edit'
end
end
def destroy
begin
@custom_field.destroy
rescue
flash[:error] = l(:error_can_not_delete_custom_field)
end
redirect_to custom_fields_path(:tab => @custom_field.class.name)
@custom_field.destroy
redirect_to :action => 'index', :tab => @custom_field.class.name
rescue
flash[:error] = l(:error_can_not_delete_custom_field)
redirect_to :action => 'index'
end
private
@@ -68,8 +67,6 @@ class CustomFieldsController < ApplicationController
@custom_field = CustomField.new_subclass_instance(params[:type], params[:custom_field])
if @custom_field.nil?
render_404
else
@custom_field.default_value = nil
end
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -27,7 +27,7 @@ class DocumentsController < ApplicationController
def index
@sort_by = %w(category date title author).include?(params[:sort_by]) ? params[:sort_by] : 'category'
documents = @project.documents.includes(:attachments, :category).all
documents = @project.documents.find :all, :include => [:attachments, :category]
case @sort_by
when 'date'
@grouped = documents.group_by {|d| d.updated_on.to_date }
@@ -43,7 +43,7 @@ class DocumentsController < ApplicationController
end
def show
@attachments = @document.attachments.all
@attachments = @document.attachments.find(:all, :order => "created_on DESC")
end
def new
@@ -58,7 +58,7 @@ class DocumentsController < ApplicationController
if @document.save
render_attachment_warning_if_needed(@document)
flash[:notice] = l(:notice_successful_create)
redirect_to project_documents_path(@project)
redirect_to :action => 'index', :project_id => @project
else
render :action => 'new'
end
@@ -71,7 +71,7 @@ class DocumentsController < ApplicationController
@document.safe_attributes = params[:document]
if request.put? and @document.save
flash[:notice] = l(:notice_successful_update)
redirect_to document_path(@document)
redirect_to :action => 'show', :id => @document
else
render :action => 'edit'
end
@@ -79,7 +79,7 @@ class DocumentsController < ApplicationController
def destroy
@document.destroy if request.delete?
redirect_to project_documents_path(@project)
redirect_to :controller => 'documents', :action => 'index', :project_id => @project
end
def add_attachment
@@ -89,6 +89,6 @@ class DocumentsController < ApplicationController
if attachments.present? && attachments[:files].present? && Setting.notified_events.include?('document_added')
Mailer.attachments_added(attachments[:files]).deliver
end
redirect_to document_path(@document)
redirect_to :action => 'show', :id => @document
end
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -46,7 +46,7 @@ class EnumerationsController < ApplicationController
def create
if request.post? && @enumeration.save
flash[:notice] = l(:notice_successful_create)
redirect_to enumerations_path
redirect_to :action => 'index'
else
render :action => 'new'
end
@@ -58,7 +58,7 @@ class EnumerationsController < ApplicationController
def update
if request.put? && @enumeration.update_attributes(params[:enumeration])
flash[:notice] = l(:notice_successful_update)
redirect_to enumerations_path
redirect_to :action => 'index'
else
render :action => 'edit'
end
@@ -68,14 +68,16 @@ class EnumerationsController < ApplicationController
if !@enumeration.in_use?
# No associated objects
@enumeration.destroy
redirect_to enumerations_path
return
elsif params[:reassign_to_id].present? && (reassign_to = @enumeration.class.find_by_id(params[:reassign_to_id].to_i))
@enumeration.destroy(reassign_to)
redirect_to enumerations_path
redirect_to :action => 'index'
return
elsif params[:reassign_to_id]
if reassign_to = @enumeration.class.find_by_id(params[:reassign_to_id])
@enumeration.destroy(reassign_to)
redirect_to :action => 'index'
return
end
end
@enumerations = @enumeration.class.system.all - [@enumeration]
@enumerations = @enumeration.class.all - [@enumeration]
end
private

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -31,8 +31,8 @@ class FilesController < ApplicationController
'size' => "#{Attachment.table_name}.filesize",
'downloads' => "#{Attachment.table_name}.downloads"
@containers = [ Project.includes(:attachments).reorder(sort_clause).find(@project.id)]
@containers += @project.versions.includes(:attachments).reorder(sort_clause).all.sort.reverse
@containers = [ Project.find(@project.id, :include => :attachments, :order => sort_clause)]
@containers += @project.versions.find(:all, :include => :attachments, :order => sort_clause).sort.reverse
render :layout => !request.xhr?
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -84,7 +84,7 @@ class GroupsController < ApplicationController
@group.destroy
respond_to do |format|
format.html { redirect_to(groups_path) }
format.html { redirect_to(groups_url) }
format.api { render_api_ok }
end
end
@@ -93,7 +93,7 @@ class GroupsController < ApplicationController
@users = User.find_all_by_id(params[:user_id] || params[:user_ids])
@group.users << @users if request.post?
respond_to do |format|
format.html { redirect_to edit_group_path(@group, :tab => 'users') }
format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'users' }
format.js
format.api { render_api_ok }
end
@@ -102,23 +102,22 @@ class GroupsController < ApplicationController
def remove_user
@group.users.delete(User.find(params[:user_id])) if request.delete?
respond_to do |format|
format.html { redirect_to edit_group_path(@group, :tab => 'users') }
format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'users' }
format.js
format.api { render_api_ok }
end
end
def autocomplete_for_user
respond_to do |format|
format.js
end
@users = User.active.not_in_group(@group).like(params[:q]).all(:limit => 100)
render :layout => false
end
def edit_membership
@membership = Member.edit_membership(params[:membership_id], params[:membership], @group)
@membership.save if request.post?
respond_to do |format|
format.html { redirect_to edit_group_path(@group, :tab => 'memberships') }
format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'memberships' }
format.js
end
end
@@ -126,7 +125,7 @@ class GroupsController < ApplicationController
def destroy_membership
Member.find(params[:membership_id]).destroy if request.post?
respond_to do |format|
format.html { redirect_to edit_group_path(@group, :tab => 'memberships') }
format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'memberships' }
format.js
end
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -26,14 +26,14 @@ class IssueCategoriesController < ApplicationController
def index
respond_to do |format|
format.html { redirect_to_settings_in_projects }
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project }
format.api { @categories = @project.issue_categories.all }
end
end
def show
respond_to do |format|
format.html { redirect_to_settings_in_projects }
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project }
format.api
end
end
@@ -55,7 +55,7 @@ class IssueCategoriesController < ApplicationController
respond_to do |format|
format.html do
flash[:notice] = l(:notice_successful_create)
redirect_to_settings_in_projects
redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
end
format.js
format.api { render :action => 'show', :status => :created, :location => issue_category_path(@category) }
@@ -78,7 +78,7 @@ class IssueCategoriesController < ApplicationController
respond_to do |format|
format.html {
flash[:notice] = l(:notice_successful_update)
redirect_to_settings_in_projects
redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
}
format.api { render_api_ok }
end
@@ -99,7 +99,7 @@ class IssueCategoriesController < ApplicationController
end
@category.destroy(reassign_to)
respond_to do |format|
format.html { redirect_to_settings_in_projects }
format.html { redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories' }
format.api { render_api_ok }
end
return
@@ -107,12 +107,7 @@ class IssueCategoriesController < ApplicationController
@categories = @project.issue_categories - [@category]
end
private
def redirect_to_settings_in_projects
redirect_to settings_project_path(@project, :tab => 'categories')
end
private
# Wrap ApplicationController's find_model_object method to set
# @category instead of just @issue_category
def find_model_object

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -48,9 +48,9 @@ class IssueRelationsController < ApplicationController
saved = @relation.save
respond_to do |format|
format.html { redirect_to issue_path(@issue) }
format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue }
format.js {
@relations = @issue.reload.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
@relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
}
format.api {
if saved
@@ -67,7 +67,7 @@ class IssueRelationsController < ApplicationController
@relation.destroy
respond_to do |format|
format.html { redirect_to issue_path(@relation.issue_from) }
format.html { redirect_to issue_path } # TODO : does this really work since @issue is always nil? What is it useful to?
format.js
format.api { render_api_ok }
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -25,7 +25,7 @@ class IssueStatusesController < ApplicationController
def index
respond_to do |format|
format.html {
@issue_status_pages, @issue_statuses = paginate IssueStatus.sorted, :per_page => 25
@issue_status_pages, @issue_statuses = paginate :issue_statuses, :per_page => 25, :order => "position"
render :action => "index", :layout => false if request.xhr?
}
format.api {
@@ -42,7 +42,7 @@ class IssueStatusesController < ApplicationController
@issue_status = IssueStatus.new(params[:issue_status])
if request.post? && @issue_status.save
flash[:notice] = l(:notice_successful_create)
redirect_to issue_statuses_path
redirect_to :action => 'index'
else
render :action => 'new'
end
@@ -56,7 +56,7 @@ class IssueStatusesController < ApplicationController
@issue_status = IssueStatus.find(params[:id])
if request.put? && @issue_status.update_attributes(params[:issue_status])
flash[:notice] = l(:notice_successful_update)
redirect_to issue_statuses_path
redirect_to :action => 'index'
else
render :action => 'edit'
end
@@ -64,11 +64,11 @@ class IssueStatusesController < ApplicationController
def destroy
IssueStatus.find(params[:id]).destroy
redirect_to issue_statuses_path
redirect_to :action => 'index'
rescue
flash[:error] = l(:error_unable_delete_issue_status)
redirect_to issue_statuses_path
end
redirect_to :action => 'index'
end
def update_issue_done_ratio
if request.post? && IssueStatus.update_issue_done_ratios
@@ -76,6 +76,6 @@ class IssueStatusesController < ApplicationController
else
flash[:error] = l(:error_issue_done_ratios_not_updated)
end
redirect_to issue_statuses_path
redirect_to :action => 'index'
end
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -21,11 +21,11 @@ class IssuesController < ApplicationController
before_filter :find_issue, :only => [:show, :edit, :update]
before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :destroy]
before_filter :find_project, :only => [:new, :create, :update_form]
before_filter :find_project, :only => [:new, :create]
before_filter :authorize, :except => [:index]
before_filter :find_optional_project, :only => [:index]
before_filter :check_for_default_issue_status, :only => [:new, :create]
before_filter :build_new_issue_from_params, :only => [:new, :create, :update_form]
before_filter :build_new_issue_from_params, :only => [:new, :create]
accept_rss_auth :index, :show
accept_api_auth :index, :show, :create, :update, :destroy
@@ -71,8 +71,8 @@ class IssuesController < ApplicationController
end
@issue_count = @query.issue_count
@issue_pages = Paginator.new @issue_count, @limit, params['page']
@offset ||= @issue_pages.offset
@issue_pages = Paginator.new self, @issue_count, @limit, params['page']
@offset ||= @issue_pages.current.offset
@issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version],
:order => sort_clause,
:offset => @offset,
@@ -85,8 +85,8 @@ class IssuesController < ApplicationController
Issue.load_visible_relations(@issues) if include_in_api_response?('relations')
}
format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
format.csv { send_data(query_to_csv(@issues, @query, params), :type => 'text/csv; header=present', :filename => 'issues.csv') }
format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'issues.pdf') }
format.csv { send_data(issues_to_csv(@issues, @project, @query, params), :type => 'text/csv; header=present', :filename => 'export.csv') }
format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }
end
else
respond_to do |format|
@@ -132,6 +132,7 @@ class IssuesController < ApplicationController
def new
respond_to do |format|
format.html { render :action => 'new', :layout => !request.xhr? }
format.js { render :partial => 'update_form' }
end
end
@@ -144,12 +145,8 @@ class IssuesController < ApplicationController
format.html {
render_attachment_warning_if_needed(@issue)
flash[:notice] = l(:notice_issue_successful_create, :id => view_context.link_to("##{@issue.id}", issue_path(@issue), :title => @issue.subject))
if params[:continue]
attrs = {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?}
redirect_to new_project_issue_path(@issue.project, :issue => attrs)
else
redirect_to issue_path(@issue)
end
redirect_to(params[:continue] ? { :action => 'new', :project_id => @issue.project, :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } :
{ :action => 'show', :id => @issue })
}
format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) }
end
@@ -190,7 +187,7 @@ class IssuesController < ApplicationController
flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
respond_to do |format|
format.html { redirect_back_or_default issue_path(@issue) }
format.html { redirect_back_or_default({:action => 'show', :id => @issue}) }
format.api { render_api_ok }
end
else
@@ -201,11 +198,6 @@ class IssuesController < ApplicationController
end
end
# Updates the issue form when changing the project, status or tracker
# on issue creation/update
def update_form
end
# Bulk edit/copy a set of issues
def bulk_edit
@issues.sort!
@@ -278,12 +270,12 @@ class IssuesController < ApplicationController
if params[:follow]
if @issues.size == 1 && moved_issues.size == 1
redirect_to issue_path(moved_issues.first)
redirect_to :controller => 'issues', :action => 'show', :id => moved_issues.first
elsif moved_issues.map(&:project).uniq.size == 1
redirect_to project_issues_path(moved_issues.map(&:project).first)
redirect_to :controller => 'issues', :action => 'index', :project_id => moved_issues.map(&:project).first
end
else
redirect_back_or_default _project_issues_path(@project)
redirect_back_or_default({:controller => 'issues', :action => 'index', :project_id => @project})
end
end
@@ -316,7 +308,7 @@ class IssuesController < ApplicationController
end
end
respond_to do |format|
format.html { redirect_back_or_default _project_issues_path(@project) }
format.html { redirect_back_or_default(:action => 'index', :project_id => @project) }
format.api { render_api_ok }
end
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -80,7 +80,7 @@ class JournalsController < ApplicationController
@journal.destroy if @journal.details.empty? && @journal.notes.blank?
call_hook(:controller_journals_edit_post, { :journal => @journal, :params => params})
respond_to do |format|
format.html { redirect_to issue_path(@journal.journalized) }
format.html { redirect_to :controller => 'issues', :action => 'show', :id => @journal.journalized_id }
format.js { render :action => 'update' }
end
else

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -26,8 +26,8 @@ class MembersController < ApplicationController
def index
@offset, @limit = api_offset_and_limit
@member_count = @project.member_principals.count
@member_pages = Paginator.new @member_count, @limit, params['page']
@offset ||= @member_pages.offset
@member_pages = Paginator.new self, @member_count, @limit, params['page']
@offset ||= @member_pages.current.offset
@members = @project.member_principals.all(
:order => "#{Member.table_name}.id",
:limit => @limit,
@@ -63,7 +63,7 @@ class MembersController < ApplicationController
end
respond_to do |format|
format.html { redirect_to_settings_in_projects }
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
format.js { @members = members }
format.api {
@member = members.first
@@ -82,7 +82,7 @@ class MembersController < ApplicationController
end
saved = @member.save
respond_to do |format|
format.html { redirect_to_settings_in_projects }
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
format.js
format.api {
if saved
@@ -99,7 +99,7 @@ class MembersController < ApplicationController
@member.destroy
end
respond_to do |format|
format.html { redirect_to_settings_in_projects }
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
format.js
format.api {
if @member.destroyed?
@@ -112,14 +112,7 @@ class MembersController < ApplicationController
end
def autocomplete
respond_to do |format|
format.js
end
end
private
def redirect_to_settings_in_projects
redirect_to settings_project_path(@project, :tab => 'members')
@principals = Principal.active.not_member_of(@project).like(params[:q]).all(:limit => 100)
render :layout => false
end
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -19,7 +19,6 @@ class MessagesController < ApplicationController
menu_item :boards
default_search_scope :messages
before_filter :find_board, :only => [:new, :preview]
before_filter :find_attachments, :only => [:preview]
before_filter :find_message, :except => [:new, :preview]
before_filter :authorize, :except => [:preview, :edit, :destroy]
@@ -40,13 +39,11 @@ class MessagesController < ApplicationController
end
@reply_count = @topic.children.count
@reply_pages = Paginator.new @reply_count, REPLIES_PER_PAGE, page
@replies = @topic.children.
includes(:author, :attachments, {:board => :project}).
reorder("#{Message.table_name}.created_on ASC").
limit(@reply_pages.per_page).
offset(@reply_pages.offset).
all
@reply_pages = Paginator.new self, @reply_count, REPLIES_PER_PAGE, page
@replies = @topic.children.find(:all, :include => [:author, :attachments, {:board => :project}],
:order => "#{Message.table_name}.created_on ASC",
:limit => @reply_pages.items_per_page,
:offset => @reply_pages.current.offset)
@reply = Message.new(:subject => "RE: #{@message.subject}")
render :action => "show", :layout => false if request.xhr?
@@ -118,6 +115,7 @@ class MessagesController < ApplicationController
def preview
message = @board.messages.find_by_id(params[:id])
@attachements = message.attachments if message
@text = (params[:message] || params[:reply])[:content]
@previewed = message
render :partial => 'common/preview'
@@ -125,7 +123,7 @@ class MessagesController < ApplicationController
private
def find_message
return unless find_board
find_board
@message = @board.messages.find(params[:id], :include => :parent)
@topic = @message.root
rescue ActiveRecord::RecordNotFound
@@ -137,6 +135,5 @@ private
@project = @board.project
rescue ActiveRecord::RecordNotFound
render_404
nil
end
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -53,12 +53,13 @@ class MyController < ApplicationController
if request.post?
@user.safe_attributes = params[:user]
@user.pref.attributes = params[:pref]
@user.pref[:no_self_notified] = (params[:no_self_notified] == '1')
if @user.save
@user.pref.save
@user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : [])
set_language_if_valid @user.language
flash[:notice] = l(:notice_account_updated)
redirect_to my_account_path
redirect_to :action => 'account'
return
end
end
@@ -68,7 +69,7 @@ class MyController < ApplicationController
def destroy
@user = User.current
unless @user.own_account_deletable?
redirect_to my_account_path
redirect_to :action => 'account'
return
end
@@ -87,7 +88,7 @@ class MyController < ApplicationController
@user = User.current
unless @user.change_password_allowed?
flash[:error] = l(:notice_can_t_change_password)
redirect_to my_account_path
redirect_to :action => 'account'
return
end
if request.post?
@@ -95,7 +96,7 @@ class MyController < ApplicationController
@user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
if @user.save
flash[:notice] = l(:notice_account_password_updated)
redirect_to my_account_path
redirect_to :action => 'account'
end
else
flash[:error] = l(:notice_account_wrong_password)
@@ -113,7 +114,7 @@ class MyController < ApplicationController
User.current.rss_key
flash[:notice] = l(:notice_feeds_access_key_reseted)
end
redirect_to my_account_path
redirect_to :action => 'account'
end
# Create a new API key
@@ -126,7 +127,7 @@ class MyController < ApplicationController
User.current.api_key
flash[:notice] = l(:notice_api_access_key_reseted)
end
redirect_to my_account_path
redirect_to :action => 'account'
end
# User's page layout configuration
@@ -156,7 +157,7 @@ class MyController < ApplicationController
@user.pref[:my_page_layout] = layout
@user.pref.save
end
redirect_to my_page_layout_path
redirect_to :action => 'page_layout'
end
# Remove a block to user's page
@@ -169,7 +170,7 @@ class MyController < ApplicationController
%w(top left right).each {|f| (layout[f] ||= []).delete block }
@user.pref[:my_page_layout] = layout
@user.pref.save
redirect_to my_page_layout_path
redirect_to :action => 'page_layout'
end
# Change blocks order on user's page

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -40,8 +40,8 @@ class NewsController < ApplicationController
scope = @project ? @project.news.visible : News.visible
@news_count = scope.count
@news_pages = Paginator.new @news_count, @limit, params['page']
@offset ||= @news_pages.offset
@news_pages = Paginator.new self, @news_count, @limit, params['page']
@offset ||= @news_pages.current.offset
@newss = scope.all(:include => [:author, :project],
:order => "#{News.table_name}.created_on DESC",
:offset => @offset,
@@ -73,7 +73,7 @@ class NewsController < ApplicationController
if @news.save
render_attachment_warning_if_needed(@news)
flash[:notice] = l(:notice_successful_create)
redirect_to project_news_index_path(@project)
redirect_to :controller => 'news', :action => 'index', :project_id => @project
else
render :action => 'new'
end
@@ -88,7 +88,7 @@ class NewsController < ApplicationController
if @news.save
render_attachment_warning_if_needed(@news)
flash[:notice] = l(:notice_successful_update)
redirect_to news_path(@news)
redirect_to :action => 'show', :id => @news
else
render :action => 'edit'
end
@@ -96,7 +96,7 @@ class NewsController < ApplicationController
def destroy
@news.destroy
redirect_to project_news_index_path(@project)
redirect_to :action => 'index', :project_id => @project
end
private

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -16,11 +16,12 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class PreviewsController < ApplicationController
before_filter :find_project, :find_attachments
before_filter :find_project
def issue
@issue = @project.issues.find_by_id(params[:id]) unless params[:id].blank?
if @issue
@attachements = @issue.attachments
@description = params[:issue] && params[:issue][:description]
if @description && @description.gsub(/(\r?\n|\n\r?)/, "\n") == @issue.description.to_s.gsub(/(\r?\n|\n\r?)/, "\n")
@description = nil
@@ -36,6 +37,7 @@ class PreviewsController < ApplicationController
def news
if params[:id].present? && news = News.visible.find_by_id(params[:id])
@previewed = news
@attachments = news.attachments
end
@text = (params[:news] ? params[:news][:description] : nil)
render :partial => 'common/preview'

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -29,7 +29,7 @@ class ProjectEnumerationsController < ApplicationController
flash[:notice] = l(:notice_successful_update)
end
redirect_to settings_project_path(@project, :tab => 'activities')
redirect_to :controller => 'projects', :action => 'settings', :tab => 'activities', :id => @project
end
def destroy
@@ -37,6 +37,7 @@ class ProjectEnumerationsController < ApplicationController
time_entry_activity.destroy(time_entry_activity.parent)
end
flash[:notice] = l(:notice_successful_update)
redirect_to settings_project_path(@project, :tab => 'activities')
redirect_to :controller => 'projects', :action => 'settings', :tab => 'activities', :id => @project
end
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -43,7 +43,6 @@ class ProjectsController < ApplicationController
helper :repositories
include RepositoriesHelper
include ProjectsHelper
helper :members
# Lists visible projects
def index
@@ -58,24 +57,25 @@ class ProjectsController < ApplicationController
format.api {
@offset, @limit = api_offset_and_limit
@project_count = Project.visible.count
@projects = Project.visible.offset(@offset).limit(@limit).order('lft').all
@projects = Project.visible.all(:offset => @offset, :limit => @limit, :order => 'lft')
}
format.atom {
projects = Project.visible.order('created_on DESC').limit(Setting.feeds_limit.to_i).all
projects = Project.visible.find(:all, :order => 'created_on DESC',
:limit => Setting.feeds_limit.to_i)
render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}")
}
end
end
def new
@issue_custom_fields = IssueCustomField.sorted.all
@issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
@trackers = Tracker.sorted.all
@project = Project.new
@project.safe_attributes = params[:project]
end
def create
@issue_custom_fields = IssueCustomField.sorted.all
@issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
@trackers = Tracker.sorted.all
@project = Project.new
@project.safe_attributes = params[:project]
@@ -91,12 +91,10 @@ class ProjectsController < ApplicationController
respond_to do |format|
format.html {
flash[:notice] = l(:notice_successful_create)
if params[:continue]
attrs = {:parent_id => @project.parent_id}.reject {|k,v| v.nil?}
redirect_to new_project_path(attrs)
else
redirect_to settings_project_path(@project)
end
redirect_to(params[:continue] ?
{:controller => 'projects', :action => 'new', :project => {:parent_id => @project.parent_id}.reject {|k,v| v.nil?}} :
{:controller => 'projects', :action => 'settings', :id => @project}
)
}
format.api { render :action => 'show', :status => :created, :location => url_for(:controller => 'projects', :action => 'show', :id => @project.id) }
end
@@ -106,11 +104,15 @@ class ProjectsController < ApplicationController
format.api { render_validation_errors(@project) }
end
end
end
def copy
@issue_custom_fields = IssueCustomField.sorted.all
@issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
@trackers = Tracker.sorted.all
@root_projects = Project.find(:all,
:conditions => "parent_id IS NULL AND status = #{Project::STATUS_ACTIVE}",
:order => 'name')
@source_project = Project.find(params[:id])
if request.get?
@project = Project.copy_from(@source_project)
@@ -122,13 +124,13 @@ class ProjectsController < ApplicationController
if validate_parent_id && @project.copy(@source_project, :only => params[:only])
@project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
flash[:notice] = l(:notice_successful_create)
redirect_to settings_project_path(@project)
redirect_to :controller => 'projects', :action => 'settings', :id => @project
elsif !@project.new_record?
# Project was created
# But some objects were not copied due to validation failures
# (eg. issues from disabled trackers)
# TODO: inform about that
redirect_to settings_project_path(@project)
redirect_to :controller => 'projects', :action => 'settings', :id => @project
end
end
end
@@ -136,17 +138,17 @@ class ProjectsController < ApplicationController
# source_project not found
render_404
end
# Show @project
def show
# try to redirect to the requested menu item
if params[:jump] && redirect_to_project_menu_item(@project, params[:jump])
return
if params[:jump]
# try to redirect to the requested menu item
redirect_to_project_menu_item(@project, params[:jump]) && return
end
@users_by_role = @project.users_by_role
@subprojects = @project.children.visible.all
@news = @project.news.limit(5).includes(:author, :project).reorder("#{News.table_name}.created_on DESC").all
@news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
@trackers = @project.rolled_up_trackers
cond = @project.project_condition(Setting.display_subprojects_issues?)
@@ -167,7 +169,7 @@ class ProjectsController < ApplicationController
end
def settings
@issue_custom_fields = IssueCustomField.sorted.all
@issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
@issue_category ||= IssueCategory.new
@member ||= @project.members.new
@trackers = Tracker.sorted.all
@@ -184,7 +186,7 @@ class ProjectsController < ApplicationController
respond_to do |format|
format.html {
flash[:notice] = l(:notice_successful_update)
redirect_to settings_project_path(@project)
redirect_to :action => 'settings', :id => @project
}
format.api { render_api_ok }
end
@@ -202,7 +204,7 @@ class ProjectsController < ApplicationController
def modules
@project.enabled_module_names = params[:enabled_module_names]
flash[:notice] = l(:notice_successful_update)
redirect_to settings_project_path(@project, :tab => 'modules')
redirect_to :action => 'settings', :id => @project, :tab => 'modules'
end
def archive
@@ -211,12 +213,12 @@ class ProjectsController < ApplicationController
flash[:error] = l(:error_can_not_archive_project)
end
end
redirect_to admin_projects_path(:status => params[:status])
redirect_to(url_for(:controller => 'admin', :action => 'projects', :status => params[:status]))
end
def unarchive
@project.unarchive if request.post? && !@project.active?
redirect_to admin_projects_path(:status => params[:status])
redirect_to(url_for(:controller => 'admin', :action => 'projects', :status => params[:status]))
end
def close
@@ -235,7 +237,7 @@ class ProjectsController < ApplicationController
if api_request? || params[:confirm]
@project_to_destroy.destroy
respond_to do |format|
format.html { redirect_to admin_projects_path }
format.html { redirect_to :controller => 'admin', :action => 'projects' }
format.api { render_api_ok }
end
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -32,34 +32,35 @@ class QueriesController < ApplicationController
@limit = per_page_option
end
@query_count = IssueQuery.visible.count
@query_pages = Paginator.new @query_count, @limit, params['page']
@queries = IssueQuery.visible.all(:limit => @limit, :offset => @offset, :order => "#{Query.table_name}.name")
@query_count = Query.visible.count
@query_pages = Paginator.new self, @query_count, @limit, params['page']
@queries = Query.visible.all(:limit => @limit, :offset => @offset, :order => "#{Query.table_name}.name")
respond_to do |format|
format.html { render :nothing => true }
format.api
end
end
def new
@query = IssueQuery.new
@query = Query.new
@query.user = User.current
@query.project = @project
@query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
@query.build_from_params(params)
build_query_from_params
end
def create
@query = IssueQuery.new(params[:query])
@query = Query.new(params[:query])
@query.user = User.current
@query.project = params[:query_is_for_all] ? nil : @project
@query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
@query.build_from_params(params)
build_query_from_params
@query.column_names = nil if params[:default_columns]
if @query.save
flash[:notice] = l(:notice_successful_create)
redirect_to _project_issues_path(@project, :query_id => @query)
redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query
else
render :action => 'new', :layout => !request.xhr?
end
@@ -72,12 +73,12 @@ class QueriesController < ApplicationController
@query.attributes = params[:query]
@query.project = nil if params[:query_is_for_all]
@query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
@query.build_from_params(params)
build_query_from_params
@query.column_names = nil if params[:default_columns]
if @query.save
flash[:notice] = l(:notice_successful_update)
redirect_to _project_issues_path(@project, :query_id => @query)
redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query
else
render :action => 'edit'
end
@@ -85,12 +86,12 @@ class QueriesController < ApplicationController
def destroy
@query.destroy
redirect_to _project_issues_path(@project, :set_filter => 1)
redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1
end
private
def find_query
@query = IssueQuery.find(params[:id])
@query = Query.find(params[:id])
@project = @query.project
render_403 unless @query.editable_by?(User.current)
rescue ActiveRecord::RecordNotFound

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -90,6 +90,6 @@ class ReportsController < ApplicationController
private
def find_issue_statuses
@statuses = IssueStatus.sorted.all
@statuses = IssueStatus.find(:all, :order => 'position')
end
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -138,14 +138,13 @@ class RepositoriesController < ApplicationController
def revisions
@changeset_count = @repository.changesets.count
@changeset_pages = Paginator.new @changeset_count,
@changeset_pages = Paginator.new self, @changeset_count,
per_page_option,
params['page']
@changesets = @repository.changesets.
limit(@changeset_pages.per_page).
offset(@changeset_pages.offset).
includes(:user, :repository, :parents).
all
@changesets = @repository.changesets.find(:all,
:limit => @changeset_pages.items_per_page,
:offset => @changeset_pages.current.offset,
:include => [:user, :repository, :parents])
respond_to do |format|
format.html { render :layout => false if request.xhr? }

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -26,7 +26,7 @@ class RolesController < ApplicationController
def index
respond_to do |format|
format.html {
@role_pages, @roles = paginate Role.sorted, :per_page => 25
@role_pages, @roles = paginate :roles, :per_page => 25, :order => 'builtin, position'
render :action => "index", :layout => false if request.xhr?
}
format.api {
@@ -58,7 +58,7 @@ class RolesController < ApplicationController
@role.workflow_rules.copy(copy_from)
end
flash[:notice] = l(:notice_successful_create)
redirect_to roles_path
redirect_to :action => 'index'
else
@roles = Role.sorted.all
render :action => 'new'
@@ -71,7 +71,7 @@ class RolesController < ApplicationController
def update
if request.put? and @role.update_attributes(params[:role])
flash[:notice] = l(:notice_successful_update)
redirect_to roles_path
redirect_to :action => 'index'
else
render :action => 'edit'
end
@@ -79,10 +79,10 @@ class RolesController < ApplicationController
def destroy
@role.destroy
redirect_to roles_path
redirect_to :action => 'index'
rescue
flash[:error] = l(:error_can_not_remove_role)
redirect_to roles_path
redirect_to :action => 'index'
end
def permissions
@@ -94,7 +94,7 @@ class RolesController < ApplicationController
role.save
end
flash[:notice] = l(:notice_successful_update)
redirect_to roles_path
redirect_to :action => 'index'
end
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -18,6 +18,9 @@
class SearchController < ApplicationController
before_filter :find_optional_project
helper :messages
include MessagesHelper
def index
@question = params[:q] || ""
@question.strip!
@@ -40,8 +43,8 @@ class SearchController < ApplicationController
begin; offset = params[:offset].to_time if params[:offset]; rescue; end
# quick jump to an issue
if (m = @question.match(/^#?(\d+)$/)) && (issue = Issue.visible.find_by_id(m[1].to_i))
redirect_to issue_path(issue)
if @question.match(/^#?(\d+)$/) && Issue.visible.find_by_id($1.to_i)
redirect_to :controller => "issues", :action => "show", :id => $1
return
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -19,8 +19,6 @@ class SettingsController < ApplicationController
layout 'admin'
menu_item :plugins, :only => :plugin
helper :queries
before_filter :require_admin
def index
@@ -38,7 +36,7 @@ class SettingsController < ApplicationController
Setting[name] = value
end
flash[:notice] = l(:notice_successful_update)
redirect_to settings_path(:tab => params[:tab])
redirect_to :action => 'edit', :tab => params[:tab]
else
@options = {}
user_format = User::USER_FORMATS.collect{|key, value| [key, value[:setting_order]]}.sort{|a, b| a[1] <=> b[1]}
@@ -54,15 +52,10 @@ class SettingsController < ApplicationController
def plugin
@plugin = Redmine::Plugin.find(params[:id])
unless @plugin.configurable?
render_404
return
end
if request.post?
Setting.send "plugin_#{@plugin.id}=", params[:settings]
flash[:notice] = l(:notice_successful_update)
redirect_to plugin_settings_path(@plugin)
redirect_to :action => 'plugin', :id => @plugin.id
else
@partial = @plugin.settings[:partial]
@settings = Setting.send "plugin_#{@plugin.id}"

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -30,33 +30,41 @@ class TimelogController < ApplicationController
accept_rss_auth :index
accept_api_auth :index, :show, :create, :update, :destroy
rescue_from Query::StatementInvalid, :with => :query_statement_invalid
helper :sort
include SortHelper
helper :issues
include TimelogHelper
helper :custom_fields
include CustomFieldsHelper
helper :queries
include QueriesHelper
def index
@query = TimeEntryQuery.build_from_params(params, :project => @project, :name => '_')
sort_init 'spent_on', 'desc'
sort_update 'spent_on' => ['spent_on', "#{TimeEntry.table_name}.created_on"],
'user' => 'user_id',
'activity' => 'activity_id',
'project' => "#{Project.table_name}.name",
'issue' => 'issue_id',
'hours' => 'hours'
sort_init(@query.sort_criteria.empty? ? [['spent_on', 'desc']] : @query.sort_criteria)
sort_update(@query.sortable_columns)
scope = time_entry_scope(:order => sort_clause)
retrieve_date_range
scope = TimeEntry.visible.spent_between(@from, @to)
if @issue
scope = scope.on_issue(@issue)
elsif @project
scope = scope.on_project(@project, Setting.display_subprojects_issues?)
end
respond_to do |format|
format.html {
# Paginate results
@entry_count = scope.count
@entry_pages = Paginator.new @entry_count, per_page_option, params['page']
@entry_pages = Paginator.new self, @entry_count, per_page_option, params['page']
@entries = scope.all(
:include => [:project, :activity, :user, {:issue => :tracker}],
:limit => @entry_pages.per_page,
:offset => @entry_pages.offset
:order => sort_clause,
:limit => @entry_pages.items_per_page,
:offset => @entry_pages.current.offset
)
@total_hours = scope.sum(:hours).to_f
@@ -67,13 +75,15 @@ class TimelogController < ApplicationController
@offset, @limit = api_offset_and_limit
@entries = scope.all(
:include => [:project, :activity, :user, {:issue => :tracker}],
:order => sort_clause,
:limit => @limit,
:offset => @offset
)
}
format.atom {
entries = scope.reorder("#{TimeEntry.table_name}.created_on DESC").all(
entries = scope.all(
:include => [:project, :activity, :user, {:issue => :tracker}],
:order => "#{TimeEntry.table_name}.created_on DESC",
:limit => Setting.feeds_limit.to_i
)
render_feed(entries, :title => l(:label_spent_time))
@@ -81,18 +91,17 @@ class TimelogController < ApplicationController
format.csv {
# Export all entries
@entries = scope.all(
:include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}]
:include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}],
:order => sort_clause
)
send_data(query_to_csv(@entries, @query, params), :type => 'text/csv; header=present', :filename => 'timelog.csv')
send_data(entries_to_csv(@entries), :type => 'text/csv; header=present', :filename => 'timelog.csv')
}
end
end
def report
@query = TimeEntryQuery.build_from_params(params, :project => @project, :name => '_')
scope = time_entry_scope
@report = Redmine::Helpers::TimeReport.new(@project, @issue, params[:criteria], params[:columns], scope)
retrieve_date_range
@report = Redmine::Helpers::TimeReport.new(@project, @issue, params[:criteria], params[:columns], @from, @to)
respond_to do |format|
format.html { render :layout => !request.xhr? }
@@ -125,24 +134,16 @@ class TimelogController < ApplicationController
flash[:notice] = l(:notice_successful_create)
if params[:continue]
if params[:project_id]
options = {
redirect_to :action => 'new', :project_id => @time_entry.project, :issue_id => @time_entry.issue,
:time_entry => {:issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id},
:back_url => params[:back_url]
}
if @time_entry.issue
redirect_to new_project_issue_time_entry_path(@time_entry.project, @time_entry.issue, options)
else
redirect_to new_project_time_entry_path(@time_entry.project, options)
end
else
options = {
redirect_to :action => 'new',
:time_entry => {:project_id => @time_entry.project_id, :issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id},
:back_url => params[:back_url]
}
redirect_to new_time_entry_path(options)
end
else
redirect_back_or_default project_time_entries_path(@time_entry.project)
redirect_back_or_default :action => 'index', :project_id => @time_entry.project
end
}
format.api { render :action => 'show', :status => :created, :location => time_entry_url(@time_entry) }
@@ -168,7 +169,7 @@ class TimelogController < ApplicationController
respond_to do |format|
format.html {
flash[:notice] = l(:notice_successful_update)
redirect_back_or_default project_time_entries_path(@time_entry.project)
redirect_back_or_default :action => 'index', :project_id => @time_entry.project
}
format.api { render_api_ok }
end
@@ -199,7 +200,7 @@ class TimelogController < ApplicationController
end
end
set_flash_from_bulk_time_entry_save(@time_entries, unsaved_time_entry_ids)
redirect_back_or_default project_time_entries_path(@projects.first)
redirect_back_or_default({:controller => 'timelog', :action => 'index', :project_id => @projects.first})
end
def destroy
@@ -218,7 +219,7 @@ class TimelogController < ApplicationController
else
flash[:error] = l(:notice_unable_delete_time_entry)
end
redirect_back_or_default project_time_entries_path(@projects.first)
redirect_back_or_default(:action => 'index', :project_id => @projects.first)
}
format.api {
if destroyed
@@ -290,13 +291,51 @@ private
end
end
# Returns the TimeEntry scope for index and report actions
def time_entry_scope(options={})
scope = @query.results_scope(options)
if @issue
scope = scope.on_issue(@issue)
# Retrieves the date range based on predefined ranges or specific from/to param dates
def retrieve_date_range
@free_period = false
@from, @to = nil, nil
if params[:period_type] == '1' || (params[:period_type].nil? && !params[:period].nil?)
case params[:period].to_s
when 'today'
@from = @to = Date.today
when 'yesterday'
@from = @to = Date.today - 1
when 'current_week'
@from = Date.today - (Date.today.cwday - 1)%7
@to = @from + 6
when 'last_week'
@from = Date.today - 7 - (Date.today.cwday - 1)%7
@to = @from + 6
when 'last_2_weeks'
@from = Date.today - 14 - (Date.today.cwday - 1)%7
@to = @from + 13
when '7_days'
@from = Date.today - 7
@to = Date.today
when 'current_month'
@from = Date.civil(Date.today.year, Date.today.month, 1)
@to = (@from >> 1) - 1
when 'last_month'
@from = Date.civil(Date.today.year, Date.today.month, 1) << 1
@to = (@from >> 1) - 1
when '30_days'
@from = Date.today - 30
@to = Date.today
when 'current_year'
@from = Date.civil(Date.today.year, 1, 1)
@to = Date.civil(Date.today.year, 12, 31)
end
elsif params[:period_type] == '2' || (params[:period_type].nil? && (!params[:from].nil? || !params[:to].nil?))
begin; @from = params[:from].to_s.to_date unless params[:from].blank?; rescue; end
begin; @to = params[:to].to_s.to_date unless params[:to].blank?; rescue; end
@free_period = true
else
# default
end
scope
@from, @to = @to, @from if @from && @to && @from > @to
end
def parse_params_for_bulk_time_entry_attributes(params)

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -25,7 +25,7 @@ class TrackersController < ApplicationController
def index
respond_to do |format|
format.html {
@tracker_pages, @trackers = paginate Tracker.sorted, :per_page => 25
@tracker_pages, @trackers = paginate :trackers, :per_page => 10, :order => 'position'
render :action => "index", :layout => false if request.xhr?
}
format.api {
@@ -36,19 +36,19 @@ class TrackersController < ApplicationController
def new
@tracker ||= Tracker.new(params[:tracker])
@trackers = Tracker.sorted.all
@projects = Project.all
@trackers = Tracker.find :all, :order => 'position'
@projects = Project.find(:all)
end
def create
@tracker = Tracker.new(params[:tracker])
if @tracker.save
if request.post? and @tracker.save
# workflow copy
if !params[:copy_workflow_from].blank? && (copy_from = Tracker.find_by_id(params[:copy_workflow_from]))
@tracker.workflow_rules.copy(copy_from)
end
flash[:notice] = l(:notice_successful_create)
redirect_to trackers_path
redirect_to :action => 'index'
return
end
new
@@ -57,14 +57,14 @@ class TrackersController < ApplicationController
def edit
@tracker ||= Tracker.find(params[:id])
@projects = Project.all
@projects = Project.find(:all)
end
def update
@tracker = Tracker.find(params[:id])
if @tracker.update_attributes(params[:tracker])
if request.put? and @tracker.update_attributes(params[:tracker])
flash[:notice] = l(:notice_successful_update)
redirect_to trackers_path
redirect_to :action => 'index'
return
end
edit
@@ -78,7 +78,7 @@ class TrackersController < ApplicationController
else
@tracker.destroy
end
redirect_to trackers_path
redirect_to :action => 'index'
end
def fields
@@ -92,7 +92,7 @@ class TrackersController < ApplicationController
end
end
flash[:notice] = l(:notice_successful_update)
redirect_to fields_trackers_path
redirect_to :action => 'fields'
return
end
@trackers = Tracker.sorted.all

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -45,9 +45,12 @@ class UsersController < ApplicationController
scope = scope.in_group(params[:group_id]) if params[:group_id].present?
@user_count = scope.count
@user_pages = Paginator.new @user_count, @limit, params['page']
@offset ||= @user_pages.offset
@users = scope.order(sort_clause).limit(@limit).offset(@offset).all
@user_pages = Paginator.new self, @user_count, @limit, params['page']
@offset ||= @user_pages.current.offset
@users = scope.find :all,
:order => sort_clause,
:limit => @limit,
:offset => @offset
respond_to do |format|
format.html {
@@ -55,7 +58,7 @@ class UsersController < ApplicationController
render :layout => !request.xhr?
}
format.api
end
end
end
def show
@@ -80,7 +83,7 @@ class UsersController < ApplicationController
def new
@user = User.new(:language => Setting.default_language, :mail_notification => Setting.default_notification_option)
@auth_sources = AuthSource.all
@auth_sources = AuthSource.find(:all)
end
def create
@@ -92,6 +95,7 @@ class UsersController < ApplicationController
if @user.save
@user.pref.attributes = params[:pref]
@user.pref[:no_self_notified] = (params[:no_self_notified] == '1')
@user.pref.save
@user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : [])
@@ -100,16 +104,15 @@ class UsersController < ApplicationController
respond_to do |format|
format.html {
flash[:notice] = l(:notice_user_successful_create, :id => view_context.link_to(@user.login, user_path(@user)))
if params[:continue]
redirect_to new_user_path
else
redirect_to edit_user_path(@user)
end
redirect_to(params[:continue] ?
{:controller => 'users', :action => 'new'} :
{:controller => 'users', :action => 'edit', :id => @user}
)
}
format.api { render :action => 'show', :status => :created, :location => user_url(@user) }
end
else
@auth_sources = AuthSource.all
@auth_sources = AuthSource.find(:all)
# Clear password input
@user.password = @user.password_confirmation = nil
@@ -121,7 +124,7 @@ class UsersController < ApplicationController
end
def edit
@auth_sources = AuthSource.all
@auth_sources = AuthSource.find(:all)
@membership ||= Member.new
end
@@ -136,6 +139,7 @@ class UsersController < ApplicationController
was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE])
# TODO: Similar to My#account
@user.pref.attributes = params[:pref]
@user.pref[:no_self_notified] = (params[:no_self_notified] == '1')
if @user.save
@user.pref.save
@@ -155,7 +159,7 @@ class UsersController < ApplicationController
format.api { render_api_ok }
end
else
@auth_sources = AuthSource.all
@auth_sources = AuthSource.find(:all)
@membership ||= Member.new
# Clear password input
@user.password = @user.password_confirmation = nil
@@ -170,7 +174,7 @@ class UsersController < ApplicationController
def destroy
@user.destroy
respond_to do |format|
format.html { redirect_back_or_default(users_path) }
format.html { redirect_back_or_default(users_url) }
format.api { render_api_ok }
end
end
@@ -179,7 +183,7 @@ class UsersController < ApplicationController
@membership = Member.edit_membership(params[:membership_id], params[:membership], @user)
@membership.save
respond_to do |format|
format.html { redirect_to edit_user_path(@user, :tab => 'memberships') }
format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' }
format.js
end
end
@@ -190,7 +194,7 @@ class UsersController < ApplicationController
@membership.destroy
end
respond_to do |format|
format.html { redirect_to edit_user_path(@user, :tab => 'memberships') }
format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' }
format.js
end
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -31,7 +31,7 @@ class VersionsController < ApplicationController
def index
respond_to do |format|
format.html {
@trackers = @project.trackers.sorted.all
@trackers = @project.trackers.find(:all, :order => 'position')
retrieve_selected_tracker_ids(@trackers, @trackers.select {|t| t.is_in_roadmap?})
@with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
project_ids = @with_subprojects ? @project.self_and_descendants.collect(&:id) : [@project.id]
@@ -64,10 +64,9 @@ class VersionsController < ApplicationController
def show
respond_to do |format|
format.html {
@issues = @version.fixed_issues.visible.
includes(:status, :tracker, :priority).
reorder("#{Tracker.table_name}.position, #{Issue.table_name}.id").
all
@issues = @version.fixed_issues.visible.find(:all,
:include => [:status, :tracker, :priority],
:order => "#{Tracker.table_name}.position, #{Issue.table_name}.id")
}
format.api
end
@@ -96,7 +95,7 @@ class VersionsController < ApplicationController
respond_to do |format|
format.html do
flash[:notice] = l(:notice_successful_create)
redirect_back_or_default settings_project_path(@project, :tab => 'versions')
redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
end
format.js
format.api do
@@ -125,7 +124,7 @@ class VersionsController < ApplicationController
respond_to do |format|
format.html {
flash[:notice] = l(:notice_successful_update)
redirect_back_or_default settings_project_path(@project, :tab => 'versions')
redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
}
format.api { render_api_ok }
end
@@ -142,21 +141,21 @@ class VersionsController < ApplicationController
if request.put?
@project.close_completed_versions
end
redirect_to settings_project_path(@project, :tab => 'versions')
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
end
def destroy
if @version.fixed_issues.empty?
@version.destroy
respond_to do |format|
format.html { redirect_back_or_default settings_project_path(@project, :tab => 'versions') }
format.html { redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project }
format.api { render_api_ok }
end
else
respond_to do |format|
format.html {
flash[:error] = l(:notice_unable_delete_version)
redirect_to settings_project_path(@project, :tab => 'versions')
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
}
format.api { head :unprocessable_entity }
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -16,36 +16,35 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class WatchersController < ApplicationController
before_filter :require_login, :find_watchables, :only => [:watch, :unwatch]
before_filter :find_project
before_filter :require_login, :check_project_privacy, :only => [:watch, :unwatch]
before_filter :authorize, :only => [:new, :destroy]
def watch
set_watcher(@watchables, User.current, true)
if @watched.respond_to?(:visible?) && !@watched.visible?(User.current)
render_403
else
set_watcher(User.current, true)
end
end
def unwatch
set_watcher(@watchables, User.current, false)
set_watcher(User.current, false)
end
before_filter :find_project, :authorize, :only => [:new, :create, :append, :destroy, :autocomplete_for_user]
accept_api_auth :create, :destroy
def new
end
def create
user_ids = []
if params[:watcher].is_a?(Hash)
user_ids << (params[:watcher][:user_ids] || params[:watcher][:user_id])
else
user_ids << params[:user_id]
end
user_ids.flatten.compact.uniq.each do |user_id|
Watcher.create(:watchable => @watched, :user_id => user_id)
if params[:watcher].is_a?(Hash) && request.post?
user_ids = params[:watcher][:user_ids] || [params[:watcher][:user_id]]
user_ids.each do |user_id|
Watcher.create(:watchable => @watched, :user_id => user_id)
end
end
respond_to do |format|
format.html { redirect_to_referer_or {render :text => 'Watcher added.', :layout => true}}
format.js
format.api { render_api_ok }
end
end
@@ -57,24 +56,22 @@ class WatchersController < ApplicationController
end
def destroy
@watched.set_watcher(User.find(params[:user_id]), false)
@watched.set_watcher(User.find(params[:user_id]), false) if request.post?
respond_to do |format|
format.html { redirect_to :back }
format.js
format.api { render_api_ok }
end
end
def autocomplete_for_user
@users = User.active.sorted.like(params[:q]).limit(100).all
@users = User.active.like(params[:q]).find(:all, :limit => 100)
if @watched
@users -= @watched.watcher_users
end
render :layout => false
end
private
private
def find_project
if params[:object_type] && params[:object_id]
klass = Object.const_get(params[:object_type].camelcase)
@@ -88,22 +85,11 @@ class WatchersController < ApplicationController
render_404
end
def find_watchables
klass = Object.const_get(params[:object_type].camelcase) rescue nil
if klass && klass.respond_to?('watched_by')
@watchables = klass.find_all_by_id(Array.wrap(params[:object_id]))
raise Unauthorized if @watchables.any? {|w| w.respond_to?(:visible?) && !w.visible?}
end
render_404 unless @watchables.present?
end
def set_watcher(watchables, user, watching)
watchables.each do |watchable|
watchable.set_watcher(user, watching)
end
def set_watcher(user, watching)
@watched.set_watcher(user, watching)
respond_to do |format|
format.html { redirect_to_referer_or {render :text => (watching ? 'Watcher added.' : 'Watcher removed.'), :layout => true}}
format.js { render :partial => 'set_watcher', :locals => {:user => user, :watched => watchables} }
format.js { render :partial => 'set_watcher', :locals => {:user => user, :watched => @watched} }
end
end
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -37,7 +37,6 @@ class WikiController < ApplicationController
before_filter :find_existing_or_new_page, :only => [:show, :edit, :update]
before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy, :destroy_version]
accept_api_auth :index, :show, :update, :destroy
before_filter :find_attachments, :only => [:preview]
helper :attachments
include AttachmentsHelper
@@ -160,10 +159,10 @@ class WikiController < ApplicationController
call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page})
respond_to do |format|
format.html { redirect_to project_wiki_page_path(@project, @page.title) }
format.html { redirect_to :action => 'show', :project_id => @project, :id => @page.title }
format.api {
if was_new_page
render :action => 'show', :status => :created, :location => project_wiki_page_path(@project, @page.title)
render :action => 'show', :status => :created, :location => url_for(:controller => 'wiki', :action => 'show', :project_id => @project, :id => @page.title)
else
render_api_ok
end
@@ -200,26 +199,25 @@ class WikiController < ApplicationController
@original_title = @page.pretty_title
if request.post? && @page.update_attributes(params[:wiki_page])
flash[:notice] = l(:notice_successful_update)
redirect_to project_wiki_page_path(@project, @page.title)
redirect_to :action => 'show', :project_id => @project, :id => @page.title
end
end
def protect
@page.update_attribute :protected, params[:protected]
redirect_to project_wiki_page_path(@project, @page.title)
redirect_to :action => 'show', :project_id => @project, :id => @page.title
end
# show page history
def history
@version_count = @page.content.versions.count
@version_pages = Paginator.new @version_count, per_page_option, params['page']
@version_pages = Paginator.new self, @version_count, per_page_option, params['page']
# don't load text
@versions = @page.content.versions.
select("id, author_id, comments, updated_on, version").
reorder('version DESC').
limit(@version_pages.per_page + 1).
offset(@version_pages.offset).
all
@versions = @page.content.versions.find :all,
:select => "id, author_id, comments, updated_on, version",
:order => 'version DESC',
:limit => @version_pages.items_per_page + 1,
:offset => @version_pages.current.offset
render :layout => false if request.xhr?
end
@@ -262,7 +260,7 @@ class WikiController < ApplicationController
end
@page.destroy
respond_to do |format|
format.html { redirect_to project_wiki_index_path(@project) }
format.html { redirect_to :action => 'index', :project_id => @project }
format.api { render_api_ok }
end
end
@@ -272,7 +270,7 @@ class WikiController < ApplicationController
@content = @page.content_for_version(params[:version])
@content.destroy
redirect_to_referer_or history_project_wiki_page_path(@project, @page.title)
redirect_to_referer_or :action => 'history', :id => @page.title, :project_id => @project
end
# Export wiki to a single pdf or html file
@@ -294,7 +292,7 @@ class WikiController < ApplicationController
# page is nil when previewing a new page
return render_403 unless page.nil? || editable?(page)
if page
@attachments += page.attachments
@attachements = page.attachments
@previewed = page.content
end
@text = params[:content][:text]
@@ -351,6 +349,6 @@ private
end
def load_pages_for_index
@pages = @wiki.pages.with_updated_on.reorder("#{WikiPage.table_name}.title").includes(:wiki => :project).includes(:parent).all
@pages = @wiki.pages.with_updated_on.order("#{WikiPage.table_name}.title").includes(:wiki => :project).includes(:parent).all
end
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -30,7 +30,7 @@ class WikisController < ApplicationController
def destroy
if request.post? && params[:confirm] && @project.wiki
@project.wiki.destroy
redirect_to settings_project_path(@project, :tab => 'wiki')
redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'wiki'
end
end
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -38,7 +38,7 @@ class WorkflowsController < ApplicationController
}
}
if @role.save
redirect_to workflows_edit_path(:role_id => @role, :tracker_id => @tracker, :used_statuses_only => params[:used_statuses_only])
redirect_to :action => 'edit', :role_id => @role, :tracker_id => @tracker, :used_statuses_only => params[:used_statuses_only]
return
end
end
@@ -64,7 +64,7 @@ class WorkflowsController < ApplicationController
if request.post? && @role && @tracker
WorkflowPermission.replace_permissions(@tracker, @role, params[:permissions] || {})
redirect_to workflows_permissions_path(:role_id => @role, :tracker_id => @tracker, :used_statuses_only => params[:used_statuses_only])
redirect_to :action => 'permissions', :role_id => @role, :tracker_id => @tracker, :used_statuses_only => params[:used_statuses_only]
return
end
@@ -106,12 +106,12 @@ class WorkflowsController < ApplicationController
if request.post?
if params[:source_tracker_id].blank? || params[:source_role_id].blank? || (@source_tracker.nil? && @source_role.nil?)
flash.now[:error] = l(:error_workflow_copy_source)
elsif @target_trackers.blank? || @target_roles.blank?
elsif @target_trackers.nil? || @target_roles.nil?
flash.now[:error] = l(:error_workflow_copy_target)
else
WorkflowRule.copy(@source_tracker, @source_role, @target_trackers, @target_roles)
flash[:notice] = l(:notice_successful_update)
redirect_to workflows_copy_path(:source_tracker_id => @source_tracker, :source_role_id => @source_role)
redirect_to :action => 'copy', :source_tracker_id => @source_tracker, :source_role_id => @source_role
end
end
end

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,33 +0,0 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 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.
module ActivitiesHelper
def sort_activity_events(events)
events_by_group = events.group_by(&:event_group)
sorted_events = []
events.sort {|x, y| y.event_datetime <=> x.event_datetime}.each do |event|
if group_events = events_by_group.delete(event.event_group)
group_events.sort {|x, y| y.event_datetime <=> x.event_datetime}.each_with_index do |e, i|
sorted_events << [e, i > 0]
end
end
end
sorted_events
end
end

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -24,7 +24,6 @@ module ApplicationHelper
include Redmine::WikiFormatting::Macros::Definitions
include Redmine::I18n
include GravatarHelper::PublicMethods
include Redmine::Pagination::Helper
extend Forwardable
def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter
@@ -91,10 +90,14 @@ module ApplicationHelper
# * :download - Force download (default: false)
def link_to_attachment(attachment, options={})
text = options.delete(:text) || attachment.filename
route_method = options.delete(:download) ? :download_named_attachment_path : :named_attachment_path
html_options = options.slice!(:only_path)
url = send(route_method, attachment, attachment.filename, options)
link_to text, url, html_options
action = options.delete(:download) ? 'download' : 'show'
opt_only_path = {}
opt_only_path[:only_path] = (options[:only_path] == false ? false : true)
options.delete(:only_path)
link_to(h(text),
{:controller => 'attachments', :action => action,
:id => attachment, :filename => attachment.filename}.merge(opt_only_path),
options)
end
# Generates a link to a SCM revision
@@ -116,11 +119,13 @@ module ApplicationHelper
# Generates a link to a message
def link_to_message(message, options={}, html_options = nil)
link_to(
truncate(message.subject, :length => 60),
board_message_path(message.board_id, message.parent_id || message.id, {
h(truncate(message.subject, :length => 60)),
{ :controller => 'messages', :action => 'show',
:board_id => message.board_id,
:id => (message.parent_id || message.id),
:r => (message.parent_id && message.id),
:anchor => (message.parent_id ? "message-#{message.id}" : nil)
}.merge(options)),
}.merge(options),
html_options
)
end
@@ -129,29 +134,16 @@ module ApplicationHelper
# Examples:
#
# link_to_project(project) # => link to the specified project overview
# link_to_project(project, :action=>'settings') # => link to project settings
# link_to_project(project, {:only_path => false}, :class => "project") # => 3rd arg adds html options
# link_to_project(project, {}, :class => "project") # => html options with default url (project overview)
#
def link_to_project(project, options={}, html_options = nil)
if project.archived?
h(project.name)
elsif options.key?(:action)
ActiveSupport::Deprecation.warn "#link_to_project with :action option is deprecated and will be removed in Redmine 3.0."
h(project)
else
url = {:controller => 'projects', :action => 'show', :id => project}.merge(options)
link_to project.name, url, html_options
else
link_to project.name, project_path(project, options), html_options
end
end
# Generates a link to a project settings if active
def link_to_project_settings(project, options={}, html_options=nil)
if project.active?
link_to project.name, settings_project_path(project, options), html_options
elsif project.archived?
h(project.name)
else
link_to project.name, project_path(project, options), html_options
link_to(h(project), url, html_options)
end
end
@@ -160,8 +152,8 @@ module ApplicationHelper
end
def thumbnail_tag(attachment)
link_to image_tag(thumbnail_path(attachment)),
named_attachment_path(attachment, attachment.filename),
link_to image_tag(url_for(:controller => 'attachments', :action => 'thumbnail', :id => attachment)),
{:controller => 'attachments', :action => 'show', :id => attachment, :filename => attachment.filename},
:title => attachment.filename
end
@@ -195,7 +187,7 @@ module ApplicationHelper
def format_version_name(version)
if version.project == @project
h(version)
h(version)
else
h("#{version.project} - #{version}")
end
@@ -316,8 +308,8 @@ module ApplicationHelper
def principals_check_box_tags(name, principals)
s = ''
principals.each do |principal|
s << "<label>#{ check_box_tag name, principal.id, false, :id => nil } #{h principal}</label>\n"
principals.sort.each do |principal|
s << "<label>#{ check_box_tag name, principal.id, false } #{h principal}</label>\n"
end
s.html_safe
end
@@ -343,7 +335,7 @@ module ApplicationHelper
def options_for_membership_project_select(principal, projects)
options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---")
options << project_tree_options_for_select(projects) do |p|
{:disabled => principal.projects.to_a.include?(p)}
{:disabled => principal.projects.include?(p)}
end
options
end
@@ -399,6 +391,59 @@ module ApplicationHelper
str.blank? ? nil : str
end
def pagination_links_full(paginator, count=nil, options={})
page_param = options.delete(:page_param) || :page
per_page_links = options.delete(:per_page_links)
url_param = params.dup
html = ''
if paginator.current.previous
# \xc2\xab(utf-8) = &#171;
html << link_to_content_update(
"\xc2\xab " + l(:label_previous),
url_param.merge(page_param => paginator.current.previous)) + ' '
end
html << (pagination_links_each(paginator, options) do |n|
link_to_content_update(n.to_s, url_param.merge(page_param => n))
end || '')
if paginator.current.next
# \xc2\xbb(utf-8) = &#187;
html << ' ' + link_to_content_update(
(l(:label_next) + " \xc2\xbb"),
url_param.merge(page_param => paginator.current.next))
end
unless count.nil?
html << " (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})"
if per_page_links != false && links = per_page_links(paginator.items_per_page, count)
html << " | #{links}"
end
end
html.html_safe
end
def per_page_links(selected=nil, item_count=nil)
values = Setting.per_page_options_array
if item_count && values.any?
if item_count > values.first
max = values.detect {|value| value >= item_count} || item_count
else
max = item_count
end
values = values.select {|value| value <= max || value == selected}
end
if values.empty? || (values.size == 1 && values.first == selected)
return nil
end
links = values.collect do |n|
n == selected ? n : link_to_content_update(n, params.merge(:per_page => n))
end
l(:label_display_per_page, links.join(', '))
end
def reorder_links(name, url, method = :post)
link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)),
url.merge({"#{name}[move_to]" => 'highest'}),
@@ -471,11 +516,7 @@ module ApplicationHelper
end
def accesskey(s)
@used_accesskeys ||= []
key = Redmine::AccessKeys.key_for(s)
return nil if @used_accesskeys.include?(key)
@used_accesskeys << key
key
Redmine::AccessKeys.key_for s
end
# Formats text according to system settings.
@@ -563,7 +604,8 @@ module ApplicationHelper
filename, ext, alt, alttext = $1.downcase, $2, $3, $4
# search for the picture in attachments
if found = Attachment.latest_attach(attachments, filename)
image_url = download_named_attachment_path(found, found.filename, :only_path => only_path)
image_url = url_for :only_path => only_path, :controller => 'attachments',
:action => 'download', :id => found
desc = found.description.to_s.gsub('"', '')
if !desc.blank? && alttext.blank?
alt = " title=\"#{desc}\" alt=\"#{desc}\""
@@ -592,9 +634,9 @@ module ApplicationHelper
esc, all, page, title = $1, $2, $3, $5
if esc.nil?
if page =~ /^([^\:]+)\:(.*)$/
identifier, page = $1, $2
link_project = Project.find_by_identifier(identifier) || Project.find_by_name(identifier)
title ||= identifier if page.blank?
link_project = Project.find_by_identifier($1) || Project.find_by_name($1)
page = $2
title ||= $1 if page.blank?
end
if link_project && link_project.wiki
@@ -759,14 +801,14 @@ module ApplicationHelper
repository = project.repository
end
if prefix == 'commit'
if repository && (changeset = Changeset.visible.where("repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%").first)
if repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%"]))
link = link_to h("#{project_prefix}#{repo_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.identifier},
:class => 'changeset',
:title => truncate_single_line(changeset.comments, :length => 100)
:title => truncate_single_line(h(changeset.comments), :length => 100)
end
else
if repository && User.current.allowed_to?(:browse_repository, project)
name =~ %r{^[/\\]*(.*?)(@([^/\\@]+?))?(#(L\d+))?$}
name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
path, rev, anchor = $1, $3, $5
link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:controller => 'repositories', :action => (prefix == 'export' ? 'raw' : 'entry'), :id => project, :repository_id => repository.identifier_param,
:path => to_path_param(path),
@@ -780,10 +822,11 @@ module ApplicationHelper
when 'attachment'
attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
if attachments && attachment = Attachment.latest_attach(attachments, name)
link = link_to_attachment(attachment, :only_path => only_path, :download => true, :class => 'attachment')
link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment},
:class => 'attachment'
end
when 'project'
if p = Project.visible.where("identifier = :s OR LOWER(name) = :s", :s => name.downcase).first
if p = Project.visible.find(:first, :conditions => ["identifier = :s OR LOWER(name) = :s", {:s => name.downcase}])
link = link_to_project(p, {:only_path => only_path}, :class => 'project')
end
end
@@ -1036,7 +1079,7 @@ module ApplicationHelper
(pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : ''.html_safe) +
(pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : ''.html_safe)
), :class => 'progress', :style => "width: #{width};").html_safe +
content_tag('p', legend, :class => 'percent').html_safe
content_tag('p', legend, :class => 'pourcent').html_safe
end
def checked_image(checked=true)
@@ -1080,7 +1123,7 @@ module ApplicationHelper
"var datepickerOptions={dateFormat: 'yy-mm-dd', firstDay: #{start_of_week}, " +
"showOn: 'button', buttonImageOnly: true, buttonImage: '" +
path_to_image('/images/calendar.png') +
"', showButtonPanel: true, showWeek: true, showOtherMonths: true, selectOtherMonths: true};")
"', showButtonPanel: true};")
jquery_locale = l('jquery.locale', :default => current_language.to_s)
unless jquery_locale == 'en'
tags << javascript_include_tag("i18n/jquery.ui.datepicker-#{jquery_locale}.js")
@@ -1184,7 +1227,7 @@ module ApplicationHelper
def sanitize_anchor_name(anchor)
if ''.respond_to?(:encoding) || RUBY_PLATFORM == 'java'
anchor.gsub(%r{[^\s\-\p{Word}]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
anchor.gsub(%r{[^\p{Word}\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
else
# TODO: remove when ruby1.8 is no longer supported
anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
@@ -1193,7 +1236,7 @@ module ApplicationHelper
# Returns the javascript tags that are included in the html layout head
def javascript_heads
tags = javascript_include_tag('jquery-1.8.3-ui-1.9.2-ujs-2.0.3', 'application')
tags = javascript_include_tag('jquery-1.7.2-ui-1.8.21-ujs-2.0.3', 'application')
unless User.current.pref.warn_on_leaving_unsaved == '0'
tags << "\n".html_safe + javascript_tag("$(window).load(function(){ warnLeavingUnsaved('#{escape_javascript l(:text_warn_on_leaving_unsaved)}'); });")
end

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -36,7 +36,7 @@ module ContextMenusHelper
def bulk_update_custom_field_context_menu_link(field, text, value)
context_menu_link h(text),
bulk_update_issues_path(:ids => @issue_ids, :issue => {'custom_field_values' => {field.id => value}}, :back_url => @back),
{:controller => 'issues', :action => 'bulk_update', :ids => @issue_ids, :issue => {'custom_field_values' => {field.id => value}}, :back_url => @back},
:method => :post,
:selected => (@issue && @issue.custom_field_value(field) == value)
end

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -24,7 +24,7 @@ module CustomFieldsHelper
end
# Return custom field html tag corresponding to its format
def custom_field_tag(name, custom_value)
def custom_field_tag(name, custom_value)
custom_field = custom_value.custom_field
field_name = "#{name}[custom_field_values][#{custom_field.id}]"
field_name << "[]" if custom_field.multiple?

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -24,19 +24,19 @@ module GanttHelper
when :in
if gantt.zoom < 4
link_to_content_update l(:text_zoom_in),
params.merge(gantt.params.merge(:zoom => (gantt.zoom + 1))),
params.merge(gantt.params.merge(:zoom => (gantt.zoom+1))),
:class => 'icon icon-zoom-in'
else
content_tag(:span, l(:text_zoom_in), :class => 'icon icon-zoom-in').html_safe
content_tag('span', l(:text_zoom_in), :class => 'icon icon-zoom-in').html_safe
end
when :out
if gantt.zoom > 1
link_to_content_update l(:text_zoom_out),
params.merge(gantt.params.merge(:zoom => (gantt.zoom - 1))),
params.merge(gantt.params.merge(:zoom => (gantt.zoom-1))),
:class => 'icon icon-zoom-out'
else
content_tag(:span, l(:text_zoom_out), :class => 'icon icon-zoom-out').html_safe
content_tag('span', l(:text_zoom_out), :class => 'icon icon-zoom-out').html_safe
end
end
end

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -24,19 +24,4 @@ module GroupsHelper
{:name => 'memberships', :partial => 'groups/memberships', :label => :label_project_plural}
]
end
def render_principals_for_new_group_users(group)
scope = User.active.sorted.not_in_group(group).like(params[:q])
principal_count = scope.count
principal_pages = Redmine::Pagination::Paginator.new principal_count, 100, params['page']
principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).all
s = content_tag('div', principals_check_box_tags('user_ids[]', principals), :id => 'principals')
links = pagination_links_full(principal_pages, principal_count, :per_page_links => false) {|text, parameters, options|
link_to text, autocomplete_for_user_group_path(group, parameters.merge(:q => params[:q], :format => 'js')), :remote => true
}
s + content_tag('p', links, :class => 'pagination')
end
end

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -184,7 +184,7 @@ module IssuesHelper
def sidebar_queries
unless @sidebar_queries
@sidebar_queries = IssueQuery.visible.all(
@sidebar_queries = Query.visible.all(
:order => "#{Query.table_name}.name ASC",
# Project specific queries and global queries
:conditions => (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id])
@@ -214,28 +214,6 @@ module IssuesHelper
out
end
def email_issue_attributes(issue)
items = []
%w(author status priority assigned_to category fixed_version).each do |attribute|
unless issue.disabled_core_fields.include?(attribute+"_id")
items << "#{l("field_#{attribute}")}: #{issue.send attribute}"
end
end
issue.custom_field_values.each do |value|
items << "#{value.custom_field.name}: #{show_value(value)}"
end
items
end
def render_email_issue_attributes(issue, html=false)
items = email_issue_attributes(issue)
if html
content_tag('ul', items.map{|s| content_tag('li', s)}.join("\n").html_safe)
else
items.map{|s| "* #{s}"}.join("\n")
end
end
# Returns the textual representation of a journal details
# as an array of strings
def details_to_strings(details, no_html=false, options={})
@@ -369,16 +347,10 @@ module IssuesHelper
# Find the name of an associated record stored in the field attribute
def find_name_by_reflection(field, id)
unless id.present?
return nil
end
association = Issue.reflect_on_association(field.to_sym)
if association
record = association.class_name.constantize.find_by_id(id)
if record
record.name.force_encoding('UTF-8') if record.name.respond_to?(:force_encoding)
return record.name
end
return record.name if record
end
end
@@ -395,4 +367,44 @@ module IssuesHelper
end
end
end
def issues_to_csv(issues, project, query, options={})
decimal_separator = l(:general_csv_decimal_separator)
encoding = l(:general_csv_encoding)
columns = (options[:columns] == 'all' ? query.available_inline_columns : query.inline_columns)
if options[:description]
if description = query.available_columns.detect {|q| q.name == :description}
columns << description
end
end
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
# csv header fields
csv << [ "#" ] + columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) }
# csv lines
issues.each do |issue|
col_values = columns.collect do |column|
s = if column.is_a?(QueryCustomFieldColumn)
cv = issue.custom_field_values.detect {|v| v.custom_field_id == column.custom_field.id}
show_value(cv)
else
value = column.value(issue)
if value.is_a?(Date)
format_date(value)
elsif value.is_a?(Time)
format_time(value)
elsif value.is_a?(Float)
("%.2f" % value).gsub('.', decimal_separator)
else
value
end
end
s.to_s
end
csv << [ issue.id.to_s ] + col_values.collect {|c| Redmine::CodesetUtil.from_utf8(c.to_s, encoding) }
end
end
export
end
end

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -18,18 +18,4 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module MembersHelper
def render_principals_for_new_members(project)
scope = Principal.active.sorted.not_member_of(project).like(params[:q])
principal_count = scope.count
principal_pages = Redmine::Pagination::Paginator.new principal_count, 100, params['page']
principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).all
s = content_tag('div', principals_check_box_tags('membership[user_ids][]', principals), :id => 'principals')
links = pagination_links_full(principal_pages, principal_count, :per_page_links => false) {|text, parameters, options|
link_to text, autocomplete_project_memberships_path(project, parameters.merge(:q => params[:q], :format => 'js')), :remote => true
}
s + content_tag('p', links, :class => 'pagination')
end
end

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -18,54 +18,4 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module MyHelper
def calendar_items(startdt, enddt)
Issue.visible.
where(:project_id => User.current.projects.map(&:id)).
where("(start_date>=? and start_date<=?) or (due_date>=? and due_date<=?)", startdt, enddt, startdt, enddt).
includes(:project, :tracker, :priority, :assigned_to).
all
end
def documents_items
Document.visible.order("#{Document.table_name}.created_on DESC").limit(10).all
end
def issuesassignedtome_items
Issue.visible.open.
where(:assigned_to_id => ([User.current.id] + User.current.group_ids)).
limit(10).
includes(:status, :project, :tracker, :priority).
order("#{IssuePriority.table_name}.position DESC, #{Issue.table_name}.updated_on DESC").
all
end
def issuesreportedbyme_items
Issue.visible.
where(:author_id => User.current.id).
limit(10).
includes(:status, :project, :tracker).
order("#{Issue.table_name}.updated_on DESC").
all
end
def issueswatched_items
Issue.visible.on_active_project.watched_by(User.current.id).recently_updated.limit(10).all
end
def news_items
News.visible.
where(:project_id => User.current.projects.map(&:id)).
limit(10).
includes(:project, :author).
order("#{News.table_name}.created_on DESC").
all
end
def timelog_items
TimeEntry.
where("#{TimeEntry.table_name}.user_id = ? AND #{TimeEntry.table_name}.spent_on BETWEEN ? AND ?", User.current.id, Date.today - 6, Date.today).
includes(:activity, :project, {:issue => [:tracker, :status]}).
order("#{TimeEntry.table_name}.spent_on DESC, #{Project.table_name}.name ASC, #{Tracker.table_name}.position ASC, #{Issue.table_name}.id ASC").
all
end
end

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -24,35 +24,32 @@ module QueriesHelper
def filters_options(query)
options = [[]]
options += query.available_filters.map do |field, field_options|
sorted_options = query.available_filters.sort do |a, b|
ord = 0
if !(a[1][:order] == 20 && b[1][:order] == 20)
ord = a[1][:order] <=> b[1][:order]
else
cn = (CustomField::CUSTOM_FIELDS_NAMES.index(a[1][:field].class.name) <=>
CustomField::CUSTOM_FIELDS_NAMES.index(b[1][:field].class.name))
if cn != 0
ord = cn
else
f = (a[1][:field] <=> b[1][:field])
if f != 0
ord = f
else
# assigned_to or author
ord = (a[0] <=> b[0])
end
end
end
ord
end
options += sorted_options.map do |field, field_options|
[field_options[:name], field]
end
end
def query_filters_hidden_tags(query)
tags = ''.html_safe
query.filters.each do |field, options|
tags << hidden_field_tag("f[]", field, :id => nil)
tags << hidden_field_tag("op[#{field}]", options[:operator], :id => nil)
options[:values].each do |value|
tags << hidden_field_tag("v[#{field}][]", value, :id => nil)
end
end
tags
end
def query_columns_hidden_tags(query)
tags = ''.html_safe
query.columns.each do |column|
tags << hidden_field_tag("c[]", column.name, :id => nil)
end
tags
end
def query_hidden_tags(query)
query_filters_hidden_tags(query) + query_columns_hidden_tags(query)
end
def available_block_columns_tags(query)
tags = ''.html_safe
query.available_block_columns.each do |column|
@@ -61,19 +58,6 @@ module QueriesHelper
tags
end
def query_available_inline_columns_options(query)
(query.available_inline_columns - query.columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}
end
def query_selected_inline_columns_options(query)
(query.inline_columns & query.available_inline_columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}
end
def render_query_columns_selection(query, options={})
tag_name = (options[:name] || 'c') + '[]'
render :partial => 'queries/columns', :locals => {:query => query, :tag_name => tag_name}
end
def column_header(column)
column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption,
:default_order => column.default_order) :
@@ -104,9 +88,7 @@ module QueriesHelper
when 'Date'
format_date(value)
when 'Fixnum'
if column.name == :id
link_to value, issue_path(issue)
elsif column.name == :done_ratio
if column.name == :done_ratio
progress_bar(value, :width => '80px')
else
value.to_s
@@ -124,7 +106,7 @@ module QueriesHelper
when 'FalseClass'
l(:general_text_No)
when 'Issue'
value.visible? ? link_to_issue(value) : "##{value.id}"
link_to_issue(value, :subject => false)
when 'IssueRelation'
other = value.other_issue(issue)
content_tag('span',
@@ -135,71 +117,26 @@ module QueriesHelper
end
end
def csv_content(column, issue)
value = column.value(issue)
if value.is_a?(Array)
value.collect {|v| csv_value(column, issue, v)}.compact.join(', ')
else
csv_value(column, issue, value)
end
end
def csv_value(column, issue, value)
case value.class.name
when 'Time'
format_time(value)
when 'Date'
format_date(value)
when 'Float'
sprintf("%.2f", value).gsub('.', l(:general_csv_decimal_separator))
when 'IssueRelation'
other = value.other_issue(issue)
l(value.label_for(issue)) + " ##{other.id}"
else
value.to_s
end
end
def query_to_csv(items, query, options={})
encoding = l(:general_csv_encoding)
columns = (options[:columns] == 'all' ? query.available_inline_columns : query.inline_columns)
query.available_block_columns.each do |column|
if options[column.name].present?
columns << column
end
end
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
# csv header fields
csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) }
# csv lines
items.each do |item|
csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(csv_content(c, item), encoding) }
end
end
export
end
# Retrieve query from session or build a new query
def retrieve_query
if !params[:query_id].blank?
cond = "project_id IS NULL"
cond << " OR project_id = #{@project.id}" if @project
@query = IssueQuery.find(params[:query_id], :conditions => cond)
@query = Query.find(params[:query_id], :conditions => cond)
raise ::Unauthorized unless @query.visible?
@query.project = @project
session[:query] = {:id => @query.id, :project_id => @query.project_id}
sort_clear
elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil)
# Give it a name, required to be valid
@query = IssueQuery.new(:name => "_")
@query = Query.new(:name => "_")
@query.project = @project
@query.build_from_params(params)
build_query_from_params
session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names}
else
# retrieve from session
@query = IssueQuery.find_by_id(session[:query][:id]) if session[:query][:id]
@query ||= IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
@query = Query.find_by_id(session[:query][:id]) if session[:query][:id]
@query ||= Query.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
@query.project = @project
end
end
@@ -207,10 +144,10 @@ module QueriesHelper
def retrieve_query_from_session
if session[:query]
if session[:query][:id]
@query = IssueQuery.find_by_id(session[:query][:id])
@query = Query.find_by_id(session[:query][:id])
return unless @query
else
@query = IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
@query = Query.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
end
if session[:query].has_key?(:project_id)
@query.project_id = session[:query][:project_id]
@@ -220,4 +157,17 @@ module QueriesHelper
@query
end
end
def build_query_from_params
if params[:fields] || params[:f]
@query.filters = {}
@query.add_filters(params[:fields] || params[:f], params[:operators] || params[:op], params[:values] || params[:v])
else
@query.available_filters.keys.each do |field|
@query.add_short_filter(field, params[field]) if params[field]
end
end
@query.group_by = params[:group_by] || (params[:query] && params[:query][:group_by])
@query.column_names = params[:c] || (params[:query] && params[:query][:column_names])
end
end

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -24,7 +24,7 @@ module ReportsHelper
data.each { |row|
match = 1
criteria.each { |k, v|
match = 0 unless (row[k].to_s == v.to_s) || (k == 'closed' && (v == 0 ? ['f', false] : ['t', true]).include?(row[k]))
match = 0 unless (row[k].to_s == v.to_s) || (k == 'closed' && row[k] == (v == 0 ? "f" : "t"))
} unless criteria.nil?
a = a + row["total"].to_i if match == 1
} unless data.nil?
@@ -35,9 +35,4 @@ module ReportsHelper
a = aggregate data, criteria
a > 0 ? link_to(h(a), *args) : '-'
end
def aggregate_path(project, field, row, options={})
parameters = {:set_filter => 1, :subproject_id => '!*', field => row.id}.merge(options)
project_issues_path(row.is_a?(Project) ? row : project, parameters)
end
end

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -43,7 +43,7 @@ module RepositoriesHelper
end
def render_changeset_changes
changes = @changeset.filechanges.limit(1000).reorder('path').all.collect do |change|
changes = @changeset.filechanges.find(:all, :limit => 1000, :order => 'path').collect do |change|
case change.action
when 'A'
# Detects moved/copied files

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,39 +0,0 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 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.
module RoutesHelper
# Returns the path to project issues or to the cross-project
# issue list if project is nil
def _project_issues_path(project, *args)
if project
project_issues_path(project, *args)
else
issues_path(*args)
end
end
def _project_calendar_path(project, *args)
project ? project_calendar_path(project, *args) : issues_calendar_path(*args)
end
def _project_gantt_path(project, *args)
project ? project_gantt_path(project, *args) : issues_gantt_path(*args)
end
end

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -53,7 +53,7 @@ module SettingsHelper
check_box_tag(
"settings[#{setting}][]",
value,
setting_values.include?(value),
Setting.send(setting).include?(value),
:id => nil
) + text.to_s,
:class => (options[:inline] ? 'inline' : 'block')

View File

@@ -80,13 +80,12 @@ module SortHelper
@criteria.collect {|k,o| k + (o ? '' : ':desc')}.join(',')
end
# Returns an array of SQL fragments used to sort the list
def to_sql
sql = @criteria.collect do |k,o|
if s = @available_criteria[k]
(o ? s.to_a : s.to_a.collect {|c| append_desc(c)})
(o ? s.to_a : s.to_a.collect {|c| append_desc(c)}).join(', ')
end
end.flatten.compact
end.compact.join(', ')
sql.blank? ? nil : sql
end

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -56,10 +56,10 @@ module TimelogHelper
end
def select_hours(data, criteria, value)
if value.to_s.empty?
data.select {|row| row[criteria].blank? }
if value.to_s.empty?
data.select {|row| row[criteria].blank? }
else
data.select {|row| row[criteria].to_s == value.to_s}
data.select {|row| row[criteria].to_s == value.to_s}
end
end
@@ -86,6 +86,49 @@ module TimelogHelper
value)
end
def entries_to_csv(entries)
decimal_separator = l(:general_csv_decimal_separator)
custom_fields = TimeEntryCustomField.find(:all)
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
# csv header fields
headers = [l(:field_spent_on),
l(:field_user),
l(:field_activity),
l(:field_project),
l(:field_issue),
l(:field_tracker),
l(:field_subject),
l(:field_hours),
l(:field_comments)
]
# Export custom fields
headers += custom_fields.collect(&:name)
csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8(
c.to_s,
l(:general_csv_encoding) ) }
# csv lines
entries.each do |entry|
fields = [format_date(entry.spent_on),
entry.user,
entry.activity,
entry.project,
(entry.issue ? entry.issue.id : nil),
(entry.issue ? entry.issue.tracker : nil),
(entry.issue ? entry.issue.subject : nil),
entry.hours.to_s.gsub('.', decimal_separator),
entry.comments
]
fields += custom_fields.collect {|f| show_value(entry.custom_field_values.detect {|v| v.custom_field_id == f.id}) }
csv << fields.collect {|c| Redmine::CodesetUtil.from_utf8(
c.to_s,
l(:general_csv_encoding) ) }
end
end
export
end
def format_criteria_value(criteria_options, value)
if value.blank?
"[#{l(:label_none)}]"
@@ -107,14 +150,14 @@ module TimelogHelper
# Column headers
headers = report.criteria.collect {|criteria| l(report.available_criteria[criteria][:label]) }
headers += report.periods
headers << l(:label_total_time)
headers << l(:label_total)
csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8(
c.to_s,
l(:general_csv_encoding) ) }
# Content
report_criteria_to_csv(csv, report.available_criteria, report.columns, report.criteria, report.periods, report.hours)
# Total row
str_total = Redmine::CodesetUtil.from_utf8(l(:label_total_time), l(:general_csv_encoding))
str_total = Redmine::CodesetUtil.from_utf8(l(:label_total), l(:general_csv_encoding))
row = [ str_total ] + [''] * (report.criteria.size - 1)
total = 0
report.periods.each do |period|

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -20,31 +20,24 @@
module WatchersHelper
def watcher_tag(object, user, options={})
ActiveSupport::Deprecation.warn "#watcher_tag is deprecated and will be removed in Redmine 3.0. Use #watcher_link instead."
watcher_link(object, user)
content_tag("span", watcher_link(object, user), :class => watcher_css(object))
end
def watcher_link(objects, user)
return '' unless user && user.logged?
objects = Array.wrap(objects)
def watcher_link(object, user)
return '' unless user && user.logged? && object.respond_to?('watched_by?')
watched = object.watched_by?(user)
url = {:controller => 'watchers',
:action => (watched ? 'unwatch' : 'watch'),
:object_type => object.class.to_s.underscore,
:object_id => object.id}
link_to((watched ? l(:button_unwatch) : l(:button_watch)), url,
:remote => true, :method => 'post', :class => (watched ? 'icon icon-fav' : 'icon icon-fav-off'))
watched = objects.any? {|object| object.watched_by?(user)}
css = [watcher_css(objects), watched ? 'icon icon-fav' : 'icon icon-fav-off'].join(' ')
text = watched ? l(:button_unwatch) : l(:button_watch)
url = watch_path(
:object_type => objects.first.class.to_s.underscore,
:object_id => (objects.size == 1 ? objects.first.id : objects.map(&:id).sort)
)
method = watched ? 'delete' : 'post'
link_to text, url, :remote => true, :method => method, :class => css
end
# Returns the css class used to identify watch links for a given +object+
def watcher_css(objects)
objects = Array.wrap(objects)
id = (objects.size == 1 ? objects.first.id : 'bulk')
"#{objects.first.class.to_s.underscore}-#{id}-watcher"
def watcher_css(object)
"#{object.class.to_s.underscore}-#{object.id}-watcher"
end
# Returns a comma separated list of users watching the given object
@@ -63,11 +56,11 @@ module WatchersHelper
:user_id => user}
s << ' '
s << link_to(image_tag('delete.png'), url,
:remote => true, :method => 'delete', :class => "delete")
:remote => true, :method => 'post', :style => "vertical-align: middle", :class => "delete")
end
content << content_tag('li', s, :class => "user-#{user.id}")
content << content_tag('li', s)
end
content.present? ? content_tag('ul', content, :class => 'watchers') : content
content.present? ? content_tag('ul', content) : content
end
def watchers_checkboxes(object, users, checked=nil)

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,7 +1,7 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -16,7 +16,6 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require "digest/md5"
require "fileutils"
class Attachment < ActiveRecord::Base
belongs_to :container, :polymorphic => true
@@ -93,6 +92,9 @@ class Attachment < ActiveRecord::Base
def filename=(arg)
write_attribute :filename, sanitize_filename(arg.to_s)
if new_record? && disk_filename.blank?
self.disk_filename = Attachment.disk_filename(filename)
end
filename
end
@@ -100,13 +102,7 @@ class Attachment < ActiveRecord::Base
# and computes its MD5 hash
def files_to_final_location
if @temp_file && (@temp_file.size > 0)
self.disk_directory = target_directory
self.disk_filename = Attachment.disk_filename(filename, disk_directory)
logger.info("Saving attachment '#{self.diskfile}' (#{@temp_file.size} bytes)")
path = File.dirname(diskfile)
unless File.directory?(path)
FileUtils.mkdir_p(path)
end
md5 = Digest::MD5.new
File.open(diskfile, "wb") do |f|
if @temp_file.respond_to?(:read)
@@ -138,7 +134,7 @@ class Attachment < ActiveRecord::Base
# Returns file's location on disk
def diskfile
File.join(self.class.storage_path, disk_directory.to_s, disk_filename.to_s)
File.join(self.class.storage_path, disk_filename.to_s)
end
def title
@@ -158,19 +154,11 @@ class Attachment < ActiveRecord::Base
end
def visible?(user=User.current)
if container_id
container && container.attachments_visible?(user)
else
author == user
end
container && container.attachments_visible?(user)
end
def deletable?(user=User.current)
if container_id
container && container.attachments_deletable?(user)
else
author == user
end
container && container.attachments_deletable?(user)
end
def image?
@@ -263,26 +251,6 @@ class Attachment < ActiveRecord::Base
Attachment.where("created_on < ? AND (container_type IS NULL OR container_type = '')", Time.now - age).destroy_all
end
# Moves an existing attachment to its target directory
def move_to_target_directory!
if !new_record? & readable?
src = diskfile
self.disk_directory = target_directory
dest = diskfile
if src != dest && FileUtils.mkdir_p(File.dirname(dest)) && FileUtils.mv(src, dest)
update_column :disk_directory, disk_directory
end
end
end
# Moves existing attachments that are stored at the root of the files
# directory (ie. created before Redmine 2.3) to their target subdirectories
def self.move_from_root_to_target_directory
Attachment.where("disk_directory IS NULL OR disk_directory = ''").find_each do |attachment|
attachment.move_to_target_directory!
end
end
private
# Physically deletes the file from the file system
@@ -300,15 +268,8 @@ class Attachment < ActiveRecord::Base
@filename = just_filename.gsub(/[\/\?\%\*\:\|\"\'<>]+/, '_')
end
# Returns the subdirectory in which the attachment will be saved
def target_directory
time = created_on || DateTime.now
time.strftime("%Y/%m")
end
# Returns an ASCII or hashed filename that do not
# exists yet in the given subdirectory
def self.disk_filename(filename, directory=nil)
# Returns an ASCII or hashed filename
def self.disk_filename(filename)
timestamp = DateTime.now.strftime("%y%m%d%H%M%S")
ascii = ''
if filename =~ %r{^[a-zA-Z0-9_\.\-]*$}
@@ -318,7 +279,7 @@ class Attachment < ActiveRecord::Base
# keep the extension if any
ascii << $1 if filename =~ %r{(\.[a-zA-Z0-9]+)$}
end
while File.exist?(File.join(storage_path, directory.to_s, "#{timestamp}_#{ascii}"))
while File.exist?(File.join(@@storage_path, "#{timestamp}_#{ascii}"))
timestamp.succ!
end
"#{timestamp}_#{ascii}"

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -48,24 +48,6 @@ class AuthSource < ActiveRecord::Base
write_ciphered_attribute(:account_password, arg)
end
def searchable?
false
end
def self.search(q)
results = []
AuthSource.all.each do |source|
begin
if source.searchable?
results += source.search(q)
end
rescue AuthSourceException => e
logger.error "Error while searching users in #{source.name}: #{e.message}"
end
end
results
end
def allow_password_changes?
self.class.allow_password_changes?
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -15,6 +15,7 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require 'iconv'
require 'net/ldap'
require 'net/ldap/dn'
require 'timeout'
@@ -63,32 +64,6 @@ class AuthSourceLdap < AuthSource
"LDAP"
end
# Returns true if this source can be searched for users
def searchable?
!account.to_s.include?("$login") && %w(login firstname lastname mail).all? {|a| send("attr_#{a}?")}
end
# Searches the source for users and returns an array of results
def search(q)
q = q.to_s.strip
return [] unless searchable? && q.present?
results = []
search_filter = base_filter & Net::LDAP::Filter.begins(self.attr_login, q)
ldap_con = initialize_ldap_con(self.account, self.account_password)
ldap_con.search(:base => self.base_dn,
:filter => search_filter,
:attributes => ['dn', self.attr_login, self.attr_firstname, self.attr_lastname, self.attr_mail],
:size => 10) do |entry|
attrs = get_user_attributes_from_ldap_entry(entry)
attrs[:login] = AuthSourceLdap.get_attr(entry, self.attr_login)
results << attrs
end
results
rescue Net::LDAP::LdapError => e
raise AuthSourceException.new(e.message)
end
private
def with_timeout(&block)
@@ -109,14 +84,6 @@ class AuthSourceLdap < AuthSource
nil
end
def base_filter
filter = Net::LDAP::Filter.eq("objectClass", "*")
if f = ldap_filter
filter = filter & f
end
filter
end
def validate_filter
if filter.present? && ldap_filter.nil?
errors.add(:filter, :invalid)
@@ -173,8 +140,14 @@ class AuthSourceLdap < AuthSource
else
ldap_con = initialize_ldap_con(self.account, self.account_password)
end
login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )
attrs = {}
search_filter = base_filter & Net::LDAP::Filter.eq(self.attr_login, login)
search_filter = object_filter & login_filter
if f = ldap_filter
search_filter = search_filter & f
end
ldap_con.search( :base => self.base_dn,
:filter => search_filter,

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -30,9 +30,8 @@ class Board < ActiveRecord::Base
validates_length_of :description, :maximum => 255
validate :validate_board
scope :visible, lambda {|*args|
includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_messages, *args))
}
scope :visible, lambda {|*args| { :include => :project,
:conditions => Project.allowed_to_condition(args.shift || User.current, :view_messages, *args) } }
safe_attributes 'name', 'description', 'parent_id', 'move_to'

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -15,6 +15,8 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require 'iconv'
class Changeset < ActiveRecord::Base
belongs_to :repository
belongs_to :user
@@ -47,9 +49,9 @@ class Changeset < ActiveRecord::Base
validates_uniqueness_of :revision, :scope => :repository_id
validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true
scope :visible, lambda {|*args|
includes(:repository => :project).where(Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args))
}
scope :visible,
lambda {|*args| { :include => {:repository => :project},
:conditions => Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args) } }
after_create :scan_for_issues
before_create :before_create_cs

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -29,9 +29,6 @@ class CustomField < ActiveRecord::Base
validate :validate_custom_field
before_validation :set_searchable
after_save :handle_multiplicity_change
scope :sorted, lambda { order("#{table_name}.position ASC") }
CUSTOM_FIELDS_TABS = [
{:name => 'IssueCustomField', :partial => 'custom_fields/index',
@@ -172,7 +169,7 @@ class CustomField < ActiveRecord::Base
keyword
end
end
# Returns a ORDER BY clause that can used to sort customized
# objects by their value of the custom field.
# Returns nil if the custom field can not be used for sorting.
@@ -181,12 +178,18 @@ class CustomField < ActiveRecord::Base
case field_format
when 'string', 'text', 'list', 'date', 'bool'
# COALESCE is here to make sure that blank and NULL values are sorted equally
"COALESCE(#{join_alias}.value, '')"
"COALESCE((SELECT cv_sort.value FROM #{CustomValue.table_name} cv_sort" +
" WHERE cv_sort.customized_type='#{self.class.customized_class.base_class.name}'" +
" AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" +
" AND cv_sort.custom_field_id=#{id} LIMIT 1), '')"
when 'int', 'float'
# Make the database cast values into numeric
# Postgresql will raise an error if a value can not be casted!
# CustomValue validations should ensure that it doesn't occur
"CAST(CASE #{join_alias}.value WHEN '' THEN '0' ELSE #{join_alias}.value END AS decimal(30,3))"
"(SELECT CAST(cv_sort.value AS decimal(60,3)) FROM #{CustomValue.table_name} cv_sort" +
" WHERE cv_sort.customized_type='#{self.class.customized_class.base_class.name}'" +
" AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" +
" AND cv_sort.custom_field_id=#{id} AND cv_sort.value <> '' AND cv_sort.value IS NOT NULL LIMIT 1)"
when 'user', 'version'
value_class.fields_for_order_statement(value_join_alias)
else
@@ -196,13 +199,16 @@ class CustomField < ActiveRecord::Base
# Returns a GROUP BY clause that can used to group by custom value
# Returns nil if the custom field can not be used for grouping.
def group_statement
def group_statement
return nil if multiple?
case field_format
when 'list', 'date', 'bool', 'int'
order_statement
when 'user', 'version'
"COALESCE(#{join_alias}.value, '')"
"COALESCE((SELECT cv_sort.value FROM #{CustomValue.table_name} cv_sort" +
" WHERE cv_sort.customized_type='#{self.class.customized_class.base_class.name}'" +
" AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" +
" AND cv_sort.custom_field_id=#{id} LIMIT 1), '')"
else
nil
end
@@ -221,26 +227,7 @@ class CustomField < ActiveRecord::Base
" AND #{join_alias}_2.customized_id = #{join_alias}.customized_id" +
" AND #{join_alias}_2.custom_field_id = #{join_alias}.custom_field_id)" +
" LEFT OUTER JOIN #{value_class.table_name} #{value_join_alias}" +
" ON CAST(CASE #{join_alias}.value WHEN '' THEN '0' ELSE #{join_alias}.value END AS decimal(30,0)) = #{value_join_alias}.id"
when 'int', 'float'
"LEFT OUTER JOIN #{CustomValue.table_name} #{join_alias}" +
" ON #{join_alias}.customized_type = '#{self.class.customized_class.base_class.name}'" +
" AND #{join_alias}.customized_id = #{self.class.customized_class.table_name}.id" +
" AND #{join_alias}.custom_field_id = #{id}" +
" AND #{join_alias}.value <> ''" +
" AND #{join_alias}.id = (SELECT max(#{join_alias}_2.id) FROM #{CustomValue.table_name} #{join_alias}_2" +
" WHERE #{join_alias}_2.customized_type = #{join_alias}.customized_type" +
" AND #{join_alias}_2.customized_id = #{join_alias}.customized_id" +
" AND #{join_alias}_2.custom_field_id = #{join_alias}.custom_field_id)"
when 'string', 'text', 'list', 'date', 'bool'
"LEFT OUTER JOIN #{CustomValue.table_name} #{join_alias}" +
" ON #{join_alias}.customized_type = '#{self.class.customized_class.base_class.name}'" +
" AND #{join_alias}.customized_id = #{self.class.customized_class.table_name}.id" +
" AND #{join_alias}.custom_field_id = #{id}" +
" AND #{join_alias}.id = (SELECT max(#{join_alias}_2.id) FROM #{CustomValue.table_name} #{join_alias}_2" +
" WHERE #{join_alias}_2.customized_type = #{join_alias}.customized_type" +
" AND #{join_alias}_2.customized_id = #{join_alias}.customized_id" +
" AND #{join_alias}_2.custom_field_id = #{join_alias}.custom_field_id)"
" ON CAST(#{join_alias}.value as decimal(60,0)) = #{value_join_alias}.id"
else
nil
end
@@ -275,7 +262,7 @@ class CustomField < ActiveRecord::Base
# to move in project_custom_field
def self.for_all
where(:is_for_all => true).order('position').all
find(:all, :conditions => ["is_for_all=?", true], :order => 'position')
end
def type_name
@@ -336,20 +323,4 @@ class CustomField < ActiveRecord::Base
end
errs
end
# Removes multiple values for the custom field after setting the multiple attribute to false
# We kepp the value with the highest id for each customized object
def handle_multiplicity_change
if !new_record? && multiple_was && !multiple
ids = custom_values.
where("EXISTS(SELECT 1 FROM #{CustomValue.table_name} cve WHERE cve.custom_field_id = #{CustomValue.table_name}.custom_field_id" +
" AND cve.customized_type = #{CustomValue.table_name}.customized_type AND cve.customized_id = #{CustomValue.table_name}.customized_id" +
" AND cve.id > #{CustomValue.table_name}.id)").
pluck(:id)
if ids.any?
custom_values.where(:id => ids).delete_all
end
end
end
end

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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

View File

@@ -1,5 +1,5 @@
# Redmine - project management software
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2006-2012 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
@@ -19,20 +19,19 @@ class Document < ActiveRecord::Base
include Redmine::SafeAttributes
belongs_to :project
belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id"
acts_as_attachable :delete_permission => :delete_documents
acts_as_attachable :delete_permission => :manage_documents
acts_as_searchable :columns => ['title', "#{table_name}.description"], :include => :project
acts_as_event :title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"},
:author => Proc.new {|o| o.attachments.reorder("#{Attachment.table_name}.created_on ASC").first.try(:author) },
:author => Proc.new {|o| (a = o.attachments.find(:first, :order => "#{Attachment.table_name}.created_on ASC")) ? a.author : nil },
:url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.id}}
acts_as_activity_provider :find_options => {:include => :project}
validates_presence_of :project, :title, :category
validates_length_of :title, :maximum => 60
scope :visible, lambda {|*args|
includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_documents, *args))
}
scope :visible, lambda {|*args| { :include => :project,
:conditions => Project.allowed_to_condition(args.shift || User.current, :view_documents, *args) } }
safe_attributes 'category_id', 'title', 'description'

Some files were not shown because too many files have changed in this diff Show More