Compare commits
135
Commits
1.3.3
..
1.1-stable
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bc79904e4e | ||
|
|
ffc111bd23 | ||
|
|
2a2e705e9e | ||
|
|
31cd20f2b6 | ||
|
|
4fc2e757f6 | ||
|
|
240254b1a3 | ||
|
|
95f3c336d5 | ||
|
|
d63e3a781f | ||
|
|
0aab60943c | ||
|
|
935306af80 | ||
|
|
6fce2170c4 | ||
|
|
3f302b66ce | ||
|
|
32022267af | ||
|
|
f078f7127c | ||
|
|
c2cd4b7f48 | ||
|
|
0b5b8bebd1 | ||
|
|
9f36f18b39 | ||
|
|
fab0774c4b | ||
|
|
93c0b120de | ||
|
|
e20191e666 | ||
|
|
8d3b32644b | ||
|
|
6153d5ab83 | ||
|
|
f49904569d | ||
|
|
f48460da4f | ||
|
|
bd55d7f815 | ||
|
|
4402e7e232 | ||
|
|
b43ebcbdc4 | ||
|
|
55fd2f5562 | ||
|
|
8a734f9997 | ||
|
|
d60949ca87 | ||
|
|
aef8228b0e | ||
|
|
20e6652109 | ||
|
|
d2bc5a9473 | ||
|
|
23e75d87d3 | ||
|
|
8a13595c64 | ||
|
|
7845843596 | ||
|
|
f26a504045 | ||
|
|
f274193893 | ||
|
|
0ba400834c | ||
|
|
e6148cfdd4 | ||
|
|
99b1b95222 | ||
|
|
a9a5870d25 | ||
|
|
f09f2e8e63 | ||
|
|
2a1203bfef | ||
|
|
f6918d0242 | ||
|
|
e338f522dd | ||
|
|
ab10e187a6 | ||
|
|
12801275a8 | ||
|
|
e35e04de8e | ||
|
|
3ca48e1ecf | ||
|
|
f49bbf48e7 | ||
|
|
891ed84fe3 | ||
|
|
78a4a995e6 | ||
|
|
465534a298 | ||
|
|
d5f1bd07b2 | ||
|
|
50863117b8 | ||
|
|
c6693fc78b | ||
|
|
1e01711e3d | ||
|
|
1ab7f6f930 | ||
|
|
f6f7467cdd | ||
|
|
4d0a955d3c | ||
|
|
c45044f13c | ||
|
|
4761e55691 | ||
|
|
af7fb657f4 | ||
|
|
0805ab943e | ||
|
|
9589c0bcad | ||
|
|
91295ea6cd | ||
|
|
d0f4b5aa50 | ||
|
|
008e8d4fbf | ||
|
|
1e50fea55a | ||
|
|
008d38d6b4 | ||
|
|
c61c9e6471 | ||
|
|
e5b5b61d6e | ||
|
|
6a8cdf54b3 | ||
|
|
e43d98a6f5 | ||
|
|
11b774d39d | ||
|
|
77c4667dbc | ||
|
|
f05fdd5cfa | ||
|
|
a0bb70ed2d | ||
|
|
1d5c3f7fba | ||
|
|
8b83aa1470 | ||
|
|
3a92721af4 | ||
|
|
b3218ba4d4 | ||
|
|
975ee2b522 | ||
|
|
27a319e66d | ||
|
|
7be5bf6e4d | ||
|
|
c73d4042d1 | ||
|
|
8270ad1e64 | ||
|
|
26016fbf43 | ||
|
|
307e4ceaa2 | ||
|
|
03085e85f9 | ||
|
|
1f4e0dc10c | ||
|
|
f69c95306d | ||
|
|
634ede3e8b | ||
|
|
c2a2979189 | ||
|
|
9800469943 | ||
|
|
e47f1d5595 | ||
|
|
135fe04d02 | ||
|
|
794d7c0959 | ||
|
|
b8f365f2a1 | ||
|
|
6188b9eddb | ||
|
|
96c4dc3f1e | ||
|
|
b877215261 | ||
|
|
788b143596 | ||
|
|
6a261eb5a0 | ||
|
|
007fbc00cf | ||
|
|
9b8b4b3bfc | ||
|
|
6734f91a72 | ||
|
|
5266346315 | ||
|
|
d426e4452b | ||
|
|
f8af1bebd7 | ||
|
|
6e695a4d1a | ||
|
|
e5b7c94cb4 | ||
|
|
9028e664c4 | ||
|
|
6318affd31 | ||
|
|
8794cd3344 | ||
|
|
2fcd4e5271 | ||
|
|
ea60705ca7 | ||
|
|
90bce4e366 | ||
|
|
9f7cc355ad | ||
|
|
6ee4c0bac7 | ||
|
|
b0f0bd1848 | ||
|
|
fe563a8802 | ||
|
|
8ebab00767 | ||
|
|
d97297e45d | ||
|
|
f06500dcce | ||
|
|
b098e2b63f | ||
|
|
151a49b319 | ||
|
|
ded234794e | ||
|
|
119732c3ee | ||
|
|
730fcef844 | ||
|
|
1cb33f3a95 | ||
|
|
69edd3c53f | ||
|
|
ad784e2146 | ||
|
|
c783ae4b3d |
@@ -1,7 +1,6 @@
|
|||||||
/.project
|
/.project
|
||||||
/.loadpath
|
/.loadpath
|
||||||
/config/additional_environment.rb
|
/config/additional_environment.rb
|
||||||
/config/configuration.yml
|
|
||||||
/config/database.yml
|
/config/database.yml
|
||||||
/config/email.yml
|
/config/email.yml
|
||||||
/config/initializers/session_store.rb
|
/config/initializers/session_store.rb
|
||||||
@@ -10,8 +9,6 @@
|
|||||||
/db/*.sqlite3
|
/db/*.sqlite3
|
||||||
/db/schema.rb
|
/db/schema.rb
|
||||||
/files/*
|
/files/*
|
||||||
/lib/redmine/scm/adapters/mercurial/redminehelper.pyc
|
|
||||||
/lib/redmine/scm/adapters/mercurial/redminehelper.pyo
|
|
||||||
/log/*.log*
|
/log/*.log*
|
||||||
/log/mongrel_debug
|
/log/mongrel_debug
|
||||||
/public/dispatch.*
|
/public/dispatch.*
|
||||||
@@ -23,8 +20,3 @@
|
|||||||
/tmp/test/*
|
/tmp/test/*
|
||||||
/vendor/rails
|
/vendor/rails
|
||||||
*.rbc
|
*.rbc
|
||||||
|
|
||||||
/.bundle
|
|
||||||
/Gemfile.lock
|
|
||||||
/Gemfile.local
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ syntax: glob
|
|||||||
.project
|
.project
|
||||||
.loadpath
|
.loadpath
|
||||||
config/additional_environment.rb
|
config/additional_environment.rb
|
||||||
config/configuration.yml
|
|
||||||
config/database.yml
|
config/database.yml
|
||||||
config/email.yml
|
config/email.yml
|
||||||
config/initializers/session_store.rb
|
config/initializers/session_store.rb
|
||||||
@@ -12,8 +11,6 @@ db/*.db
|
|||||||
db/*.sqlite3
|
db/*.sqlite3
|
||||||
db/schema.rb
|
db/schema.rb
|
||||||
files/*
|
files/*
|
||||||
lib/redmine/scm/adapters/mercurial/redminehelper.pyc
|
|
||||||
lib/redmine/scm/adapters/mercurial/redminehelper.pyo
|
|
||||||
log/*.log*
|
log/*.log*
|
||||||
log/mongrel_debug
|
log/mongrel_debug
|
||||||
public/dispatch.*
|
public/dispatch.*
|
||||||
@@ -25,11 +22,3 @@ tmp/sockets/*
|
|||||||
tmp/test/*
|
tmp/test/*
|
||||||
vendor/rails
|
vendor/rails
|
||||||
*.rbc
|
*.rbc
|
||||||
|
|
||||||
.svn/
|
|
||||||
.git/
|
|
||||||
|
|
||||||
.bundle
|
|
||||||
Gemfile.lock
|
|
||||||
Gemfile.local
|
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
Redmine is a flexible project management web application written using Ruby on Rails framework.
|
Redmine is a flexible project management web application written using Ruby on Rails framework.
|
||||||
|
|
||||||
More details can be found in the doc directory or on the official website http://www.redmine.org
|
More details can be found at in the doc directory or on the official website http://www.redmine.org
|
||||||
|
|||||||
@@ -5,11 +5,6 @@ require(File.join(File.dirname(__FILE__), 'config', 'boot'))
|
|||||||
|
|
||||||
require 'rake'
|
require 'rake'
|
||||||
require 'rake/testtask'
|
require 'rake/testtask'
|
||||||
|
require 'rake/rdoctask'
|
||||||
begin
|
|
||||||
require 'rdoc/task'
|
|
||||||
rescue LoadError
|
|
||||||
# RDoc is not available
|
|
||||||
end
|
|
||||||
|
|
||||||
require 'tasks/rails'
|
require 'tasks/rails'
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2009 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -156,6 +156,7 @@ class AccountController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
def open_id_authenticate(openid_url)
|
def open_id_authenticate(openid_url)
|
||||||
authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => signin_url) do |result, identity_url, registration|
|
authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => signin_url) do |result, identity_url, registration|
|
||||||
if result.successful?
|
if result.successful?
|
||||||
@@ -202,25 +203,13 @@ class AccountController < ApplicationController
|
|||||||
self.logged_user = user
|
self.logged_user = user
|
||||||
# generate a key and set cookie if autologin
|
# generate a key and set cookie if autologin
|
||||||
if params[:autologin] && Setting.autologin?
|
if params[:autologin] && Setting.autologin?
|
||||||
set_autologin_cookie(user)
|
token = Token.create(:user => user, :action => 'autologin')
|
||||||
|
cookies[:autologin] = { :value => token.value, :expires => 1.year.from_now }
|
||||||
end
|
end
|
||||||
call_hook(:controller_account_success_authentication_after, {:user => user })
|
call_hook(:controller_account_success_authentication_after, {:user => user })
|
||||||
redirect_back_or_default :controller => 'my', :action => 'page'
|
redirect_back_or_default :controller => 'my', :action => 'page'
|
||||||
end
|
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,
|
|
||||||
:path => (Redmine::Configuration['autologin_cookie_path'] || '/'),
|
|
||||||
:secure => (Redmine::Configuration['autologin_cookie_secure'] ? true : false),
|
|
||||||
:httponly => true
|
|
||||||
}
|
|
||||||
cookies[cookie_name] = cookie_options
|
|
||||||
end
|
|
||||||
|
|
||||||
# Onthefly creation failed, display the registration form to fill/fix attributes
|
# Onthefly creation failed, display the registration form to fill/fix attributes
|
||||||
def onthefly_creation_failed(user, auth_source_options = { })
|
def onthefly_creation_failed(user, auth_source_options = { })
|
||||||
@user = user
|
@user = user
|
||||||
|
|||||||
@@ -1,24 +1,7 @@
|
|||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 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.
|
|
||||||
|
|
||||||
class ActivitiesController < ApplicationController
|
class ActivitiesController < ApplicationController
|
||||||
menu_item :activity
|
menu_item :activity
|
||||||
before_filter :find_optional_project
|
before_filter :find_optional_project
|
||||||
accept_rss_auth :index
|
accept_key_auth :index
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@days = Setting.activity_days_default.to_i
|
@days = Setting.activity_days_default.to_i
|
||||||
@@ -72,4 +55,5 @@ class ActivitiesController < ApplicationController
|
|||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
render_404
|
render_404
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -17,7 +17,9 @@
|
|||||||
|
|
||||||
class AdminController < ApplicationController
|
class AdminController < ApplicationController
|
||||||
layout 'admin'
|
layout 'admin'
|
||||||
|
|
||||||
before_filter :require_admin
|
before_filter :require_admin
|
||||||
|
|
||||||
helper :sort
|
helper :sort
|
||||||
include SortHelper
|
include SortHelper
|
||||||
|
|
||||||
@@ -28,10 +30,12 @@ class AdminController < ApplicationController
|
|||||||
def projects
|
def projects
|
||||||
@status = params[:status] ? params[:status].to_i : 1
|
@status = params[:status] ? params[:status].to_i : 1
|
||||||
c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status])
|
c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status])
|
||||||
|
|
||||||
unless params[:name].blank?
|
unless params[:name].blank?
|
||||||
name = "%#{params[:name].strip.downcase}%"
|
name = "%#{params[:name].strip.downcase}%"
|
||||||
c << ["LOWER(identifier) LIKE ? OR LOWER(name) LIKE ?", name, name]
|
c << ["LOWER(identifier) LIKE ? OR LOWER(name) LIKE ?", name, name]
|
||||||
end
|
end
|
||||||
|
|
||||||
@projects = Project.find :all, :order => 'lft',
|
@projects = Project.find :all, :order => 'lft',
|
||||||
:conditions => c.conditions
|
:conditions => c.conditions
|
||||||
|
|
||||||
@@ -73,10 +77,10 @@ class AdminController < ApplicationController
|
|||||||
def info
|
def info
|
||||||
@db_adapter_name = ActiveRecord::Base.connection.adapter_name
|
@db_adapter_name = ActiveRecord::Base.connection.adapter_name
|
||||||
@checklist = [
|
@checklist = [
|
||||||
[:text_default_administrator_account_changed, User.default_admin_account_changed?],
|
[:text_default_administrator_account_changed, User.find(:first, :conditions => ["login=? and hashed_password=?", 'admin', User.hash_password('admin')]).nil?],
|
||||||
[:text_file_repository_writable, File.writable?(Attachment.storage_path)],
|
[:text_file_repository_writable, File.writable?(Attachment.storage_path)],
|
||||||
[:text_plugin_assets_writable, File.writable?(Engines.public_directory)],
|
[:text_plugin_assets_writable, File.writable?(Engines.public_directory)],
|
||||||
[:text_rmagick_available, Object.const_defined?(:Magick)]
|
[:text_rmagick_available, Object.const_defined?(:Magick)]
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -18,19 +18,12 @@
|
|||||||
require 'uri'
|
require 'uri'
|
||||||
require 'cgi'
|
require 'cgi'
|
||||||
|
|
||||||
class Unauthorized < Exception; end
|
|
||||||
|
|
||||||
class ApplicationController < ActionController::Base
|
class ApplicationController < ActionController::Base
|
||||||
include Redmine::I18n
|
include Redmine::I18n
|
||||||
|
|
||||||
layout 'base'
|
layout 'base'
|
||||||
exempt_from_layout 'builder', 'rsb'
|
exempt_from_layout 'builder', 'rsb'
|
||||||
|
|
||||||
protect_from_forgery
|
|
||||||
def handle_unverified_request
|
|
||||||
super
|
|
||||||
cookies.delete(:autologin)
|
|
||||||
end
|
|
||||||
# Remove broken cookie after upgrade from 0.8.x (#4292)
|
# Remove broken cookie after upgrade from 0.8.x (#4292)
|
||||||
# See https://rails.lighthouseapp.com/projects/8994/tickets/3360
|
# See https://rails.lighthouseapp.com/projects/8994/tickets/3360
|
||||||
# TODO: remove it when Rails is fixed
|
# TODO: remove it when Rails is fixed
|
||||||
@@ -45,9 +38,9 @@ class ApplicationController < ActionController::Base
|
|||||||
|
|
||||||
before_filter :user_setup, :check_if_login_required, :set_localization
|
before_filter :user_setup, :check_if_login_required, :set_localization
|
||||||
filter_parameter_logging :password
|
filter_parameter_logging :password
|
||||||
|
protect_from_forgery
|
||||||
|
|
||||||
rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token
|
rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token
|
||||||
rescue_from ::Unauthorized, :with => :deny_access
|
|
||||||
|
|
||||||
include Redmine::Search::Controller
|
include Redmine::Search::Controller
|
||||||
include Redmine::MenuManager::MenuController
|
include Redmine::MenuManager::MenuController
|
||||||
@@ -75,11 +68,11 @@ class ApplicationController < ActionController::Base
|
|||||||
user = User.try_to_autologin(cookies[:autologin])
|
user = User.try_to_autologin(cookies[:autologin])
|
||||||
session[:user_id] = user.id if user
|
session[:user_id] = user.id if user
|
||||||
user
|
user
|
||||||
elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth?
|
elsif params[:format] == 'atom' && params[:key] && accept_key_auth_actions.include?(params[:action])
|
||||||
# RSS key authentication does not start a session
|
# RSS key authentication does not start a session
|
||||||
User.find_by_rss_key(params[:key])
|
User.find_by_rss_key(params[:key])
|
||||||
elsif Setting.rest_api_enabled? && accept_api_auth?
|
elsif Setting.rest_api_enabled? && api_request?
|
||||||
if (key = api_key_from_request)
|
if (key = api_key_from_request) && accept_key_auth_actions.include?(params[:action])
|
||||||
# Use API key
|
# Use API key
|
||||||
User.find_by_api_key(key)
|
User.find_by_api_key(key)
|
||||||
else
|
else
|
||||||
@@ -206,6 +199,8 @@ class ApplicationController < ActionController::Base
|
|||||||
render_404 unless @object.present?
|
render_404 unless @object.present?
|
||||||
|
|
||||||
@project = @object.project
|
@project = @object.project
|
||||||
|
rescue ActiveRecord::RecordNotFound
|
||||||
|
render_404
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_model_object
|
def find_model_object
|
||||||
@@ -226,10 +221,6 @@ class ApplicationController < ActionController::Base
|
|||||||
def find_issues
|
def find_issues
|
||||||
@issues = Issue.find_all_by_id(params[:id] || params[:ids])
|
@issues = Issue.find_all_by_id(params[:id] || params[:ids])
|
||||||
raise ActiveRecord::RecordNotFound if @issues.empty?
|
raise ActiveRecord::RecordNotFound if @issues.empty?
|
||||||
if @issues.detect {|issue| !issue.visible?}
|
|
||||||
deny_access
|
|
||||||
return
|
|
||||||
end
|
|
||||||
@projects = @issues.collect(&:project).compact.uniq
|
@projects = @issues.collect(&:project).compact.uniq
|
||||||
@project = @projects.first if @projects.size == 1
|
@project = @projects.first if @projects.size == 1
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
@@ -252,7 +243,7 @@ class ApplicationController < ActionController::Base
|
|||||||
if @project.is_public? || User.current.member_of?(@project) || User.current.admin?
|
if @project.is_public? || User.current.member_of?(@project) || User.current.admin?
|
||||||
true
|
true
|
||||||
else
|
else
|
||||||
deny_access
|
User.current.logged? ? render_403 : require_login
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@project = nil
|
@project = nil
|
||||||
@@ -313,19 +304,6 @@ class ApplicationController < ActionController::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Filter for actions that provide an API response
|
|
||||||
# but have no HTML representation for non admin users
|
|
||||||
def require_admin_or_api_request
|
|
||||||
return true if api_request?
|
|
||||||
if User.current.admin?
|
|
||||||
true
|
|
||||||
elsif User.current.logged?
|
|
||||||
render_error(:status => 406)
|
|
||||||
else
|
|
||||||
deny_access
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Picks which layout to use based on the request
|
# Picks which layout to use based on the request
|
||||||
#
|
#
|
||||||
# @return [boolean, string] name of the layout to use or false for no layout
|
# @return [boolean, string] name of the layout to use or false for no layout
|
||||||
@@ -345,44 +323,16 @@ class ApplicationController < ActionController::Base
|
|||||||
@items.sort! {|x,y| y.event_datetime <=> x.event_datetime }
|
@items.sort! {|x,y| y.event_datetime <=> x.event_datetime }
|
||||||
@items = @items.slice(0, Setting.feeds_limit.to_i)
|
@items = @items.slice(0, Setting.feeds_limit.to_i)
|
||||||
@title = options[:title] || Setting.app_title
|
@title = options[:title] || Setting.app_title
|
||||||
render :template => "common/feed.atom", :layout => false,
|
render :template => "common/feed.atom.rxml", :layout => false, :content_type => 'application/atom+xml'
|
||||||
:content_type => 'application/atom+xml'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: remove in Redmine 1.4
|
|
||||||
def self.accept_key_auth(*actions)
|
def self.accept_key_auth(*actions)
|
||||||
ActiveSupport::Deprecation.warn "ApplicationController.accept_key_auth is deprecated and will be removed in Redmine 1.4. Use accept_rss_auth (or accept_api_auth) instead."
|
actions = actions.flatten.map(&:to_s)
|
||||||
accept_rss_auth(*actions)
|
write_inheritable_attribute('accept_key_auth_actions', actions)
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: remove in Redmine 1.4
|
|
||||||
def accept_key_auth_actions
|
def accept_key_auth_actions
|
||||||
ActiveSupport::Deprecation.warn "ApplicationController.accept_key_auth_actions is deprecated and will be removed in Redmine 1.4. Use accept_rss_auth (or accept_api_auth) instead."
|
self.class.read_inheritable_attribute('accept_key_auth_actions') || []
|
||||||
self.class.accept_rss_auth
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.accept_rss_auth(*actions)
|
|
||||||
if actions.any?
|
|
||||||
write_inheritable_attribute('accept_rss_auth_actions', actions)
|
|
||||||
else
|
|
||||||
read_inheritable_attribute('accept_rss_auth_actions') || []
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def accept_rss_auth?(action=action_name)
|
|
||||||
self.class.accept_rss_auth.include?(action.to_sym)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.accept_api_auth(*actions)
|
|
||||||
if actions.any?
|
|
||||||
write_inheritable_attribute('accept_api_auth_actions', actions)
|
|
||||||
else
|
|
||||||
read_inheritable_attribute('accept_api_auth_actions') || []
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def accept_api_auth?(action=action_name)
|
|
||||||
self.class.accept_api_auth.include?(action.to_sym)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the number of objects that should be displayed
|
# Returns the number of objects that should be displayed
|
||||||
@@ -491,6 +441,13 @@ class ApplicationController < ActionController::Base
|
|||||||
render_error "An error occurred while executing the query and has been logged. Please report this error to your Redmine administrator."
|
render_error "An error occurred while executing the query and has been logged. Please report this error to your Redmine administrator."
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Converts the errors on an ActiveRecord object into a common JSON format
|
||||||
|
def object_errors_to_json(object)
|
||||||
|
object.errors.collect do |attribute, error|
|
||||||
|
{ attribute => error }
|
||||||
|
end.to_json
|
||||||
|
end
|
||||||
|
|
||||||
# Renders API response on validation failure
|
# Renders API response on validation failure
|
||||||
def render_validation_errors(object)
|
def render_validation_errors(object)
|
||||||
options = { :status => :unprocessable_entity, :layout => false }
|
options = { :status => :unprocessable_entity, :layout => false }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2008 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -20,29 +20,17 @@ class AttachmentsController < ApplicationController
|
|||||||
before_filter :file_readable, :read_authorize, :except => :destroy
|
before_filter :file_readable, :read_authorize, :except => :destroy
|
||||||
before_filter :delete_authorize, :only => :destroy
|
before_filter :delete_authorize, :only => :destroy
|
||||||
|
|
||||||
accept_api_auth :show, :download
|
verify :method => :post, :only => :destroy
|
||||||
|
|
||||||
def show
|
def show
|
||||||
respond_to do |format|
|
if @attachment.is_diff?
|
||||||
format.html {
|
@diff = File.new(@attachment.diskfile, "rb").read
|
||||||
if @attachment.is_diff?
|
render :action => 'diff'
|
||||||
@diff = File.new(@attachment.diskfile, "rb").read
|
elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte
|
||||||
@diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
|
@content = File.new(@attachment.diskfile, "rb").read
|
||||||
@diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
|
render :action => 'file'
|
||||||
# Save diff type as user preference
|
else
|
||||||
if User.current.logged? && @diff_type != User.current.pref[:diff_type]
|
download
|
||||||
User.current.pref[:diff_type] = @diff_type
|
|
||||||
User.current.preference.save
|
|
||||||
end
|
|
||||||
render :action => 'diff'
|
|
||||||
elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte
|
|
||||||
@content = File.new(@attachment.diskfile, "rb").read
|
|
||||||
render :action => 'file'
|
|
||||||
else
|
|
||||||
download
|
|
||||||
end
|
|
||||||
}
|
|
||||||
format.api
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -58,7 +46,6 @@ class AttachmentsController < ApplicationController
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
verify :method => :delete, :only => :destroy
|
|
||||||
def destroy
|
def destroy
|
||||||
# Make sure association callbacks are called
|
# Make sure association callbacks are called
|
||||||
@attachment.container.attachments.delete(@attachment)
|
@attachment.container.attachments.delete(@attachment)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -18,7 +18,7 @@
|
|||||||
class BoardsController < ApplicationController
|
class BoardsController < ApplicationController
|
||||||
default_search_scope :messages
|
default_search_scope :messages
|
||||||
before_filter :find_project, :find_board_if_available, :authorize
|
before_filter :find_project, :find_board_if_available, :authorize
|
||||||
accept_rss_auth :index, :show
|
accept_key_auth :index, :show
|
||||||
|
|
||||||
helper :messages
|
helper :messages
|
||||||
include MessagesHelper
|
include MessagesHelper
|
||||||
@@ -65,8 +65,7 @@ class BoardsController < ApplicationController
|
|||||||
verify :method => :post, :only => [ :destroy ], :redirect_to => { :action => :index }
|
verify :method => :post, :only => [ :destroy ], :redirect_to => { :action => :index }
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@board = Board.new
|
@board = Board.new(params[:board])
|
||||||
@board.safe_attributes = params[:board]
|
|
||||||
@board.project = @project
|
@board.project = @project
|
||||||
if request.post? && @board.save
|
if request.post? && @board.save
|
||||||
flash[:notice] = l(:notice_successful_create)
|
flash[:notice] = l(:notice_successful_create)
|
||||||
@@ -75,8 +74,7 @@ class BoardsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
@board.safe_attributes = params[:board]
|
if request.post? && @board.update_attributes(params[:board])
|
||||||
if request.post? && @board.save
|
|
||||||
redirect_to_settings_in_projects
|
redirect_to_settings_in_projects
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,20 +1,3 @@
|
|||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 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.
|
|
||||||
|
|
||||||
class CalendarsController < ApplicationController
|
class CalendarsController < ApplicationController
|
||||||
menu_item :calendar
|
menu_item :calendar
|
||||||
before_filter :find_optional_project
|
before_filter :find_optional_project
|
||||||
@@ -53,4 +36,9 @@ class CalendarsController < ApplicationController
|
|||||||
|
|
||||||
render :action => 'show', :layout => false if request.xhr?
|
render :action => 'show', :layout => false if request.xhr?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
show
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ class CommentsController < ApplicationController
|
|||||||
|
|
||||||
verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
|
verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
|
||||||
def create
|
def create
|
||||||
@comment = Comment.new
|
@comment = Comment.new(params[:comment])
|
||||||
@comment.safe_attributes = params[:comment]
|
|
||||||
@comment.author = User.current
|
@comment.author = User.current
|
||||||
if @news.comments << @comment
|
if @news.comments << @comment
|
||||||
flash[:notice] = l(:label_comment_added)
|
flash[:notice] = l(:label_comment_added)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
class ContextMenusController < ApplicationController
|
class ContextMenusController < ApplicationController
|
||||||
helper :watchers
|
helper :watchers
|
||||||
helper :issues
|
|
||||||
|
|
||||||
def issues
|
def issues
|
||||||
@issues = Issue.visible.all(:conditions => {:id => params[:ids]}, :include => :project)
|
@issues = Issue.visible.all(:conditions => {:id => params[:ids]}, :include => :project)
|
||||||
@@ -26,11 +25,8 @@ class ContextMenusController < ApplicationController
|
|||||||
:delete => User.current.allowed_to?(:delete_issues, @projects)
|
:delete => User.current.allowed_to?(:delete_issues, @projects)
|
||||||
}
|
}
|
||||||
if @project
|
if @project
|
||||||
if @issue
|
@assignables = @project.assignable_users
|
||||||
@assignables = @issue.assignable_users
|
@assignables << @issue.assigned_to if @issue && @issue.assigned_to && !@assignables.include?(@issue.assigned_to)
|
||||||
else
|
|
||||||
@assignables = @project.assignable_users
|
|
||||||
end
|
|
||||||
@trackers = @project.trackers
|
@trackers = @project.trackers
|
||||||
else
|
else
|
||||||
#when multiple projects, we only keep the intersection of each set
|
#when multiple projects, we only keep the intersection of each set
|
||||||
@@ -38,23 +34,11 @@ class ContextMenusController < ApplicationController
|
|||||||
@trackers = @projects.map(&:trackers).inject{|memo,t| memo & t}
|
@trackers = @projects.map(&:trackers).inject{|memo,t| memo & t}
|
||||||
end
|
end
|
||||||
|
|
||||||
@priorities = IssuePriority.active.reverse
|
@priorities = IssuePriority.all.reverse
|
||||||
@statuses = IssueStatus.find(:all, :order => 'position')
|
@statuses = IssueStatus.find(:all, :order => 'position')
|
||||||
@back = back_url
|
@back = back_url
|
||||||
|
|
||||||
render :layout => false
|
render :layout => false
|
||||||
end
|
end
|
||||||
|
|
||||||
def time_entries
|
|
||||||
@time_entries = TimeEntry.all(
|
|
||||||
:conditions => {:id => params[:ids]}, :include => :project)
|
|
||||||
@projects = @time_entries.collect(&:project).compact.uniq
|
|
||||||
@project = @projects.first if @projects.size == 1
|
|
||||||
@activities = TimeEntryActivity.shared.active
|
|
||||||
@can = {:edit => User.current.allowed_to?(:edit_time_entries, @projects),
|
|
||||||
:delete => User.current.allowed_to?(:edit_time_entries, @projects)
|
|
||||||
}
|
|
||||||
@back = back_url
|
|
||||||
render :layout => false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2009 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -47,8 +47,7 @@ class DocumentsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@document = @project.documents.build
|
@document = @project.documents.build(params[:document])
|
||||||
@document.safe_attributes = params[:document]
|
|
||||||
if request.post? and @document.save
|
if request.post? and @document.save
|
||||||
attachments = Attachment.attach_files(@document, params[:attachments])
|
attachments = Attachment.attach_files(@document, params[:attachments])
|
||||||
render_attachment_warning_if_needed(@document)
|
render_attachment_warning_if_needed(@document)
|
||||||
@@ -58,9 +57,8 @@ class DocumentsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
@categories = DocumentCategory.active #TODO: use it in the views
|
@categories = DocumentCategory.all
|
||||||
@document.safe_attributes = params[:document]
|
if request.post? and @document.update_attributes(params[:document])
|
||||||
if request.post? and @document.save
|
|
||||||
flash[:notice] = l(:notice_successful_update)
|
flash[:notice] = l(:notice_successful_update)
|
||||||
redirect_to :action => 'show', :id => @document
|
redirect_to :action => 'show', :id => @document
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -24,10 +24,16 @@ class EnumerationsController < ApplicationController
|
|||||||
include CustomFieldsHelper
|
include CustomFieldsHelper
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
list
|
||||||
|
render :action => 'list'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
|
||||||
verify :method => :post, :only => [ :destroy, :create, :update ],
|
verify :method => :post, :only => [ :destroy, :create, :update ],
|
||||||
:redirect_to => { :action => :index }
|
:redirect_to => { :action => :list }
|
||||||
|
|
||||||
|
def list
|
||||||
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
begin
|
begin
|
||||||
@@ -42,7 +48,7 @@ class EnumerationsController < ApplicationController
|
|||||||
@enumeration.type = params[:enumeration][:type]
|
@enumeration.type = params[:enumeration][:type]
|
||||||
if @enumeration.save
|
if @enumeration.save
|
||||||
flash[:notice] = l(:notice_successful_create)
|
flash[:notice] = l(:notice_successful_create)
|
||||||
redirect_to :action => 'index', :type => @enumeration.type
|
redirect_to :action => 'list', :type => @enumeration.type
|
||||||
else
|
else
|
||||||
render :action => 'new'
|
render :action => 'new'
|
||||||
end
|
end
|
||||||
@@ -57,7 +63,7 @@ class EnumerationsController < ApplicationController
|
|||||||
@enumeration.type = params[:enumeration][:type] if params[:enumeration][:type]
|
@enumeration.type = params[:enumeration][:type] if params[:enumeration][:type]
|
||||||
if @enumeration.update_attributes(params[:enumeration])
|
if @enumeration.update_attributes(params[:enumeration])
|
||||||
flash[:notice] = l(:notice_successful_update)
|
flash[:notice] = l(:notice_successful_update)
|
||||||
redirect_to :action => 'index', :type => @enumeration.type
|
redirect_to :action => 'list', :type => @enumeration.type
|
||||||
else
|
else
|
||||||
render :action => 'edit'
|
render :action => 'edit'
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,20 +1,3 @@
|
|||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 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.
|
|
||||||
|
|
||||||
class GanttsController < ApplicationController
|
class GanttsController < ApplicationController
|
||||||
menu_item :gantt
|
menu_item :gantt
|
||||||
before_filter :find_optional_project
|
before_filter :find_optional_project
|
||||||
@@ -45,4 +28,9 @@ class GanttsController < ApplicationController
|
|||||||
format.pdf { send_data(@gantt.to_pdf, :type => 'application/pdf', :filename => "#{basename}.pdf") }
|
format.pdf { send_data(@gantt.to_pdf, :type => 'application/pdf', :filename => "#{basename}.pdf") }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
show
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2009 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -67,10 +67,8 @@ class GroupsController < ApplicationController
|
|||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if @group.save
|
if @group.save
|
||||||
format.html {
|
flash[:notice] = l(:notice_successful_create)
|
||||||
flash[:notice] = l(:notice_successful_create)
|
format.html { redirect_to(groups_path) }
|
||||||
redirect_to(params[:continue] ? new_group_path : groups_path)
|
|
||||||
}
|
|
||||||
format.xml { render :xml => @group, :status => :created, :location => @group }
|
format.xml { render :xml => @group, :status => :created, :location => @group }
|
||||||
else
|
else
|
||||||
format.html { render :action => "new" }
|
format.html { render :action => "new" }
|
||||||
@@ -125,7 +123,7 @@ class GroupsController < ApplicationController
|
|||||||
|
|
||||||
def remove_user
|
def remove_user
|
||||||
@group = Group.find(params[:id])
|
@group = Group.find(params[:id])
|
||||||
@group.users.delete(User.find(params[:user_id])) if request.delete?
|
@group.users.delete(User.find(params[:user_id])) if request.post?
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'users' }
|
format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'users' }
|
||||||
format.js { render(:update) {|page| page.replace_html "tab-content-users", :partial => 'groups/users'} }
|
format.js { render(:update) {|page| page.replace_html "tab-content-users", :partial => 'groups/users'} }
|
||||||
@@ -134,7 +132,7 @@ class GroupsController < ApplicationController
|
|||||||
|
|
||||||
def autocomplete_for_user
|
def autocomplete_for_user
|
||||||
@group = Group.find(params[:id])
|
@group = Group.find(params[:id])
|
||||||
@users = User.active.not_in_group(@group).like(params[:q]).all(:limit => 100)
|
@users = User.active.like(params[:q]).find(:all, :limit => 100) - @group.users
|
||||||
render :layout => false
|
render :layout => false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -18,95 +18,58 @@
|
|||||||
class IssueCategoriesController < ApplicationController
|
class IssueCategoriesController < ApplicationController
|
||||||
menu_item :settings
|
menu_item :settings
|
||||||
model_object IssueCategory
|
model_object IssueCategory
|
||||||
before_filter :find_model_object, :except => [:index, :new, :create]
|
before_filter :find_model_object, :except => :new
|
||||||
before_filter :find_project_from_association, :except => [:index, :new, :create]
|
before_filter :find_project_from_association, :except => :new
|
||||||
before_filter :find_project, :only => [:index, :new, :create]
|
before_filter :find_project, :only => :new
|
||||||
before_filter :authorize
|
before_filter :authorize
|
||||||
accept_api_auth :index, :show, :create, :update, :destroy
|
|
||||||
|
|
||||||
def index
|
verify :method => :post, :only => :destroy
|
||||||
respond_to do |format|
|
|
||||||
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 :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project }
|
|
||||||
format.api
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@category = @project.issue_categories.build
|
@category = @project.issue_categories.build(params[:category])
|
||||||
@category.safe_attributes = params[:issue_category]
|
if request.post?
|
||||||
end
|
if @category.save
|
||||||
|
respond_to do |format|
|
||||||
verify :method => :post, :only => :create
|
format.html do
|
||||||
def create
|
flash[:notice] = l(:notice_successful_create)
|
||||||
@category = @project.issue_categories.build
|
redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
|
||||||
@category.safe_attributes = params[:issue_category]
|
end
|
||||||
if @category.save
|
format.js do
|
||||||
respond_to do |format|
|
# IE doesn't support the replace_html rjs method for select box options
|
||||||
format.html do
|
render(:update) {|page| page.replace "issue_category_id",
|
||||||
flash[:notice] = l(:notice_successful_create)
|
content_tag('select', '<option></option>' + options_from_collection_for_select(@project.issue_categories, 'id', 'name', @category.id), :id => 'issue_category_id', :name => 'issue[category_id]')
|
||||||
redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
format.js do
|
else
|
||||||
# IE doesn't support the replace_html rjs method for select box options
|
respond_to do |format|
|
||||||
render(:update) {|page| page.replace "issue_category_id",
|
format.html
|
||||||
content_tag('select', '<option></option>' + options_from_collection_for_select(@project.issue_categories, 'id', 'name', @category.id), :id => 'issue_category_id', :name => 'issue[category_id]')
|
format.js do
|
||||||
}
|
render(:update) {|page| page.alert(@category.errors.full_messages.join('\n')) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
format.api { render :action => 'show', :status => :created, :location => issue_category_path(@category) }
|
|
||||||
end
|
|
||||||
else
|
|
||||||
respond_to do |format|
|
|
||||||
format.html { render :action => 'new'}
|
|
||||||
format.js do
|
|
||||||
render(:update) {|page| page.alert(@category.errors.full_messages.join('\n')) }
|
|
||||||
end
|
|
||||||
format.api { render_validation_errors(@category) }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
end
|
if request.post? and @category.update_attributes(params[:category])
|
||||||
|
flash[:notice] = l(:notice_successful_update)
|
||||||
verify :method => :put, :only => :update
|
redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
|
||||||
def update
|
|
||||||
@category.safe_attributes = params[:issue_category]
|
|
||||||
if @category.save
|
|
||||||
respond_to do |format|
|
|
||||||
format.html {
|
|
||||||
flash[:notice] = l(:notice_successful_update)
|
|
||||||
redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
|
|
||||||
}
|
|
||||||
format.api { head :ok }
|
|
||||||
end
|
|
||||||
else
|
|
||||||
respond_to do |format|
|
|
||||||
format.html { render :action => 'edit' }
|
|
||||||
format.api { render_validation_errors(@category) }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
verify :method => :delete, :only => :destroy
|
|
||||||
def destroy
|
def destroy
|
||||||
@issue_count = @category.issues.size
|
@issue_count = @category.issues.size
|
||||||
if @issue_count == 0 || params[:todo] || api_request?
|
if @issue_count == 0
|
||||||
reassign_to = nil
|
# No issue assigned to this category
|
||||||
if params[:reassign_to_id] && (params[:todo] == 'reassign' || params[:todo].blank?)
|
@category.destroy
|
||||||
reassign_to = @project.issue_categories.find_by_id(params[:reassign_to_id])
|
redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories'
|
||||||
end
|
return
|
||||||
|
elsif params[:todo]
|
||||||
|
reassign_to = @project.issue_categories.find_by_id(params[:reassign_to_id]) if params[:todo] == 'reassign'
|
||||||
@category.destroy(reassign_to)
|
@category.destroy(reassign_to)
|
||||||
respond_to do |format|
|
redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories'
|
||||||
format.html { redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories' }
|
|
||||||
format.api { head :ok }
|
|
||||||
end
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@categories = @project.issue_categories - [@category]
|
@categories = @project.issue_categories - [@category]
|
||||||
|
|||||||
@@ -1,23 +1,4 @@
|
|||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 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.
|
|
||||||
|
|
||||||
class IssueMovesController < ApplicationController
|
class IssueMovesController < ApplicationController
|
||||||
menu_item :issues
|
|
||||||
|
|
||||||
default_search_scope :issues
|
default_search_scope :issues
|
||||||
before_filter :find_issues, :check_project_uniqueness
|
before_filter :find_issues, :check_project_uniqueness
|
||||||
before_filter :authorize
|
before_filter :authorize
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -16,38 +16,15 @@
|
|||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
class IssueRelationsController < ApplicationController
|
class IssueRelationsController < ApplicationController
|
||||||
before_filter :find_issue, :find_project_from_association, :authorize, :only => [:index, :create]
|
before_filter :find_issue, :find_project_from_association, :authorize
|
||||||
before_filter :find_relation, :except => [:index, :create]
|
|
||||||
|
|
||||||
accept_api_auth :index, :show, :create, :destroy
|
def new
|
||||||
|
|
||||||
def index
|
|
||||||
@relations = @issue.relations
|
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
format.html { render :nothing => true }
|
|
||||||
format.api
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def show
|
|
||||||
raise Unauthorized unless @relation.visible?
|
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
format.html { render :nothing => true }
|
|
||||||
format.api
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
|
|
||||||
def create
|
|
||||||
@relation = IssueRelation.new(params[:relation])
|
@relation = IssueRelation.new(params[:relation])
|
||||||
@relation.issue_from = @issue
|
@relation.issue_from = @issue
|
||||||
if params[:relation] && m = params[:relation][:issue_to_id].to_s.match(/^#?(\d+)$/)
|
if params[:relation] && m = params[:relation][:issue_to_id].to_s.match(/^#?(\d+)$/)
|
||||||
@relation.issue_to = Issue.visible.find_by_id(m[1].to_i)
|
@relation.issue_to = Issue.visible.find_by_id(m[1].to_i)
|
||||||
end
|
end
|
||||||
saved = @relation.save
|
@relation.save if request.post?
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue }
|
format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue }
|
||||||
format.js do
|
format.js do
|
||||||
@@ -60,25 +37,21 @@ class IssueRelationsController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
format.api {
|
|
||||||
if saved
|
|
||||||
render :action => 'show', :status => :created, :location => relation_url(@relation)
|
|
||||||
else
|
|
||||||
render_validation_errors(@relation)
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed }
|
|
||||||
def destroy
|
def destroy
|
||||||
raise Unauthorized unless @relation.deletable?
|
relation = IssueRelation.find(params[:id])
|
||||||
@relation.destroy
|
if request.post? && @issue.relations.include?(relation)
|
||||||
|
relation.destroy
|
||||||
|
@issue.reload
|
||||||
|
end
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue }
|
format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue }
|
||||||
format.js { render(:update) {|page| page.remove "relation-#{@relation.id}"} }
|
format.js {
|
||||||
format.api { head :ok }
|
@relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
|
||||||
|
render(:update) {|page| page.replace_html "relations", :partial => 'issues/relations'}
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -88,10 +61,4 @@ private
|
|||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
render_404
|
render_404
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_relation
|
|
||||||
@relation = IssueRelation.find(params[:id])
|
|
||||||
rescue ActiveRecord::RecordNotFound
|
|
||||||
render_404
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -18,20 +18,14 @@
|
|||||||
class IssueStatusesController < ApplicationController
|
class IssueStatusesController < ApplicationController
|
||||||
layout 'admin'
|
layout 'admin'
|
||||||
|
|
||||||
before_filter :require_admin, :except => :index
|
before_filter :require_admin
|
||||||
before_filter :require_admin_or_api_request, :only => :index
|
|
||||||
accept_api_auth :index
|
verify :method => :post, :only => [ :destroy, :create, :update, :move, :update_issue_done_ratio ],
|
||||||
|
:redirect_to => { :action => :index }
|
||||||
|
|
||||||
def index
|
def index
|
||||||
respond_to do |format|
|
@issue_status_pages, @issue_statuses = paginate :issue_statuses, :per_page => 25, :order => "position"
|
||||||
format.html {
|
render :action => "index", :layout => false if request.xhr?
|
||||||
@issue_status_pages, @issue_statuses = paginate :issue_statuses, :per_page => 25, :order => "position"
|
|
||||||
render :action => "index", :layout => false if request.xhr?
|
|
||||||
}
|
|
||||||
format.api {
|
|
||||||
@issue_statuses = IssueStatus.all(:order => 'position')
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@@ -40,7 +34,7 @@ class IssueStatusesController < ApplicationController
|
|||||||
|
|
||||||
def create
|
def create
|
||||||
@issue_status = IssueStatus.new(params[:issue_status])
|
@issue_status = IssueStatus.new(params[:issue_status])
|
||||||
if request.post? && @issue_status.save
|
if @issue_status.save
|
||||||
flash[:notice] = l(:notice_successful_create)
|
flash[:notice] = l(:notice_successful_create)
|
||||||
redirect_to :action => 'index'
|
redirect_to :action => 'index'
|
||||||
else
|
else
|
||||||
@@ -54,7 +48,7 @@ class IssueStatusesController < ApplicationController
|
|||||||
|
|
||||||
def update
|
def update
|
||||||
@issue_status = IssueStatus.find(params[:id])
|
@issue_status = IssueStatus.find(params[:id])
|
||||||
if request.put? && @issue_status.update_attributes(params[:issue_status])
|
if @issue_status.update_attributes(params[:issue_status])
|
||||||
flash[:notice] = l(:notice_successful_update)
|
flash[:notice] = l(:notice_successful_update)
|
||||||
redirect_to :action => 'index'
|
redirect_to :action => 'index'
|
||||||
else
|
else
|
||||||
@@ -62,7 +56,6 @@ class IssueStatusesController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
verify :method => :delete, :only => :destroy, :redirect_to => { :action => :index }
|
|
||||||
def destroy
|
def destroy
|
||||||
IssueStatus.find(params[:id]).destroy
|
IssueStatus.find(params[:id]).destroy
|
||||||
redirect_to :action => 'index'
|
redirect_to :action => 'index'
|
||||||
@@ -72,7 +65,7 @@ class IssueStatusesController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def update_issue_done_ratio
|
def update_issue_done_ratio
|
||||||
if request.post? && IssueStatus.update_issue_done_ratios
|
if IssueStatus.update_issue_done_ratios
|
||||||
flash[:notice] = l(:notice_issue_done_ratios_updated)
|
flash[:notice] = l(:notice_issue_done_ratios_updated)
|
||||||
else
|
else
|
||||||
flash[:error] = l(:error_issue_done_ratios_not_updated)
|
flash[:error] = l(:error_issue_done_ratios_not_updated)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2008 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -27,8 +27,7 @@ class IssuesController < ApplicationController
|
|||||||
before_filter :find_optional_project, :only => [:index]
|
before_filter :find_optional_project, :only => [:index]
|
||||||
before_filter :check_for_default_issue_status, :only => [:new, :create]
|
before_filter :check_for_default_issue_status, :only => [:new, :create]
|
||||||
before_filter :build_new_issue_from_params, :only => [:new, :create]
|
before_filter :build_new_issue_from_params, :only => [:new, :create]
|
||||||
accept_rss_auth :index, :show
|
accept_key_auth :index, :show, :create, :update, :destroy
|
||||||
accept_api_auth :index, :show, :create, :update, :destroy
|
|
||||||
|
|
||||||
rescue_from Query::StatementInvalid, :with => :query_statement_invalid
|
rescue_from Query::StatementInvalid, :with => :query_statement_invalid
|
||||||
|
|
||||||
@@ -89,20 +88,15 @@ class IssuesController < ApplicationController
|
|||||||
@issue_count_by_group = @query.issue_count_by_group
|
@issue_count_by_group = @query.issue_count_by_group
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { render :template => 'issues/index', :layout => !request.xhr? }
|
format.html { render :template => 'issues/index.rhtml', :layout => !request.xhr? }
|
||||||
format.api {
|
format.api
|
||||||
Issue.load_relations(@issues) if include_in_api_response?('relations')
|
|
||||||
}
|
|
||||||
format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
|
format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
|
||||||
format.csv { send_data(issues_to_csv(@issues, @project, @query, params), :type => 'text/csv; header=present', :filename => 'export.csv') }
|
format.csv { send_data(issues_to_csv(@issues, @project), :type => 'text/csv; header=present', :filename => 'export.csv') }
|
||||||
format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }
|
format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
respond_to do |format|
|
# Send html if the query is not valid
|
||||||
format.html { render(:template => 'issues/index', :layout => !request.xhr?) }
|
render(:template => 'issues/index.rhtml', :layout => !request.xhr?)
|
||||||
format.any(:atom, :csv, :pdf) { render(:nothing => true) }
|
|
||||||
format.api { render_validation_errors(@query) }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
render_404
|
render_404
|
||||||
@@ -112,19 +106,15 @@ class IssuesController < ApplicationController
|
|||||||
@journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
|
@journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
|
||||||
@journals.each_with_index {|j,i| j.indice = i+1}
|
@journals.each_with_index {|j,i| j.indice = i+1}
|
||||||
@journals.reverse! if User.current.wants_comments_in_reverse_order?
|
@journals.reverse! if User.current.wants_comments_in_reverse_order?
|
||||||
|
@changesets = @issue.changesets.visible.all
|
||||||
if User.current.allowed_to?(:view_changesets, @project)
|
@changesets.reverse! if User.current.wants_comments_in_reverse_order?
|
||||||
@changesets = @issue.changesets.visible.all
|
|
||||||
@changesets.reverse! if User.current.wants_comments_in_reverse_order?
|
|
||||||
end
|
|
||||||
|
|
||||||
@relations = @issue.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? }
|
||||||
@allowed_statuses = @issue.new_statuses_allowed_to(User.current)
|
@allowed_statuses = @issue.new_statuses_allowed_to(User.current)
|
||||||
@edit_allowed = User.current.allowed_to?(:edit_issues, @project)
|
@edit_allowed = User.current.allowed_to?(:edit_issues, @project)
|
||||||
@priorities = IssuePriority.active
|
@priorities = IssuePriority.all
|
||||||
@time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
|
@time_entry = TimeEntry.new
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { render :template => 'issues/show' }
|
format.html { render :template => 'issues/show.rhtml' }
|
||||||
format.api
|
format.api
|
||||||
format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' }
|
format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' }
|
||||||
format.pdf { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") }
|
format.pdf { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") }
|
||||||
@@ -144,11 +134,11 @@ class IssuesController < ApplicationController
|
|||||||
call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
|
call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
|
||||||
if @issue.save
|
if @issue.save
|
||||||
attachments = Attachment.attach_files(@issue, params[:attachments])
|
attachments = Attachment.attach_files(@issue, params[:attachments])
|
||||||
|
render_attachment_warning_if_needed(@issue)
|
||||||
|
flash[:notice] = l(:notice_successful_create)
|
||||||
call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue})
|
call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue})
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html {
|
format.html {
|
||||||
render_attachment_warning_if_needed(@issue)
|
|
||||||
flash[:notice] = l(:notice_issue_successful_create, :id => "<a href='#{issue_path(@issue)}'>##{@issue.id}</a>")
|
|
||||||
redirect_to(params[:continue] ? { :action => 'new', :project_id => @project, :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } :
|
redirect_to(params[:continue] ? { :action => 'new', :project_id => @project, :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } :
|
||||||
{ :action => 'show', :id => @issue })
|
{ :action => 'show', :id => @issue })
|
||||||
}
|
}
|
||||||
@@ -261,13 +251,7 @@ class IssuesController < ApplicationController
|
|||||||
|
|
||||||
private
|
private
|
||||||
def find_issue
|
def find_issue
|
||||||
# Issue.visible.find(...) can not be used to redirect user to the login form
|
|
||||||
# if the issue actually exists but requires authentication
|
|
||||||
@issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category])
|
@issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category])
|
||||||
unless @issue.visible?
|
|
||||||
deny_access
|
|
||||||
return
|
|
||||||
end
|
|
||||||
@project = @issue.project
|
@project = @issue.project
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
render_404
|
render_404
|
||||||
@@ -285,9 +269,9 @@ private
|
|||||||
# TODO: Refactor, not everything in here is needed by #edit
|
# TODO: Refactor, not everything in here is needed by #edit
|
||||||
def update_issue_from_params
|
def update_issue_from_params
|
||||||
@allowed_statuses = @issue.new_statuses_allowed_to(User.current)
|
@allowed_statuses = @issue.new_statuses_allowed_to(User.current)
|
||||||
@priorities = IssuePriority.active
|
@priorities = IssuePriority.all
|
||||||
@edit_allowed = User.current.allowed_to?(:edit_issues, @project)
|
@edit_allowed = User.current.allowed_to?(:edit_issues, @project)
|
||||||
@time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
|
@time_entry = TimeEntry.new
|
||||||
@time_entry.attributes = params[:time_entry]
|
@time_entry.attributes = params[:time_entry]
|
||||||
|
|
||||||
@notes = params[:notes] || (params[:issue].present? ? params[:issue][:notes] : nil)
|
@notes = params[:notes] || (params[:issue].present? ? params[:issue][:notes] : nil)
|
||||||
@@ -307,21 +291,21 @@ private
|
|||||||
end
|
end
|
||||||
|
|
||||||
@issue.project = @project
|
@issue.project = @project
|
||||||
@issue.author = User.current
|
|
||||||
# Tracker must be set before custom field values
|
# Tracker must be set before custom field values
|
||||||
@issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
|
@issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
|
||||||
if @issue.tracker.nil?
|
if @issue.tracker.nil?
|
||||||
render_error l(:error_no_tracker_in_project)
|
render_error l(:error_no_tracker_in_project)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@issue.start_date ||= Date.today if Setting.default_issue_start_date_to_creation_date?
|
@issue.start_date ||= Date.today
|
||||||
if params[:issue].is_a?(Hash)
|
if params[:issue].is_a?(Hash)
|
||||||
@issue.safe_attributes = params[:issue]
|
@issue.safe_attributes = params[:issue]
|
||||||
if User.current.allowed_to?(:add_issue_watchers, @project) && @issue.new_record?
|
if User.current.allowed_to?(:add_issue_watchers, @project) && @issue.new_record?
|
||||||
@issue.watcher_user_ids = params[:issue]['watcher_user_ids']
|
@issue.watcher_user_ids = params[:issue]['watcher_user_ids']
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@priorities = IssuePriority.active
|
@issue.author = User.current
|
||||||
|
@priorities = IssuePriority.all
|
||||||
@allowed_statuses = @issue.new_statuses_allowed_to(User.current, true)
|
@allowed_statuses = @issue.new_statuses_allowed_to(User.current, true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2008 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -16,12 +16,11 @@
|
|||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
class JournalsController < ApplicationController
|
class JournalsController < ApplicationController
|
||||||
before_filter :find_journal, :only => [:edit, :diff]
|
before_filter :find_journal, :only => [:edit]
|
||||||
before_filter :find_issue, :only => [:new]
|
before_filter :find_issue, :only => [:new]
|
||||||
before_filter :find_optional_project, :only => [:index]
|
before_filter :find_optional_project, :only => [:index]
|
||||||
before_filter :authorize, :only => [:new, :edit, :diff]
|
before_filter :authorize, :only => [:new, :edit]
|
||||||
accept_rss_auth :index
|
accept_key_auth :index
|
||||||
menu_item :issues
|
|
||||||
|
|
||||||
helper :issues
|
helper :issues
|
||||||
helper :custom_fields
|
helper :custom_fields
|
||||||
@@ -45,17 +44,6 @@ class JournalsController < ApplicationController
|
|||||||
render_404
|
render_404
|
||||||
end
|
end
|
||||||
|
|
||||||
def diff
|
|
||||||
@issue = @journal.issue
|
|
||||||
if params[:detail_id].present?
|
|
||||||
@detail = @journal.details.find_by_id(params[:detail_id])
|
|
||||||
else
|
|
||||||
@detail = @journal.details.detect {|d| d.prop_key == 'description'}
|
|
||||||
end
|
|
||||||
(render_404; return false) unless @issue && @detail
|
|
||||||
@diff = Redmine::Helpers::Diff.new(@detail.value, @detail.old_value)
|
|
||||||
end
|
|
||||||
|
|
||||||
def new
|
def new
|
||||||
journal = Journal.find(params[:journal_id]) if params[:journal_id]
|
journal = Journal.find(params[:journal_id]) if params[:journal_id]
|
||||||
if journal
|
if journal
|
||||||
@@ -80,7 +68,6 @@ class JournalsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
(render_403; return false) unless @journal.editable_by?(User.current)
|
|
||||||
if request.post?
|
if request.post?
|
||||||
@journal.update_attributes(:notes => params[:notes]) if params[:notes]
|
@journal.update_attributes(:notes => params[:notes]) if params[:notes]
|
||||||
@journal.destroy if @journal.details.empty? && @journal.notes.blank?
|
@journal.destroy if @journal.details.empty? && @journal.notes.blank?
|
||||||
@@ -100,10 +87,10 @@ class JournalsController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def find_journal
|
def find_journal
|
||||||
@journal = Journal.find(params[:id])
|
@journal = Journal.find(params[:id])
|
||||||
|
(render_403; return false) unless @journal.editable_by?(User.current)
|
||||||
@project = @journal.journalized.project
|
@project = @journal.journalized.project
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
render_404
|
render_404
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2008 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -28,10 +28,10 @@ class MembersController < ApplicationController
|
|||||||
attrs = params[:member].dup
|
attrs = params[:member].dup
|
||||||
if (user_ids = attrs.delete(:user_ids))
|
if (user_ids = attrs.delete(:user_ids))
|
||||||
user_ids.each do |user_id|
|
user_ids.each do |user_id|
|
||||||
members << Member.new(:role_ids => params[:member][:role_ids], :user_id => user_id)
|
members << Member.new(attrs.merge(:user_id => user_id))
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
members << Member.new(:role_ids => params[:member][:role_ids], :user_id => params[:member][:user_id])
|
members << Member.new(attrs)
|
||||||
end
|
end
|
||||||
@project.members << members
|
@project.members << members
|
||||||
end
|
end
|
||||||
@@ -64,10 +64,7 @@ class MembersController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
if params[:member]
|
if request.post? and @member.update_attributes(params[:member])
|
||||||
@member.role_ids = params[:member][:role_ids]
|
|
||||||
end
|
|
||||||
if request.post? and @member.save
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
|
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
|
||||||
format.js {
|
format.js {
|
||||||
@@ -96,7 +93,7 @@ class MembersController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def autocomplete_for_member
|
def autocomplete_for_member
|
||||||
@principals = Principal.active.not_member_of(@project).like(params[:q]).all(:limit => 100)
|
@principals = Principal.active.like(params[:q]).find(:all, :limit => 100) - @project.principals
|
||||||
render :layout => false
|
render :layout => false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -53,10 +53,13 @@ class MessagesController < ApplicationController
|
|||||||
|
|
||||||
# Create a new topic
|
# Create a new topic
|
||||||
def new
|
def new
|
||||||
@message = Message.new
|
@message = Message.new(params[:message])
|
||||||
@message.author = User.current
|
@message.author = User.current
|
||||||
@message.board = @board
|
@message.board = @board
|
||||||
@message.safe_attributes = params[:message]
|
if params[:message] && User.current.allowed_to?(:edit_messages, @project)
|
||||||
|
@message.locked = params[:message]['locked']
|
||||||
|
@message.sticky = params[:message]['sticky']
|
||||||
|
end
|
||||||
if request.post? && @message.save
|
if request.post? && @message.save
|
||||||
call_hook(:controller_messages_new_after_save, { :params => params, :message => @message})
|
call_hook(:controller_messages_new_after_save, { :params => params, :message => @message})
|
||||||
attachments = Attachment.attach_files(@message, params[:attachments])
|
attachments = Attachment.attach_files(@message, params[:attachments])
|
||||||
@@ -67,10 +70,9 @@ class MessagesController < ApplicationController
|
|||||||
|
|
||||||
# Reply to a topic
|
# Reply to a topic
|
||||||
def reply
|
def reply
|
||||||
@reply = Message.new
|
@reply = Message.new(params[:reply])
|
||||||
@reply.author = User.current
|
@reply.author = User.current
|
||||||
@reply.board = @board
|
@reply.board = @board
|
||||||
@reply.safe_attributes = params[:reply]
|
|
||||||
@topic.children << @reply
|
@topic.children << @reply
|
||||||
if !@reply.new_record?
|
if !@reply.new_record?
|
||||||
call_hook(:controller_messages_reply_after_save, { :params => params, :message => @reply})
|
call_hook(:controller_messages_reply_after_save, { :params => params, :message => @reply})
|
||||||
@@ -83,8 +85,11 @@ class MessagesController < ApplicationController
|
|||||||
# Edit a message
|
# Edit a message
|
||||||
def edit
|
def edit
|
||||||
(render_403; return false) unless @message.editable_by?(User.current)
|
(render_403; return false) unless @message.editable_by?(User.current)
|
||||||
@message.safe_attributes = params[:message]
|
if params[:message]
|
||||||
if request.post? && @message.save
|
@message.locked = params[:message]['locked']
|
||||||
|
@message.sticky = params[:message]['sticky']
|
||||||
|
end
|
||||||
|
if request.post? && @message.update_attributes(params[:message])
|
||||||
attachments = Attachment.attach_files(@message, params[:attachments])
|
attachments = Attachment.attach_files(@message, params[:attachments])
|
||||||
render_attachment_warning_if_needed(@message)
|
render_attachment_warning_if_needed(@message)
|
||||||
flash[:notice] = l(:notice_successful_update)
|
flash[:notice] = l(:notice_successful_update)
|
||||||
@@ -110,7 +115,7 @@ class MessagesController < ApplicationController
|
|||||||
content = "#{ll(Setting.default_language, :text_user_wrote, user)}\\n> "
|
content = "#{ll(Setting.default_language, :text_user_wrote, user)}\\n> "
|
||||||
content << text.to_s.strip.gsub(%r{<pre>((.|\s)*?)</pre>}m, '[...]').gsub('"', '\"').gsub(/(\r?\n|\r\n?)/, "\\n> ") + "\\n\\n"
|
content << text.to_s.strip.gsub(%r{<pre>((.|\s)*?)</pre>}m, '[...]').gsub('"', '\"').gsub(/(\r?\n|\r\n?)/, "\\n> ") + "\\n\\n"
|
||||||
render(:update) { |page|
|
render(:update) { |page|
|
||||||
page << "$('message_subject').value = \"#{subject}\";"
|
page << "$('reply_subject').value = \"#{subject}\";"
|
||||||
page.<< "$('message_content').value = \"#{content}\";"
|
page.<< "$('message_content').value = \"#{content}\";"
|
||||||
page.show 'reply'
|
page.show 'reply'
|
||||||
page << "Form.Element.focus('message_content');"
|
page << "Form.Element.focus('message_content');"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2009 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -23,10 +23,7 @@ class NewsController < ApplicationController
|
|||||||
before_filter :find_project, :only => [:new, :create]
|
before_filter :find_project, :only => [:new, :create]
|
||||||
before_filter :authorize, :except => [:index]
|
before_filter :authorize, :except => [:index]
|
||||||
before_filter :find_optional_project, :only => :index
|
before_filter :find_optional_project, :only => :index
|
||||||
accept_rss_auth :index
|
accept_key_auth :index
|
||||||
accept_api_auth :index
|
|
||||||
|
|
||||||
helper :watchers
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
case params[:format]
|
case params[:format]
|
||||||
@@ -47,10 +44,7 @@ class NewsController < ApplicationController
|
|||||||
:limit => @limit)
|
:limit => @limit)
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html {
|
format.html { render :layout => false if request.xhr? }
|
||||||
@news = News.new # for adding news inline
|
|
||||||
render :layout => false if request.xhr?
|
|
||||||
}
|
|
||||||
format.api
|
format.api
|
||||||
format.atom { render_feed(@newss, :title => (@project ? @project.name : Setting.app_title) + ": #{l(:label_news_plural)}") }
|
format.atom { render_feed(@newss, :title => (@project ? @project.name : Setting.app_title) + ": #{l(:label_news_plural)}") }
|
||||||
end
|
end
|
||||||
@@ -67,8 +61,8 @@ class NewsController < ApplicationController
|
|||||||
|
|
||||||
def create
|
def create
|
||||||
@news = News.new(:project => @project, :author => User.current)
|
@news = News.new(:project => @project, :author => User.current)
|
||||||
@news.safe_attributes = params[:news]
|
|
||||||
if request.post?
|
if request.post?
|
||||||
|
@news.attributes = params[:news]
|
||||||
if @news.save
|
if @news.save
|
||||||
flash[:notice] = l(:notice_successful_create)
|
flash[:notice] = l(:notice_successful_create)
|
||||||
redirect_to :controller => 'news', :action => 'index', :project_id => @project
|
redirect_to :controller => 'news', :action => 'index', :project_id => @project
|
||||||
@@ -82,8 +76,7 @@ class NewsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def update
|
||||||
@news.safe_attributes = params[:news]
|
if request.put? and @news.update_attributes(params[:news])
|
||||||
if request.put? and @news.save
|
|
||||||
flash[:notice] = l(:notice_successful_update)
|
flash[:notice] = l(:notice_successful_update)
|
||||||
redirect_to :action => 'show', :id => @news
|
redirect_to :action => 'show', :id => @news
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -1,20 +1,3 @@
|
|||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 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.
|
|
||||||
|
|
||||||
class PreviewsController < ApplicationController
|
class PreviewsController < ApplicationController
|
||||||
before_filter :find_project
|
before_filter :find_project
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2009 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -24,8 +24,7 @@ class ProjectsController < ApplicationController
|
|||||||
before_filter :authorize, :except => [ :index, :list, :new, :create, :copy, :archive, :unarchive, :destroy]
|
before_filter :authorize, :except => [ :index, :list, :new, :create, :copy, :archive, :unarchive, :destroy]
|
||||||
before_filter :authorize_global, :only => [:new, :create]
|
before_filter :authorize_global, :only => [:new, :create]
|
||||||
before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ]
|
before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ]
|
||||||
accept_rss_auth :index
|
accept_key_auth :index, :show, :create, :update, :destroy
|
||||||
accept_api_auth :index, :show, :create, :update, :destroy
|
|
||||||
|
|
||||||
after_filter :only => [:create, :edit, :update, :archive, :unarchive, :destroy] do |controller|
|
after_filter :only => [:create, :edit, :update, :archive, :unarchive, :destroy] do |controller|
|
||||||
if controller.request.post?
|
if controller.request.post?
|
||||||
@@ -66,8 +65,7 @@ class ProjectsController < ApplicationController
|
|||||||
def new
|
def new
|
||||||
@issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
|
@issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
|
||||||
@trackers = Tracker.all
|
@trackers = Tracker.all
|
||||||
@project = Project.new
|
@project = Project.new(params[:project])
|
||||||
@project.safe_attributes = params[:project]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
|
verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
|
||||||
@@ -88,10 +86,7 @@ class ProjectsController < ApplicationController
|
|||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html {
|
format.html {
|
||||||
flash[:notice] = l(:notice_successful_create)
|
flash[:notice] = l(:notice_successful_create)
|
||||||
redirect_to(params[:continue] ?
|
redirect_to :controller => 'projects', :action => 'settings', :id => @project
|
||||||
{: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) }
|
format.api { render :action => 'show', :status => :created, :location => url_for(:controller => 'projects', :action => 'show', :id => @project.id) }
|
||||||
end
|
end
|
||||||
@@ -147,7 +142,7 @@ class ProjectsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
@users_by_role = @project.users_by_role
|
@users_by_role = @project.users_by_role
|
||||||
@subprojects = @project.children.visible.all
|
@subprojects = @project.children.visible
|
||||||
@news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
|
@news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
|
||||||
@trackers = @project.rolled_up_trackers
|
@trackers = @project.rolled_up_trackers
|
||||||
|
|
||||||
@@ -160,10 +155,11 @@ class ProjectsController < ApplicationController
|
|||||||
:include => [:project, :status, :tracker],
|
:include => [:project, :status, :tracker],
|
||||||
:conditions => cond)
|
:conditions => cond)
|
||||||
|
|
||||||
if User.current.allowed_to?(:view_time_entries, @project)
|
TimeEntry.visible_by(User.current) do
|
||||||
@total_hours = TimeEntry.visible.sum(:hours, :include => :project, :conditions => cond).to_f
|
@total_hours = TimeEntry.sum(:hours,
|
||||||
|
:include => :project,
|
||||||
|
:conditions => cond).to_f
|
||||||
end
|
end
|
||||||
|
|
||||||
@key = User.current.rss_key
|
@key = User.current.rss_key
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -17,78 +17,45 @@
|
|||||||
|
|
||||||
class QueriesController < ApplicationController
|
class QueriesController < ApplicationController
|
||||||
menu_item :issues
|
menu_item :issues
|
||||||
before_filter :find_query, :except => [:new, :create, :index]
|
before_filter :find_query, :except => :new
|
||||||
before_filter :find_optional_project, :only => [:new, :create]
|
before_filter :find_optional_project, :only => :new
|
||||||
|
|
||||||
accept_api_auth :index
|
|
||||||
|
|
||||||
include QueriesHelper
|
|
||||||
|
|
||||||
def index
|
|
||||||
case params[:format]
|
|
||||||
when 'xml', 'json'
|
|
||||||
@offset, @limit = api_offset_and_limit
|
|
||||||
else
|
|
||||||
@limit = per_page_option
|
|
||||||
end
|
|
||||||
|
|
||||||
@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
|
def 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?
|
|
||||||
build_query_from_params
|
|
||||||
end
|
|
||||||
|
|
||||||
verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
|
|
||||||
def create
|
|
||||||
@query = Query.new(params[:query])
|
@query = Query.new(params[:query])
|
||||||
@query.user = User.current
|
|
||||||
@query.project = params[:query_is_for_all] ? nil : @project
|
@query.project = params[:query_is_for_all] ? nil : @project
|
||||||
|
@query.user = User.current
|
||||||
@query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
|
@query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
|
||||||
build_query_from_params
|
|
||||||
@query.column_names = nil if params[:default_columns]
|
@query.column_names = nil if params[:default_columns]
|
||||||
|
|
||||||
if @query.save
|
@query.add_filters(params[:fields], params[:operators], params[:values]) if params[:fields]
|
||||||
|
@query.group_by ||= params[:group_by]
|
||||||
|
|
||||||
|
if request.post? && params[:confirm] && @query.save
|
||||||
flash[:notice] = l(:notice_successful_create)
|
flash[:notice] = l(:notice_successful_create)
|
||||||
redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query
|
redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query
|
||||||
else
|
return
|
||||||
render :action => 'new', :layout => !request.xhr?
|
|
||||||
end
|
end
|
||||||
|
render :layout => false if request.xhr?
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
end
|
if request.post?
|
||||||
|
@query.filters = {}
|
||||||
|
@query.add_filters(params[:fields], params[:operators], params[:values]) if params[:fields]
|
||||||
|
@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.column_names = nil if params[:default_columns]
|
||||||
|
|
||||||
verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
|
if @query.save
|
||||||
def update
|
flash[:notice] = l(:notice_successful_update)
|
||||||
@query.attributes = params[:query]
|
redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query
|
||||||
@query.project = nil if params[:query_is_for_all]
|
end
|
||||||
@query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
|
|
||||||
build_query_from_params
|
|
||||||
@query.column_names = nil if params[:default_columns]
|
|
||||||
|
|
||||||
if @query.save
|
|
||||||
flash[:notice] = l(:notice_successful_update)
|
|
||||||
redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query
|
|
||||||
else
|
|
||||||
render :action => 'edit'
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed }
|
|
||||||
def destroy
|
def destroy
|
||||||
@query.destroy
|
@query.destroy if request.post?
|
||||||
redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1
|
redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -24,8 +24,8 @@ class ReportsController < ApplicationController
|
|||||||
@versions = @project.shared_versions.sort
|
@versions = @project.shared_versions.sort
|
||||||
@priorities = IssuePriority.all
|
@priorities = IssuePriority.all
|
||||||
@categories = @project.issue_categories
|
@categories = @project.issue_categories
|
||||||
@assignees = (Setting.issue_group_assignment? ? @project.principals : @project.users).sort
|
@assignees = @project.members.collect { |m| m.user }.sort
|
||||||
@authors = @project.users.sort
|
@authors = @project.members.collect { |m| m.user }.sort
|
||||||
@subprojects = @project.descendants.visible
|
@subprojects = @project.descendants.visible
|
||||||
|
|
||||||
@issues_by_tracker = Issue.by_tracker(@project)
|
@issues_by_tracker = Issue.by_tracker(@project)
|
||||||
@@ -63,12 +63,12 @@ class ReportsController < ApplicationController
|
|||||||
@report_title = l(:field_category)
|
@report_title = l(:field_category)
|
||||||
when "assigned_to"
|
when "assigned_to"
|
||||||
@field = "assigned_to_id"
|
@field = "assigned_to_id"
|
||||||
@rows = (Setting.issue_group_assignment? ? @project.principals : @project.users).sort
|
@rows = @project.members.collect { |m| m.user }.sort
|
||||||
@data = Issue.by_assigned_to(@project)
|
@data = Issue.by_assigned_to(@project)
|
||||||
@report_title = l(:field_assigned_to)
|
@report_title = l(:field_assigned_to)
|
||||||
when "author"
|
when "author"
|
||||||
@field = "author_id"
|
@field = "author_id"
|
||||||
@rows = @project.users.sort
|
@rows = @project.members.collect { |m| m.user }.sort
|
||||||
@data = Issue.by_author(@project)
|
@data = Issue.by_author(@project)
|
||||||
@report_title = l(:field_author)
|
@report_title = l(:field_author)
|
||||||
when "subproject"
|
when "subproject"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2009 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -30,36 +30,24 @@ class RepositoriesController < ApplicationController
|
|||||||
before_filter :find_repository, :except => :edit
|
before_filter :find_repository, :except => :edit
|
||||||
before_filter :find_project, :only => :edit
|
before_filter :find_project, :only => :edit
|
||||||
before_filter :authorize
|
before_filter :authorize
|
||||||
accept_rss_auth :revisions
|
accept_key_auth :revisions
|
||||||
|
|
||||||
rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
|
rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
@repository = @project.repository
|
@repository = @project.repository
|
||||||
if !@repository && !params[:repository_scm].blank?
|
if !@repository
|
||||||
@repository = Repository.factory(params[:repository_scm])
|
@repository = Repository.factory(params[:repository_scm])
|
||||||
@repository.project = @project if @repository
|
@repository.project = @project if @repository
|
||||||
end
|
end
|
||||||
if request.post? && @repository
|
if request.post? && @repository
|
||||||
p1 = params[:repository]
|
@repository.attributes = params[:repository]
|
||||||
p = {}
|
|
||||||
p_extra = {}
|
|
||||||
p1.each do |k, v|
|
|
||||||
if k =~ /^extra_/
|
|
||||||
p_extra[k] = v
|
|
||||||
else
|
|
||||||
p[k] = v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@repository.attributes = p
|
|
||||||
@repository.merge_extra_info(p_extra)
|
|
||||||
@repository.save
|
@repository.save
|
||||||
end
|
end
|
||||||
render(:update) do |page|
|
render(:update) do |page|
|
||||||
page.replace_html "tab-content-repository",
|
page.replace_html "tab-content-repository", :partial => 'projects/settings/repository'
|
||||||
:partial => 'projects/settings/repository'
|
|
||||||
if @repository && !@project.repository
|
if @repository && !@project.repository
|
||||||
@project.reload # needed to reload association
|
@project.reload #needed to reload association
|
||||||
page.replace_html "main-menu", render_main_menu(@project)
|
page.replace_html "main-menu", render_main_menu(@project)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -82,17 +70,13 @@ class RepositoriesController < ApplicationController
|
|||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@repository.destroy
|
@repository.destroy
|
||||||
redirect_to :controller => 'projects',
|
redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'repository'
|
||||||
:action => 'settings',
|
|
||||||
:id => @project,
|
|
||||||
:tab => 'repository'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
@repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty?
|
@repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty?
|
||||||
|
|
||||||
@entries = @repository.entries(@path, @rev)
|
@entries = @repository.entries(@path, @rev)
|
||||||
@changeset = @repository.find_changeset_by_name(@rev)
|
|
||||||
if request.xhr?
|
if request.xhr?
|
||||||
@entries ? render(:partial => 'dir_list_content') : render(:nothing => true)
|
@entries ? render(:partial => 'dir_list_content') : render(:nothing => true)
|
||||||
else
|
else
|
||||||
@@ -110,18 +94,17 @@ class RepositoriesController < ApplicationController
|
|||||||
(show_error_not_found; return) unless @entry
|
(show_error_not_found; return) unless @entry
|
||||||
@changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i)
|
@changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i)
|
||||||
@properties = @repository.properties(@path, @rev)
|
@properties = @repository.properties(@path, @rev)
|
||||||
@changeset = @repository.find_changeset_by_name(@rev)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def revisions
|
def revisions
|
||||||
@changeset_count = @repository.changesets.count
|
@changeset_count = @repository.changesets.count
|
||||||
@changeset_pages = Paginator.new self, @changeset_count,
|
@changeset_pages = Paginator.new self, @changeset_count,
|
||||||
per_page_option,
|
per_page_option,
|
||||||
params['page']
|
params['page']
|
||||||
@changesets = @repository.changesets.find(:all,
|
@changesets = @repository.changesets.find(:all,
|
||||||
:limit => @changeset_pages.items_per_page,
|
:limit => @changeset_pages.items_per_page,
|
||||||
:offset => @changeset_pages.current.offset,
|
:offset => @changeset_pages.current.offset,
|
||||||
:include => [:user, :repository, :parents])
|
:include => [:user, :repository])
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { render :layout => false if request.xhr? }
|
format.html { render :layout => false if request.xhr? }
|
||||||
@@ -138,55 +121,25 @@ class RepositoriesController < ApplicationController
|
|||||||
|
|
||||||
@content = @repository.cat(@path, @rev)
|
@content = @repository.cat(@path, @rev)
|
||||||
(show_error_not_found; return) unless @content
|
(show_error_not_found; return) unless @content
|
||||||
if 'raw' == params[:format] ||
|
if 'raw' == params[:format] || @content.is_binary_data? || (@entry.size && @entry.size > Setting.file_max_size_displayed.to_i.kilobyte)
|
||||||
(@content.size && @content.size > Setting.file_max_size_displayed.to_i.kilobyte) ||
|
|
||||||
! is_entry_text_data?(@content, @path)
|
|
||||||
# Force the download
|
# Force the download
|
||||||
send_opt = { :filename => filename_for_content_disposition(@path.split('/').last) }
|
send_data @content, :filename => filename_for_content_disposition(@path.split('/').last)
|
||||||
send_type = Redmine::MimeType.of(@path)
|
|
||||||
send_opt[:type] = send_type.to_s if send_type
|
|
||||||
send_data @content, send_opt
|
|
||||||
else
|
else
|
||||||
# Prevent empty lines when displaying a file with Windows style eol
|
# Prevent empty lines when displaying a file with Windows style eol
|
||||||
# TODO: UTF-16
|
|
||||||
# Is this needs? AttachmentsController reads file simply.
|
|
||||||
@content.gsub!("\r\n", "\n")
|
@content.gsub!("\r\n", "\n")
|
||||||
@changeset = @repository.find_changeset_by_name(@rev)
|
end
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_entry_text_data?(ent, path)
|
|
||||||
# UTF-16 contains "\x00".
|
|
||||||
# It is very strict that file contains less than 30% of ascii symbols
|
|
||||||
# in non Western Europe.
|
|
||||||
return true if Redmine::MimeType.is_type?('text', path)
|
|
||||||
# Ruby 1.8.6 has a bug of integer divisions.
|
|
||||||
# http://apidock.com/ruby/v1_8_6_287/String/is_binary_data%3F
|
|
||||||
return false if ent.is_binary_data?
|
|
||||||
true
|
|
||||||
end
|
|
||||||
private :is_entry_text_data?
|
|
||||||
|
|
||||||
def annotate
|
def annotate
|
||||||
@entry = @repository.entry(@path, @rev)
|
@entry = @repository.entry(@path, @rev)
|
||||||
(show_error_not_found; return) unless @entry
|
(show_error_not_found; return) unless @entry
|
||||||
|
|
||||||
@annotate = @repository.scm.annotate(@path, @rev)
|
@annotate = @repository.scm.annotate(@path, @rev)
|
||||||
if @annotate.nil? || @annotate.empty?
|
(render_error l(:error_scm_annotate); return) if @annotate.nil? || @annotate.empty?
|
||||||
(render_error l(:error_scm_annotate); return)
|
|
||||||
end
|
|
||||||
ann_buf_size = 0
|
|
||||||
@annotate.lines.each do |buf|
|
|
||||||
ann_buf_size += buf.size
|
|
||||||
end
|
|
||||||
if ann_buf_size > Setting.file_max_size_displayed.to_i.kilobyte
|
|
||||||
(render_error l(:error_scm_annotate_big_text_file); return)
|
|
||||||
end
|
|
||||||
@changeset = @repository.find_changeset_by_name(@rev)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def revision
|
def revision
|
||||||
raise ChangesetNotFound if @rev.blank?
|
raise ChangesetNotFound if @rev.nil? || @rev.empty?
|
||||||
@changeset = @repository.find_changeset_by_name(@rev)
|
@changeset = @repository.find_changeset_by_name(@rev)
|
||||||
raise ChangesetNotFound unless @changeset
|
raise ChangesetNotFound unless @changeset
|
||||||
|
|
||||||
@@ -216,8 +169,8 @@ class RepositoriesController < ApplicationController
|
|||||||
User.current.pref[:diff_type] = @diff_type
|
User.current.pref[:diff_type] = @diff_type
|
||||||
User.current.preference.save
|
User.current.preference.save
|
||||||
end
|
end
|
||||||
@cache_key = "repositories/diff/#{@repository.id}/" +
|
|
||||||
Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}-#{current_language}")
|
@cache_key = "repositories/diff/#{@repository.id}/" + Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}")
|
||||||
unless read_fragment(@cache_key)
|
unless read_fragment(@cache_key)
|
||||||
@diff = @repository.diff(@path, @rev, @rev_to)
|
@diff = @repository.diff(@path, @rev, @rev_to)
|
||||||
show_error_not_found unless @diff
|
show_error_not_found unless @diff
|
||||||
@@ -225,7 +178,6 @@ class RepositoriesController < ApplicationController
|
|||||||
|
|
||||||
@changeset = @repository.find_changeset_by_name(@rev)
|
@changeset = @repository.find_changeset_by_name(@rev)
|
||||||
@changeset_to = @rev_to ? @repository.find_changeset_by_name(@rev_to) : nil
|
@changeset_to = @rev_to ? @repository.find_changeset_by_name(@rev_to) : nil
|
||||||
@diff_format_revisions = @repository.diff_format_revisions(@changeset, @changeset_to)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -258,7 +210,7 @@ class RepositoriesController < ApplicationController
|
|||||||
(render_404; return false) unless @repository
|
(render_404; return false) unless @repository
|
||||||
@path = params[:path].join('/') unless params[:path].nil?
|
@path = params[:path].join('/') unless params[:path].nil?
|
||||||
@path ||= ''
|
@path ||= ''
|
||||||
@rev = params[:rev].blank? ? @repository.default_branch : params[:rev].to_s.strip
|
@rev = params[:rev].blank? ? @repository.default_branch : params[:rev].strip
|
||||||
@rev_to = params[:rev_to]
|
@rev_to = params[:rev_to]
|
||||||
|
|
||||||
unless @rev.to_s.match(REV_PARAM_RE) && @rev_to.to_s.match(REV_PARAM_RE)
|
unless @rev.to_s.match(REV_PARAM_RE) && @rev_to.to_s.match(REV_PARAM_RE)
|
||||||
@@ -285,15 +237,11 @@ class RepositoriesController < ApplicationController
|
|||||||
@date_to = Date.today
|
@date_to = Date.today
|
||||||
@date_from = @date_to << 11
|
@date_from = @date_to << 11
|
||||||
@date_from = Date.civil(@date_from.year, @date_from.month, 1)
|
@date_from = Date.civil(@date_from.year, @date_from.month, 1)
|
||||||
commits_by_day = repository.changesets.count(
|
commits_by_day = repository.changesets.count(:all, :group => :commit_date, :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
|
||||||
:all, :group => :commit_date,
|
|
||||||
:conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
|
|
||||||
commits_by_month = [0] * 12
|
commits_by_month = [0] * 12
|
||||||
commits_by_day.each {|c| commits_by_month[c.first.to_date.months_ago] += c.last }
|
commits_by_day.each {|c| commits_by_month[c.first.to_date.months_ago] += c.last }
|
||||||
|
|
||||||
changes_by_day = repository.changes.count(
|
changes_by_day = repository.changes.count(:all, :group => :commit_date, :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
|
||||||
:all, :group => :commit_date,
|
|
||||||
:conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
|
|
||||||
changes_by_month = [0] * 12
|
changes_by_month = [0] * 12
|
||||||
changes_by_day.each {|c| changes_by_month[c.first.to_date.months_ago] += c.last }
|
changes_by_day.each {|c| changes_by_month[c.first.to_date.months_ago] += c.last }
|
||||||
|
|
||||||
@@ -354,16 +302,20 @@ class RepositoriesController < ApplicationController
|
|||||||
:graph_title => l(:label_commits_per_author),
|
:graph_title => l(:label_commits_per_author),
|
||||||
:show_graph_title => true
|
:show_graph_title => true
|
||||||
)
|
)
|
||||||
|
|
||||||
graph.add_data(
|
graph.add_data(
|
||||||
:data => commits_data,
|
:data => commits_data,
|
||||||
:title => l(:label_revision_plural)
|
:title => l(:label_revision_plural)
|
||||||
)
|
)
|
||||||
|
|
||||||
graph.add_data(
|
graph.add_data(
|
||||||
:data => changes_data,
|
:data => changes_data,
|
||||||
:title => l(:label_change_plural)
|
:title => l(:label_change_plural)
|
||||||
)
|
)
|
||||||
|
|
||||||
graph.burn
|
graph.burn
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
class Date
|
class Date
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -20,7 +20,7 @@ class RolesController < ApplicationController
|
|||||||
|
|
||||||
before_filter :require_admin
|
before_filter :require_admin
|
||||||
|
|
||||||
verify :method => :post, :only => [ :destroy ],
|
verify :method => :post, :only => [ :destroy, :move ],
|
||||||
:redirect_to => { :action => :index }
|
:redirect_to => { :action => :index }
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -24,8 +24,8 @@ class SearchController < ApplicationController
|
|||||||
def index
|
def index
|
||||||
@question = params[:q] || ""
|
@question = params[:q] || ""
|
||||||
@question.strip!
|
@question.strip!
|
||||||
@all_words = params[:all_words] ? params[:all_words].present? : true
|
@all_words = params[:all_words] || (params[:submit] ? false : true)
|
||||||
@titles_only = params[:titles_only] ? params[:titles_only].present? : false
|
@titles_only = !params[:titles_only].nil?
|
||||||
|
|
||||||
projects_to_search =
|
projects_to_search =
|
||||||
case params[:scope]
|
case params[:scope]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2009 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -20,8 +20,7 @@ class SysController < ActionController::Base
|
|||||||
|
|
||||||
def projects
|
def projects
|
||||||
p = Project.active.has_module(:repository).find(:all, :include => :repository, :order => 'identifier')
|
p = Project.active.has_module(:repository).find(:all, :include => :repository, :order => 'identifier')
|
||||||
# extra_info attribute from repository breaks activeresource client
|
render :xml => p.to_xml(:include => :repository)
|
||||||
render :xml => p.to_xml(:only => [:id, :identifier, :name, :is_public, :status], :include => {:repository => {:only => [:id, :url]}})
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_project_repository
|
def create_project_repository
|
||||||
@@ -32,7 +31,7 @@ class SysController < ActionController::Base
|
|||||||
logger.info "Repository for #{project.name} was reported to be created by #{request.remote_ip}."
|
logger.info "Repository for #{project.name} was reported to be created by #{request.remote_ip}."
|
||||||
project.repository = Repository.factory(params[:vendor], params[:repository])
|
project.repository = Repository.factory(params[:vendor], params[:repository])
|
||||||
if project.repository && project.repository.save
|
if project.repository && project.repository.save
|
||||||
render :xml => project.repository.to_xml(:only => [:id, :url]), :status => 201
|
render :xml => project.repository, :status => 201
|
||||||
else
|
else
|
||||||
render :nothing => true, :status => 422
|
render :nothing => true, :status => 422
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2010 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -18,12 +18,10 @@
|
|||||||
class TimelogController < ApplicationController
|
class TimelogController < ApplicationController
|
||||||
menu_item :issues
|
menu_item :issues
|
||||||
before_filter :find_project, :only => [:new, :create]
|
before_filter :find_project, :only => [:new, :create]
|
||||||
before_filter :find_time_entry, :only => [:show, :edit, :update]
|
before_filter :find_time_entry, :only => [:show, :edit, :update, :destroy]
|
||||||
before_filter :find_time_entries, :only => [:bulk_edit, :bulk_update, :destroy]
|
|
||||||
before_filter :authorize, :except => [:index]
|
before_filter :authorize, :except => [:index]
|
||||||
before_filter :find_optional_project, :only => [:index]
|
before_filter :find_optional_project, :only => [:index]
|
||||||
accept_rss_auth :index
|
accept_key_auth :index, :show, :create, :update, :destroy
|
||||||
accept_api_auth :index, :show, :create, :update, :destroy
|
|
||||||
|
|
||||||
helper :sort
|
helper :sort
|
||||||
include SortHelper
|
include SortHelper
|
||||||
@@ -42,56 +40,60 @@ class TimelogController < ApplicationController
|
|||||||
'hours' => 'hours'
|
'hours' => 'hours'
|
||||||
|
|
||||||
cond = ARCondition.new
|
cond = ARCondition.new
|
||||||
if @issue
|
if @project.nil?
|
||||||
cond << "#{Issue.table_name}.root_id = #{@issue.root_id} AND #{Issue.table_name}.lft >= #{@issue.lft} AND #{Issue.table_name}.rgt <= #{@issue.rgt}"
|
cond << Project.allowed_to_condition(User.current, :view_time_entries)
|
||||||
elsif @project
|
elsif @issue.nil?
|
||||||
cond << @project.project_condition(Setting.display_subprojects_issues?)
|
cond << @project.project_condition(Setting.display_subprojects_issues?)
|
||||||
|
else
|
||||||
|
cond << "#{Issue.table_name}.root_id = #{@issue.root_id} AND #{Issue.table_name}.lft >= #{@issue.lft} AND #{Issue.table_name}.rgt <= #{@issue.rgt}"
|
||||||
end
|
end
|
||||||
|
|
||||||
retrieve_date_range
|
retrieve_date_range
|
||||||
cond << ['spent_on BETWEEN ? AND ?', @from, @to]
|
cond << ['spent_on BETWEEN ? AND ?', @from, @to]
|
||||||
|
|
||||||
respond_to do |format|
|
TimeEntry.visible_by(User.current) do
|
||||||
format.html {
|
respond_to do |format|
|
||||||
# Paginate results
|
format.html {
|
||||||
@entry_count = TimeEntry.visible.count(:include => [:project, :issue], :conditions => cond.conditions)
|
# Paginate results
|
||||||
@entry_pages = Paginator.new self, @entry_count, per_page_option, params['page']
|
@entry_count = TimeEntry.count(:include => [:project, :issue], :conditions => cond.conditions)
|
||||||
@entries = TimeEntry.visible.find(:all,
|
@entry_pages = Paginator.new self, @entry_count, per_page_option, params['page']
|
||||||
:include => [:project, :activity, :user, {:issue => :tracker}],
|
@entries = TimeEntry.find(:all,
|
||||||
:conditions => cond.conditions,
|
:include => [:project, :activity, :user, {:issue => :tracker}],
|
||||||
:order => sort_clause,
|
:conditions => cond.conditions,
|
||||||
:limit => @entry_pages.items_per_page,
|
:order => sort_clause,
|
||||||
:offset => @entry_pages.current.offset)
|
:limit => @entry_pages.items_per_page,
|
||||||
@total_hours = TimeEntry.visible.sum(:hours, :include => [:project, :issue], :conditions => cond.conditions).to_f
|
:offset => @entry_pages.current.offset)
|
||||||
|
@total_hours = TimeEntry.sum(:hours, :include => [:project, :issue], :conditions => cond.conditions).to_f
|
||||||
|
|
||||||
render :layout => !request.xhr?
|
render :layout => !request.xhr?
|
||||||
}
|
}
|
||||||
format.api {
|
format.api {
|
||||||
@entry_count = TimeEntry.visible.count(:include => [:project, :issue], :conditions => cond.conditions)
|
@entry_count = TimeEntry.count(:include => [:project, :issue], :conditions => cond.conditions)
|
||||||
@offset, @limit = api_offset_and_limit
|
@entry_pages = Paginator.new self, @entry_count, per_page_option, params['page']
|
||||||
@entries = TimeEntry.visible.find(:all,
|
@entries = TimeEntry.find(:all,
|
||||||
:include => [:project, :activity, :user, {:issue => :tracker}],
|
:include => [:project, :activity, :user, {:issue => :tracker}],
|
||||||
:conditions => cond.conditions,
|
:conditions => cond.conditions,
|
||||||
:order => sort_clause,
|
:order => sort_clause,
|
||||||
:limit => @limit,
|
:limit => @entry_pages.items_per_page,
|
||||||
:offset => @offset)
|
:offset => @entry_pages.current.offset)
|
||||||
}
|
}
|
||||||
format.atom {
|
format.atom {
|
||||||
entries = TimeEntry.visible.find(:all,
|
entries = TimeEntry.find(:all,
|
||||||
:include => [:project, :activity, :user, {:issue => :tracker}],
|
:include => [:project, :activity, :user, {:issue => :tracker}],
|
||||||
:conditions => cond.conditions,
|
:conditions => cond.conditions,
|
||||||
:order => "#{TimeEntry.table_name}.created_on DESC",
|
:order => "#{TimeEntry.table_name}.created_on DESC",
|
||||||
:limit => Setting.feeds_limit.to_i)
|
:limit => Setting.feeds_limit.to_i)
|
||||||
render_feed(entries, :title => l(:label_spent_time))
|
render_feed(entries, :title => l(:label_spent_time))
|
||||||
}
|
}
|
||||||
format.csv {
|
format.csv {
|
||||||
# Export all entries
|
# Export all entries
|
||||||
@entries = TimeEntry.visible.find(:all,
|
@entries = TimeEntry.find(:all,
|
||||||
:include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}],
|
:include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}],
|
||||||
:conditions => cond.conditions,
|
:conditions => cond.conditions,
|
||||||
:order => sort_clause)
|
:order => sort_clause)
|
||||||
send_data(entries_to_csv(@entries), :type => 'text/csv; header=present', :filename => 'timelog.csv')
|
send_data(entries_to_csv(@entries), :type => 'text/csv; header=present', :filename => 'timelog.csv')
|
||||||
}
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -105,7 +107,7 @@ class TimelogController < ApplicationController
|
|||||||
|
|
||||||
def new
|
def new
|
||||||
@time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today)
|
@time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today)
|
||||||
@time_entry.safe_attributes = params[:time_entry]
|
@time_entry.attributes = params[:time_entry]
|
||||||
|
|
||||||
call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
|
call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
|
||||||
render :action => 'edit'
|
render :action => 'edit'
|
||||||
@@ -114,7 +116,7 @@ class TimelogController < ApplicationController
|
|||||||
verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
|
verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
|
||||||
def create
|
def create
|
||||||
@time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today)
|
@time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today)
|
||||||
@time_entry.safe_attributes = params[:time_entry]
|
@time_entry.attributes = params[:time_entry]
|
||||||
|
|
||||||
call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
|
call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
|
||||||
|
|
||||||
@@ -135,14 +137,14 @@ class TimelogController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
@time_entry.safe_attributes = params[:time_entry]
|
@time_entry.attributes = params[:time_entry]
|
||||||
|
|
||||||
call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
|
call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
|
||||||
end
|
end
|
||||||
|
|
||||||
verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
|
verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
|
||||||
def update
|
def update
|
||||||
@time_entry.safe_attributes = params[:time_entry]
|
@time_entry.attributes = params[:time_entry]
|
||||||
|
|
||||||
call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
|
call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
|
||||||
|
|
||||||
@@ -162,55 +164,27 @@ class TimelogController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def bulk_edit
|
|
||||||
@available_activities = TimeEntryActivity.shared.active
|
|
||||||
@custom_fields = TimeEntry.first.available_custom_fields
|
|
||||||
end
|
|
||||||
|
|
||||||
def bulk_update
|
|
||||||
attributes = parse_params_for_bulk_time_entry_attributes(params)
|
|
||||||
|
|
||||||
unsaved_time_entry_ids = []
|
|
||||||
@time_entries.each do |time_entry|
|
|
||||||
time_entry.reload
|
|
||||||
time_entry.safe_attributes = attributes
|
|
||||||
call_hook(:controller_time_entries_bulk_edit_before_save, { :params => params, :time_entry => time_entry })
|
|
||||||
unless time_entry.save
|
|
||||||
# Keep unsaved time_entry ids to display them in flash error
|
|
||||||
unsaved_time_entry_ids << time_entry.id
|
|
||||||
end
|
|
||||||
end
|
|
||||||
set_flash_from_bulk_time_entry_save(@time_entries, unsaved_time_entry_ids)
|
|
||||||
redirect_back_or_default({:controller => 'timelog', :action => 'index', :project_id => @projects.first})
|
|
||||||
end
|
|
||||||
|
|
||||||
verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed }
|
verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed }
|
||||||
def destroy
|
def destroy
|
||||||
@time_entries.each do |t|
|
if @time_entry.destroy && @time_entry.destroyed?
|
||||||
begin
|
respond_to do |format|
|
||||||
unless t.destroy && t.destroyed?
|
format.html {
|
||||||
respond_to do |format|
|
flash[:notice] = l(:notice_successful_delete)
|
||||||
format.html {
|
redirect_to :back
|
||||||
flash[:error] = l(:notice_unable_delete_time_entry)
|
}
|
||||||
redirect_to :back
|
format.api { head :ok }
|
||||||
}
|
end
|
||||||
format.api { render_validation_errors(t) }
|
else
|
||||||
end
|
respond_to do |format|
|
||||||
return
|
format.html {
|
||||||
end
|
flash[:error] = l(:notice_unable_delete_time_entry)
|
||||||
rescue ::ActionController::RedirectBackError
|
redirect_to :back
|
||||||
redirect_to :action => 'index', :project_id => @projects.first
|
}
|
||||||
return
|
format.api { render_validation_errors(@time_entry) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
rescue ::ActionController::RedirectBackError
|
||||||
respond_to do |format|
|
redirect_to :action => 'index', :project_id => @time_entry.project
|
||||||
format.html {
|
|
||||||
flash[:notice] = l(:notice_successful_delete)
|
|
||||||
redirect_back_or_default(:action => 'index', :project_id => @projects.first)
|
|
||||||
}
|
|
||||||
format.api { head :ok }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@@ -225,26 +199,6 @@ private
|
|||||||
render_404
|
render_404
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_time_entries
|
|
||||||
@time_entries = TimeEntry.find_all_by_id(params[:id] || params[:ids])
|
|
||||||
raise ActiveRecord::RecordNotFound if @time_entries.empty?
|
|
||||||
@projects = @time_entries.collect(&:project).compact.uniq
|
|
||||||
@project = @projects.first if @projects.size == 1
|
|
||||||
rescue ActiveRecord::RecordNotFound
|
|
||||||
render_404
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_flash_from_bulk_time_entry_save(time_entries, unsaved_time_entry_ids)
|
|
||||||
if unsaved_time_entry_ids.empty?
|
|
||||||
flash[:notice] = l(:notice_successful_update) unless time_entries.empty?
|
|
||||||
else
|
|
||||||
flash[:error] = l(:notice_failed_to_save_time_entries,
|
|
||||||
:count => unsaved_time_entry_ids.size,
|
|
||||||
:total => time_entries.size,
|
|
||||||
:ids => '#' + unsaved_time_entry_ids.join(', #'))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def find_project
|
def find_project
|
||||||
if (issue_id = (params[:issue_id] || params[:time_entry] && params[:time_entry][:issue_id])).present?
|
if (issue_id = (params[:issue_id] || params[:time_entry] && params[:time_entry][:issue_id])).present?
|
||||||
@issue = Issue.find(issue_id)
|
@issue = Issue.find(issue_id)
|
||||||
@@ -315,10 +269,4 @@ private
|
|||||||
@to ||= (TimeEntry.latest_date_for_project(@project) || Date.today)
|
@to ||= (TimeEntry.latest_date_for_project(@project) || Date.today)
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_params_for_bulk_time_entry_attributes(params)
|
|
||||||
attributes = (params[:time_entry] || {}).reject {|k,v| v.blank?}
|
|
||||||
attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
|
|
||||||
attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values]
|
|
||||||
attributes
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2009 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -18,29 +18,16 @@
|
|||||||
class TrackersController < ApplicationController
|
class TrackersController < ApplicationController
|
||||||
layout 'admin'
|
layout 'admin'
|
||||||
|
|
||||||
before_filter :require_admin, :except => :index
|
before_filter :require_admin
|
||||||
before_filter :require_admin_or_api_request, :only => :index
|
|
||||||
accept_api_auth :index
|
verify :method => :post, :only => :destroy, :redirect_to => { :action => :index }
|
||||||
|
|
||||||
def index
|
def index
|
||||||
respond_to do |format|
|
@tracker_pages, @trackers = paginate :trackers, :per_page => 10, :order => 'position'
|
||||||
format.html {
|
render :action => "index", :layout => false if request.xhr?
|
||||||
@tracker_pages, @trackers = paginate :trackers, :per_page => 10, :order => 'position'
|
|
||||||
render :action => "index", :layout => false if request.xhr?
|
|
||||||
}
|
|
||||||
format.api {
|
|
||||||
@trackers = Tracker.all
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@tracker ||= Tracker.new(params[:tracker])
|
|
||||||
@trackers = Tracker.find :all, :order => 'position'
|
|
||||||
@projects = Project.find(:all)
|
|
||||||
end
|
|
||||||
|
|
||||||
def create
|
|
||||||
@tracker = Tracker.new(params[:tracker])
|
@tracker = Tracker.new(params[:tracker])
|
||||||
if request.post? and @tracker.save
|
if request.post? and @tracker.save
|
||||||
# workflow copy
|
# workflow copy
|
||||||
@@ -51,27 +38,20 @@ class TrackersController < ApplicationController
|
|||||||
redirect_to :action => 'index'
|
redirect_to :action => 'index'
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
new
|
@trackers = Tracker.find :all, :order => 'position'
|
||||||
render :action => 'new'
|
|
||||||
end
|
|
||||||
|
|
||||||
def edit
|
|
||||||
@tracker ||= Tracker.find(params[:id])
|
|
||||||
@projects = Project.find(:all)
|
@projects = Project.find(:all)
|
||||||
end
|
end
|
||||||
|
|
||||||
def update
|
def edit
|
||||||
@tracker = Tracker.find(params[:id])
|
@tracker = Tracker.find(params[:id])
|
||||||
if request.put? and @tracker.update_attributes(params[:tracker])
|
if request.post? and @tracker.update_attributes(params[:tracker])
|
||||||
flash[:notice] = l(:notice_successful_update)
|
flash[:notice] = l(:notice_successful_update)
|
||||||
redirect_to :action => 'index'
|
redirect_to :action => 'index'
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
edit
|
@projects = Project.find(:all)
|
||||||
render :action => 'edit'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
verify :method => :delete, :only => :destroy, :redirect_to => { :action => :index }
|
|
||||||
def destroy
|
def destroy
|
||||||
@tracker = Tracker.find(params[:id])
|
@tracker = Tracker.find(params[:id])
|
||||||
unless @tracker.issues.empty?
|
unless @tracker.issues.empty?
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2010 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -19,8 +19,8 @@ class UsersController < ApplicationController
|
|||||||
layout 'admin'
|
layout 'admin'
|
||||||
|
|
||||||
before_filter :require_admin, :except => :show
|
before_filter :require_admin, :except => :show
|
||||||
before_filter :find_user, :only => [:show, :edit, :update, :destroy, :edit_membership, :destroy_membership]
|
before_filter :find_user, :only => [:show, :edit, :update, :edit_membership, :destroy_membership]
|
||||||
accept_api_auth :index, :show, :create, :update, :destroy
|
accept_key_auth :index, :show, :create, :update
|
||||||
|
|
||||||
helper :sort
|
helper :sort
|
||||||
include SortHelper
|
include SortHelper
|
||||||
@@ -38,9 +38,6 @@ class UsersController < ApplicationController
|
|||||||
@limit = per_page_option
|
@limit = per_page_option
|
||||||
end
|
end
|
||||||
|
|
||||||
scope = User
|
|
||||||
scope = scope.in_group(params[:group_id].to_i) if params[:group_id].present?
|
|
||||||
|
|
||||||
@status = params[:status] ? params[:status].to_i : 1
|
@status = params[:status] ? params[:status].to_i : 1
|
||||||
c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status])
|
c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status])
|
||||||
|
|
||||||
@@ -49,27 +46,24 @@ class UsersController < ApplicationController
|
|||||||
c << ["LOWER(login) LIKE ? OR LOWER(firstname) LIKE ? OR LOWER(lastname) LIKE ? OR LOWER(mail) LIKE ?", name, name, name, name]
|
c << ["LOWER(login) LIKE ? OR LOWER(firstname) LIKE ? OR LOWER(lastname) LIKE ? OR LOWER(mail) LIKE ?", name, name, name, name]
|
||||||
end
|
end
|
||||||
|
|
||||||
@user_count = scope.count(:conditions => c.conditions)
|
@user_count = User.count(:conditions => c.conditions)
|
||||||
@user_pages = Paginator.new self, @user_count, @limit, params['page']
|
@user_pages = Paginator.new self, @user_count, @limit, params['page']
|
||||||
@offset ||= @user_pages.current.offset
|
@offset ||= @user_pages.current.offset
|
||||||
@users = scope.find :all,
|
@users = User.find :all,
|
||||||
:order => sort_clause,
|
:order => sort_clause,
|
||||||
:conditions => c.conditions,
|
:conditions => c.conditions,
|
||||||
:limit => @limit,
|
:limit => @limit,
|
||||||
:offset => @offset
|
:offset => @offset
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html {
|
format.html { render :layout => !request.xhr? }
|
||||||
@groups = Group.all.sort
|
|
||||||
render :layout => !request.xhr?
|
|
||||||
}
|
|
||||||
format.api
|
format.api
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
# show projects based on current user visibility
|
# show projects based on current user visibility
|
||||||
@memberships = @user.memberships.all(:conditions => Project.visible_condition(User.current))
|
@memberships = @user.memberships.all(:conditions => Project.visible_by(User.current))
|
||||||
|
|
||||||
events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10)
|
events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10)
|
||||||
@events_by_day = events.group_by(&:event_date)
|
@events_by_day = events.group_by(&:event_date)
|
||||||
@@ -183,15 +177,6 @@ class UsersController < ApplicationController
|
|||||||
redirect_to :controller => 'users', :action => 'edit', :id => @user
|
redirect_to :controller => 'users', :action => 'edit', :id => @user
|
||||||
end
|
end
|
||||||
|
|
||||||
verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed }
|
|
||||||
def destroy
|
|
||||||
@user.destroy
|
|
||||||
respond_to do |format|
|
|
||||||
format.html { redirect_to(users_url) }
|
|
||||||
format.api { head :ok }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def edit_membership
|
def edit_membership
|
||||||
@membership = Member.edit_membership(params[:membership_id], params[:membership], @user)
|
@membership = Member.edit_membership(params[:membership_id], params[:membership], @user)
|
||||||
@membership.save if request.post?
|
@membership.save if request.post?
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -23,51 +23,37 @@ class VersionsController < ApplicationController
|
|||||||
before_filter :find_project, :only => [:index, :new, :create, :close_completed]
|
before_filter :find_project, :only => [:index, :new, :create, :close_completed]
|
||||||
before_filter :authorize
|
before_filter :authorize
|
||||||
|
|
||||||
accept_api_auth :index, :show, :create, :update, :destroy
|
|
||||||
|
|
||||||
helper :custom_fields
|
helper :custom_fields
|
||||||
helper :projects
|
helper :projects
|
||||||
|
|
||||||
def index
|
def index
|
||||||
respond_to do |format|
|
@trackers = @project.trackers.find(:all, :order => 'position')
|
||||||
format.html {
|
retrieve_selected_tracker_ids(@trackers, @trackers.select {|t| t.is_in_roadmap?})
|
||||||
@trackers = @project.trackers.find(:all, :order => 'position')
|
@with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
|
||||||
retrieve_selected_tracker_ids(@trackers, @trackers.select {|t| t.is_in_roadmap?})
|
project_ids = @with_subprojects ? @project.self_and_descendants.collect(&:id) : [@project.id]
|
||||||
@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]
|
|
||||||
|
|
||||||
@versions = @project.shared_versions || []
|
@versions = @project.shared_versions || []
|
||||||
@versions += @project.rolled_up_versions.visible if @with_subprojects
|
@versions += @project.rolled_up_versions.visible if @with_subprojects
|
||||||
@versions = @versions.uniq.sort
|
@versions = @versions.uniq.sort
|
||||||
@versions.reject! {|version| version.closed? || version.completed? } unless params[:completed]
|
@versions.reject! {|version| version.closed? || version.completed? } unless params[:completed]
|
||||||
|
|
||||||
@issues_by_version = {}
|
@issues_by_version = {}
|
||||||
unless @selected_tracker_ids.empty?
|
unless @selected_tracker_ids.empty?
|
||||||
@versions.each do |version|
|
@versions.each do |version|
|
||||||
issues = version.fixed_issues.visible.find(:all,
|
issues = version.fixed_issues.visible.find(:all,
|
||||||
:include => [:project, :status, :tracker, :priority],
|
:include => [:project, :status, :tracker, :priority],
|
||||||
:conditions => {:tracker_id => @selected_tracker_ids, :project_id => project_ids},
|
:conditions => {:tracker_id => @selected_tracker_ids, :project_id => project_ids},
|
||||||
:order => "#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id")
|
:order => "#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id")
|
||||||
@issues_by_version[version] = issues
|
@issues_by_version[version] = issues
|
||||||
end
|
end
|
||||||
end
|
|
||||||
@versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?}
|
|
||||||
}
|
|
||||||
format.api {
|
|
||||||
@versions = @project.shared_versions.all
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
@versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?}
|
||||||
end
|
end
|
||||||
|
|
||||||
def show
|
def show
|
||||||
respond_to do |format|
|
@issues = @version.fixed_issues.visible.find(:all,
|
||||||
format.html {
|
:include => [:status, :tracker, :priority],
|
||||||
@issues = @version.fixed_issues.visible.find(:all,
|
:order => "#{Tracker.table_name}.position, #{Issue.table_name}.id")
|
||||||
:include => [:status, :tracker, :priority],
|
|
||||||
:order => "#{Tracker.table_name}.position, #{Issue.table_name}.id")
|
|
||||||
}
|
|
||||||
format.api
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@@ -75,7 +61,7 @@ class VersionsController < ApplicationController
|
|||||||
if params[:version]
|
if params[:version]
|
||||||
attributes = params[:version].dup
|
attributes = params[:version].dup
|
||||||
attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing'])
|
attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing'])
|
||||||
@version.safe_attributes = attributes
|
@version.attributes = attributes
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -85,7 +71,7 @@ class VersionsController < ApplicationController
|
|||||||
if params[:version]
|
if params[:version]
|
||||||
attributes = params[:version].dup
|
attributes = params[:version].dup
|
||||||
attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing'])
|
attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing'])
|
||||||
@version.safe_attributes = attributes
|
@version.attributes = attributes
|
||||||
end
|
end
|
||||||
|
|
||||||
if request.post?
|
if request.post?
|
||||||
@@ -93,7 +79,7 @@ class VersionsController < ApplicationController
|
|||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html do
|
format.html do
|
||||||
flash[:notice] = l(:notice_successful_create)
|
flash[:notice] = l(:notice_successful_create)
|
||||||
redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
|
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
|
||||||
end
|
end
|
||||||
format.js do
|
format.js do
|
||||||
# IE doesn't support the replace_html rjs method for select box options
|
# IE doesn't support the replace_html rjs method for select box options
|
||||||
@@ -101,9 +87,6 @@ class VersionsController < ApplicationController
|
|||||||
content_tag('select', '<option></option>' + version_options_for_select(@project.shared_versions.open, @version), :id => 'issue_fixed_version_id', :name => 'issue[fixed_version_id]')
|
content_tag('select', '<option></option>' + version_options_for_select(@project.shared_versions.open, @version), :id => 'issue_fixed_version_id', :name => 'issue[fixed_version_id]')
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
format.api do
|
|
||||||
render :action => 'show', :status => :created, :location => version_url(@version)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
@@ -111,7 +94,6 @@ class VersionsController < ApplicationController
|
|||||||
format.js do
|
format.js do
|
||||||
render(:update) {|page| page.alert(@version.errors.full_messages.join('\n')) }
|
render(:update) {|page| page.alert(@version.errors.full_messages.join('\n')) }
|
||||||
end
|
end
|
||||||
format.api { render_validation_errors(@version) }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -124,19 +106,12 @@ class VersionsController < ApplicationController
|
|||||||
if request.put? && params[:version]
|
if request.put? && params[:version]
|
||||||
attributes = params[:version].dup
|
attributes = params[:version].dup
|
||||||
attributes.delete('sharing') unless @version.allowed_sharings.include?(attributes['sharing'])
|
attributes.delete('sharing') unless @version.allowed_sharings.include?(attributes['sharing'])
|
||||||
@version.safe_attributes = attributes
|
if @version.update_attributes(attributes)
|
||||||
if @version.save
|
flash[:notice] = l(:notice_successful_update)
|
||||||
respond_to do |format|
|
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
|
||||||
format.html {
|
|
||||||
flash[:notice] = l(:notice_successful_update)
|
|
||||||
redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
|
|
||||||
}
|
|
||||||
format.api { head :ok }
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { render :action => 'edit' }
|
format.html { render :action => 'edit' }
|
||||||
format.api { render_validation_errors(@version) }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -149,22 +124,13 @@ class VersionsController < ApplicationController
|
|||||||
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
|
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
|
||||||
end
|
end
|
||||||
|
|
||||||
verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed }
|
|
||||||
def destroy
|
def destroy
|
||||||
if @version.fixed_issues.empty?
|
if @version.fixed_issues.empty?
|
||||||
@version.destroy
|
@version.destroy
|
||||||
respond_to do |format|
|
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
|
||||||
format.html { redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project }
|
|
||||||
format.api { head :ok }
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
respond_to do |format|
|
flash[:error] = l(:notice_unable_delete_version)
|
||||||
format.html {
|
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
|
||||||
flash[:error] = l(:notice_unable_delete_version)
|
|
||||||
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
|
|
||||||
}
|
|
||||||
format.api { head :unprocessable_entity }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -76,13 +76,21 @@ private
|
|||||||
|
|
||||||
def set_watcher(user, watching)
|
def set_watcher(user, watching)
|
||||||
@watched.set_watcher(user, watching)
|
@watched.set_watcher(user, watching)
|
||||||
|
if params[:replace].present?
|
||||||
|
if params[:replace].is_a? Array
|
||||||
|
replace_ids = params[:replace]
|
||||||
|
else
|
||||||
|
replace_ids = [params[:replace]]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
replace_ids = ['watcher']
|
||||||
|
end
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { redirect_to :back }
|
format.html { redirect_to :back }
|
||||||
format.js do
|
format.js do
|
||||||
render(:update) do |page|
|
render(:update) do |page|
|
||||||
c = watcher_css(@watched)
|
replace_ids.each do |replace_id|
|
||||||
page.select(".#{c}").each do |item|
|
page.replace_html replace_id, watcher_link(@watched, user, :replace => replace_ids)
|
||||||
page.replace_html item, watcher_link(@watched, user)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -34,28 +34,23 @@ require 'diff'
|
|||||||
class WikiController < ApplicationController
|
class WikiController < ApplicationController
|
||||||
default_search_scope :wiki_pages
|
default_search_scope :wiki_pages
|
||||||
before_filter :find_wiki, :authorize
|
before_filter :find_wiki, :authorize
|
||||||
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]
|
before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy]
|
||||||
|
|
||||||
|
verify :method => :post, :only => [:protect], :redirect_to => { :action => :show }
|
||||||
|
|
||||||
helper :attachments
|
helper :attachments
|
||||||
include AttachmentsHelper
|
include AttachmentsHelper
|
||||||
helper :watchers
|
helper :watchers
|
||||||
include Redmine::Export::PDF
|
|
||||||
|
|
||||||
# List of pages, sorted alphabetically and by parent (hierarchy)
|
# List of pages, sorted alphabetically and by parent (hierarchy)
|
||||||
def index
|
def index
|
||||||
load_pages_for_index
|
load_pages_grouped_by_date_without_content
|
||||||
@pages_by_parent_id = @pages.group_by(&:parent_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
# List of page, by last update
|
|
||||||
def date_index
|
|
||||||
load_pages_for_index
|
|
||||||
@pages_by_date = @pages.group_by {|p| p.updated_on.to_date}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# display a page (in editing mode if it doesn't exist)
|
# display a page (in editing mode if it doesn't exist)
|
||||||
def show
|
def show
|
||||||
|
page_title = params[:id]
|
||||||
|
@page = @wiki.find_or_new_page(page_title)
|
||||||
if @page.new_record?
|
if @page.new_record?
|
||||||
if User.current.allowed_to?(:edit_wiki_pages, @project) && editable?
|
if User.current.allowed_to?(:edit_wiki_pages, @project) && editable?
|
||||||
edit
|
edit
|
||||||
@@ -72,10 +67,7 @@ class WikiController < ApplicationController
|
|||||||
end
|
end
|
||||||
@content = @page.content_for_version(params[:version])
|
@content = @page.content_for_version(params[:version])
|
||||||
if User.current.allowed_to?(:export_wiki_pages, @project)
|
if User.current.allowed_to?(:export_wiki_pages, @project)
|
||||||
if params[:format] == 'pdf'
|
if params[:format] == 'html'
|
||||||
send_data(wiki_to_pdf(@page, @project), :type => 'application/pdf', :filename => "#{@page.title}.pdf")
|
|
||||||
return
|
|
||||||
elsif params[:format] == 'html'
|
|
||||||
export = render_to_string :action => 'export', :layout => false
|
export = render_to_string :action => 'export', :layout => false
|
||||||
send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
|
send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
|
||||||
return
|
return
|
||||||
@@ -85,15 +77,12 @@ class WikiController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
@editable = editable?
|
@editable = editable?
|
||||||
@sections_editable = @editable && User.current.allowed_to?(:edit_wiki_pages, @page.project) &&
|
|
||||||
@content.current_version? &&
|
|
||||||
Redmine::WikiFormatting.supports_section_edit?
|
|
||||||
|
|
||||||
render :action => 'show'
|
render :action => 'show'
|
||||||
end
|
end
|
||||||
|
|
||||||
# edit an existing page or a new one
|
# edit an existing page or a new one
|
||||||
def edit
|
def edit
|
||||||
|
@page = @wiki.find_or_new_page(params[:id])
|
||||||
return render_403 unless editable?
|
return render_403 unless editable?
|
||||||
@page.content = WikiContent.new(:page => @page) if @page.new_record?
|
@page.content = WikiContent.new(:page => @page) if @page.new_record?
|
||||||
|
|
||||||
@@ -104,18 +93,12 @@ class WikiController < ApplicationController
|
|||||||
|
|
||||||
# To prevent StaleObjectError exception when reverting to a previous version
|
# To prevent StaleObjectError exception when reverting to a previous version
|
||||||
@content.version = @page.content.version
|
@content.version = @page.content.version
|
||||||
|
|
||||||
@text = @content.text
|
|
||||||
if params[:section].present? && Redmine::WikiFormatting.supports_section_edit?
|
|
||||||
@section = params[:section].to_i
|
|
||||||
@text, @section_hash = Redmine::WikiFormatting.formatter.new(@text).get_section(@section)
|
|
||||||
render_404 if @text.blank?
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
|
verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
|
||||||
# Creates a new page or updates an existing one
|
# Creates a new page or updates an existing one
|
||||||
def update
|
def update
|
||||||
|
@page = @wiki.find_or_new_page(params[:id])
|
||||||
return render_403 unless editable?
|
return render_403 unless editable?
|
||||||
@page.content = WikiContent.new(:page => @page) if @page.new_record?
|
@page.content = WikiContent.new(:page => @page) if @page.new_record?
|
||||||
|
|
||||||
@@ -131,17 +114,7 @@ class WikiController < ApplicationController
|
|||||||
redirect_to :action => 'show', :project_id => @project, :id => @page.title
|
redirect_to :action => 'show', :project_id => @project, :id => @page.title
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@content.attributes = params[:content]
|
||||||
@content.comments = params[:content][:comments]
|
|
||||||
@text = params[:content][:text]
|
|
||||||
if params[:section].present? && Redmine::WikiFormatting.supports_section_edit?
|
|
||||||
@section = params[:section].to_i
|
|
||||||
@section_hash = params[:section_hash]
|
|
||||||
@content.text = Redmine::WikiFormatting.formatter.new(@content.text).update_section(params[:section].to_i, @text, @section_hash)
|
|
||||||
else
|
|
||||||
@content.version = params[:content][:version]
|
|
||||||
@content.text = @text
|
|
||||||
end
|
|
||||||
@content.author = User.current
|
@content.author = User.current
|
||||||
# if page is new @page.save will also save content, but not if page isn't a new record
|
# if page is new @page.save will also save content, but not if page isn't a new record
|
||||||
if (@page.new_record? ? @page.save : @content.save)
|
if (@page.new_record? ? @page.save : @content.save)
|
||||||
@@ -153,7 +126,7 @@ class WikiController < ApplicationController
|
|||||||
render :action => 'edit'
|
render :action => 'edit'
|
||||||
end
|
end
|
||||||
|
|
||||||
rescue ActiveRecord::StaleObjectError, Redmine::WikiFormatting::StaleSectionError
|
rescue ActiveRecord::StaleObjectError
|
||||||
# Optimistic locking exception
|
# Optimistic locking exception
|
||||||
flash.now[:error] = l(:notice_locking_conflict)
|
flash.now[:error] = l(:notice_locking_conflict)
|
||||||
render :action => 'edit'
|
render :action => 'edit'
|
||||||
@@ -171,7 +144,6 @@ class WikiController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
verify :method => :post, :only => :protect, :redirect_to => { :action => :show }
|
|
||||||
def protect
|
def protect
|
||||||
@page.update_attribute :protected, params[:protected]
|
@page.update_attribute :protected, params[:protected]
|
||||||
redirect_to :action => 'show', :project_id => @project, :id => @page.title
|
redirect_to :action => 'show', :project_id => @project, :id => @page.title
|
||||||
@@ -242,6 +214,10 @@ class WikiController < ApplicationController
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def date_index
|
||||||
|
load_pages_grouped_by_date_without_content
|
||||||
|
end
|
||||||
|
|
||||||
def preview
|
def preview
|
||||||
page = @wiki.find_page(params[:id])
|
page = @wiki.find_page(params[:id])
|
||||||
# page is nil when previewing a new page
|
# page is nil when previewing a new page
|
||||||
@@ -271,24 +247,10 @@ private
|
|||||||
render_404
|
render_404
|
||||||
end
|
end
|
||||||
|
|
||||||
# Finds the requested page or a new page if it doesn't exist
|
|
||||||
def find_existing_or_new_page
|
|
||||||
@page = @wiki.find_or_new_page(params[:id])
|
|
||||||
if @wiki.page_found_with_redirect?
|
|
||||||
redirect_to params.update(:id => @page.title)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Finds the requested page and returns a 404 error if it doesn't exist
|
# Finds the requested page and returns a 404 error if it doesn't exist
|
||||||
def find_existing_page
|
def find_existing_page
|
||||||
@page = @wiki.find_page(params[:id])
|
@page = @wiki.find_page(params[:id])
|
||||||
if @page.nil?
|
render_404 if @page.nil?
|
||||||
render_404
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if @wiki.page_found_with_redirect?
|
|
||||||
redirect_to params.update(:id => @page.title)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns true if the current user is allowed to edit the page, otherwise false
|
# Returns true if the current user is allowed to edit the page, otherwise false
|
||||||
@@ -303,7 +265,13 @@ private
|
|||||||
helper.instance_method(:initial_page_content).bind(self).call(page)
|
helper.instance_method(:initial_page_content).bind(self).call(page)
|
||||||
end
|
end
|
||||||
|
|
||||||
def load_pages_for_index
|
# eager load information about last updates, without loading text
|
||||||
@pages = @wiki.pages.with_updated_on.all(:order => 'title', :include => {:wiki => :project})
|
def load_pages_grouped_by_date_without_content
|
||||||
|
@pages = @wiki.pages.find :all, :select => "#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_on",
|
||||||
|
:joins => "LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id",
|
||||||
|
:order => 'title'
|
||||||
|
@pages_by_date = @pages.group_by {|p| p.updated_on.to_date}
|
||||||
|
@pages_by_parent_id = @pages.group_by(&:parent_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -22,7 +22,7 @@ class WikisController < ApplicationController
|
|||||||
# Create or update a project's wiki
|
# Create or update a project's wiki
|
||||||
def edit
|
def edit
|
||||||
@wiki = @project.wiki || Wiki.new(:project => @project)
|
@wiki = @project.wiki || Wiki.new(:project => @project)
|
||||||
@wiki.safe_attributes = params[:wiki]
|
@wiki.attributes = params[:wiki]
|
||||||
@wiki.save if request.post?
|
@wiki.save if request.post?
|
||||||
render(:update) {|page| page.replace_html "tab-content-wiki", :partial => 'projects/settings/wiki'}
|
render(:update) {|page| page.replace_html "tab-content-wiki", :partial => 'projects/settings/wiki'}
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2008 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -32,17 +32,14 @@ class WorkflowsController < ApplicationController
|
|||||||
|
|
||||||
if request.post?
|
if request.post?
|
||||||
Workflow.destroy_all( ["role_id=? and tracker_id=?", @role.id, @tracker.id])
|
Workflow.destroy_all( ["role_id=? and tracker_id=?", @role.id, @tracker.id])
|
||||||
(params[:issue_status] || []).each { |status_id, transitions|
|
(params[:issue_status] || []).each { |old, news|
|
||||||
transitions.each { |new_status_id, options|
|
news.each { |new|
|
||||||
author = options.is_a?(Array) && options.include?('author') && !options.include?('always')
|
@role.workflows.build(:tracker_id => @tracker.id, :old_status_id => old, :new_status_id => new)
|
||||||
assignee = options.is_a?(Array) && options.include?('assignee') && !options.include?('always')
|
|
||||||
@role.workflows.build(:tracker_id => @tracker.id, :old_status_id => status_id, :new_status_id => new_status_id, :author => author, :assignee => assignee)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if @role.save
|
if @role.save
|
||||||
flash[:notice] = l(:notice_successful_update)
|
flash[:notice] = l(:notice_successful_update)
|
||||||
redirect_to :action => 'edit', :role_id => @role, :tracker_id => @tracker
|
redirect_to :action => 'edit', :role_id => @role, :tracker_id => @tracker
|
||||||
return
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -51,14 +48,6 @@ class WorkflowsController < ApplicationController
|
|||||||
@statuses = @tracker.issue_statuses
|
@statuses = @tracker.issue_statuses
|
||||||
end
|
end
|
||||||
@statuses ||= IssueStatus.find(:all, :order => 'position')
|
@statuses ||= IssueStatus.find(:all, :order => 'position')
|
||||||
|
|
||||||
if @tracker && @role && @statuses.any?
|
|
||||||
workflows = Workflow.all(:conditions => {:role_id => @role.id, :tracker_id => @tracker.id})
|
|
||||||
@workflows = {}
|
|
||||||
@workflows['always'] = workflows.select {|w| !w.author && !w.assignee}
|
|
||||||
@workflows['author'] = workflows.select {|w| w.author}
|
|
||||||
@workflows['assignee'] = workflows.select {|w| w.assignee}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def copy
|
def copy
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
+104
-254
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
|
||||||
#
|
|
||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2010 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -82,7 +80,7 @@ module ApplicationHelper
|
|||||||
subject = truncate(subject, :length => options[:truncate])
|
subject = truncate(subject, :length => options[:truncate])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
s = link_to "#{h(issue.tracker)} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue},
|
s = link_to "#{issue.tracker} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue},
|
||||||
:class => issue.css_classes,
|
:class => issue.css_classes,
|
||||||
:title => title
|
:title => title
|
||||||
s << ": #{h subject}" if subject
|
s << ": #{h subject}" if subject
|
||||||
@@ -97,10 +95,8 @@ module ApplicationHelper
|
|||||||
def link_to_attachment(attachment, options={})
|
def link_to_attachment(attachment, options={})
|
||||||
text = options.delete(:text) || attachment.filename
|
text = options.delete(:text) || attachment.filename
|
||||||
action = options.delete(:download) ? 'download' : 'show'
|
action = options.delete(:download) ? 'download' : 'show'
|
||||||
link_to(h(text),
|
|
||||||
{:controller => 'attachments', :action => action,
|
link_to(h(text), {:controller => 'attachments', :action => action, :id => attachment, :filename => attachment.filename }, options)
|
||||||
:id => attachment, :filename => attachment.filename },
|
|
||||||
options)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Generates a link to a SCM revision
|
# Generates a link to a SCM revision
|
||||||
@@ -110,24 +106,10 @@ module ApplicationHelper
|
|||||||
text = options.delete(:text) || format_revision(revision)
|
text = options.delete(:text) || format_revision(revision)
|
||||||
rev = revision.respond_to?(:identifier) ? revision.identifier : revision
|
rev = revision.respond_to?(:identifier) ? revision.identifier : revision
|
||||||
|
|
||||||
link_to(h(text), {:controller => 'repositories', :action => 'revision', :id => project, :rev => rev},
|
link_to(text, {:controller => 'repositories', :action => 'revision', :id => project, :rev => rev},
|
||||||
:title => l(:label_revision_id, format_revision(revision)))
|
:title => l(:label_revision_id, format_revision(revision)))
|
||||||
end
|
end
|
||||||
|
|
||||||
# Generates a link to a message
|
|
||||||
def link_to_message(message, options={}, html_options = nil)
|
|
||||||
link_to(
|
|
||||||
h(truncate(message.subject, :length => 60)),
|
|
||||||
{ :controller => 'messages', :action => 'show',
|
|
||||||
:board_id => message.board_id,
|
|
||||||
:id => message.root,
|
|
||||||
:r => (message.parent_id && message.id),
|
|
||||||
:anchor => (message.parent_id ? "message-#{message.id}" : nil)
|
|
||||||
}.merge(options),
|
|
||||||
html_options
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Generates a link to a project if active
|
# Generates a link to a project if active
|
||||||
# Examples:
|
# Examples:
|
||||||
#
|
#
|
||||||
@@ -191,20 +173,20 @@ module ApplicationHelper
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_page_hierarchy(pages, node=nil, options={})
|
def render_page_hierarchy(pages, node=nil)
|
||||||
content = ''
|
content = ''
|
||||||
if pages[node]
|
if pages[node]
|
||||||
content << "<ul class=\"pages-hierarchy\">\n"
|
content << "<ul class=\"pages-hierarchy\">\n"
|
||||||
pages[node].each do |page|
|
pages[node].each do |page|
|
||||||
content << "<li>"
|
content << "<li>"
|
||||||
content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title},
|
content << link_to(h(page.pretty_title), {:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title},
|
||||||
:title => (options[:timestamp] && page.updated_on ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
|
:title => (page.respond_to?(:updated_on) ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil))
|
||||||
content << "\n" + render_page_hierarchy(pages, page.id, options) if pages[page.id]
|
content << "\n" + render_page_hierarchy(pages, page.id) if pages[page.id]
|
||||||
content << "</li>\n"
|
content << "</li>\n"
|
||||||
end
|
end
|
||||||
content << "</ul>\n"
|
content << "</ul>\n"
|
||||||
end
|
end
|
||||||
content.html_safe
|
content
|
||||||
end
|
end
|
||||||
|
|
||||||
# Renders flash messages
|
# Renders flash messages
|
||||||
@@ -213,7 +195,7 @@ module ApplicationHelper
|
|||||||
flash.each do |k,v|
|
flash.each do |k,v|
|
||||||
s << content_tag('div', v, :class => "flash #{k}")
|
s << content_tag('div', v, :class => "flash #{k}")
|
||||||
end
|
end
|
||||||
s.html_safe
|
s
|
||||||
end
|
end
|
||||||
|
|
||||||
# Renders tabs and their content
|
# Renders tabs and their content
|
||||||
@@ -227,8 +209,8 @@ module ApplicationHelper
|
|||||||
|
|
||||||
# Renders the project quick-jump box
|
# Renders the project quick-jump box
|
||||||
def render_project_jump_box
|
def render_project_jump_box
|
||||||
return unless User.current.logged?
|
# Retrieve them now to avoid a COUNT query
|
||||||
projects = User.current.memberships.collect(&:project).compact.uniq
|
projects = User.current.projects.all
|
||||||
if projects.any?
|
if projects.any?
|
||||||
s = '<select onchange="if (this.value != \'\') { window.location = this.value; }">' +
|
s = '<select onchange="if (this.value != \'\') { window.location = this.value; }">' +
|
||||||
"<option value=''>#{ l(:label_jump_to_a_project) }</option>" +
|
"<option value=''>#{ l(:label_jump_to_a_project) }</option>" +
|
||||||
@@ -237,7 +219,7 @@ module ApplicationHelper
|
|||||||
{ :value => url_for(:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item) }
|
{ :value => url_for(:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item) }
|
||||||
end
|
end
|
||||||
s << '</select>'
|
s << '</select>'
|
||||||
s.html_safe
|
s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -254,7 +236,7 @@ module ApplicationHelper
|
|||||||
tag_options.merge!(yield(project)) if block_given?
|
tag_options.merge!(yield(project)) if block_given?
|
||||||
s << content_tag('option', name_prefix + h(project), tag_options)
|
s << content_tag('option', name_prefix + h(project), tag_options)
|
||||||
end
|
end
|
||||||
s.html_safe
|
s
|
||||||
end
|
end
|
||||||
|
|
||||||
# Yields the given block for each project with its level in the tree
|
# Yields the given block for each project with its level in the tree
|
||||||
@@ -285,7 +267,7 @@ module ApplicationHelper
|
|||||||
end
|
end
|
||||||
s << ("</li></ul>\n" * ancestors.size)
|
s << ("</li></ul>\n" * ancestors.size)
|
||||||
end
|
end
|
||||||
s.html_safe
|
s
|
||||||
end
|
end
|
||||||
|
|
||||||
def principals_check_box_tags(name, principals)
|
def principals_check_box_tags(name, principals)
|
||||||
@@ -293,20 +275,6 @@ module ApplicationHelper
|
|||||||
principals.sort.each do |principal|
|
principals.sort.each do |principal|
|
||||||
s << "<label>#{ check_box_tag name, principal.id, false } #{h principal}</label>\n"
|
s << "<label>#{ check_box_tag name, principal.id, false } #{h principal}</label>\n"
|
||||||
end
|
end
|
||||||
s.html_safe
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns a string for users/groups option tags
|
|
||||||
def principals_options_for_select(collection, selected=nil)
|
|
||||||
s = ''
|
|
||||||
groups = ''
|
|
||||||
collection.sort.each do |element|
|
|
||||||
selected_attribute = ' selected="selected"' if option_value_selected?(element, selected)
|
|
||||||
(element.is_a?(Group) ? groups : s) << %(<option value="#{element.id}"#{selected_attribute}>#{h element.name}</option>)
|
|
||||||
end
|
|
||||||
unless groups.empty?
|
|
||||||
s << %(<optgroup label="#{h(l(:label_group_plural))}">#{groups}</optgroup>)
|
|
||||||
end
|
|
||||||
s
|
s
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -326,11 +294,11 @@ module ApplicationHelper
|
|||||||
end
|
end
|
||||||
|
|
||||||
def html_hours(text)
|
def html_hours(text)
|
||||||
text.gsub(%r{(\d+)\.(\d+)}, '<span class="hours hours-int">\1</span><span class="hours hours-dec">.\2</span>').html_safe
|
text.gsub(%r{(\d+)\.(\d+)}, '<span class="hours hours-int">\1</span><span class="hours hours-dec">.\2</span>')
|
||||||
end
|
end
|
||||||
|
|
||||||
def authoring(created, author, options={})
|
def authoring(created, author, options={})
|
||||||
l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created)).html_safe
|
l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created))
|
||||||
end
|
end
|
||||||
|
|
||||||
def time_tag(time)
|
def time_tag(time)
|
||||||
@@ -354,24 +322,20 @@ module ApplicationHelper
|
|||||||
page_param = options.delete(:page_param) || :page
|
page_param = options.delete(:page_param) || :page
|
||||||
per_page_links = options.delete(:per_page_links)
|
per_page_links = options.delete(:per_page_links)
|
||||||
url_param = params.dup
|
url_param = params.dup
|
||||||
|
# don't reuse query params if filters are present
|
||||||
|
url_param.merge!(:fields => nil, :values => nil, :operators => nil) if url_param.delete(:set_filter)
|
||||||
|
|
||||||
html = ''
|
html = ''
|
||||||
if paginator.current.previous
|
if paginator.current.previous
|
||||||
# \xc2\xab(utf-8) = «
|
html << link_to_remote_content_update('« ' + l(:label_previous), url_param.merge(page_param => paginator.current.previous)) + ' '
|
||||||
html << link_to_content_update(
|
|
||||||
"\xc2\xab " + l(:label_previous),
|
|
||||||
url_param.merge(page_param => paginator.current.previous)) + ' '
|
|
||||||
end
|
end
|
||||||
|
|
||||||
html << (pagination_links_each(paginator, options) do |n|
|
html << (pagination_links_each(paginator, options) do |n|
|
||||||
link_to_content_update(n.to_s, url_param.merge(page_param => n))
|
link_to_remote_content_update(n.to_s, url_param.merge(page_param => n))
|
||||||
end || '')
|
end || '')
|
||||||
|
|
||||||
if paginator.current.next
|
if paginator.current.next
|
||||||
# \xc2\xbb(utf-8) = »
|
html << ' ' + link_to_remote_content_update((l(:label_next) + ' »'), url_param.merge(page_param => paginator.current.next))
|
||||||
html << ' ' + link_to_content_update(
|
|
||||||
(l(:label_next) + " \xc2\xbb"),
|
|
||||||
url_param.merge(page_param => paginator.current.next))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
unless count.nil?
|
unless count.nil?
|
||||||
@@ -381,40 +345,38 @@ module ApplicationHelper
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
html.html_safe
|
html
|
||||||
end
|
end
|
||||||
|
|
||||||
def per_page_links(selected=nil)
|
def per_page_links(selected=nil)
|
||||||
|
url_param = params.dup
|
||||||
|
url_param.clear if url_param.has_key?(:set_filter)
|
||||||
|
|
||||||
links = Setting.per_page_options_array.collect do |n|
|
links = Setting.per_page_options_array.collect do |n|
|
||||||
n == selected ? n : link_to_content_update(n, params.merge(:per_page => n))
|
n == selected ? n : link_to_remote(n, {:update => "content",
|
||||||
|
:url => params.dup.merge(:per_page => n),
|
||||||
|
:method => :get},
|
||||||
|
{:href => url_for(url_param.merge(:per_page => n))})
|
||||||
end
|
end
|
||||||
links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil
|
links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def reorder_links(name, url, method = :post)
|
def reorder_links(name, url)
|
||||||
link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)),
|
link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)), url.merge({"#{name}[move_to]" => 'highest'}), :method => :post, :title => l(:label_sort_highest)) +
|
||||||
url.merge({"#{name}[move_to]" => 'highest'}),
|
link_to(image_tag('1uparrow.png', :alt => l(:label_sort_higher)), url.merge({"#{name}[move_to]" => 'higher'}), :method => :post, :title => l(:label_sort_higher)) +
|
||||||
:method => method, :title => l(:label_sort_highest)) +
|
link_to(image_tag('1downarrow.png', :alt => l(:label_sort_lower)), url.merge({"#{name}[move_to]" => 'lower'}), :method => :post, :title => l(:label_sort_lower)) +
|
||||||
link_to(image_tag('1uparrow.png', :alt => l(:label_sort_higher)),
|
link_to(image_tag('2downarrow.png', :alt => l(:label_sort_lowest)), url.merge({"#{name}[move_to]" => 'lowest'}), :method => :post, :title => l(:label_sort_lowest))
|
||||||
url.merge({"#{name}[move_to]" => 'higher'}),
|
|
||||||
:method => method, :title => l(:label_sort_higher)) +
|
|
||||||
link_to(image_tag('1downarrow.png', :alt => l(:label_sort_lower)),
|
|
||||||
url.merge({"#{name}[move_to]" => 'lower'}),
|
|
||||||
:method => method, :title => l(:label_sort_lower)) +
|
|
||||||
link_to(image_tag('2downarrow.png', :alt => l(:label_sort_lowest)),
|
|
||||||
url.merge({"#{name}[move_to]" => 'lowest'}),
|
|
||||||
:method => method, :title => l(:label_sort_lowest))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def breadcrumb(*args)
|
def breadcrumb(*args)
|
||||||
elements = args.flatten
|
elements = args.flatten
|
||||||
elements.any? ? content_tag('p', (args.join(" \xc2\xbb ") + " \xc2\xbb ").html_safe, :class => 'breadcrumb') : nil
|
elements.any? ? content_tag('p', args.join(' » ') + ' » ', :class => 'breadcrumb') : nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def other_formats_links(&block)
|
def other_formats_links(&block)
|
||||||
concat('<p class="other-formats">'.html_safe + l(:label_export_to))
|
concat('<p class="other-formats">' + l(:label_export_to))
|
||||||
yield Redmine::Views::OtherFormatsBuilder.new(self)
|
yield Redmine::Views::OtherFormatsBuilder.new(self)
|
||||||
concat('</p>'.html_safe)
|
concat('</p>')
|
||||||
end
|
end
|
||||||
|
|
||||||
def page_header_title
|
def page_header_title
|
||||||
@@ -422,26 +384,27 @@ module ApplicationHelper
|
|||||||
h(Setting.app_title)
|
h(Setting.app_title)
|
||||||
else
|
else
|
||||||
b = []
|
b = []
|
||||||
ancestors = (@project.root? ? [] : @project.ancestors.visible.all)
|
ancestors = (@project.root? ? [] : @project.ancestors.visible)
|
||||||
if ancestors.any?
|
if ancestors.any?
|
||||||
root = ancestors.shift
|
root = ancestors.shift
|
||||||
b << link_to_project(root, {:jump => current_menu_item}, :class => 'root')
|
b << link_to_project(root, {:jump => current_menu_item}, :class => 'root')
|
||||||
if ancestors.size > 2
|
if ancestors.size > 2
|
||||||
b << "\xe2\x80\xa6"
|
b << '…'
|
||||||
ancestors = ancestors[-2, 2]
|
ancestors = ancestors[-2, 2]
|
||||||
end
|
end
|
||||||
b += ancestors.collect {|p| link_to_project(p, {:jump => current_menu_item}, :class => 'ancestor') }
|
b += ancestors.collect {|p| link_to_project(p, {:jump => current_menu_item}, :class => 'ancestor') }
|
||||||
end
|
end
|
||||||
b << h(@project)
|
b << h(@project)
|
||||||
b.join(" \xc2\xbb ").html_safe
|
b.join(' » ')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def html_title(*args)
|
def html_title(*args)
|
||||||
if args.empty?
|
if args.empty?
|
||||||
title = @html_title || []
|
title = []
|
||||||
title << @project.name if @project
|
title << @project.name if @project
|
||||||
title << Setting.app_title unless Setting.app_title == title.last
|
title += @html_title if @html_title
|
||||||
|
title << Setting.app_title
|
||||||
title.select {|t| !t.blank? }.join(' - ')
|
title.select {|t| !t.blank? }.join(' - ')
|
||||||
else
|
else
|
||||||
@html_title ||= []
|
@html_title ||= []
|
||||||
@@ -487,19 +450,14 @@ module ApplicationHelper
|
|||||||
project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)
|
project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)
|
||||||
only_path = options.delete(:only_path) == false ? false : true
|
only_path = options.delete(:only_path) == false ? false : true
|
||||||
|
|
||||||
text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr)
|
text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) { |macro, args| exec_macro(macro, obj, args) }
|
||||||
|
|
||||||
@parsed_headings = []
|
@parsed_headings = []
|
||||||
@heading_anchors = {}
|
|
||||||
@current_section = 0 if options[:edit_section_links]
|
|
||||||
|
|
||||||
parse_sections(text, project, obj, attr, only_path, options)
|
|
||||||
text = parse_non_pre_blocks(text) do |text|
|
text = parse_non_pre_blocks(text) do |text|
|
||||||
[:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_macros].each do |method_name|
|
[:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_headings].each do |method_name|
|
||||||
send method_name, text, project, obj, attr, only_path, options
|
send method_name, text, project, obj, attr, only_path, options
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
parse_headings(text, project, obj, attr, only_path, options)
|
|
||||||
|
|
||||||
if @parsed_headings.any?
|
if @parsed_headings.any?
|
||||||
replace_toc(text, @parsed_headings)
|
replace_toc(text, @parsed_headings)
|
||||||
@@ -534,26 +492,26 @@ module ApplicationHelper
|
|||||||
while tag = tags.pop
|
while tag = tags.pop
|
||||||
parsed << "</#{tag}>"
|
parsed << "</#{tag}>"
|
||||||
end
|
end
|
||||||
parsed.html_safe
|
parsed
|
||||||
end
|
end
|
||||||
|
|
||||||
def parse_inline_attachments(text, project, obj, attr, only_path, options)
|
def parse_inline_attachments(text, project, obj, attr, only_path, options)
|
||||||
# when using an image link, try to use an attachment, if possible
|
# when using an image link, try to use an attachment, if possible
|
||||||
if options[:attachments] || (obj && obj.respond_to?(:attachments))
|
if options[:attachments] || (obj && obj.respond_to?(:attachments))
|
||||||
attachments = options[:attachments] || obj.attachments
|
attachments = nil
|
||||||
text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m|
|
text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m|
|
||||||
filename, ext, alt, alttext = $1.downcase, $2, $3, $4
|
filename, ext, alt, alttext = $1.downcase, $2, $3, $4
|
||||||
|
attachments ||= (options[:attachments] || obj.attachments).sort_by(&:created_on).reverse
|
||||||
# search for the picture in attachments
|
# search for the picture in attachments
|
||||||
if found = Attachment.latest_attach(attachments, filename)
|
if found = attachments.detect { |att| att.filename.downcase == filename }
|
||||||
image_url = url_for :only_path => only_path, :controller => 'attachments',
|
image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found
|
||||||
:action => 'download', :id => found
|
|
||||||
desc = found.description.to_s.gsub('"', '')
|
desc = found.description.to_s.gsub('"', '')
|
||||||
if !desc.blank? && alttext.blank?
|
if !desc.blank? && alttext.blank?
|
||||||
alt = " title=\"#{desc}\" alt=\"#{desc}\""
|
alt = " title=\"#{desc}\" alt=\"#{desc}\""
|
||||||
end
|
end
|
||||||
"src=\"#{image_url}\"#{alt}".html_safe
|
"src=\"#{image_url}\"#{alt}"
|
||||||
else
|
else
|
||||||
m.html_safe
|
m
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -586,27 +544,22 @@ module ApplicationHelper
|
|||||||
if page =~ /^(.+?)\#(.+)$/
|
if page =~ /^(.+?)\#(.+)$/
|
||||||
page, anchor = $1, $2
|
page, anchor = $1, $2
|
||||||
end
|
end
|
||||||
anchor = sanitize_anchor_name(anchor) if anchor.present?
|
|
||||||
# check if page exists
|
# check if page exists
|
||||||
wiki_page = link_project.wiki.find_page(page)
|
wiki_page = link_project.wiki.find_page(page)
|
||||||
url = if anchor.present? && wiki_page.present? && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)) && obj.page == wiki_page
|
url = case options[:wiki_links]
|
||||||
"##{anchor}"
|
when :local; "#{title}.html"
|
||||||
else
|
when :anchor; "##{title}" # used for single-file wiki export
|
||||||
case options[:wiki_links]
|
|
||||||
when :local; "#{page.present? ? Wiki.titleize(page) : ''}.html" + (anchor.present? ? "##{anchor}" : '')
|
|
||||||
when :anchor; "##{page.present? ? Wiki.titleize(page) : title}" + (anchor.present? ? "_#{anchor}" : '') # used for single-file wiki export
|
|
||||||
else
|
else
|
||||||
wiki_page_id = page.present? ? Wiki.titleize(page) : nil
|
wiki_page_id = page.present? ? Wiki.titleize(page) : nil
|
||||||
url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project, :id => wiki_page_id, :anchor => anchor)
|
url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project, :id => wiki_page_id, :anchor => anchor)
|
||||||
end
|
end
|
||||||
end
|
link_to((title || page), url, :class => ('wiki-page' + (wiki_page ? '' : ' new')))
|
||||||
link_to(title.present? ? title.html_safe : h(page), url, :class => ('wiki-page' + (wiki_page ? '' : ' new')))
|
|
||||||
else
|
else
|
||||||
# project or wiki doesn't exist
|
# project or wiki doesn't exist
|
||||||
all.html_safe
|
all
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
all.html_safe
|
all
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -635,26 +588,16 @@ module ApplicationHelper
|
|||||||
# source:some/file#L120 -> Link to line 120 of the file
|
# source:some/file#L120 -> Link to line 120 of the file
|
||||||
# source:some/file@52#L120 -> Link to line 120 of the file's revision 52
|
# source:some/file@52#L120 -> Link to line 120 of the file's revision 52
|
||||||
# export:some/file -> Force the download of the file
|
# export:some/file -> Force the download of the file
|
||||||
# Forum messages:
|
# Forum messages:
|
||||||
# message#1218 -> Link to message with id 1218
|
# message#1218 -> Link to message with id 1218
|
||||||
#
|
|
||||||
# Links can refer other objects from other projects, using project identifier:
|
|
||||||
# identifier:r52
|
|
||||||
# identifier:document:"Some document"
|
|
||||||
# identifier:version:1.0.0
|
|
||||||
# identifier:source:some/file
|
|
||||||
def parse_redmine_links(text, project, obj, attr, only_path, options)
|
def parse_redmine_links(text, project, obj, attr, only_path, options)
|
||||||
text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-]+):)?(attachment|document|version|forum|news|commit|source|export|message|project)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|\]|<|$)}) do |m|
|
text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(attachment|document|version|commit|source|export|message|project)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|\]|<|$)}) do |m|
|
||||||
leading, esc, project_prefix, project_identifier, prefix, sep, identifier = $1, $2, $3, $4, $5, $7 || $9, $8 || $10
|
leading, esc, prefix, sep, identifier = $1, $2, $3, $5 || $7, $6 || $8
|
||||||
link = nil
|
link = nil
|
||||||
if project_identifier
|
|
||||||
project = Project.visible.find_by_identifier(project_identifier)
|
|
||||||
end
|
|
||||||
if esc.nil?
|
if esc.nil?
|
||||||
if prefix.nil? && sep == 'r'
|
if prefix.nil? && sep == 'r'
|
||||||
# project.changesets.visible raises an SQL error because of a double join on repositories
|
if project && (changeset = project.changesets.find_by_revision(identifier))
|
||||||
if project && project.repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(project.repository.id, identifier))
|
link = link_to("r#{identifier}", {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision},
|
||||||
link = link_to(h("#{project_prefix}r#{identifier}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision},
|
|
||||||
:class => 'changeset',
|
:class => 'changeset',
|
||||||
:title => truncate_single_line(changeset.comments, :length => 100))
|
:title => truncate_single_line(changeset.comments, :length => 100))
|
||||||
end
|
end
|
||||||
@@ -668,28 +611,24 @@ module ApplicationHelper
|
|||||||
:title => "#{truncate(issue.subject, :length => 100)} (#{issue.status.name})")
|
:title => "#{truncate(issue.subject, :length => 100)} (#{issue.status.name})")
|
||||||
end
|
end
|
||||||
when 'document'
|
when 'document'
|
||||||
if document = Document.visible.find_by_id(oid)
|
if document = Document.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current))
|
||||||
link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
|
link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
|
||||||
:class => 'document'
|
:class => 'document'
|
||||||
end
|
end
|
||||||
when 'version'
|
when 'version'
|
||||||
if version = Version.visible.find_by_id(oid)
|
if version = Version.find_by_id(oid, :include => [:project], :conditions => Project.visible_by(User.current))
|
||||||
link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
|
link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
|
||||||
:class => 'version'
|
:class => 'version'
|
||||||
end
|
end
|
||||||
when 'message'
|
when 'message'
|
||||||
if message = Message.visible.find_by_id(oid, :include => :parent)
|
if message = Message.find_by_id(oid, :include => [:parent, {:board => :project}], :conditions => Project.visible_by(User.current))
|
||||||
link = link_to_message(message, {:only_path => only_path}, :class => 'message')
|
link = link_to h(truncate(message.subject, :length => 60)), {:only_path => only_path,
|
||||||
end
|
:controller => 'messages',
|
||||||
when 'forum'
|
:action => 'show',
|
||||||
if board = Board.visible.find_by_id(oid)
|
:board_id => message.board,
|
||||||
link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project},
|
:id => message.root,
|
||||||
:class => 'board'
|
:anchor => (message.parent ? "message-#{message.id}" : nil)},
|
||||||
end
|
:class => 'message'
|
||||||
when 'news'
|
|
||||||
if news = News.visible.find_by_id(oid)
|
|
||||||
link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news},
|
|
||||||
:class => 'news'
|
|
||||||
end
|
end
|
||||||
when 'project'
|
when 'project'
|
||||||
if p = Project.visible.find_by_id(oid)
|
if p = Project.visible.find_by_id(oid)
|
||||||
@@ -701,36 +640,26 @@ module ApplicationHelper
|
|||||||
name = identifier.gsub(%r{^"(.*)"$}, "\\1")
|
name = identifier.gsub(%r{^"(.*)"$}, "\\1")
|
||||||
case prefix
|
case prefix
|
||||||
when 'document'
|
when 'document'
|
||||||
if project && document = project.documents.visible.find_by_title(name)
|
if project && document = project.documents.find_by_title(name)
|
||||||
link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
|
link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document},
|
||||||
:class => 'document'
|
:class => 'document'
|
||||||
end
|
end
|
||||||
when 'version'
|
when 'version'
|
||||||
if project && version = project.versions.visible.find_by_name(name)
|
if project && version = project.versions.find_by_name(name)
|
||||||
link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
|
link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
|
||||||
:class => 'version'
|
:class => 'version'
|
||||||
end
|
end
|
||||||
when 'forum'
|
|
||||||
if project && board = project.boards.visible.find_by_name(name)
|
|
||||||
link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project},
|
|
||||||
:class => 'board'
|
|
||||||
end
|
|
||||||
when 'news'
|
|
||||||
if project && news = project.news.visible.find_by_title(name)
|
|
||||||
link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news},
|
|
||||||
:class => 'news'
|
|
||||||
end
|
|
||||||
when 'commit'
|
when 'commit'
|
||||||
if project && project.repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", project.repository.id, "#{name}%"]))
|
if project && (changeset = project.changesets.find(:first, :conditions => ["scmid LIKE ?", "#{name}%"]))
|
||||||
link = link_to h("#{project_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.identifier},
|
link = link_to h("#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision},
|
||||||
:class => 'changeset',
|
:class => 'changeset',
|
||||||
:title => truncate_single_line(h(changeset.comments), :length => 100)
|
:title => truncate_single_line(changeset.comments, :length => 100)
|
||||||
end
|
end
|
||||||
when 'source', 'export'
|
when 'source', 'export'
|
||||||
if project && project.repository && User.current.allowed_to?(:browse_repository, project)
|
if project && project.repository
|
||||||
name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
|
name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
|
||||||
path, rev, anchor = $1, $3, $5
|
path, rev, anchor = $1, $3, $5
|
||||||
link = link_to h("#{project_prefix}#{prefix}:#{name}"), {:controller => 'repositories', :action => 'entry', :id => project,
|
link = link_to h("#{prefix}:#{name}"), {:controller => 'repositories', :action => 'entry', :id => project,
|
||||||
:path => to_path_param(path),
|
:path => to_path_param(path),
|
||||||
:rev => rev,
|
:rev => rev,
|
||||||
:anchor => anchor,
|
:anchor => anchor,
|
||||||
@@ -750,26 +679,11 @@ module ApplicationHelper
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
(leading + (link || "#{project_prefix}#{prefix}#{sep}#{identifier}")).html_safe
|
leading + (link || "#{prefix}#{sep}#{identifier}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
HEADING_RE = /(<h(1|2|3|4)( [^>]+)?>(.+?)<\/h(1|2|3|4)>)/i unless const_defined?(:HEADING_RE)
|
HEADING_RE = /<h(1|2|3|4)( [^>]+)?>(.+?)<\/h(1|2|3|4)>/i unless const_defined?(:HEADING_RE)
|
||||||
|
|
||||||
def parse_sections(text, project, obj, attr, only_path, options)
|
|
||||||
return unless options[:edit_section_links]
|
|
||||||
text.gsub!(HEADING_RE) do
|
|
||||||
@current_section += 1
|
|
||||||
if @current_section > 1
|
|
||||||
content_tag('div',
|
|
||||||
link_to(image_tag('edit.png'), options[:edit_section_links].merge(:section => @current_section)),
|
|
||||||
:class => 'contextual',
|
|
||||||
:title => l(:button_edit_section)) + $1
|
|
||||||
else
|
|
||||||
$1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Headings and TOC
|
# Headings and TOC
|
||||||
# Adds ids and links to headings unless options[:headings] is set to false
|
# Adds ids and links to headings unless options[:headings] is set to false
|
||||||
@@ -777,45 +691,11 @@ module ApplicationHelper
|
|||||||
return if options[:headings] == false
|
return if options[:headings] == false
|
||||||
|
|
||||||
text.gsub!(HEADING_RE) do
|
text.gsub!(HEADING_RE) do
|
||||||
level, attrs, content = $2.to_i, $3, $4
|
level, attrs, content = $1.to_i, $2, $3
|
||||||
item = strip_tags(content).strip
|
item = strip_tags(content).strip
|
||||||
anchor = sanitize_anchor_name(item)
|
anchor = item.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
|
||||||
# used for single-file wiki export
|
|
||||||
anchor = "#{obj.page.title}_#{anchor}" if options[:wiki_links] == :anchor && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version))
|
|
||||||
@heading_anchors[anchor] ||= 0
|
|
||||||
idx = (@heading_anchors[anchor] += 1)
|
|
||||||
if idx > 1
|
|
||||||
anchor = "#{anchor}-#{idx}"
|
|
||||||
end
|
|
||||||
@parsed_headings << [level, anchor, item]
|
@parsed_headings << [level, anchor, item]
|
||||||
"<a name=\"#{anchor}\"></a>\n<h#{level} #{attrs}>#{content}<a href=\"##{anchor}\" class=\"wiki-anchor\">¶</a></h#{level}>"
|
"<h#{level} #{attrs} id=\"#{anchor}\">#{content}<a href=\"##{anchor}\" class=\"wiki-anchor\">¶</a></h#{level}>"
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
MACROS_RE = /
|
|
||||||
(!)? # escaping
|
|
||||||
(
|
|
||||||
\{\{ # opening tag
|
|
||||||
([\w]+) # macro name
|
|
||||||
(\(([^\}]*)\))? # optional arguments
|
|
||||||
\}\} # closing tag
|
|
||||||
)
|
|
||||||
/x unless const_defined?(:MACROS_RE)
|
|
||||||
|
|
||||||
# Macros substitution
|
|
||||||
def parse_macros(text, project, obj, attr, only_path, options)
|
|
||||||
text.gsub!(MACROS_RE) do
|
|
||||||
esc, all, macro = $1, $2, $3.downcase
|
|
||||||
args = ($5 || '').split(',').each(&:strip)
|
|
||||||
if esc.nil?
|
|
||||||
begin
|
|
||||||
exec_macro(macro, obj, args)
|
|
||||||
rescue => e
|
|
||||||
"<div class=\"flash error\">Error executing the <strong>#{macro}</strong> macro (#{e})</div>"
|
|
||||||
end || all
|
|
||||||
else
|
|
||||||
all
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -857,8 +737,7 @@ module ApplicationHelper
|
|||||||
text.to_s.
|
text.to_s.
|
||||||
gsub(/\r\n?/, "\n"). # \r\n and \r -> \n
|
gsub(/\r\n?/, "\n"). # \r\n and \r -> \n
|
||||||
gsub(/\n\n+/, "<br /><br />"). # 2+ newline -> 2 br
|
gsub(/\n\n+/, "<br /><br />"). # 2+ newline -> 2 br
|
||||||
gsub(/([^\n]\n)(?=[^\n])/, '\1<br />'). # 1 newline -> br
|
gsub(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
|
||||||
html_safe
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def lang_options_for_select(blank=true)
|
def lang_options_for_select(blank=true)
|
||||||
@@ -871,20 +750,10 @@ module ApplicationHelper
|
|||||||
content_tag("label", label_text)
|
content_tag("label", label_text)
|
||||||
end
|
end
|
||||||
|
|
||||||
def labelled_tabular_form_for(*args, &proc)
|
def labelled_tabular_form_for(name, object, options, &proc)
|
||||||
args << {} unless args.last.is_a?(Hash)
|
|
||||||
options = args.last
|
|
||||||
options[:html] ||= {}
|
options[:html] ||= {}
|
||||||
options[:html][:class] = 'tabular' unless options[:html].has_key?(:class)
|
options[:html][:class] = 'tabular' unless options[:html].has_key?(:class)
|
||||||
options.merge!({:builder => TabularFormBuilder})
|
form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)
|
||||||
form_for(*args, &proc)
|
|
||||||
end
|
|
||||||
|
|
||||||
def labelled_form_for(*args, &proc)
|
|
||||||
args << {} unless args.last.is_a?(Hash)
|
|
||||||
options = args.last
|
|
||||||
options.merge!({:builder => TabularFormBuilder})
|
|
||||||
form_for(*args, &proc)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def back_url_hidden_field_tag
|
def back_url_hidden_field_tag
|
||||||
@@ -895,7 +764,7 @@ module ApplicationHelper
|
|||||||
|
|
||||||
def check_all_links(form_name)
|
def check_all_links(form_name)
|
||||||
link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
|
link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
|
||||||
" | ".html_safe +
|
" | " +
|
||||||
link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
|
link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -908,11 +777,11 @@ module ApplicationHelper
|
|||||||
legend = options[:legend] || ''
|
legend = options[:legend] || ''
|
||||||
content_tag('table',
|
content_tag('table',
|
||||||
content_tag('tr',
|
content_tag('tr',
|
||||||
(pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : ''.html_safe) +
|
(pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : '') +
|
||||||
(pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : ''.html_safe) +
|
(pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : '') +
|
||||||
(pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : ''.html_safe)
|
(pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : '')
|
||||||
), :class => 'progress', :style => "width: #{width};").html_safe +
|
), :class => 'progress', :style => "width: #{width};") +
|
||||||
content_tag('p', legend, :class => 'pourcent').html_safe
|
content_tag('p', legend, :class => 'pourcent')
|
||||||
end
|
end
|
||||||
|
|
||||||
def checked_image(checked=true)
|
def checked_image(checked=true)
|
||||||
@@ -950,7 +819,7 @@ module ApplicationHelper
|
|||||||
options[:class] << ' disabled'
|
options[:class] << ' disabled'
|
||||||
url = '#'
|
url = '#'
|
||||||
end
|
end
|
||||||
link_to h(name), url, options
|
link_to name, url, options
|
||||||
end
|
end
|
||||||
|
|
||||||
def calendar_for(field_id)
|
def calendar_for(field_id)
|
||||||
@@ -968,8 +837,6 @@ module ApplicationHelper
|
|||||||
'Calendar._FD = 1;' # Monday
|
'Calendar._FD = 1;' # Monday
|
||||||
when 7
|
when 7
|
||||||
'Calendar._FD = 0;' # Sunday
|
'Calendar._FD = 0;' # Sunday
|
||||||
when 6
|
|
||||||
'Calendar._FD = 6;' # Saturday
|
|
||||||
else
|
else
|
||||||
'' # use language
|
'' # use language
|
||||||
end
|
end
|
||||||
@@ -993,10 +860,6 @@ module ApplicationHelper
|
|||||||
(@has_content && @has_content[name]) || false
|
(@has_content && @has_content[name]) || false
|
||||||
end
|
end
|
||||||
|
|
||||||
def email_delivery_enabled?
|
|
||||||
!!ActionMailer::Base.perform_deliveries
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the avatar image tag for the given +user+ if avatars are enabled
|
# Returns the avatar image tag for the given +user+ if avatars are enabled
|
||||||
# +user+ can be a User or a string that will be scanned for an email address (eg. 'joe <joe@foo.bar>')
|
# +user+ can be a User or a string that will be scanned for an email address (eg. 'joe <joe@foo.bar>')
|
||||||
def avatar(user, options = { })
|
def avatar(user, options = { })
|
||||||
@@ -1014,25 +877,8 @@ module ApplicationHelper
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def sanitize_anchor_name(anchor)
|
|
||||||
anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the javascript tags that are included in the html layout head
|
|
||||||
def javascript_heads
|
|
||||||
tags = javascript_include_tag(:defaults)
|
|
||||||
unless User.current.pref.warn_on_leaving_unsaved == '0'
|
|
||||||
tags << "\n".html_safe + javascript_tag("Event.observe(window, 'load', function(){ new WarnLeavingUnsaved('#{escape_javascript( l(:text_warn_on_leaving_unsaved) )}'); });")
|
|
||||||
end
|
|
||||||
tags
|
|
||||||
end
|
|
||||||
|
|
||||||
def favicon
|
def favicon
|
||||||
"<link rel='shortcut icon' href='#{image_path('/favicon.ico')}' />".html_safe
|
"<link rel='shortcut icon' href='#{image_path('/favicon.ico')}' />"
|
||||||
end
|
|
||||||
|
|
||||||
def robot_exclusion_tag
|
|
||||||
'<meta name="robots" content="noindex,follow,noarchive" />'.html_safe
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns true if arg is expected in the API response
|
# Returns true if arg is expected in the API response
|
||||||
@@ -1065,7 +911,11 @@ module ApplicationHelper
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
def link_to_content_update(text, url_params = {}, html_options = {})
|
def link_to_remote_content_update(text, url_params)
|
||||||
link_to(text, url_params, html_options)
|
link_to_remote(text,
|
||||||
|
{:url => url_params, :method => :get, :update => 'content', :complete => 'window.scrollTo(0,0)'},
|
||||||
|
{:href => url_for(:params => url_params)}
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -30,16 +28,7 @@ module AttachmentsHelper
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_api_attachment(attachment, api)
|
def to_utf8(str)
|
||||||
api.attachment do
|
str
|
||||||
api.id attachment.id
|
|
||||||
api.filename attachment.filename
|
|
||||||
api.filesize attachment.filesize
|
|
||||||
api.content_type attachment.content_type
|
|
||||||
api.description attachment.description
|
|
||||||
api.content_url url_for(:controller => 'attachments', :action => 'download', :id => attachment, :filename => attachment.filename, :only_path => false)
|
|
||||||
api.author(:id => attachment.author.id, :name => attachment.author.name) if attachment.author
|
|
||||||
api.created_on attachment.created_on
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,22 +1,3 @@
|
|||||||
# encoding: utf-8
|
|
||||||
#
|
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 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 CalendarsHelper
|
module CalendarsHelper
|
||||||
def link_to_previous_month(year, month, options={})
|
def link_to_previous_month(year, month, options={})
|
||||||
target_year, target_month = if month == 1
|
target_year, target_month = if month == 1
|
||||||
@@ -31,8 +12,7 @@ module CalendarsHelper
|
|||||||
"#{month_name(target_month)}"
|
"#{month_name(target_month)}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# \xc2\xab(utf-8) = «
|
link_to_month(('« ' + name), target_year, target_month, options)
|
||||||
link_to_month(("\xc2\xab " + name), target_year, target_month, options)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def link_to_next_month(year, month, options={})
|
def link_to_next_month(year, month, options={})
|
||||||
@@ -48,11 +28,18 @@ module CalendarsHelper
|
|||||||
"#{month_name(target_month)}"
|
"#{month_name(target_month)}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# \xc2\xbb(utf-8) = »
|
link_to_month((name + ' »'), target_year, target_month, options)
|
||||||
link_to_month((name + " \xc2\xbb"), target_year, target_month, options)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def link_to_month(link_name, year, month, options={})
|
def link_to_month(link_name, year, month, options={})
|
||||||
link_to_content_update(h(link_name), params.merge(:year => year, :month => month))
|
project_id = options[:project].present? ? options[:project].to_param : nil
|
||||||
|
|
||||||
|
link_target = calendar_path(:year => year, :month => month, :project_id => project_id)
|
||||||
|
|
||||||
|
link_to_remote(link_name,
|
||||||
|
{:update => "content", :url => link_target, :method => :put},
|
||||||
|
{:href => link_target})
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# encoding: utf-8
|
|
||||||
#
|
|
||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
@@ -51,7 +49,7 @@ module CustomFieldsHelper
|
|||||||
blank_option = custom_field.is_required? ?
|
blank_option = custom_field.is_required? ?
|
||||||
(custom_field.default_value.blank? ? "<option value=\"\">--- #{l(:actionview_instancetag_blank_option)} ---</option>" : '') :
|
(custom_field.default_value.blank? ? "<option value=\"\">--- #{l(:actionview_instancetag_blank_option)} ---</option>" : '') :
|
||||||
'<option></option>'
|
'<option></option>'
|
||||||
select_tag(field_name, blank_option + options_for_select(custom_field.possible_values_options(custom_value.customized), custom_value.value), :id => field_id)
|
select_tag(field_name, blank_option + options_for_select(custom_field.possible_values, custom_value.value), :id => field_id)
|
||||||
else
|
else
|
||||||
text_field_tag(field_name, custom_value.value, :id => field_id)
|
text_field_tag(field_name, custom_value.value, :id => field_id)
|
||||||
end
|
end
|
||||||
@@ -59,8 +57,8 @@ module CustomFieldsHelper
|
|||||||
|
|
||||||
# Return custom field label tag
|
# Return custom field label tag
|
||||||
def custom_field_label_tag(name, custom_value)
|
def custom_field_label_tag(name, custom_value)
|
||||||
content_tag "label", h(custom_value.custom_field.name) +
|
content_tag "label", custom_value.custom_field.name +
|
||||||
(custom_value.custom_field.is_required? ? " <span class=\"required\">*</span>".html_safe : ""),
|
(custom_value.custom_field.is_required? ? " <span class=\"required\">*</span>" : ""),
|
||||||
:for => "#{name}_custom_field_values_#{custom_value.custom_field.id}",
|
:for => "#{name}_custom_field_values_#{custom_value.custom_field.id}",
|
||||||
:class => (custom_value.errors.empty? ? nil : "error" )
|
:class => (custom_value.errors.empty? ? nil : "error" )
|
||||||
end
|
end
|
||||||
@@ -70,7 +68,7 @@ module CustomFieldsHelper
|
|||||||
custom_field_label_tag(name, custom_value) + custom_field_tag(name, custom_value)
|
custom_field_label_tag(name, custom_value) + custom_field_tag(name, custom_value)
|
||||||
end
|
end
|
||||||
|
|
||||||
def custom_field_tag_for_bulk_edit(name, custom_field, projects=nil)
|
def custom_field_tag_for_bulk_edit(name, custom_field)
|
||||||
field_name = "#{name}[custom_field_values][#{custom_field.id}]"
|
field_name = "#{name}[custom_field_values][#{custom_field.id}]"
|
||||||
field_id = "#{name}_custom_field_values_#{custom_field.id}"
|
field_id = "#{name}_custom_field_values_#{custom_field.id}"
|
||||||
field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format)
|
field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format)
|
||||||
@@ -85,7 +83,7 @@ module CustomFieldsHelper
|
|||||||
[l(:general_text_yes), '1'],
|
[l(:general_text_yes), '1'],
|
||||||
[l(:general_text_no), '0']]), :id => field_id)
|
[l(:general_text_no), '0']]), :id => field_id)
|
||||||
when "list"
|
when "list"
|
||||||
select_tag(field_name, options_for_select([[l(:label_no_change_option), '']] + custom_field.possible_values_options(projects)), :id => field_id)
|
select_tag(field_name, options_for_select([[l(:label_no_change_option), '']] + custom_field.possible_values), :id => field_id)
|
||||||
else
|
else
|
||||||
text_field_tag(field_name, '', :id => field_id)
|
text_field_tag(field_name, '', :id => field_id)
|
||||||
end
|
end
|
||||||
@@ -103,8 +101,8 @@ module CustomFieldsHelper
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Return an array of custom field formats which can be used in select_tag
|
# Return an array of custom field formats which can be used in select_tag
|
||||||
def custom_field_formats_for_select(custom_field)
|
def custom_field_formats_for_select
|
||||||
Redmine::CustomFieldFormat.as_select(custom_field.class.customized_class.name)
|
Redmine::CustomFieldFormat.as_select
|
||||||
end
|
end
|
||||||
|
|
||||||
# Renders the custom_values in api views
|
# Renders the custom_values in api views
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
+18
-12
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -23,21 +21,29 @@ module GanttHelper
|
|||||||
case in_or_out
|
case in_or_out
|
||||||
when :in
|
when :in
|
||||||
if gantt.zoom < 4
|
if gantt.zoom < 4
|
||||||
link_to_content_update l(:text_zoom_in),
|
link_to_remote(l(:text_zoom_in),
|
||||||
params.merge(gantt.params.merge(:zoom => (gantt.zoom+1))),
|
{:url => gantt.params.merge(:zoom => (gantt.zoom+1)), :method => :get, :update => 'content'},
|
||||||
:class => 'icon icon-zoom-in'
|
{:href => url_for(gantt.params.merge(:zoom => (gantt.zoom+1))),
|
||||||
|
:class => 'icon icon-zoom-in'})
|
||||||
else
|
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')
|
||||||
end
|
end
|
||||||
|
|
||||||
when :out
|
when :out
|
||||||
if gantt.zoom > 1
|
if gantt.zoom > 1
|
||||||
link_to_content_update l(:text_zoom_out),
|
link_to_remote(l(:text_zoom_out),
|
||||||
params.merge(gantt.params.merge(:zoom => (gantt.zoom-1))),
|
{:url => gantt.params.merge(:zoom => (gantt.zoom-1)), :method => :get, :update => 'content'},
|
||||||
:class => 'icon icon-zoom-out'
|
{:href => url_for(gantt.params.merge(:zoom => (gantt.zoom-1))),
|
||||||
|
:class => 'icon icon-zoom-out'})
|
||||||
else
|
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')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def number_of_issues_on_versions(gantt)
|
||||||
|
versions = gantt.events.collect {|event| (event.is_a? Version) ? event : nil}.compact
|
||||||
|
|
||||||
|
versions.sum {|v| v.fixed_issues.for_gantt.with_query(@query).count}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
|
||||||
#
|
|
||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2009 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,4 +1,2 @@
|
|||||||
# encoding: utf-8
|
|
||||||
#
|
|
||||||
module IssueMovesHelper
|
module IssueMovesHelper
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
+64
-105
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -48,38 +46,28 @@ module IssuesHelper
|
|||||||
@cached_label_priority ||= l(:field_priority)
|
@cached_label_priority ||= l(:field_priority)
|
||||||
@cached_label_project ||= l(:field_project)
|
@cached_label_project ||= l(:field_project)
|
||||||
|
|
||||||
(link_to_issue(issue) + "<br /><br />" +
|
link_to_issue(issue) + "<br /><br />" +
|
||||||
"<strong>#{@cached_label_project}</strong>: #{link_to_project(issue.project)}<br />" +
|
"<strong>#{@cached_label_project}</strong>: #{link_to_project(issue.project)}<br />" +
|
||||||
"<strong>#{@cached_label_status}</strong>: #{h(issue.status.name)}<br />" +
|
"<strong>#{@cached_label_status}</strong>: #{issue.status.name}<br />" +
|
||||||
"<strong>#{@cached_label_start_date}</strong>: #{format_date(issue.start_date)}<br />" +
|
"<strong>#{@cached_label_start_date}</strong>: #{format_date(issue.start_date)}<br />" +
|
||||||
"<strong>#{@cached_label_due_date}</strong>: #{format_date(issue.due_date)}<br />" +
|
"<strong>#{@cached_label_due_date}</strong>: #{format_date(issue.due_date)}<br />" +
|
||||||
"<strong>#{@cached_label_assigned_to}</strong>: #{h(issue.assigned_to)}<br />" +
|
"<strong>#{@cached_label_assigned_to}</strong>: #{issue.assigned_to}<br />" +
|
||||||
"<strong>#{@cached_label_priority}</strong>: #{h(issue.priority.name)}").html_safe
|
"<strong>#{@cached_label_priority}</strong>: #{issue.priority.name}"
|
||||||
end
|
|
||||||
|
|
||||||
def issue_heading(issue)
|
|
||||||
h("#{issue.tracker} ##{issue.id}")
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_issue_subject_with_tree(issue)
|
def render_issue_subject_with_tree(issue)
|
||||||
s = ''
|
s = ''
|
||||||
ancestors = issue.root? ? [] : issue.ancestors.visible.all
|
issue.ancestors.each do |ancestor|
|
||||||
ancestors.each do |ancestor|
|
|
||||||
s << '<div>' + content_tag('p', link_to_issue(ancestor))
|
s << '<div>' + content_tag('p', link_to_issue(ancestor))
|
||||||
end
|
end
|
||||||
s << '<div>'
|
s << '<div>' + content_tag('h3', h(issue.subject))
|
||||||
subject = h(issue.subject)
|
s << '</div>' * (issue.ancestors.size + 1)
|
||||||
if issue.is_private?
|
s
|
||||||
subject = content_tag('span', l(:field_is_private), :class => 'private') + ' ' + subject
|
|
||||||
end
|
|
||||||
s << content_tag('h3', subject)
|
|
||||||
s << '</div>' * (ancestors.size + 1)
|
|
||||||
s.html_safe
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_descendants_tree(issue)
|
def render_descendants_tree(issue)
|
||||||
s = '<form><table class="list issues">'
|
s = '<form><table class="list issues">'
|
||||||
issue_list(issue.descendants.visible.sort_by(&:lft)) do |child, level|
|
issue_list(issue.descendants.sort_by(&:lft)) do |child, level|
|
||||||
s << content_tag('tr',
|
s << content_tag('tr',
|
||||||
content_tag('td', check_box_tag("ids[]", child.id, false, :id => nil), :class => 'checkbox') +
|
content_tag('td', check_box_tag("ids[]", child.id, false, :id => nil), :class => 'checkbox') +
|
||||||
content_tag('td', link_to_issue(child, :truncate => 60), :class => 'subject') +
|
content_tag('td', link_to_issue(child, :truncate => 60), :class => 'subject') +
|
||||||
@@ -89,7 +77,7 @@ module IssuesHelper
|
|||||||
:class => "issue issue-#{child.id} hascontextmenu #{level > 0 ? "idnt idnt-#{level}" : nil}")
|
:class => "issue issue-#{child.id} hascontextmenu #{level > 0 ? "idnt idnt-#{level}" : nil}")
|
||||||
end
|
end
|
||||||
s << '</form></table>'
|
s << '</form></table>'
|
||||||
s.html_safe
|
s
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_custom_fields_rows(issue)
|
def render_custom_fields_rows(issue)
|
||||||
@@ -108,25 +96,7 @@ module IssuesHelper
|
|||||||
n += 1
|
n += 1
|
||||||
end
|
end
|
||||||
s << "</tr>\n"
|
s << "</tr>\n"
|
||||||
s.html_safe
|
s
|
||||||
end
|
|
||||||
|
|
||||||
def issues_destroy_confirmation_message(issues)
|
|
||||||
issues = [issues] unless issues.is_a?(Array)
|
|
||||||
message = l(:text_issues_destroy_confirmation)
|
|
||||||
descendant_count = issues.inject(0) {|memo, i| memo += (i.right - i.left - 1)/2}
|
|
||||||
if descendant_count > 0
|
|
||||||
issues.each do |issue|
|
|
||||||
next if issue.root?
|
|
||||||
issues.each do |other_issue|
|
|
||||||
descendant_count -= 1 if issue.is_descendant_of?(other_issue)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if descendant_count > 0
|
|
||||||
message << "\n" + l(:text_issues_destroy_descendants_confirmation, :count => descendant_count)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
message
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def sidebar_queries
|
def sidebar_queries
|
||||||
@@ -136,32 +106,13 @@ module IssuesHelper
|
|||||||
# Project specific queries and global queries
|
# Project specific queries and global queries
|
||||||
visible << (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id])
|
visible << (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id])
|
||||||
@sidebar_queries = Query.find(:all,
|
@sidebar_queries = Query.find(:all,
|
||||||
:select => 'id, name, is_public',
|
:select => 'id, name',
|
||||||
:order => "name ASC",
|
:order => "name ASC",
|
||||||
:conditions => visible.conditions)
|
:conditions => visible.conditions)
|
||||||
end
|
end
|
||||||
@sidebar_queries
|
@sidebar_queries
|
||||||
end
|
end
|
||||||
|
|
||||||
def query_links(title, queries)
|
|
||||||
# links to #index on issues/show
|
|
||||||
url_params = controller_name == 'issues' ? {:controller => 'issues', :action => 'index', :project_id => @project} : params
|
|
||||||
|
|
||||||
content_tag('h3', h(title)) +
|
|
||||||
queries.collect {|query|
|
|
||||||
link_to(h(query.name), url_params.merge(:query_id => query))
|
|
||||||
}.join('<br />')
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_sidebar_queries
|
|
||||||
out = ''
|
|
||||||
queries = sidebar_queries.select {|q| !q.is_public?}
|
|
||||||
out << query_links(l(:label_my_queries), queries) if queries.any?
|
|
||||||
queries = sidebar_queries.select {|q| q.is_public?}
|
|
||||||
out << query_links(l(:label_query_plural), queries) if queries.any?
|
|
||||||
out
|
|
||||||
end
|
|
||||||
|
|
||||||
def show_detail(detail, no_html=false)
|
def show_detail(detail, no_html=false)
|
||||||
case detail.property
|
case detail.property
|
||||||
when 'attr'
|
when 'attr'
|
||||||
@@ -184,10 +135,6 @@ module IssuesHelper
|
|||||||
label = l(:field_parent_issue)
|
label = l(:field_parent_issue)
|
||||||
value = "##{detail.value}" unless detail.value.blank?
|
value = "##{detail.value}" unless detail.value.blank?
|
||||||
old_value = "##{detail.old_value}" unless detail.old_value.blank?
|
old_value = "##{detail.old_value}" unless detail.old_value.blank?
|
||||||
|
|
||||||
when detail.prop_key == 'is_private'
|
|
||||||
value = l(detail.value == "0" ? :general_text_No : :general_text_Yes) unless detail.value.blank?
|
|
||||||
old_value = l(detail.old_value == "0" ? :general_text_No : :general_text_Yes) unless detail.old_value.blank?
|
|
||||||
end
|
end
|
||||||
when 'cf'
|
when 'cf'
|
||||||
custom_field = CustomField.find_by_id(detail.prop_key)
|
custom_field = CustomField.find_by_id(detail.prop_key)
|
||||||
@@ -208,7 +155,7 @@ module IssuesHelper
|
|||||||
unless no_html
|
unless no_html
|
||||||
label = content_tag('strong', label)
|
label = content_tag('strong', label)
|
||||||
old_value = content_tag("i", h(old_value)) if detail.old_value
|
old_value = content_tag("i", h(old_value)) if detail.old_value
|
||||||
old_value = content_tag("strike", old_value) if detail.old_value and detail.value.blank?
|
old_value = content_tag("strike", old_value) if detail.old_value and (!detail.value or detail.value.empty?)
|
||||||
if detail.property == 'attachment' && !value.blank? && a = Attachment.find_by_id(detail.prop_key)
|
if detail.property == 'attachment' && !value.blank? && a = Attachment.find_by_id(detail.prop_key)
|
||||||
# Link to the attachment if it has not been removed
|
# Link to the attachment if it has not been removed
|
||||||
value = link_to_attachment(a)
|
value = link_to_attachment(a)
|
||||||
@@ -217,16 +164,7 @@ module IssuesHelper
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if detail.property == 'attr' && detail.prop_key == 'description'
|
if !detail.value.blank?
|
||||||
s = l(:text_journal_changed_no_detail, :label => label)
|
|
||||||
unless no_html
|
|
||||||
diff_link = link_to 'diff',
|
|
||||||
{:controller => 'journals', :action => 'diff', :id => detail.journal_id, :detail_id => detail.id},
|
|
||||||
:title => l(:label_view_diff)
|
|
||||||
s << " (#{ diff_link })"
|
|
||||||
end
|
|
||||||
s
|
|
||||||
elsif !detail.value.blank?
|
|
||||||
case detail.property
|
case detail.property
|
||||||
when 'attr', 'cf'
|
when 'attr', 'cf'
|
||||||
if !detail.old_value.blank?
|
if !detail.old_value.blank?
|
||||||
@@ -265,38 +203,59 @@ module IssuesHelper
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def issues_to_csv(issues, project, query, options={})
|
def issues_to_csv(issues, project = nil)
|
||||||
|
ic = Iconv.new(l(:general_csv_encoding), 'UTF-8')
|
||||||
decimal_separator = l(:general_csv_decimal_separator)
|
decimal_separator = l(:general_csv_decimal_separator)
|
||||||
encoding = l(:general_csv_encoding)
|
|
||||||
columns = (options[:columns] == 'all' ? query.available_columns : query.columns)
|
|
||||||
|
|
||||||
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
|
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
|
||||||
# csv header fields
|
# csv header fields
|
||||||
csv << [ "#" ] + columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) } +
|
headers = [ "#",
|
||||||
(options[:description] ? [Redmine::CodesetUtil.from_utf8(l(:field_description), encoding)] : [])
|
l(:field_status),
|
||||||
|
l(:field_project),
|
||||||
|
l(:field_tracker),
|
||||||
|
l(:field_priority),
|
||||||
|
l(:field_subject),
|
||||||
|
l(:field_assigned_to),
|
||||||
|
l(:field_category),
|
||||||
|
l(:field_fixed_version),
|
||||||
|
l(:field_author),
|
||||||
|
l(:field_start_date),
|
||||||
|
l(:field_due_date),
|
||||||
|
l(:field_done_ratio),
|
||||||
|
l(:field_estimated_hours),
|
||||||
|
l(:field_parent_issue),
|
||||||
|
l(:field_created_on),
|
||||||
|
l(:field_updated_on)
|
||||||
|
]
|
||||||
|
# Export project custom fields if project is given
|
||||||
|
# otherwise export custom fields marked as "For all projects"
|
||||||
|
custom_fields = project.nil? ? IssueCustomField.for_all : project.all_issue_custom_fields
|
||||||
|
custom_fields.each {|f| headers << f.name}
|
||||||
|
# Description in the last column
|
||||||
|
headers << l(:field_description)
|
||||||
|
csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
|
||||||
# csv lines
|
# csv lines
|
||||||
issues.each do |issue|
|
issues.each do |issue|
|
||||||
col_values = columns.collect do |column|
|
fields = [issue.id,
|
||||||
s = if column.is_a?(QueryCustomFieldColumn)
|
issue.status.name,
|
||||||
cv = issue.custom_values.detect {|v| v.custom_field_id == column.custom_field.id}
|
issue.project.name,
|
||||||
show_value(cv)
|
issue.tracker.name,
|
||||||
else
|
issue.priority.name,
|
||||||
value = issue.send(column.name)
|
issue.subject,
|
||||||
if value.is_a?(Date)
|
issue.assigned_to,
|
||||||
format_date(value)
|
issue.category,
|
||||||
elsif value.is_a?(Time)
|
issue.fixed_version,
|
||||||
format_time(value)
|
issue.author.name,
|
||||||
elsif value.is_a?(Float)
|
format_date(issue.start_date),
|
||||||
value.to_s.gsub('.', decimal_separator)
|
format_date(issue.due_date),
|
||||||
else
|
issue.done_ratio,
|
||||||
value
|
issue.estimated_hours.to_s.gsub('.', decimal_separator),
|
||||||
end
|
issue.parent_id,
|
||||||
end
|
format_time(issue.created_on),
|
||||||
s.to_s
|
format_time(issue.updated_on)
|
||||||
end
|
]
|
||||||
csv << [ issue.id.to_s ] + col_values.collect {|c| Redmine::CodesetUtil.from_utf8(c.to_s, encoding) } +
|
custom_fields.each {|f| fields << show_value(issue.custom_value_for(f)) }
|
||||||
(options[:description] ? [Redmine::CodesetUtil.from_utf8(issue.description, encoding)] : [])
|
fields << issue.description
|
||||||
|
csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
export
|
export
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006-2008 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006-2008 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -18,4 +16,14 @@
|
|||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
module MessagesHelper
|
module MessagesHelper
|
||||||
|
|
||||||
|
def link_to_message(message)
|
||||||
|
return '' unless message
|
||||||
|
link_to h(truncate(message.subject, :length => 60)), :controller => 'messages',
|
||||||
|
:action => 'show',
|
||||||
|
:board_id => message.board_id,
|
||||||
|
:id => message.root,
|
||||||
|
:r => (message.parent_id && message.id),
|
||||||
|
:anchor => (message.parent_id ? "message-#{message.id}" : nil)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -48,7 +46,7 @@ module ProjectsHelper
|
|||||||
options = ''
|
options = ''
|
||||||
options << "<option value=''></option>" if project.allowed_parents.include?(nil)
|
options << "<option value=''></option>" if project.allowed_parents.include?(nil)
|
||||||
options << project_tree_options_for_select(project.allowed_parents.compact, :selected => selected)
|
options << project_tree_options_for_select(project.allowed_parents.compact, :selected => selected)
|
||||||
content_tag('select', options.html_safe, :name => 'project[parent_id]', :id => 'project_parent_id')
|
content_tag('select', options, :name => 'project[parent_id]', :id => 'project_parent_id')
|
||||||
end
|
end
|
||||||
|
|
||||||
# Renders a tree of projects as a nested set of unordered lists
|
# Renders a tree of projects as a nested set of unordered lists
|
||||||
@@ -82,7 +80,7 @@ module ProjectsHelper
|
|||||||
s << ("</li></ul>\n" * ancestors.size)
|
s << ("</li></ul>\n" * ancestors.size)
|
||||||
@project = original_project
|
@project = original_project
|
||||||
end
|
end
|
||||||
s.html_safe
|
s
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns a set of options for a select field, grouped by project.
|
# Returns a set of options for a select field, grouped by project.
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -26,7 +24,7 @@ module QueriesHelper
|
|||||||
def column_header(column)
|
def column_header(column)
|
||||||
column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption,
|
column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption,
|
||||||
:default_order => column.default_order) :
|
:default_order => column.default_order) :
|
||||||
content_tag('th', h(column.caption))
|
content_tag('th', column.caption)
|
||||||
end
|
end
|
||||||
|
|
||||||
def column_content(column, issue)
|
def column_content(column, issue)
|
||||||
@@ -47,7 +45,7 @@ module QueriesHelper
|
|||||||
if column.name == :done_ratio
|
if column.name == :done_ratio
|
||||||
progress_bar(value, :width => '80px')
|
progress_bar(value, :width => '80px')
|
||||||
else
|
else
|
||||||
h(value.to_s)
|
value.to_s
|
||||||
end
|
end
|
||||||
when 'User'
|
when 'User'
|
||||||
link_to_user value
|
link_to_user value
|
||||||
@@ -72,34 +70,30 @@ module QueriesHelper
|
|||||||
cond = "project_id IS NULL"
|
cond = "project_id IS NULL"
|
||||||
cond << " OR project_id = #{@project.id}" if @project
|
cond << " OR project_id = #{@project.id}" if @project
|
||||||
@query = Query.find(params[:query_id], :conditions => cond)
|
@query = Query.find(params[:query_id], :conditions => cond)
|
||||||
raise ::Unauthorized unless @query.visible?
|
|
||||||
@query.project = @project
|
@query.project = @project
|
||||||
session[:query] = {:id => @query.id, :project_id => @query.project_id}
|
session[:query] = {:id => @query.id, :project_id => @query.project_id}
|
||||||
sort_clear
|
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 = Query.new(:name => "_")
|
|
||||||
@query.project = @project
|
|
||||||
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
|
else
|
||||||
# retrieve from session
|
if api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil)
|
||||||
@query = Query.find_by_id(session[:query][:id]) if session[:query][:id]
|
# Give it a name, required to be valid
|
||||||
@query ||= Query.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
|
@query = Query.new(:name => "_")
|
||||||
@query.project = @project
|
@query.project = @project
|
||||||
end
|
if params[:fields]
|
||||||
end
|
@query.filters = {}
|
||||||
|
@query.add_filters(params[:fields], params[:operators], params[:values])
|
||||||
def build_query_from_params
|
else
|
||||||
if params[:fields] || params[:f]
|
@query.available_filters.keys.each do |field|
|
||||||
@query.filters = {}
|
@query.add_short_filter(field, params[field]) if params[field]
|
||||||
@query.add_filters(params[:fields] || params[:f], params[:operators] || params[:op], params[:values] || params[:v])
|
end
|
||||||
else
|
end
|
||||||
@query.available_filters.keys.each do |field|
|
@query.group_by = params[:group_by]
|
||||||
@query.add_short_filter(field, params[field]) if params[field]
|
@query.column_names = params[:query] && params[:query][:column_names]
|
||||||
|
session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names}
|
||||||
|
else
|
||||||
|
@query = Query.find_by_id(session[:query][:id]) if session[:query][:id]
|
||||||
|
@query ||= Query.new(:name => "_", :project => @project, :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
|
||||||
|
@query.project = @project
|
||||||
end
|
end
|
||||||
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
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -33,6 +31,6 @@ module ReportsHelper
|
|||||||
|
|
||||||
def aggregate_link(data, criteria, *args)
|
def aggregate_link(data, criteria, *args)
|
||||||
a = aggregate data, criteria
|
a = aggregate data, criteria
|
||||||
a > 0 ? link_to(h(a), *args) : '-'
|
a > 0 ? link_to(a, *args) : '-'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -18,7 +16,6 @@
|
|||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
require 'iconv'
|
require 'iconv'
|
||||||
require 'redmine/codeset_util'
|
|
||||||
|
|
||||||
module RepositoriesHelper
|
module RepositoriesHelper
|
||||||
def format_revision(revision)
|
def format_revision(revision)
|
||||||
@@ -39,9 +36,9 @@ module RepositoriesHelper
|
|||||||
unless properties.nil? || properties.empty?
|
unless properties.nil? || properties.empty?
|
||||||
content = ''
|
content = ''
|
||||||
properties.keys.sort.each do |property|
|
properties.keys.sort.each do |property|
|
||||||
content << content_tag('li', "<b>#{h property}</b>: <span>#{h properties[property]}</span>".html_safe)
|
content << content_tag('li', "<b>#{h property}</b>: <span>#{h properties[property]}</span>")
|
||||||
end
|
end
|
||||||
content_tag('ul', content.html_safe, :class => 'properties')
|
content_tag('ul', content, :class => 'properties')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -51,8 +48,7 @@ module RepositoriesHelper
|
|||||||
when 'A'
|
when 'A'
|
||||||
# Detects moved/copied files
|
# Detects moved/copied files
|
||||||
if !change.from_path.blank?
|
if !change.from_path.blank?
|
||||||
change.action =
|
change.action = @changeset.changes.detect {|c| c.action == 'D' && c.path == change.from_path} ? 'R' : 'C'
|
||||||
@changeset.changes.detect {|c| c.action == 'D' && c.path == change.from_path} ? 'R' : 'C'
|
|
||||||
end
|
end
|
||||||
change
|
change
|
||||||
when 'D'
|
when 'D'
|
||||||
@@ -60,7 +56,7 @@ module RepositoriesHelper
|
|||||||
else
|
else
|
||||||
change
|
change
|
||||||
end
|
end
|
||||||
end.compact
|
end.compact
|
||||||
|
|
||||||
tree = { }
|
tree = { }
|
||||||
changes.each do |change|
|
changes.each do |change|
|
||||||
@@ -76,11 +72,13 @@ module RepositoriesHelper
|
|||||||
end
|
end
|
||||||
p[:c] = change
|
p[:c] = change
|
||||||
end
|
end
|
||||||
|
|
||||||
render_changes_tree(tree[:s])
|
render_changes_tree(tree[:s])
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_changes_tree(tree)
|
def render_changes_tree(tree)
|
||||||
return '' if tree.nil?
|
return '' if tree.nil?
|
||||||
|
|
||||||
output = ''
|
output = ''
|
||||||
output << '<ul>'
|
output << '<ul>'
|
||||||
tree.keys.sort.each do |file|
|
tree.keys.sort.each do |file|
|
||||||
@@ -89,7 +87,7 @@ module RepositoriesHelper
|
|||||||
if s = tree[file][:s]
|
if s = tree[file][:s]
|
||||||
style << ' folder'
|
style << ' folder'
|
||||||
path_param = to_path_param(@repository.relative_path(file))
|
path_param = to_path_param(@repository.relative_path(file))
|
||||||
text = link_to(h(text), :controller => 'repositories',
|
text = link_to(text, :controller => 'repositories',
|
||||||
:action => 'show',
|
:action => 'show',
|
||||||
:id => @project,
|
:id => @project,
|
||||||
:path => path_param,
|
:path => path_param,
|
||||||
@@ -99,53 +97,54 @@ module RepositoriesHelper
|
|||||||
elsif c = tree[file][:c]
|
elsif c = tree[file][:c]
|
||||||
style << " change-#{c.action}"
|
style << " change-#{c.action}"
|
||||||
path_param = to_path_param(@repository.relative_path(c.path))
|
path_param = to_path_param(@repository.relative_path(c.path))
|
||||||
text = link_to(h(text), :controller => 'repositories',
|
text = link_to(text, :controller => 'repositories',
|
||||||
:action => 'entry',
|
:action => 'entry',
|
||||||
:id => @project,
|
:id => @project,
|
||||||
:path => path_param,
|
:path => path_param,
|
||||||
:rev => @changeset.identifier) unless c.action == 'D'
|
:rev => @changeset.identifier) unless c.action == 'D'
|
||||||
text << " - #{h(c.revision)}" unless c.revision.blank?
|
text << " - #{c.revision}" unless c.revision.blank?
|
||||||
text << ' ('.html_safe + link_to(l(:label_diff), :controller => 'repositories',
|
text << ' (' + link_to('diff', :controller => 'repositories',
|
||||||
:action => 'diff',
|
:action => 'diff',
|
||||||
:id => @project,
|
:id => @project,
|
||||||
:path => path_param,
|
:path => path_param,
|
||||||
:rev => @changeset.identifier) + ') '.html_safe if c.action == 'M'
|
:rev => @changeset.identifier) + ') ' if c.action == 'M'
|
||||||
text << ' '.html_safe + content_tag('span', h(c.from_path), :class => 'copied-from') unless c.from_path.blank?
|
text << ' ' + content_tag('span', c.from_path, :class => 'copied-from') unless c.from_path.blank?
|
||||||
output << "<li class='#{style}'>#{text}</li>"
|
output << "<li class='#{style}'>#{text}</li>"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
output << '</ul>'
|
output << '</ul>'
|
||||||
output.html_safe
|
output
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_utf8(str)
|
||||||
|
return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii
|
||||||
|
@encodings ||= Setting.repositories_encodings.split(',').collect(&:strip)
|
||||||
|
@encodings.each do |encoding|
|
||||||
|
begin
|
||||||
|
return Iconv.conv('UTF-8', encoding, str)
|
||||||
|
rescue Iconv::Failure
|
||||||
|
# do nothing here and try the next encoding
|
||||||
|
end
|
||||||
|
end
|
||||||
|
str
|
||||||
end
|
end
|
||||||
|
|
||||||
def repository_field_tags(form, repository)
|
def repository_field_tags(form, repository)
|
||||||
method = repository.class.name.demodulize.underscore + "_field_tags"
|
method = repository.class.name.demodulize.underscore + "_field_tags"
|
||||||
if repository.is_a?(Repository) &&
|
send(method, form, repository) if repository.is_a?(Repository) && respond_to?(method) && method != 'repository_field_tags'
|
||||||
respond_to?(method) && method != 'repository_field_tags'
|
|
||||||
send(method, form, repository)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def scm_select_tag(repository)
|
def scm_select_tag(repository)
|
||||||
scm_options = [["--- #{l(:actionview_instancetag_blank_option)} ---", '']]
|
scm_options = [["--- #{l(:actionview_instancetag_blank_option)} ---", '']]
|
||||||
Redmine::Scm::Base.all.each do |scm|
|
Redmine::Scm::Base.all.each do |scm|
|
||||||
if Setting.enabled_scm.include?(scm) ||
|
scm_options << ["Repository::#{scm}".constantize.scm_name, scm] if Setting.enabled_scm.include?(scm) || (repository && repository.class.name.demodulize == scm)
|
||||||
(repository && repository.class.name.demodulize == scm)
|
|
||||||
scm_options << ["Repository::#{scm}".constantize.scm_name, scm]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
select_tag('repository_scm',
|
select_tag('repository_scm',
|
||||||
options_for_select(scm_options, repository.class.name.demodulize),
|
options_for_select(scm_options, repository.class.name.demodulize),
|
||||||
:disabled => (repository && !repository.new_record?),
|
:disabled => (repository && !repository.new_record?),
|
||||||
:onchange => remote_function(
|
:onchange => remote_function(:url => { :controller => 'repositories', :action => 'edit', :id => @project }, :method => :get, :with => "Form.serialize(this.form)")
|
||||||
:url => {
|
)
|
||||||
:controller => 'repositories',
|
|
||||||
:action => 'edit',
|
|
||||||
:id => @project
|
|
||||||
},
|
|
||||||
:method => :get,
|
|
||||||
:with => "Form.serialize(this.form)")
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def with_leading_slash(path)
|
def with_leading_slash(path)
|
||||||
@@ -157,157 +156,37 @@ module RepositoriesHelper
|
|||||||
end
|
end
|
||||||
|
|
||||||
def subversion_field_tags(form, repository)
|
def subversion_field_tags(form, repository)
|
||||||
content_tag('p', form.text_field(:url, :size => 60, :required => true,
|
content_tag('p', form.text_field(:url, :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)) +
|
||||||
:disabled => (repository && !repository.root_url.blank?)) +
|
'<br />(file:///, http://, https://, svn://, svn+[tunnelscheme]://)') +
|
||||||
'<br />'.html_safe +
|
|
||||||
'(file:///, http://, https://, svn://, svn+[tunnelscheme]://)') +
|
|
||||||
content_tag('p', form.text_field(:login, :size => 30)) +
|
content_tag('p', form.text_field(:login, :size => 30)) +
|
||||||
content_tag('p', form.password_field(
|
content_tag('p', form.password_field(:password, :size => 30, :name => 'ignore',
|
||||||
:password, :size => 30, :name => 'ignore',
|
:value => ((repository.new_record? || repository.password.blank?) ? '' : ('x'*15)),
|
||||||
:value => ((repository.new_record? || repository.password.blank?) ? '' : ('x'*15)),
|
:onfocus => "this.value=''; this.name='repository[password]';",
|
||||||
:onfocus => "this.value=''; this.name='repository[password]';",
|
:onchange => "this.name='repository[password]';"))
|
||||||
:onchange => "this.name='repository[password]';"))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def darcs_field_tags(form, repository)
|
def darcs_field_tags(form, repository)
|
||||||
content_tag('p', form.text_field(
|
content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.new_record?)))
|
||||||
:url, :label => l(:field_path_to_repository),
|
|
||||||
:size => 60, :required => true,
|
|
||||||
:disabled => (repository && !repository.new_record?))) +
|
|
||||||
content_tag('p', form.select(
|
|
||||||
:log_encoding, [nil] + Setting::ENCODINGS,
|
|
||||||
:label => l(:field_commit_logs_encoding), :required => true))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def mercurial_field_tags(form, repository)
|
def mercurial_field_tags(form, repository)
|
||||||
content_tag('p', form.text_field(
|
content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)))
|
||||||
:url, :label => l(:field_path_to_repository),
|
|
||||||
:size => 60, :required => true,
|
|
||||||
:disabled => (repository && !repository.root_url.blank?)
|
|
||||||
) +
|
|
||||||
'<br />'.html_safe + l(:text_mercurial_repository_note)) +
|
|
||||||
content_tag('p', form.select(
|
|
||||||
:path_encoding, [nil] + Setting::ENCODINGS,
|
|
||||||
:label => l(:field_scm_path_encoding)
|
|
||||||
) +
|
|
||||||
'<br />'.html_safe + l(:text_scm_path_encoding_note))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def git_field_tags(form, repository)
|
def git_field_tags(form, repository)
|
||||||
content_tag('p', form.text_field(
|
content_tag('p', form.text_field(:url, :label => 'Path to .git directory', :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)))
|
||||||
:url, :label => l(:field_path_to_repository),
|
|
||||||
:size => 60, :required => true,
|
|
||||||
:disabled => (repository && !repository.root_url.blank?)
|
|
||||||
) +
|
|
||||||
'<br />'.html_safe +
|
|
||||||
l(:text_git_repository_note)) +
|
|
||||||
content_tag('p', form.select(
|
|
||||||
:path_encoding, [nil] + Setting::ENCODINGS,
|
|
||||||
:label => l(:field_scm_path_encoding)
|
|
||||||
) +
|
|
||||||
'<br />'.html_safe + l(:text_scm_path_encoding_note)) +
|
|
||||||
content_tag('p', form.check_box(
|
|
||||||
:extra_report_last_commit,
|
|
||||||
:label => l(:label_git_report_last_commit)
|
|
||||||
))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def cvs_field_tags(form, repository)
|
def cvs_field_tags(form, repository)
|
||||||
content_tag('p', form.text_field(
|
content_tag('p', form.text_field(:root_url, :label => 'CVSROOT', :size => 60, :required => true, :disabled => !repository.new_record?)) +
|
||||||
:root_url,
|
content_tag('p', form.text_field(:url, :label => 'Module', :size => 30, :required => true, :disabled => !repository.new_record?))
|
||||||
:label => l(:field_cvsroot),
|
|
||||||
:size => 60, :required => true,
|
|
||||||
:disabled => !repository.new_record?)) +
|
|
||||||
content_tag('p', form.text_field(
|
|
||||||
:url,
|
|
||||||
:label => l(:field_cvs_module),
|
|
||||||
:size => 30, :required => true,
|
|
||||||
:disabled => !repository.new_record?)) +
|
|
||||||
content_tag('p', form.select(
|
|
||||||
:log_encoding, [nil] + Setting::ENCODINGS,
|
|
||||||
:label => l(:field_commit_logs_encoding), :required => true)) +
|
|
||||||
content_tag('p', form.select(
|
|
||||||
:path_encoding, [nil] + Setting::ENCODINGS,
|
|
||||||
:label => l(:field_scm_path_encoding)
|
|
||||||
) +
|
|
||||||
'<br />'.html_safe + l(:text_scm_path_encoding_note))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def bazaar_field_tags(form, repository)
|
def bazaar_field_tags(form, repository)
|
||||||
content_tag('p', form.text_field(
|
content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.new_record?)))
|
||||||
:url, :label => l(:field_path_to_repository),
|
|
||||||
:size => 60, :required => true,
|
|
||||||
:disabled => (repository && !repository.new_record?))) +
|
|
||||||
content_tag('p', form.select(
|
|
||||||
:log_encoding, [nil] + Setting::ENCODINGS,
|
|
||||||
:label => l(:field_commit_logs_encoding), :required => true))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def filesystem_field_tags(form, repository)
|
def filesystem_field_tags(form, repository)
|
||||||
content_tag('p', form.text_field(
|
content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)))
|
||||||
:url, :label => l(:field_root_directory),
|
|
||||||
:size => 60, :required => true,
|
|
||||||
:disabled => (repository && !repository.root_url.blank?))) +
|
|
||||||
content_tag('p', form.select(
|
|
||||||
:path_encoding, [nil] + Setting::ENCODINGS,
|
|
||||||
:label => l(:field_scm_path_encoding)
|
|
||||||
) +
|
|
||||||
'<br />'.html_safe + l(:text_scm_path_encoding_note))
|
|
||||||
end
|
|
||||||
|
|
||||||
def index_commits(commits, heads, href_proc = nil)
|
|
||||||
return nil if commits.nil? or commits.first.parents.nil?
|
|
||||||
map = {}
|
|
||||||
commit_hashes = []
|
|
||||||
refs_map = {}
|
|
||||||
href_proc ||= Proc.new {|x|x}
|
|
||||||
heads.each{|r| refs_map[r.scmid] ||= []; refs_map[r.scmid] << r}
|
|
||||||
commits.reverse.each_with_index do |c, i|
|
|
||||||
h = {}
|
|
||||||
h[:parents] = c.parents.collect do |p|
|
|
||||||
[p.scmid, 0, 0]
|
|
||||||
end
|
|
||||||
h[:rdmid] = i
|
|
||||||
h[:space] = 0
|
|
||||||
h[:refs] = refs_map[c.scmid].join(" ") if refs_map.include? c.scmid
|
|
||||||
h[:scmid] = c.scmid
|
|
||||||
h[:href] = href_proc.call(c.scmid)
|
|
||||||
commit_hashes << h
|
|
||||||
map[c.scmid] = h
|
|
||||||
end
|
|
||||||
heads.sort! do |a,b|
|
|
||||||
a.to_s <=> b.to_s
|
|
||||||
end
|
|
||||||
j = 0
|
|
||||||
heads.each do |h|
|
|
||||||
if map.include? h.scmid then
|
|
||||||
j = mark_chain(j += 1, map[h.scmid], map)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
# when no head matched anything use first commit
|
|
||||||
if j == 0 then
|
|
||||||
mark_chain(j += 1, map.values.first, map)
|
|
||||||
end
|
|
||||||
map
|
|
||||||
end
|
|
||||||
|
|
||||||
def mark_chain(mark, commit, map)
|
|
||||||
stack = [[mark, commit]]
|
|
||||||
markmax = mark
|
|
||||||
until stack.empty?
|
|
||||||
current = stack.pop
|
|
||||||
m, commit = current
|
|
||||||
commit[:space] = m if commit[:space] == 0
|
|
||||||
m1 = m - 1
|
|
||||||
commit[:parents].each_with_index do |p, i|
|
|
||||||
psha = p[0]
|
|
||||||
if map.include? psha and map[psha][:space] == 0 then
|
|
||||||
stack << [m1 += 1, map[psha]] if i == 0
|
|
||||||
stack = [[m1 += 1, map[psha]]] + stack if i > 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
markmax = m1 if markmax < m1
|
|
||||||
end
|
|
||||||
markmax
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -49,7 +47,6 @@ module SearchHelper
|
|||||||
options << [l(:label_my_projects), 'my_projects'] unless User.current.memberships.empty?
|
options << [l(:label_my_projects), 'my_projects'] unless User.current.memberships.empty?
|
||||||
options << [l(:label_and_its_subprojects, @project.name), 'subprojects'] unless @project.nil? || @project.descendants.active.empty?
|
options << [l(:label_and_its_subprojects, @project.name), 'subprojects'] unless @project.nil? || @project.descendants.active.empty?
|
||||||
options << [@project.name, ''] unless @project.nil?
|
options << [@project.name, ''] unless @project.nil?
|
||||||
label_tag("scope", l(:description_project_scope), :class => "hidden-for-sighted") +
|
|
||||||
select_tag('scope', options_for_select(options, params[:scope].to_s)) if options.size > 1
|
select_tag('scope', options_for_select(options, params[:scope].to_s)) if options.size > 1
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -60,8 +57,7 @@ module SearchHelper
|
|||||||
c = results_by_type[t]
|
c = results_by_type[t]
|
||||||
next if c == 0
|
next if c == 0
|
||||||
text = "#{type_label(t)} (#{c})"
|
text = "#{type_label(t)} (#{c})"
|
||||||
links << link_to(h(text), :q => params[:q], :titles_only => params[:titles_only],
|
links << link_to(text, :q => params[:q], :titles_only => params[:title_only], :all_words => params[:all_words], :scope => params[:scope], t => 1)
|
||||||
:all_words => params[:all_words], :scope => params[:scope], t => 1)
|
|
||||||
end
|
end
|
||||||
('<ul>' + links.map {|link| content_tag('li', link)}.join(' ') + '</ul>') unless links.empty?
|
('<ul>' + links.map {|link| content_tag('li', link)}.join(' ') + '</ul>') unless links.empty?
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
|
||||||
#
|
|
||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2009 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -34,51 +32,44 @@ module SettingsHelper
|
|||||||
if blank_text = options.delete(:blank)
|
if blank_text = options.delete(:blank)
|
||||||
choices = [[blank_text.is_a?(Symbol) ? l(blank_text) : blank_text, '']] + choices
|
choices = [[blank_text.is_a?(Symbol) ? l(blank_text) : blank_text, '']] + choices
|
||||||
end
|
end
|
||||||
setting_label(setting, options).html_safe +
|
setting_label(setting, options) +
|
||||||
select_tag("settings[#{setting}]",
|
select_tag("settings[#{setting}]", options_for_select(choices, Setting.send(setting).to_s), options)
|
||||||
options_for_select(choices, Setting.send(setting).to_s),
|
|
||||||
options).html_safe
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def setting_multiselect(setting, choices, options={})
|
def setting_multiselect(setting, choices, options={})
|
||||||
setting_values = Setting.send(setting)
|
setting_values = Setting.send(setting)
|
||||||
setting_values = [] unless setting_values.is_a?(Array)
|
setting_values = [] unless setting_values.is_a?(Array)
|
||||||
|
|
||||||
setting_label(setting, options).html_safe +
|
setting_label(setting, options) +
|
||||||
hidden_field_tag("settings[#{setting}][]", '').html_safe +
|
hidden_field_tag("settings[#{setting}][]", '') +
|
||||||
choices.collect do |choice|
|
choices.collect do |choice|
|
||||||
text, value = (choice.is_a?(Array) ? choice : [choice, choice])
|
text, value = (choice.is_a?(Array) ? choice : [choice, choice])
|
||||||
content_tag(
|
content_tag('label',
|
||||||
'label',
|
check_box_tag("settings[#{setting}][]", value, Setting.send(setting).include?(value)) + text.to_s,
|
||||||
check_box_tag(
|
|
||||||
"settings[#{setting}][]",
|
|
||||||
value,
|
|
||||||
Setting.send(setting).include?(value)
|
|
||||||
) + text.to_s,
|
|
||||||
:class => 'block'
|
:class => 'block'
|
||||||
)
|
)
|
||||||
end.join.html_safe
|
end.join
|
||||||
end
|
end
|
||||||
|
|
||||||
def setting_text_field(setting, options={})
|
def setting_text_field(setting, options={})
|
||||||
setting_label(setting, options).html_safe +
|
setting_label(setting, options) +
|
||||||
text_field_tag("settings[#{setting}]", Setting.send(setting), options).html_safe
|
text_field_tag("settings[#{setting}]", Setting.send(setting), options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def setting_text_area(setting, options={})
|
def setting_text_area(setting, options={})
|
||||||
setting_label(setting, options).html_safe +
|
setting_label(setting, options) +
|
||||||
text_area_tag("settings[#{setting}]", Setting.send(setting), options).html_safe
|
text_area_tag("settings[#{setting}]", Setting.send(setting), options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def setting_check_box(setting, options={})
|
def setting_check_box(setting, options={})
|
||||||
setting_label(setting, options).html_safe +
|
setting_label(setting, options) +
|
||||||
hidden_field_tag("settings[#{setting}]", 0).html_safe +
|
hidden_field_tag("settings[#{setting}]", 0) +
|
||||||
check_box_tag("settings[#{setting}]", 1, Setting.send("#{setting}?"), options).html_safe
|
check_box_tag("settings[#{setting}]", 1, Setting.send("#{setting}?"), options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def setting_label(setting, options={})
|
def setting_label(setting, options={})
|
||||||
label = options.delete(:label)
|
label = options.delete(:label)
|
||||||
label != false ? content_tag("label", l(label || "setting_#{setting}")).html_safe : ''
|
label != false ? content_tag("label", l(label || "setting_#{setting}")) : ''
|
||||||
end
|
end
|
||||||
|
|
||||||
# Renders a notification field for a Redmine::Notifiable option
|
# Renders a notification field for a Redmine::Notifiable option
|
||||||
@@ -86,8 +77,8 @@ module SettingsHelper
|
|||||||
return content_tag(:label,
|
return content_tag(:label,
|
||||||
check_box_tag('settings[notified_events][]',
|
check_box_tag('settings[notified_events][]',
|
||||||
notifiable.name,
|
notifiable.name,
|
||||||
Setting.notified_events.include?(notifiable.name)).html_safe +
|
Setting.notified_events.include?(notifiable.name)) +
|
||||||
l_or_humanize(notifiable.name, :prefix => 'label_').html_safe,
|
l_or_humanize(notifiable.name, :prefix => 'label_'),
|
||||||
:class => notifiable.parent.present? ? "parent" : '').html_safe
|
:class => notifiable.parent.present? ? "parent" : '')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
# encoding: utf-8
|
|
||||||
#
|
|
||||||
# Helpers to sort tables using clickable column headers.
|
# Helpers to sort tables using clickable column headers.
|
||||||
#
|
#
|
||||||
# Author: Stuart Rackham <srackham@methods.co.nz>, March 2005.
|
# Author: Stuart Rackham <srackham@methods.co.nz>, March 2005.
|
||||||
@@ -202,12 +200,16 @@ module SortHelper
|
|||||||
caption = column.to_s.humanize unless caption
|
caption = column.to_s.humanize unless caption
|
||||||
|
|
||||||
sort_options = { :sort => @sort_criteria.add(column.to_s, order).to_param }
|
sort_options = { :sort => @sort_criteria.add(column.to_s, order).to_param }
|
||||||
url_options = params.merge(sort_options)
|
# don't reuse params if filters are present
|
||||||
|
url_options = params.has_key?(:set_filter) ? sort_options : params.merge(sort_options)
|
||||||
|
|
||||||
# Add project_id to url_options
|
# Add project_id to url_options
|
||||||
url_options = url_options.merge(:project_id => params[:project_id]) if params.has_key?(:project_id)
|
url_options = url_options.merge(:project_id => params[:project_id]) if params.has_key?(:project_id)
|
||||||
|
|
||||||
link_to_content_update(h(caption), url_options, :class => css)
|
link_to_remote(caption,
|
||||||
|
{:update => "content", :url => url_options, :method => :get},
|
||||||
|
{:href => url_for(url_options),
|
||||||
|
:class => css})
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns a table header <th> tag with a sort link for the named column
|
# Returns a table header <th> tag with a sort link for the named column
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -86,6 +84,7 @@ module TimelogHelper
|
|||||||
end
|
end
|
||||||
|
|
||||||
def entries_to_csv(entries)
|
def entries_to_csv(entries)
|
||||||
|
ic = Iconv.new(l(:general_csv_encoding), 'UTF-8')
|
||||||
decimal_separator = l(:general_csv_decimal_separator)
|
decimal_separator = l(:general_csv_decimal_separator)
|
||||||
custom_fields = TimeEntryCustomField.find(:all)
|
custom_fields = TimeEntryCustomField.find(:all)
|
||||||
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
|
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
|
||||||
@@ -103,9 +102,7 @@ module TimelogHelper
|
|||||||
# Export custom fields
|
# Export custom fields
|
||||||
headers += custom_fields.collect(&:name)
|
headers += custom_fields.collect(&:name)
|
||||||
|
|
||||||
csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8(
|
csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
|
||||||
c.to_s,
|
|
||||||
l(:general_csv_encoding) ) }
|
|
||||||
# csv lines
|
# csv lines
|
||||||
entries.each do |entry|
|
entries.each do |entry|
|
||||||
fields = [format_date(entry.spent_on),
|
fields = [format_date(entry.spent_on),
|
||||||
@@ -120,9 +117,7 @@ module TimelogHelper
|
|||||||
]
|
]
|
||||||
fields += custom_fields.collect {|f| show_value(entry.custom_value_for(f)) }
|
fields += custom_fields.collect {|f| show_value(entry.custom_value_for(f)) }
|
||||||
|
|
||||||
csv << fields.collect {|c| Redmine::CodesetUtil.from_utf8(
|
csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
|
||||||
c.to_s,
|
|
||||||
l(:general_csv_encoding) ) }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
export
|
export
|
||||||
@@ -144,53 +139,52 @@ module TimelogHelper
|
|||||||
end
|
end
|
||||||
|
|
||||||
def report_to_csv(criterias, periods, hours)
|
def report_to_csv(criterias, periods, hours)
|
||||||
decimal_separator = l(:general_csv_decimal_separator)
|
|
||||||
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
|
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
|
||||||
# Column headers
|
# Column headers
|
||||||
headers = criterias.collect {|criteria| l(@available_criterias[criteria][:label]) }
|
headers = criterias.collect {|criteria| l(@available_criterias[criteria][:label]) }
|
||||||
headers += periods
|
headers += periods
|
||||||
headers << l(:label_total)
|
headers << l(:label_total)
|
||||||
csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8(
|
csv << headers.collect {|c| to_utf8(c) }
|
||||||
c.to_s,
|
|
||||||
l(:general_csv_encoding) ) }
|
|
||||||
# Content
|
# Content
|
||||||
report_criteria_to_csv(csv, criterias, periods, hours)
|
report_criteria_to_csv(csv, criterias, periods, hours)
|
||||||
# Total row
|
# Total row
|
||||||
str_total = Redmine::CodesetUtil.from_utf8(l(:label_total), l(:general_csv_encoding))
|
row = [ l(:label_total) ] + [''] * (criterias.size - 1)
|
||||||
row = [ str_total ] + [''] * (criterias.size - 1)
|
|
||||||
total = 0
|
total = 0
|
||||||
periods.each do |period|
|
periods.each do |period|
|
||||||
sum = sum_hours(select_hours(hours, @columns, period.to_s))
|
sum = sum_hours(select_hours(hours, @columns, period.to_s))
|
||||||
total += sum
|
total += sum
|
||||||
row << (sum > 0 ? ("%.2f" % sum).gsub('.',decimal_separator) : '')
|
row << (sum > 0 ? "%.2f" % sum : '')
|
||||||
end
|
end
|
||||||
row << ("%.2f" % total).gsub('.',decimal_separator)
|
row << "%.2f" %total
|
||||||
csv << row
|
csv << row
|
||||||
end
|
end
|
||||||
export
|
export
|
||||||
end
|
end
|
||||||
|
|
||||||
def report_criteria_to_csv(csv, criterias, periods, hours, level=0)
|
def report_criteria_to_csv(csv, criterias, periods, hours, level=0)
|
||||||
decimal_separator = l(:general_csv_decimal_separator)
|
|
||||||
hours.collect {|h| h[criterias[level]].to_s}.uniq.each do |value|
|
hours.collect {|h| h[criterias[level]].to_s}.uniq.each do |value|
|
||||||
hours_for_value = select_hours(hours, criterias[level], value)
|
hours_for_value = select_hours(hours, criterias[level], value)
|
||||||
next if hours_for_value.empty?
|
next if hours_for_value.empty?
|
||||||
row = [''] * level
|
row = [''] * level
|
||||||
row << Redmine::CodesetUtil.from_utf8(
|
row << to_utf8(format_criteria_value(criterias[level], value))
|
||||||
format_criteria_value(criterias[level], value).to_s,
|
|
||||||
l(:general_csv_encoding) )
|
|
||||||
row += [''] * (criterias.length - level - 1)
|
row += [''] * (criterias.length - level - 1)
|
||||||
total = 0
|
total = 0
|
||||||
periods.each do |period|
|
periods.each do |period|
|
||||||
sum = sum_hours(select_hours(hours_for_value, @columns, period.to_s))
|
sum = sum_hours(select_hours(hours_for_value, @columns, period.to_s))
|
||||||
total += sum
|
total += sum
|
||||||
row << (sum > 0 ? ("%.2f" % sum).gsub('.',decimal_separator) : '')
|
row << (sum > 0 ? "%.2f" % sum : '')
|
||||||
end
|
end
|
||||||
row << ("%.2f" % total).gsub('.',decimal_separator)
|
row << "%.2f" %total
|
||||||
csv << row
|
csv << row
|
||||||
|
|
||||||
if criterias.length > level + 1
|
if criterias.length > level + 1
|
||||||
report_criteria_to_csv(csv, criterias, periods, hours_for_value, level + 1)
|
report_criteria_to_csv(csv, criterias, periods, hours_for_value, level + 1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def to_utf8(s)
|
||||||
|
@ic ||= Iconv.new(l(:general_csv_encoding), 'UTF-8')
|
||||||
|
begin; @ic.iconv(s.to_s); rescue; s.to_s; end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -19,10 +17,11 @@
|
|||||||
|
|
||||||
module VersionsHelper
|
module VersionsHelper
|
||||||
|
|
||||||
STATUS_BY_CRITERIAS = %w(category tracker status priority author assigned_to)
|
STATUS_BY_CRITERIAS = %w(category tracker priority author assigned_to)
|
||||||
|
|
||||||
def render_issue_status_by(version, criteria)
|
def render_issue_status_by(version, criteria)
|
||||||
criteria = 'category' unless STATUS_BY_CRITERIAS.include?(criteria)
|
criteria ||= 'category'
|
||||||
|
raise 'Unknown criteria' unless STATUS_BY_CRITERIAS.include?(criteria)
|
||||||
|
|
||||||
h = Hash.new {|k,v| k[v] = [0, 0]}
|
h = Hash.new {|k,v| k[v] = [0, 0]}
|
||||||
begin
|
begin
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -19,17 +17,27 @@
|
|||||||
|
|
||||||
module WatchersHelper
|
module WatchersHelper
|
||||||
|
|
||||||
def watcher_tag(object, user, options={})
|
# Valid options
|
||||||
content_tag("span", watcher_link(object, user), :class => watcher_css(object))
|
# * :id - the element id
|
||||||
|
# * :replace - a string or array of element ids that will be
|
||||||
|
# replaced
|
||||||
|
def watcher_tag(object, user, options={:replace => 'watcher'})
|
||||||
|
id = options[:id]
|
||||||
|
id ||= options[:replace] if options[:replace].is_a? String
|
||||||
|
content_tag("span", watcher_link(object, user, options), :id => id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def watcher_link(object, user)
|
# Valid options
|
||||||
|
# * :replace - a string or array of element ids that will be
|
||||||
|
# replaced
|
||||||
|
def watcher_link(object, user, options={:replace => 'watcher'})
|
||||||
return '' unless user && user.logged? && object.respond_to?('watched_by?')
|
return '' unless user && user.logged? && object.respond_to?('watched_by?')
|
||||||
watched = object.watched_by?(user)
|
watched = object.watched_by?(user)
|
||||||
url = {:controller => 'watchers',
|
url = {:controller => 'watchers',
|
||||||
:action => (watched ? 'unwatch' : 'watch'),
|
:action => (watched ? 'unwatch' : 'watch'),
|
||||||
:object_type => object.class.to_s.underscore,
|
:object_type => object.class.to_s.underscore,
|
||||||
:object_id => object.id}
|
:object_id => object.id,
|
||||||
|
:replace => options[:replace]}
|
||||||
link_to_remote((watched ? l(:button_unwatch) : l(:button_watch)),
|
link_to_remote((watched ? l(:button_unwatch) : l(:button_watch)),
|
||||||
{:url => url},
|
{:url => url},
|
||||||
:href => url_for(url),
|
:href => url_for(url),
|
||||||
@@ -37,11 +45,6 @@ module WatchersHelper
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the css class used to identify watch links for a given +object+
|
|
||||||
def watcher_css(object)
|
|
||||||
"#{object.class.to_s.underscore}-#{object.id}-watcher"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns a comma separated list of users watching the given object
|
# Returns a comma separated list of users watching the given object
|
||||||
def watchers_list(object)
|
def watchers_list(object)
|
||||||
remove_allowed = User.current.allowed_to?("delete_#{object.class.name.underscore}_watchers".to_sym, object.project)
|
remove_allowed = User.current.allowed_to?("delete_#{object.class.name.underscore}_watchers".to_sym, object.project)
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
+43
-17
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
# redMine - project management software
|
||||||
#
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -20,24 +18,52 @@
|
|||||||
module WikiHelper
|
module WikiHelper
|
||||||
|
|
||||||
def wiki_page_options_for_select(pages, selected = nil, parent = nil, level = 0)
|
def wiki_page_options_for_select(pages, selected = nil, parent = nil, level = 0)
|
||||||
pages = pages.group_by(&:parent) unless pages.is_a?(Hash)
|
|
||||||
s = ''
|
s = ''
|
||||||
if pages.has_key?(parent)
|
pages.select {|p| p.parent == parent}.each do |page|
|
||||||
pages[parent].each do |page|
|
attrs = "value='#{page.id}'"
|
||||||
attrs = "value='#{page.id}'"
|
attrs << " selected='selected'" if selected == page
|
||||||
attrs << " selected='selected'" if selected == page
|
indent = (level > 0) ? (' ' * level * 2 + '» ') : nil
|
||||||
indent = (level > 0) ? (' ' * level * 2 + '» ') : nil
|
|
||||||
|
|
||||||
s << "<option #{attrs}>#{indent}#{h page.pretty_title}</option>\n" +
|
s << "<option #{attrs}>#{indent}#{h page.pretty_title}</option>\n" +
|
||||||
wiki_page_options_for_select(pages, selected, page, level + 1)
|
wiki_page_options_for_select(pages, selected, page, level + 1)
|
||||||
end
|
|
||||||
end
|
end
|
||||||
s
|
s
|
||||||
end
|
end
|
||||||
|
|
||||||
def wiki_page_breadcrumb(page)
|
def html_diff(wdiff)
|
||||||
breadcrumb(page.ancestors.reverse.collect {|parent|
|
words = wdiff.words.collect{|word| h(word)}
|
||||||
link_to(h(parent.pretty_title), {:controller => 'wiki', :action => 'show', :id => parent.title, :project_id => parent.project})
|
words_add = 0
|
||||||
})
|
words_del = 0
|
||||||
|
dels = 0
|
||||||
|
del_off = 0
|
||||||
|
wdiff.diff.diffs.each do |diff|
|
||||||
|
add_at = nil
|
||||||
|
add_to = nil
|
||||||
|
del_at = nil
|
||||||
|
deleted = ""
|
||||||
|
diff.each do |change|
|
||||||
|
pos = change[1]
|
||||||
|
if change[0] == "+"
|
||||||
|
add_at = pos + dels unless add_at
|
||||||
|
add_to = pos + dels
|
||||||
|
words_add += 1
|
||||||
|
else
|
||||||
|
del_at = pos unless del_at
|
||||||
|
deleted << ' ' + h(change[2])
|
||||||
|
words_del += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if add_at
|
||||||
|
words[add_at] = '<span class="diff_in">' + words[add_at]
|
||||||
|
words[add_to] = words[add_to] + '</span>'
|
||||||
|
end
|
||||||
|
if del_at
|
||||||
|
words.insert del_at - del_off + dels + words_add, '<span class="diff_out">' + deleted + '</span>'
|
||||||
|
dels += 1
|
||||||
|
del_off += words_del
|
||||||
|
words_del = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
simple_format_without_paragraph(words.join(' '))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
# encoding: utf-8
|
|
||||||
#
|
|
||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2008 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
+12
-22
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -24,7 +24,6 @@ class Attachment < ActiveRecord::Base
|
|||||||
validates_presence_of :container, :filename, :author
|
validates_presence_of :container, :filename, :author
|
||||||
validates_length_of :filename, :maximum => 255
|
validates_length_of :filename, :maximum => 255
|
||||||
validates_length_of :disk_filename, :maximum => 255
|
validates_length_of :disk_filename, :maximum => 255
|
||||||
validate :validate_max_file_size
|
|
||||||
|
|
||||||
acts_as_event :title => :filename,
|
acts_as_event :title => :filename,
|
||||||
:url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id, :filename => o.filename}}
|
:url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id, :filename => o.filename}}
|
||||||
@@ -44,12 +43,9 @@ class Attachment < ActiveRecord::Base
|
|||||||
"LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id"}
|
"LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id"}
|
||||||
|
|
||||||
cattr_accessor :storage_path
|
cattr_accessor :storage_path
|
||||||
@@storage_path = Redmine::Configuration['attachments_storage_path'] || "#{Rails.root}/files"
|
@@storage_path = "#{RAILS_ROOT}/files"
|
||||||
|
|
||||||
before_save :files_to_final_location
|
def validate
|
||||||
after_destroy :delete_from_disk
|
|
||||||
|
|
||||||
def validate_max_file_size
|
|
||||||
if self.filesize > Setting.attachment_max_size.to_i.kilobytes
|
if self.filesize > Setting.attachment_max_size.to_i.kilobytes
|
||||||
errors.add(:base, :too_long, :count => Setting.attachment_max_size.to_i.kilobytes)
|
errors.add(:base, :too_long, :count => Setting.attachment_max_size.to_i.kilobytes)
|
||||||
end
|
end
|
||||||
@@ -76,9 +72,9 @@ class Attachment < ActiveRecord::Base
|
|||||||
|
|
||||||
# Copies the temporary file to its final location
|
# Copies the temporary file to its final location
|
||||||
# and computes its MD5 hash
|
# and computes its MD5 hash
|
||||||
def files_to_final_location
|
def before_save
|
||||||
if @temp_file && (@temp_file.size > 0)
|
if @temp_file && (@temp_file.size > 0)
|
||||||
logger.info("Saving attachment '#{self.diskfile}' (#{@temp_file.size} bytes)")
|
logger.debug("saving '#{self.diskfile}'")
|
||||||
md5 = Digest::MD5.new
|
md5 = Digest::MD5.new
|
||||||
File.open(diskfile, "wb") do |f|
|
File.open(diskfile, "wb") do |f|
|
||||||
buffer = ""
|
buffer = ""
|
||||||
@@ -89,7 +85,6 @@ class Attachment < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
self.digest = md5.hexdigest
|
self.digest = md5.hexdigest
|
||||||
end
|
end
|
||||||
@temp_file = nil
|
|
||||||
# Don't save the content type if it's longer than the authorized length
|
# Don't save the content type if it's longer than the authorized length
|
||||||
if self.content_type && self.content_type.length > 255
|
if self.content_type && self.content_type.length > 255
|
||||||
self.content_type = nil
|
self.content_type = nil
|
||||||
@@ -97,7 +92,7 @@ class Attachment < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Deletes file on the disk
|
# Deletes file on the disk
|
||||||
def delete_from_disk
|
def after_destroy
|
||||||
File.delete(diskfile) if !filename.blank? && File.exist?(diskfile)
|
File.delete(diskfile) if !filename.blank? && File.exist?(diskfile)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -123,7 +118,7 @@ class Attachment < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def image?
|
def image?
|
||||||
self.filename =~ /\.(bmp|gif|jpg|jpe|jpeg|png)$/i
|
self.filename =~ /\.(jpe?g|gif|png)$/i
|
||||||
end
|
end
|
||||||
|
|
||||||
def is_text?
|
def is_text?
|
||||||
@@ -154,7 +149,6 @@ class Attachment < ActiveRecord::Base
|
|||||||
:file => file,
|
:file => file,
|
||||||
:description => attachment['description'].to_s.strip,
|
:description => attachment['description'].to_s.strip,
|
||||||
:author => User.current)
|
:author => User.current)
|
||||||
obj.attachments << a
|
|
||||||
|
|
||||||
if a.new_record?
|
if a.new_record?
|
||||||
obj.unsaved_attachments ||= []
|
obj.unsaved_attachments ||= []
|
||||||
@@ -167,19 +161,15 @@ class Attachment < ActiveRecord::Base
|
|||||||
{:files => attached, :unsaved => obj.unsaved_attachments}
|
{:files => attached, :unsaved => obj.unsaved_attachments}
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.latest_attach(attachments, filename)
|
|
||||||
attachments.sort_by(&:created_on).reverse.detect {
|
|
||||||
|att| att.filename.downcase == filename.downcase
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
def sanitize_filename(value)
|
def sanitize_filename(value)
|
||||||
# get only the filename, not the whole path
|
# get only the filename, not the whole path
|
||||||
just_filename = value.gsub(/^.*(\\|\/)/, '')
|
just_filename = value.gsub(/^.*(\\|\/)/, '')
|
||||||
|
# NOTE: File.basename doesn't work right with Windows paths on Unix
|
||||||
|
# INCORRECT: just_filename = File.basename(value.gsub('\\\\', '/'))
|
||||||
|
|
||||||
# Finally, replace invalid characters with underscore
|
# Finally, replace all non alphanumeric, hyphens or periods with underscore
|
||||||
@filename = just_filename.gsub(/[\/\?\%\*\:\|\"\'<>]+/, '_')
|
@filename = just_filename.gsub(/[^\w\.\-]/,'_')
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns an ASCII or hashed filename
|
# Returns an ASCII or hashed filename
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -16,8 +16,6 @@
|
|||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
class AuthSource < ActiveRecord::Base
|
class AuthSource < ActiveRecord::Base
|
||||||
include Redmine::Ciphering
|
|
||||||
|
|
||||||
has_many :users
|
has_many :users
|
||||||
|
|
||||||
validates_presence_of :name
|
validates_presence_of :name
|
||||||
@@ -34,14 +32,6 @@ class AuthSource < ActiveRecord::Base
|
|||||||
"Abstract"
|
"Abstract"
|
||||||
end
|
end
|
||||||
|
|
||||||
def account_password
|
|
||||||
read_ciphered_attribute(:account_password)
|
|
||||||
end
|
|
||||||
|
|
||||||
def account_password=(arg)
|
|
||||||
write_ciphered_attribute(:account_password, arg)
|
|
||||||
end
|
|
||||||
|
|
||||||
def allow_password_changes?
|
def allow_password_changes?
|
||||||
self.class.allow_password_changes?
|
self.class.allow_password_changes?
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -20,8 +20,8 @@ require 'iconv'
|
|||||||
|
|
||||||
class AuthSourceLdap < AuthSource
|
class AuthSourceLdap < AuthSource
|
||||||
validates_presence_of :host, :port, :attr_login
|
validates_presence_of :host, :port, :attr_login
|
||||||
validates_length_of :name, :host, :maximum => 60, :allow_nil => true
|
validates_length_of :name, :host, :account_password, :maximum => 60, :allow_nil => true
|
||||||
validates_length_of :account, :account_password, :base_dn, :maximum => 255, :allow_nil => true
|
validates_length_of :account, :base_dn, :maximum => 255, :allow_nil => true
|
||||||
validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true
|
validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true
|
||||||
validates_numericality_of :port, :only_integer => true
|
validates_numericality_of :port, :only_integer => true
|
||||||
|
|
||||||
|
|||||||
+2
-8
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# 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.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
class Board < ActiveRecord::Base
|
class Board < ActiveRecord::Base
|
||||||
include Redmine::SafeAttributes
|
|
||||||
belongs_to :project
|
belongs_to :project
|
||||||
has_many :topics, :class_name => 'Message', :conditions => "#{Message.table_name}.parent_id IS NULL", :order => "#{Message.table_name}.created_on DESC"
|
has_many :topics, :class_name => 'Message', :conditions => "#{Message.table_name}.parent_id IS NULL", :order => "#{Message.table_name}.created_on DESC"
|
||||||
has_many :messages, :dependent => :destroy, :order => "#{Message.table_name}.created_on DESC"
|
has_many :messages, :dependent => :destroy, :order => "#{Message.table_name}.created_on DESC"
|
||||||
@@ -28,11 +27,6 @@ class Board < ActiveRecord::Base
|
|||||||
validates_length_of :name, :maximum => 30
|
validates_length_of :name, :maximum => 30
|
||||||
validates_length_of :description, :maximum => 255
|
validates_length_of :description, :maximum => 255
|
||||||
|
|
||||||
named_scope :visible, lambda {|*args| { :include => :project,
|
|
||||||
:conditions => Project.allowed_to_condition(args.shift || User.current, :view_messages, *args) } }
|
|
||||||
|
|
||||||
safe_attributes 'name', 'description', 'move_to'
|
|
||||||
|
|
||||||
def visible?(user=User.current)
|
def visible?(user=User.current)
|
||||||
!user.nil? && user.allowed_to?(:view_messages, project)
|
!user.nil? && user.allowed_to?(:view_messages, project)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -20,17 +20,11 @@ class Change < ActiveRecord::Base
|
|||||||
|
|
||||||
validates_presence_of :changeset_id, :action, :path
|
validates_presence_of :changeset_id, :action, :path
|
||||||
before_save :init_path
|
before_save :init_path
|
||||||
before_validation :replace_invalid_utf8_of_path
|
|
||||||
|
|
||||||
def relative_path
|
def relative_path
|
||||||
changeset.repository.relative_path(path)
|
changeset.repository.relative_path(path)
|
||||||
end
|
end
|
||||||
|
|
||||||
def replace_invalid_utf8_of_path
|
|
||||||
self.path = Redmine::CodesetUtil.replace_invalid_utf8(self.path)
|
|
||||||
self.from_path = Redmine::CodesetUtil.replace_invalid_utf8(self.from_path)
|
|
||||||
end
|
|
||||||
|
|
||||||
def init_path
|
def init_path
|
||||||
self.path ||= ""
|
self.path ||= ""
|
||||||
end
|
end
|
||||||
|
|||||||
+47
-53
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006-2010 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -22,14 +22,6 @@ class Changeset < ActiveRecord::Base
|
|||||||
belongs_to :user
|
belongs_to :user
|
||||||
has_many :changes, :dependent => :delete_all
|
has_many :changes, :dependent => :delete_all
|
||||||
has_and_belongs_to_many :issues
|
has_and_belongs_to_many :issues
|
||||||
has_and_belongs_to_many :parents,
|
|
||||||
:class_name => "Changeset",
|
|
||||||
:join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}",
|
|
||||||
:association_foreign_key => 'parent_id', :foreign_key => 'changeset_id'
|
|
||||||
has_and_belongs_to_many :children,
|
|
||||||
:class_name => "Changeset",
|
|
||||||
:join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}",
|
|
||||||
:association_foreign_key => 'changeset_id', :foreign_key => 'parent_id'
|
|
||||||
|
|
||||||
acts_as_event :title => Proc.new {|o| "#{l(:label_revision)} #{o.format_identifier}" + (o.short_comments.blank? ? '' : (': ' + o.short_comments))},
|
acts_as_event :title => Proc.new {|o| "#{l(:label_revision)} #{o.format_identifier}" + (o.short_comments.blank? ? '' : (': ' + o.short_comments))},
|
||||||
:description => :long_comments,
|
:description => :long_comments,
|
||||||
@@ -50,10 +42,7 @@ class Changeset < ActiveRecord::Base
|
|||||||
validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true
|
validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true
|
||||||
|
|
||||||
named_scope :visible, lambda {|*args| { :include => {:repository => :project},
|
named_scope :visible, lambda {|*args| { :include => {:repository => :project},
|
||||||
:conditions => Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args) } }
|
:conditions => Project.allowed_to_condition(args.first || User.current, :view_changesets) } }
|
||||||
|
|
||||||
after_create :scan_for_issues
|
|
||||||
before_create :before_create_cs
|
|
||||||
|
|
||||||
def revision=(r)
|
def revision=(r)
|
||||||
write_attribute :revision, (r.nil? ? nil : r.to_s)
|
write_attribute :revision, (r.nil? ? nil : r.to_s)
|
||||||
@@ -68,6 +57,10 @@ class Changeset < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def comments=(comment)
|
||||||
|
write_attribute(:comments, Changeset.normalize_comments(comment))
|
||||||
|
end
|
||||||
|
|
||||||
def committed_on=(date)
|
def committed_on=(date)
|
||||||
self.commit_date = date
|
self.commit_date = date
|
||||||
super
|
super
|
||||||
@@ -82,6 +75,10 @@ class Changeset < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def committer=(arg)
|
||||||
|
write_attribute(:committer, self.class.to_utf8(arg.to_s))
|
||||||
|
end
|
||||||
|
|
||||||
def project
|
def project
|
||||||
repository.project
|
repository.project
|
||||||
end
|
end
|
||||||
@@ -90,14 +87,11 @@ class Changeset < ActiveRecord::Base
|
|||||||
user || committer.to_s.split('<').first
|
user || committer.to_s.split('<').first
|
||||||
end
|
end
|
||||||
|
|
||||||
def before_create_cs
|
def before_create
|
||||||
self.committer = self.class.to_utf8(self.committer, repository.repo_log_encoding)
|
self.user = repository.find_committer_user(committer)
|
||||||
self.comments = self.class.normalize_comments(
|
|
||||||
self.comments, repository.repo_log_encoding)
|
|
||||||
self.user = repository.find_committer_user(self.committer)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def scan_for_issues
|
def after_create
|
||||||
scan_comment_for_issue_ids
|
scan_comment_for_issue_ids
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -151,40 +145,35 @@ class Changeset < ActiveRecord::Base
|
|||||||
@long_comments || split_comments.last
|
@long_comments || split_comments.last
|
||||||
end
|
end
|
||||||
|
|
||||||
def text_tag(ref_project=nil)
|
def text_tag
|
||||||
tag = if scmid?
|
if scmid?
|
||||||
"commit:#{scmid}"
|
"commit:#{scmid}"
|
||||||
else
|
else
|
||||||
"r#{revision}"
|
"r#{revision}"
|
||||||
end
|
end
|
||||||
if ref_project && project && ref_project != project
|
|
||||||
tag = "#{project.identifier}:#{tag}"
|
|
||||||
end
|
|
||||||
tag
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the previous changeset
|
# Returns the previous changeset
|
||||||
def previous
|
def previous
|
||||||
@previous ||= Changeset.find(:first,
|
@previous ||= Changeset.find(:first, :conditions => ['id < ? AND repository_id = ?', self.id, self.repository_id], :order => 'id DESC')
|
||||||
:conditions => ['id < ? AND repository_id = ?',
|
|
||||||
self.id, self.repository_id],
|
|
||||||
:order => 'id DESC')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the next changeset
|
# Returns the next changeset
|
||||||
def next
|
def next
|
||||||
@next ||= Changeset.find(:first,
|
@next ||= Changeset.find(:first, :conditions => ['id > ? AND repository_id = ?', self.id, self.repository_id], :order => 'id ASC')
|
||||||
:conditions => ['id > ? AND repository_id = ?',
|
end
|
||||||
self.id, self.repository_id],
|
|
||||||
:order => 'id ASC')
|
# Strips and reencodes a commit log before insertion into the database
|
||||||
|
def self.normalize_comments(str)
|
||||||
|
to_utf8(str.to_s.strip)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Creates a new Change from it's common parameters
|
# Creates a new Change from it's common parameters
|
||||||
def create_change(change)
|
def create_change(change)
|
||||||
Change.create(:changeset => self,
|
Change.create(:changeset => self,
|
||||||
:action => change[:action],
|
:action => change[:action],
|
||||||
:path => change[:path],
|
:path => change[:path],
|
||||||
:from_path => change[:from_path],
|
:from_path => change[:from_path],
|
||||||
:from_revision => change[:from_revision])
|
:from_revision => change[:from_revision])
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -196,9 +185,7 @@ class Changeset < ActiveRecord::Base
|
|||||||
return nil if id.blank?
|
return nil if id.blank?
|
||||||
issue = Issue.find_by_id(id.to_i, :include => :project)
|
issue = Issue.find_by_id(id.to_i, :include => :project)
|
||||||
if issue
|
if issue
|
||||||
unless issue.project &&
|
unless issue.project && (project == issue.project || project.is_ancestor_of?(issue.project) || project.is_descendant_of?(issue.project))
|
||||||
(project == issue.project || project.is_ancestor_of?(issue.project) ||
|
|
||||||
project.is_descendant_of?(issue.project))
|
|
||||||
issue = nil
|
issue = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -208,7 +195,7 @@ class Changeset < ActiveRecord::Base
|
|||||||
def fix_issue(issue)
|
def fix_issue(issue)
|
||||||
status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i)
|
status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i)
|
||||||
if status.nil?
|
if status.nil?
|
||||||
logger.warn("No status matches commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger
|
logger.warn("No status macthes commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger
|
||||||
return issue
|
return issue
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -217,7 +204,7 @@ class Changeset < ActiveRecord::Base
|
|||||||
# don't change the status is the issue is closed
|
# don't change the status is the issue is closed
|
||||||
return if issue.status && issue.status.is_closed?
|
return if issue.status && issue.status.is_closed?
|
||||||
|
|
||||||
journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag(issue.project)))
|
journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag))
|
||||||
issue.status = status
|
issue.status = status
|
||||||
unless Setting.commit_fix_done_ratio.blank?
|
unless Setting.commit_fix_done_ratio.blank?
|
||||||
issue.done_ratio = Setting.commit_fix_done_ratio.to_i
|
issue.done_ratio = Setting.commit_fix_done_ratio.to_i
|
||||||
@@ -236,8 +223,7 @@ class Changeset < ActiveRecord::Base
|
|||||||
:hours => hours,
|
:hours => hours,
|
||||||
:issue => issue,
|
:issue => issue,
|
||||||
:spent_on => commit_date,
|
:spent_on => commit_date,
|
||||||
:comments => l(:text_time_logged_by_changeset, :value => text_tag(issue.project),
|
:comments => l(:text_time_logged_by_changeset, :value => text_tag, :locale => Setting.default_language)
|
||||||
:locale => Setting.default_language)
|
|
||||||
)
|
)
|
||||||
time_entry.activity = log_time_activity unless log_time_activity.nil?
|
time_entry.activity = log_time_activity unless log_time_activity.nil?
|
||||||
|
|
||||||
@@ -260,14 +246,22 @@ class Changeset < ActiveRecord::Base
|
|||||||
return @short_comments, @long_comments
|
return @short_comments, @long_comments
|
||||||
end
|
end
|
||||||
|
|
||||||
public
|
def self.to_utf8(str)
|
||||||
|
return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii
|
||||||
# Strips and reencodes a commit log before insertion into the database
|
encoding = Setting.commit_logs_encoding.to_s.strip
|
||||||
def self.normalize_comments(str, encoding)
|
unless encoding.blank? || encoding == 'UTF-8'
|
||||||
Changeset.to_utf8(str.to_s.strip, encoding)
|
begin
|
||||||
end
|
str = Iconv.conv('UTF-8', encoding, str)
|
||||||
|
rescue Iconv::Failure
|
||||||
def self.to_utf8(str, encoding)
|
# do nothing here
|
||||||
Redmine::CodesetUtil.to_utf8(str, encoding)
|
end
|
||||||
|
end
|
||||||
|
# removes invalid UTF8 sequences
|
||||||
|
begin
|
||||||
|
Iconv.conv('UTF-8//IGNORE', 'UTF-8', str + ' ')[0..-3]
|
||||||
|
rescue Iconv::InvalidEncoding
|
||||||
|
# "UTF-8//IGNORE" is not supported on some OS
|
||||||
|
str
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -16,11 +16,8 @@
|
|||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
class Comment < ActiveRecord::Base
|
class Comment < ActiveRecord::Base
|
||||||
include Redmine::SafeAttributes
|
|
||||||
belongs_to :commented, :polymorphic => true, :counter_cache => true
|
belongs_to :commented, :polymorphic => true, :counter_cache => true
|
||||||
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
|
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
|
||||||
|
|
||||||
validates_presence_of :commented, :author, :comments
|
validates_presence_of :commented, :author, :comments
|
||||||
|
|
||||||
safe_attributes 'comments'
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
# Redmine - project management software
|
|
||||||
# Copyright (C) 2006-2011 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.
|
|
||||||
|
|
||||||
class CommentObserver < ActiveRecord::Observer
|
|
||||||
def after_create(comment)
|
|
||||||
if comment.commented.is_a?(News) && Setting.notified_events.include?('news_comment_added')
|
|
||||||
Mailer.deliver_news_comment_added(comment)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -23,10 +23,9 @@ class CustomField < ActiveRecord::Base
|
|||||||
validates_presence_of :name, :field_format
|
validates_presence_of :name, :field_format
|
||||||
validates_uniqueness_of :name, :scope => :type
|
validates_uniqueness_of :name, :scope => :type
|
||||||
validates_length_of :name, :maximum => 30
|
validates_length_of :name, :maximum => 30
|
||||||
|
validates_format_of :name, :with => /^[\w\s\.\'\-]*$/i
|
||||||
validates_inclusion_of :field_format, :in => Redmine::CustomFieldFormat.available_formats
|
validates_inclusion_of :field_format, :in => Redmine::CustomFieldFormat.available_formats
|
||||||
|
|
||||||
validate :validate_values
|
|
||||||
|
|
||||||
def initialize(attributes = nil)
|
def initialize(attributes = nil)
|
||||||
super
|
super
|
||||||
self.possible_values ||= []
|
self.possible_values ||= []
|
||||||
@@ -38,55 +37,18 @@ class CustomField < ActiveRecord::Base
|
|||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_values
|
def validate
|
||||||
if self.field_format == "list"
|
if self.field_format == "list"
|
||||||
errors.add(:possible_values, :blank) if self.possible_values.nil? || self.possible_values.empty?
|
errors.add(:possible_values, :blank) if self.possible_values.nil? || self.possible_values.empty?
|
||||||
errors.add(:possible_values, :invalid) unless self.possible_values.is_a? Array
|
errors.add(:possible_values, :invalid) unless self.possible_values.is_a? Array
|
||||||
end
|
end
|
||||||
|
|
||||||
if regexp.present?
|
|
||||||
begin
|
|
||||||
Regexp.new(regexp)
|
|
||||||
rescue
|
|
||||||
errors.add(:regexp, :invalid)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# validate default value
|
# validate default value
|
||||||
v = CustomValue.new(:custom_field => self.clone, :value => default_value, :customized => nil)
|
v = CustomValue.new(:custom_field => self.clone, :value => default_value, :customized => nil)
|
||||||
v.custom_field.is_required = false
|
v.custom_field.is_required = false
|
||||||
errors.add(:default_value, :invalid) unless v.valid?
|
errors.add(:default_value, :invalid) unless v.valid?
|
||||||
end
|
end
|
||||||
|
|
||||||
def possible_values_options(obj=nil)
|
|
||||||
case field_format
|
|
||||||
when 'user', 'version'
|
|
||||||
if obj.respond_to?(:project) && obj.project
|
|
||||||
case field_format
|
|
||||||
when 'user'
|
|
||||||
obj.project.users.sort.collect {|u| [u.to_s, u.id.to_s]}
|
|
||||||
when 'version'
|
|
||||||
obj.project.shared_versions.sort.collect {|u| [u.to_s, u.id.to_s]}
|
|
||||||
end
|
|
||||||
elsif obj.is_a?(Array)
|
|
||||||
obj.collect {|o| possible_values_options(o)}.inject {|memo, v| memo & v}
|
|
||||||
else
|
|
||||||
[]
|
|
||||||
end
|
|
||||||
else
|
|
||||||
read_attribute :possible_values
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def possible_values(obj=nil)
|
|
||||||
case field_format
|
|
||||||
when 'user', 'version'
|
|
||||||
possible_values_options(obj).collect(&:last)
|
|
||||||
else
|
|
||||||
read_attribute :possible_values
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Makes possible_values accept a multiline string
|
# Makes possible_values accept a multiline string
|
||||||
def possible_values=(arg)
|
def possible_values=(arg)
|
||||||
if arg.is_a?(Array)
|
if arg.is_a?(Array)
|
||||||
@@ -110,8 +72,6 @@ class CustomField < ActiveRecord::Base
|
|||||||
casted = value.to_i
|
casted = value.to_i
|
||||||
when 'float'
|
when 'float'
|
||||||
casted = value.to_f
|
casted = value.to_f
|
||||||
when 'user', 'version'
|
|
||||||
casted = (value.blank? ? nil : field_format.classify.constantize.find_by_id(value.to_i))
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
casted
|
casted
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
@@ -19,8 +19,6 @@ class CustomValue < ActiveRecord::Base
|
|||||||
belongs_to :custom_field
|
belongs_to :custom_field
|
||||||
belongs_to :customized, :polymorphic => true
|
belongs_to :customized, :polymorphic => true
|
||||||
|
|
||||||
validate :validate_custom_value
|
|
||||||
|
|
||||||
def after_initialize
|
def after_initialize
|
||||||
if new_record? && custom_field && (customized_type.blank? || (customized && customized.new_record?))
|
if new_record? && custom_field && (customized_type.blank? || (customized && customized.new_record?))
|
||||||
self.value ||= custom_field.default_value
|
self.value ||= custom_field.default_value
|
||||||
@@ -49,7 +47,7 @@ class CustomValue < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
def validate_custom_value
|
def validate
|
||||||
if value.blank?
|
if value.blank?
|
||||||
errors.add(:value, :blank) if custom_field.is_required? and value.blank?
|
errors.add(:value, :blank) if custom_field.is_required? and value.blank?
|
||||||
else
|
else
|
||||||
@@ -64,7 +62,7 @@ protected
|
|||||||
when 'float'
|
when 'float'
|
||||||
begin; Kernel.Float(value); rescue; errors.add(:value, :invalid) end
|
begin; Kernel.Float(value); rescue; errors.add(:value, :invalid) end
|
||||||
when 'date'
|
when 'date'
|
||||||
errors.add(:value, :not_a_date) unless value =~ /^\d{4}-\d{2}-\d{2}$/ && begin; value.to_date; rescue; false end
|
errors.add(:value, :not_a_date) unless value =~ /^\d{4}-\d{2}-\d{2}$/
|
||||||
when 'list'
|
when 'list'
|
||||||
errors.add(:value, :inclusion) unless custom_field.possible_values.include?(value)
|
errors.add(:value, :inclusion) unless custom_field.possible_values.include?(value)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# RedMine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# 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.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
class Document < ActiveRecord::Base
|
class Document < ActiveRecord::Base
|
||||||
include Redmine::SafeAttributes
|
|
||||||
belongs_to :project
|
belongs_to :project
|
||||||
belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id"
|
belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id"
|
||||||
acts_as_attachable :delete_permission => :manage_documents
|
acts_as_attachable :delete_permission => :manage_documents
|
||||||
@@ -30,11 +29,6 @@ class Document < ActiveRecord::Base
|
|||||||
validates_presence_of :project, :title, :category
|
validates_presence_of :project, :title, :category
|
||||||
validates_length_of :title, :maximum => 60
|
validates_length_of :title, :maximum => 60
|
||||||
|
|
||||||
named_scope :visible, lambda {|*args| { :include => :project,
|
|
||||||
:conditions => Project.allowed_to_condition(args.shift || User.current, :view_documents, *args) } }
|
|
||||||
|
|
||||||
safe_attributes 'category_id', 'title', 'description'
|
|
||||||
|
|
||||||
def visible?(user=User.current)
|
def visible?(user=User.current)
|
||||||
!user.nil? && user.allowed_to?(:view_documents, project)
|
!user.nil? && user.allowed_to?(:view_documents, project)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2011 Jean-Philippe Lang
|
# Copyright (C) 2006 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or
|
# This program is free software; you can redistribute it and/or
|
||||||
# modify it under the terms of the GNU General Public License
|
# modify it under the terms of the GNU General Public License
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user