Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b1b08e2c89 | ||
|
|
edd584d59e | ||
|
|
e2b27ab696 | ||
|
|
1968d039ee | ||
|
|
fddc33cd45 | ||
|
|
29518ba0cf | ||
|
|
acd27b9eb1 | ||
|
|
6445b5997c | ||
|
|
416d33973f | ||
|
|
82c7dc11d2 | ||
|
|
d22f782d3f | ||
|
|
3717fdfa79 | ||
|
|
9d3d932703 | ||
|
|
3a379ce4b9 | ||
|
|
daa77f0109 | ||
|
|
c0d66d626b | ||
|
|
bf02b76ca3 | ||
|
|
75e02ca486 |
86
Gemfile
86
Gemfile
@@ -1,6 +1,6 @@
|
||||
source 'https://rubygems.org'
|
||||
source 'http://rubygems.org'
|
||||
|
||||
gem "rails", "3.2.13"
|
||||
gem 'rails', '3.2.9'
|
||||
gem "jquery-rails", "~> 2.0.2"
|
||||
gem "i18n", "~> 0.6.0"
|
||||
gem "coderay", "~> 1.0.6"
|
||||
@@ -28,47 +28,43 @@ platforms :mri, :mingw do
|
||||
end
|
||||
end
|
||||
|
||||
platforms :jruby do
|
||||
# jruby-openssl is bundled with JRuby 1.7.0
|
||||
gem "jruby-openssl" if Object.const_defined?(:JRUBY_VERSION) && JRUBY_VERSION < '1.7.0'
|
||||
gem "activerecord-jdbc-adapter", "1.2.5"
|
||||
# Database gems
|
||||
platforms :mri, :mingw do
|
||||
group :postgresql do
|
||||
gem "pg", ">= 0.11.0"
|
||||
end
|
||||
|
||||
group :sqlite do
|
||||
gem "sqlite3"
|
||||
end
|
||||
end
|
||||
|
||||
# Include database gems for the adapters found in the database
|
||||
# configuration file
|
||||
require 'erb'
|
||||
require 'yaml'
|
||||
database_file = File.join(File.dirname(__FILE__), "config/database.yml")
|
||||
if File.exist?(database_file)
|
||||
database_config = YAML::load(ERB.new(IO.read(database_file)).result)
|
||||
adapters = database_config.values.map {|c| c['adapter']}.compact.uniq
|
||||
if adapters.any?
|
||||
adapters.each do |adapter|
|
||||
case adapter
|
||||
when 'mysql2'
|
||||
gem "mysql2", "~> 0.3.11", :platforms => [:mri, :mingw]
|
||||
gem "activerecord-jdbcmysql-adapter", :platforms => :jruby
|
||||
when 'mysql'
|
||||
gem "mysql", "~> 2.8.1", :platforms => [:mri, :mingw]
|
||||
gem "activerecord-jdbcmysql-adapter", :platforms => :jruby
|
||||
when /postgresql/
|
||||
gem "pg", ">= 0.11.0", :platforms => [:mri, :mingw]
|
||||
gem "activerecord-jdbcpostgresql-adapter", :platforms => :jruby
|
||||
when /sqlite3/
|
||||
gem "sqlite3", :platforms => [:mri, :mingw]
|
||||
gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
|
||||
when /sqlserver/
|
||||
gem "tiny_tds", "~> 0.5.1", :platforms => [:mri, :mingw]
|
||||
gem "activerecord-sqlserver-adapter", :platforms => [:mri, :mingw]
|
||||
else
|
||||
warn("Unknown database adapter `#{adapter}` found in config/database.yml, use Gemfile.local to load your own database gems")
|
||||
end
|
||||
end
|
||||
else
|
||||
warn("No adapter found in config/database.yml, please configure it first")
|
||||
platforms :mri_18, :mingw_18 do
|
||||
group :mysql do
|
||||
gem "mysql", "~> 2.8.1"
|
||||
end
|
||||
end
|
||||
|
||||
platforms :mri_19, :mingw_19 do
|
||||
group :mysql do
|
||||
gem "mysql2", "~> 0.3.11"
|
||||
end
|
||||
end
|
||||
|
||||
platforms :jruby do
|
||||
gem "jruby-openssl"
|
||||
|
||||
group :mysql do
|
||||
gem "activerecord-jdbcmysql-adapter"
|
||||
end
|
||||
|
||||
group :postgresql do
|
||||
gem "activerecord-jdbcpostgresql-adapter"
|
||||
end
|
||||
|
||||
group :sqlite do
|
||||
gem "activerecord-jdbcsqlite3-adapter"
|
||||
end
|
||||
else
|
||||
warn("Please configure your config/database.yml first")
|
||||
end
|
||||
|
||||
group :development do
|
||||
@@ -77,9 +73,13 @@ group :development do
|
||||
end
|
||||
|
||||
group :test do
|
||||
gem "shoulda", "~> 3.3.2"
|
||||
gem "mocha", "~> 0.13.3"
|
||||
gem 'capybara', '~> 2.0.0'
|
||||
gem "shoulda", "~> 2.11"
|
||||
# Shoulda does not work nice on Ruby 1.9.3 and JRuby 1.7.
|
||||
# It seems to need test-unit explicitely.
|
||||
platforms = [:mri_19]
|
||||
platforms << :jruby if defined?(JRUBY_VERSION) && JRUBY_VERSION >= "1.7"
|
||||
gem "test-unit", :platforms => platforms
|
||||
gem "mocha", "0.12.3"
|
||||
end
|
||||
|
||||
local_gemfile = File.join(File.dirname(__FILE__), "Gemfile.local")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -25,9 +25,7 @@ class AccountController < ApplicationController
|
||||
# Login request and validation
|
||||
def login
|
||||
if request.get?
|
||||
if User.current.logged?
|
||||
redirect_to home_url
|
||||
end
|
||||
logout_user
|
||||
else
|
||||
authenticate_user
|
||||
end
|
||||
@@ -38,20 +36,15 @@ class AccountController < ApplicationController
|
||||
|
||||
# Log out current user and redirect to welcome page
|
||||
def logout
|
||||
if User.current.anonymous?
|
||||
redirect_to home_url
|
||||
elsif request.post?
|
||||
logout_user
|
||||
redirect_to home_url
|
||||
end
|
||||
# display the logout form
|
||||
logout_user
|
||||
redirect_to home_url
|
||||
end
|
||||
|
||||
# Lets user choose a new password
|
||||
def lost_password
|
||||
(redirect_to(home_url); return) unless Setting.lost_password?
|
||||
redirect_to(home_url) && return unless Setting.lost_password?
|
||||
if params[:token]
|
||||
@token = Token.find_token("recovery", params[:token].to_s)
|
||||
@token = Token.find_by_action_and_value("recovery", params[:token].to_s)
|
||||
if @token.nil? || @token.expired?
|
||||
redirect_to home_url
|
||||
return
|
||||
@@ -99,10 +92,10 @@ class AccountController < ApplicationController
|
||||
|
||||
# User self-registration
|
||||
def register
|
||||
(redirect_to(home_url); return) unless Setting.self_registration? || session[:auth_source_registration]
|
||||
redirect_to(home_url) && return unless Setting.self_registration? || session[:auth_source_registration]
|
||||
if request.get?
|
||||
session[:auth_source_registration] = nil
|
||||
@user = User.new(:language => current_language.to_s)
|
||||
@user = User.new(:language => Setting.default_language)
|
||||
else
|
||||
user_params = params[:user] || {}
|
||||
@user = User.new
|
||||
@@ -117,7 +110,7 @@ class AccountController < ApplicationController
|
||||
session[:auth_source_registration] = nil
|
||||
self.logged_user = @user
|
||||
flash[:notice] = l(:notice_account_activated)
|
||||
redirect_to my_account_path
|
||||
redirect_to :controller => 'my', :action => 'account'
|
||||
end
|
||||
else
|
||||
@user.login = params[:user][:login]
|
||||
@@ -139,11 +132,11 @@ class AccountController < ApplicationController
|
||||
|
||||
# Token based account activation
|
||||
def activate
|
||||
(redirect_to(home_url); return) unless Setting.self_registration? && params[:token].present?
|
||||
token = Token.find_token('register', params[:token].to_s)
|
||||
(redirect_to(home_url); return) unless token and !token.expired?
|
||||
redirect_to(home_url) && return unless Setting.self_registration? && params[:token]
|
||||
token = Token.find_by_action_and_value('register', params[:token])
|
||||
redirect_to(home_url) && return unless token and !token.expired?
|
||||
user = token.user
|
||||
(redirect_to(home_url); return) unless user.registered?
|
||||
redirect_to(home_url) && return unless user.registered?
|
||||
user.activate
|
||||
if user.save
|
||||
token.destroy
|
||||
@@ -176,14 +169,12 @@ class AccountController < ApplicationController
|
||||
end
|
||||
|
||||
def open_id_authenticate(openid_url)
|
||||
back_url = signin_url(:autologin => params[:autologin])
|
||||
|
||||
authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => back_url, :method => :post) do |result, identity_url, registration|
|
||||
authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => signin_url, :method => :post) do |result, identity_url, registration|
|
||||
if result.successful?
|
||||
user = User.find_or_initialize_by_identity_url(identity_url)
|
||||
if user.new_record?
|
||||
# Self-registration off
|
||||
(redirect_to(home_url); return) unless Setting.self_registration?
|
||||
redirect_to(home_url) && return unless Setting.self_registration?
|
||||
|
||||
# Create on the fly
|
||||
user.login = registration['nickname'] unless registration['nickname'].nil?
|
||||
@@ -227,11 +218,12 @@ class AccountController < ApplicationController
|
||||
set_autologin_cookie(user)
|
||||
end
|
||||
call_hook(:controller_account_success_authentication_after, {:user => user })
|
||||
redirect_back_or_default my_page_path
|
||||
redirect_back_or_default :controller => 'my', :action => 'page'
|
||||
end
|
||||
|
||||
def set_autologin_cookie(user)
|
||||
token = Token.create(:user => user, :action => 'autologin')
|
||||
cookie_name = Redmine::Configuration['autologin_cookie_name'] || 'autologin'
|
||||
cookie_options = {
|
||||
:value => token.value,
|
||||
:expires => 1.year.from_now,
|
||||
@@ -239,7 +231,7 @@ class AccountController < ApplicationController
|
||||
:secure => (Redmine::Configuration['autologin_cookie_secure'] ? true : false),
|
||||
:httponly => true
|
||||
}
|
||||
cookies[autologin_cookie_name] = cookie_options
|
||||
cookies[cookie_name] = cookie_options
|
||||
end
|
||||
|
||||
# Onthefly creation failed, display the registration form to fill/fix attributes
|
||||
@@ -278,7 +270,7 @@ class AccountController < ApplicationController
|
||||
if user.save
|
||||
self.logged_user = user
|
||||
flash[:notice] = l(:notice_account_activated)
|
||||
redirect_to my_account_path
|
||||
redirect_to :controller => 'my', :action => 'account'
|
||||
else
|
||||
yield if block_given?
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -23,18 +23,19 @@ class AdminController < ApplicationController
|
||||
|
||||
before_filter :require_admin
|
||||
helper :sort
|
||||
include SortHelper
|
||||
include SortHelper
|
||||
|
||||
def index
|
||||
@no_configuration_data = Redmine::DefaultData::Loader::no_data?
|
||||
end
|
||||
|
||||
|
||||
def projects
|
||||
@status = params[:status] || 1
|
||||
|
||||
scope = Project.status(@status).order('lft')
|
||||
scope = Project.status(@status)
|
||||
scope = scope.like(params[:name]) if params[:name].present?
|
||||
@projects = scope.all
|
||||
|
||||
@projects = scope.all(:order => 'lft')
|
||||
|
||||
render :action => "projects", :layout => false if request.xhr?
|
||||
end
|
||||
@@ -54,7 +55,7 @@ class AdminController < ApplicationController
|
||||
flash[:error] = l(:error_can_t_load_default_data, e.message)
|
||||
end
|
||||
end
|
||||
redirect_to admin_path
|
||||
redirect_to :action => 'index'
|
||||
end
|
||||
|
||||
def test_email
|
||||
@@ -68,7 +69,7 @@ class AdminController < ApplicationController
|
||||
flash[:error] = l(:notice_email_error, e.message)
|
||||
end
|
||||
ActionMailer::Base.raise_delivery_errors = raise_delivery_errors
|
||||
redirect_to settings_path(:tab => 'notifications')
|
||||
redirect_to :controller => 'settings', :action => 'edit', :tab => 'notifications'
|
||||
end
|
||||
|
||||
def info
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -22,9 +22,6 @@ class Unauthorized < Exception; end
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
include Redmine::I18n
|
||||
include Redmine::Pagination
|
||||
include RoutesHelper
|
||||
helper :routes
|
||||
|
||||
class_attribute :accept_api_auth_actions
|
||||
class_attribute :accept_rss_auth_actions
|
||||
@@ -35,7 +32,7 @@ class ApplicationController < ActionController::Base
|
||||
protect_from_forgery
|
||||
def handle_unverified_request
|
||||
super
|
||||
cookies.delete(autologin_cookie_name)
|
||||
cookies.delete(:autologin)
|
||||
end
|
||||
|
||||
before_filter :session_expiration, :user_setup, :check_if_login_required, :set_localization
|
||||
@@ -127,14 +124,10 @@ class ApplicationController < ActionController::Base
|
||||
user
|
||||
end
|
||||
|
||||
def autologin_cookie_name
|
||||
Redmine::Configuration['autologin_cookie_name'].presence || 'autologin'
|
||||
end
|
||||
|
||||
def try_to_autologin
|
||||
if cookies[autologin_cookie_name] && Setting.autologin?
|
||||
if cookies[:autologin] && Setting.autologin?
|
||||
# auto-login feature starts a new session
|
||||
user = User.try_to_autologin(cookies[autologin_cookie_name])
|
||||
user = User.try_to_autologin(cookies[:autologin])
|
||||
if user
|
||||
reset_session
|
||||
start_user_session(user)
|
||||
@@ -157,7 +150,7 @@ class ApplicationController < ActionController::Base
|
||||
# Logs out current user
|
||||
def logout_user
|
||||
if User.current.logged?
|
||||
cookies.delete(autologin_cookie_name)
|
||||
cookies.delete :autologin
|
||||
Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin'])
|
||||
self.logged_user = nil
|
||||
end
|
||||
@@ -307,16 +300,6 @@ class ApplicationController < ActionController::Base
|
||||
render_404
|
||||
end
|
||||
|
||||
def find_attachments
|
||||
if (attachments = params[:attachments]).present?
|
||||
att = attachments.values.collect do |attachment|
|
||||
Attachment.find_by_token( attachment[:token] ) if attachment[:token].present?
|
||||
end
|
||||
att.compact!
|
||||
end
|
||||
@attachments = att || []
|
||||
end
|
||||
|
||||
# make sure that the user is a member of the project (or admin) if project is private
|
||||
# used as a before_filter for actions that do not require any particular permission on the project
|
||||
def check_project_privacy
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -85,17 +85,15 @@ class AttachmentsController < ApplicationController
|
||||
@attachment = Attachment.new(:file => request.raw_post)
|
||||
@attachment.author = User.current
|
||||
@attachment.filename = params[:filename].presence || Redmine::Utils.random_hex(16)
|
||||
saved = @attachment.save
|
||||
|
||||
respond_to do |format|
|
||||
format.js
|
||||
format.api {
|
||||
if saved
|
||||
render :action => 'upload', :status => :created
|
||||
else
|
||||
render_validation_errors(@attachment)
|
||||
end
|
||||
}
|
||||
if @attachment.save
|
||||
respond_to do |format|
|
||||
format.api { render :action => 'upload', :status => :created }
|
||||
end
|
||||
else
|
||||
respond_to do |format|
|
||||
format.api { render_validation_errors(@attachment) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -103,17 +101,9 @@ class AttachmentsController < ApplicationController
|
||||
if @attachment.container.respond_to?(:init_journal)
|
||||
@attachment.container.init_journal(User.current)
|
||||
end
|
||||
if @attachment.container
|
||||
# Make sure association callbacks are called
|
||||
@attachment.container.attachments.delete(@attachment)
|
||||
else
|
||||
@attachment.destroy
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to_referer_or project_path(@project) }
|
||||
format.js
|
||||
end
|
||||
# Make sure association callbacks are called
|
||||
@attachment.container.attachments.delete(@attachment)
|
||||
redirect_to_referer_or project_path(@project)
|
||||
end
|
||||
|
||||
private
|
||||
@@ -128,12 +118,7 @@ private
|
||||
|
||||
# Checks that the file exists and is readable
|
||||
def file_readable
|
||||
if @attachment.readable?
|
||||
true
|
||||
else
|
||||
logger.error "Cannot send attachment, #{@attachment.diskfile} does not exist or is unreadable."
|
||||
render_404
|
||||
end
|
||||
@attachment.readable? ? true : render_404
|
||||
end
|
||||
|
||||
def read_authorize
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -20,77 +20,57 @@ class AuthSourcesController < ApplicationController
|
||||
menu_item :ldap_authentication
|
||||
|
||||
before_filter :require_admin
|
||||
before_filter :find_auth_source, :only => [:edit, :update, :test_connection, :destroy]
|
||||
|
||||
def index
|
||||
@auth_source_pages, @auth_sources = paginate AuthSource, :per_page => 25
|
||||
@auth_source_pages, @auth_sources = paginate AuthSource, :per_page => 10
|
||||
end
|
||||
|
||||
def new
|
||||
klass_name = params[:type] || 'AuthSourceLdap'
|
||||
@auth_source = AuthSource.new_subclass_instance(klass_name, params[:auth_source])
|
||||
render_404 unless @auth_source
|
||||
end
|
||||
|
||||
def create
|
||||
@auth_source = AuthSource.new_subclass_instance(params[:type], params[:auth_source])
|
||||
if @auth_source.save
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
redirect_to auth_sources_path
|
||||
redirect_to :action => 'index'
|
||||
else
|
||||
render :action => 'new'
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
@auth_source = AuthSource.find(params[:id])
|
||||
end
|
||||
|
||||
def update
|
||||
@auth_source = AuthSource.find(params[:id])
|
||||
if @auth_source.update_attributes(params[:auth_source])
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to auth_sources_path
|
||||
redirect_to :action => 'index'
|
||||
else
|
||||
render :action => 'edit'
|
||||
end
|
||||
end
|
||||
|
||||
def test_connection
|
||||
@auth_source = AuthSource.find(params[:id])
|
||||
begin
|
||||
@auth_source.test_connection
|
||||
flash[:notice] = l(:notice_successful_connection)
|
||||
rescue Exception => e
|
||||
flash[:error] = l(:error_unable_to_connect, e.message)
|
||||
end
|
||||
redirect_to auth_sources_path
|
||||
redirect_to :action => 'index'
|
||||
end
|
||||
|
||||
def destroy
|
||||
unless @auth_source.users.exists?
|
||||
@auth_source = AuthSource.find(params[:id])
|
||||
unless @auth_source.users.find(:first)
|
||||
@auth_source.destroy
|
||||
flash[:notice] = l(:notice_successful_delete)
|
||||
end
|
||||
redirect_to auth_sources_path
|
||||
end
|
||||
|
||||
def autocomplete_for_new_user
|
||||
results = AuthSource.search(params[:term])
|
||||
|
||||
render :json => results.map {|result| {
|
||||
'value' => result[:login],
|
||||
'label' => "#{result[:login]} (#{result[:firstname]} #{result[:lastname]})",
|
||||
'login' => result[:login].to_s,
|
||||
'firstname' => result[:firstname].to_s,
|
||||
'lastname' => result[:lastname].to_s,
|
||||
'mail' => result[:mail].to_s,
|
||||
'auth_source_id' => result[:auth_source_id].to_s
|
||||
}}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_auth_source
|
||||
@auth_source = AuthSource.find(params[:id])
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
render_404
|
||||
redirect_to :action => 'index'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -23,10 +23,10 @@ class AutoCompletesController < ApplicationController
|
||||
q = (params[:q] || params[:term]).to_s.strip
|
||||
if q.present?
|
||||
scope = (params[:scope] == "all" || @project.nil? ? Issue : @project.issues).visible
|
||||
if q.match(/\A#?(\d+)\z/)
|
||||
@issues << scope.find_by_id($1.to_i)
|
||||
if q.match(/^\d+$/)
|
||||
@issues << scope.find_by_id(q.to_i)
|
||||
end
|
||||
@issues += scope.where("LOWER(#{Issue.table_name}.subject) LIKE LOWER(?)", "%#{q}%").order("#{Issue.table_name}.id DESC").limit(10).all
|
||||
@issues += scope.where("LOWER(#{Issue.table_name}.subject) LIKE ?", "%#{q.downcase}%").order("#{Issue.table_name}.id DESC").limit(10).all
|
||||
@issues.compact!
|
||||
end
|
||||
render :layout => false
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -37,29 +37,23 @@ class BoardsController < ApplicationController
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
sort_init 'updated_on', 'desc'
|
||||
sort_update 'created_on' => "#{Message.table_name}.created_on",
|
||||
sort_update 'created_on' => "#{Message.table_name}.created_on",
|
||||
'replies' => "#{Message.table_name}.replies_count",
|
||||
'updated_on' => "COALESCE(last_replies_messages.created_on, #{Message.table_name}.created_on)"
|
||||
'updated_on' => "#{Message.table_name}.updated_on"
|
||||
|
||||
@topic_count = @board.topics.count
|
||||
@topic_pages = Paginator.new @topic_count, per_page_option, params['page']
|
||||
@topics = @board.topics.
|
||||
reorder("#{Message.table_name}.sticky DESC").
|
||||
includes(:last_reply).
|
||||
limit(@topic_pages.per_page).
|
||||
offset(@topic_pages.offset).
|
||||
order(sort_clause).
|
||||
preload(:author, {:last_reply => :author}).
|
||||
all
|
||||
@topic_pages = Paginator.new self, @topic_count, per_page_option, params['page']
|
||||
@topics = @board.topics.reorder("#{Message.table_name}.sticky DESC").order(sort_clause).all(
|
||||
:include => [:author, {:last_reply => :author}],
|
||||
:limit => @topic_pages.items_per_page,
|
||||
:offset => @topic_pages.current.offset)
|
||||
@message = Message.new(:board => @board)
|
||||
render :action => 'show', :layout => !request.xhr?
|
||||
}
|
||||
format.atom {
|
||||
@messages = @board.messages.
|
||||
reorder('created_on DESC').
|
||||
includes(:author, :board).
|
||||
limit(Setting.feeds_limit.to_i).
|
||||
all
|
||||
@messages = @board.messages.find :all, :order => 'created_on DESC',
|
||||
:include => [:author, :board],
|
||||
:limit => Setting.feeds_limit.to_i
|
||||
render_feed(@messages, :title => "#{@project}: #{@board}")
|
||||
}
|
||||
end
|
||||
@@ -100,7 +94,7 @@ class BoardsController < ApplicationController
|
||||
|
||||
private
|
||||
def redirect_to_settings_in_projects
|
||||
redirect_to settings_project_path(@project, :tab => 'boards')
|
||||
redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'boards'
|
||||
end
|
||||
|
||||
def find_board_if_available
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -32,12 +32,12 @@ class CommentsController < ApplicationController
|
||||
flash[:notice] = l(:label_comment_added)
|
||||
end
|
||||
|
||||
redirect_to news_path(@news)
|
||||
redirect_to :controller => 'news', :action => 'show', :id => @news
|
||||
end
|
||||
|
||||
def destroy
|
||||
@news.comments.find(params[:comment_id]).destroy
|
||||
redirect_to news_path(@news)
|
||||
redirect_to :controller => 'news', :action => 'show', :id => @news
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -21,7 +21,6 @@ class ContextMenusController < ApplicationController
|
||||
|
||||
def issues
|
||||
@issues = Issue.visible.all(:conditions => {:id => params[:ids]}, :include => :project)
|
||||
(render_404; return) unless @issues.present?
|
||||
if (@issues.size == 1)
|
||||
@issue = @issues.first
|
||||
end
|
||||
@@ -75,8 +74,6 @@ class ContextMenusController < ApplicationController
|
||||
def time_entries
|
||||
@time_entries = TimeEntry.all(
|
||||
:conditions => {:id => params[:ids]}, :include => :project)
|
||||
(render_404; return) unless @time_entries.present?
|
||||
|
||||
@projects = @time_entries.collect(&:project).compact.uniq
|
||||
@project = @projects.first if @projects.size == 1
|
||||
@activities = TimeEntryActivity.shared.active
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -23,7 +23,7 @@ class CustomFieldsController < ApplicationController
|
||||
before_filter :find_custom_field, :only => [:edit, :update, :destroy]
|
||||
|
||||
def index
|
||||
@custom_fields_by_type = CustomField.all.group_by {|f| f.class.name }
|
||||
@custom_fields_by_type = CustomField.find(:all).group_by {|f| f.class.name }
|
||||
@tab = params[:tab] || 'IssueCustomField'
|
||||
end
|
||||
|
||||
@@ -31,10 +31,10 @@ class CustomFieldsController < ApplicationController
|
||||
end
|
||||
|
||||
def create
|
||||
if @custom_field.save
|
||||
if request.post? and @custom_field.save
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
call_hook(:controller_custom_fields_new_after_save, :params => params, :custom_field => @custom_field)
|
||||
redirect_to custom_fields_path(:tab => @custom_field.class.name)
|
||||
redirect_to :action => 'index', :tab => @custom_field.class.name
|
||||
else
|
||||
render :action => 'new'
|
||||
end
|
||||
@@ -44,22 +44,21 @@ class CustomFieldsController < ApplicationController
|
||||
end
|
||||
|
||||
def update
|
||||
if @custom_field.update_attributes(params[:custom_field])
|
||||
if request.put? and @custom_field.update_attributes(params[:custom_field])
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
call_hook(:controller_custom_fields_edit_after_save, :params => params, :custom_field => @custom_field)
|
||||
redirect_to custom_fields_path(:tab => @custom_field.class.name)
|
||||
redirect_to :action => 'index', :tab => @custom_field.class.name
|
||||
else
|
||||
render :action => 'edit'
|
||||
end
|
||||
end
|
||||
|
||||
def destroy
|
||||
begin
|
||||
@custom_field.destroy
|
||||
rescue
|
||||
flash[:error] = l(:error_can_not_delete_custom_field)
|
||||
end
|
||||
redirect_to custom_fields_path(:tab => @custom_field.class.name)
|
||||
@custom_field.destroy
|
||||
redirect_to :action => 'index', :tab => @custom_field.class.name
|
||||
rescue
|
||||
flash[:error] = l(:error_can_not_delete_custom_field)
|
||||
redirect_to :action => 'index'
|
||||
end
|
||||
|
||||
private
|
||||
@@ -68,8 +67,6 @@ class CustomFieldsController < ApplicationController
|
||||
@custom_field = CustomField.new_subclass_instance(params[:type], params[:custom_field])
|
||||
if @custom_field.nil?
|
||||
render_404
|
||||
else
|
||||
@custom_field.default_value = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -27,7 +27,7 @@ class DocumentsController < ApplicationController
|
||||
|
||||
def index
|
||||
@sort_by = %w(category date title author).include?(params[:sort_by]) ? params[:sort_by] : 'category'
|
||||
documents = @project.documents.includes(:attachments, :category).all
|
||||
documents = @project.documents.find :all, :include => [:attachments, :category]
|
||||
case @sort_by
|
||||
when 'date'
|
||||
@grouped = documents.group_by {|d| d.updated_on.to_date }
|
||||
@@ -43,7 +43,7 @@ class DocumentsController < ApplicationController
|
||||
end
|
||||
|
||||
def show
|
||||
@attachments = @document.attachments.all
|
||||
@attachments = @document.attachments.find(:all, :order => "created_on DESC")
|
||||
end
|
||||
|
||||
def new
|
||||
@@ -58,7 +58,7 @@ class DocumentsController < ApplicationController
|
||||
if @document.save
|
||||
render_attachment_warning_if_needed(@document)
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
redirect_to project_documents_path(@project)
|
||||
redirect_to :action => 'index', :project_id => @project
|
||||
else
|
||||
render :action => 'new'
|
||||
end
|
||||
@@ -71,7 +71,7 @@ class DocumentsController < ApplicationController
|
||||
@document.safe_attributes = params[:document]
|
||||
if request.put? and @document.save
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to document_path(@document)
|
||||
redirect_to :action => 'show', :id => @document
|
||||
else
|
||||
render :action => 'edit'
|
||||
end
|
||||
@@ -79,7 +79,7 @@ class DocumentsController < ApplicationController
|
||||
|
||||
def destroy
|
||||
@document.destroy if request.delete?
|
||||
redirect_to project_documents_path(@project)
|
||||
redirect_to :controller => 'documents', :action => 'index', :project_id => @project
|
||||
end
|
||||
|
||||
def add_attachment
|
||||
@@ -89,6 +89,6 @@ class DocumentsController < ApplicationController
|
||||
if attachments.present? && attachments[:files].present? && Setting.notified_events.include?('document_added')
|
||||
Mailer.attachments_added(attachments[:files]).deliver
|
||||
end
|
||||
redirect_to document_path(@document)
|
||||
redirect_to :action => 'show', :id => @document
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -46,7 +46,7 @@ class EnumerationsController < ApplicationController
|
||||
def create
|
||||
if request.post? && @enumeration.save
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
redirect_to enumerations_path
|
||||
redirect_to :action => 'index'
|
||||
else
|
||||
render :action => 'new'
|
||||
end
|
||||
@@ -58,7 +58,7 @@ class EnumerationsController < ApplicationController
|
||||
def update
|
||||
if request.put? && @enumeration.update_attributes(params[:enumeration])
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to enumerations_path
|
||||
redirect_to :action => 'index'
|
||||
else
|
||||
render :action => 'edit'
|
||||
end
|
||||
@@ -68,12 +68,12 @@ class EnumerationsController < ApplicationController
|
||||
if !@enumeration.in_use?
|
||||
# No associated objects
|
||||
@enumeration.destroy
|
||||
redirect_to enumerations_path
|
||||
redirect_to :action => 'index'
|
||||
return
|
||||
elsif params[:reassign_to_id]
|
||||
if reassign_to = @enumeration.class.find_by_id(params[:reassign_to_id])
|
||||
@enumeration.destroy(reassign_to)
|
||||
redirect_to enumerations_path
|
||||
redirect_to :action => 'index'
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -31,8 +31,8 @@ class FilesController < ApplicationController
|
||||
'size' => "#{Attachment.table_name}.filesize",
|
||||
'downloads' => "#{Attachment.table_name}.downloads"
|
||||
|
||||
@containers = [ Project.includes(:attachments).reorder(sort_clause).find(@project.id)]
|
||||
@containers += @project.versions.includes(:attachments).reorder(sort_clause).all.sort.reverse
|
||||
@containers = [ Project.find(@project.id, :include => :attachments, :order => sort_clause)]
|
||||
@containers += @project.versions.find(:all, :include => :attachments, :order => sort_clause).sort.reverse
|
||||
render :layout => !request.xhr?
|
||||
end
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -84,7 +84,7 @@ class GroupsController < ApplicationController
|
||||
@group.destroy
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to(groups_path) }
|
||||
format.html { redirect_to(groups_url) }
|
||||
format.api { render_api_ok }
|
||||
end
|
||||
end
|
||||
@@ -93,7 +93,7 @@ class GroupsController < ApplicationController
|
||||
@users = User.find_all_by_id(params[:user_id] || params[:user_ids])
|
||||
@group.users << @users if request.post?
|
||||
respond_to do |format|
|
||||
format.html { redirect_to edit_group_path(@group, :tab => 'users') }
|
||||
format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'users' }
|
||||
format.js
|
||||
format.api { render_api_ok }
|
||||
end
|
||||
@@ -102,23 +102,22 @@ class GroupsController < ApplicationController
|
||||
def remove_user
|
||||
@group.users.delete(User.find(params[:user_id])) if request.delete?
|
||||
respond_to do |format|
|
||||
format.html { redirect_to edit_group_path(@group, :tab => 'users') }
|
||||
format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'users' }
|
||||
format.js
|
||||
format.api { render_api_ok }
|
||||
end
|
||||
end
|
||||
|
||||
def autocomplete_for_user
|
||||
respond_to do |format|
|
||||
format.js
|
||||
end
|
||||
@users = User.active.not_in_group(@group).like(params[:q]).all(:limit => 100)
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
def edit_membership
|
||||
@membership = Member.edit_membership(params[:membership_id], params[:membership], @group)
|
||||
@membership.save if request.post?
|
||||
respond_to do |format|
|
||||
format.html { redirect_to edit_group_path(@group, :tab => 'memberships') }
|
||||
format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'memberships' }
|
||||
format.js
|
||||
end
|
||||
end
|
||||
@@ -126,7 +125,7 @@ class GroupsController < ApplicationController
|
||||
def destroy_membership
|
||||
Member.find(params[:membership_id]).destroy if request.post?
|
||||
respond_to do |format|
|
||||
format.html { redirect_to edit_group_path(@group, :tab => 'memberships') }
|
||||
format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'memberships' }
|
||||
format.js
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -26,14 +26,14 @@ class IssueCategoriesController < ApplicationController
|
||||
|
||||
def index
|
||||
respond_to do |format|
|
||||
format.html { redirect_to_settings_in_projects }
|
||||
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project }
|
||||
format.api { @categories = @project.issue_categories.all }
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
respond_to do |format|
|
||||
format.html { redirect_to_settings_in_projects }
|
||||
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project }
|
||||
format.api
|
||||
end
|
||||
end
|
||||
@@ -55,7 +55,7 @@ class IssueCategoriesController < ApplicationController
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
redirect_to_settings_in_projects
|
||||
redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
|
||||
end
|
||||
format.js
|
||||
format.api { render :action => 'show', :status => :created, :location => issue_category_path(@category) }
|
||||
@@ -78,7 +78,7 @@ class IssueCategoriesController < ApplicationController
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to_settings_in_projects
|
||||
redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
|
||||
}
|
||||
format.api { render_api_ok }
|
||||
end
|
||||
@@ -99,7 +99,7 @@ class IssueCategoriesController < ApplicationController
|
||||
end
|
||||
@category.destroy(reassign_to)
|
||||
respond_to do |format|
|
||||
format.html { redirect_to_settings_in_projects }
|
||||
format.html { redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories' }
|
||||
format.api { render_api_ok }
|
||||
end
|
||||
return
|
||||
@@ -107,12 +107,7 @@ class IssueCategoriesController < ApplicationController
|
||||
@categories = @project.issue_categories - [@category]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def redirect_to_settings_in_projects
|
||||
redirect_to settings_project_path(@project, :tab => 'categories')
|
||||
end
|
||||
|
||||
private
|
||||
# Wrap ApplicationController's find_model_object method to set
|
||||
# @category instead of just @issue_category
|
||||
def find_model_object
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -48,9 +48,9 @@ class IssueRelationsController < ApplicationController
|
||||
saved = @relation.save
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to issue_path(@issue) }
|
||||
format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue }
|
||||
format.js {
|
||||
@relations = @issue.reload.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
|
||||
@relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
|
||||
}
|
||||
format.api {
|
||||
if saved
|
||||
@@ -67,7 +67,7 @@ class IssueRelationsController < ApplicationController
|
||||
@relation.destroy
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to issue_path(@relation.issue_from) }
|
||||
format.html { redirect_to issue_path } # TODO : does this really work since @issue is always nil? What is it useful to?
|
||||
format.js
|
||||
format.api { render_api_ok }
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -25,7 +25,7 @@ class IssueStatusesController < ApplicationController
|
||||
def index
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
@issue_status_pages, @issue_statuses = paginate IssueStatus.sorted, :per_page => 25
|
||||
@issue_status_pages, @issue_statuses = paginate :issue_statuses, :per_page => 25, :order => "position"
|
||||
render :action => "index", :layout => false if request.xhr?
|
||||
}
|
||||
format.api {
|
||||
@@ -42,7 +42,7 @@ class IssueStatusesController < ApplicationController
|
||||
@issue_status = IssueStatus.new(params[:issue_status])
|
||||
if request.post? && @issue_status.save
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
redirect_to issue_statuses_path
|
||||
redirect_to :action => 'index'
|
||||
else
|
||||
render :action => 'new'
|
||||
end
|
||||
@@ -56,7 +56,7 @@ class IssueStatusesController < ApplicationController
|
||||
@issue_status = IssueStatus.find(params[:id])
|
||||
if request.put? && @issue_status.update_attributes(params[:issue_status])
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to issue_statuses_path
|
||||
redirect_to :action => 'index'
|
||||
else
|
||||
render :action => 'edit'
|
||||
end
|
||||
@@ -64,11 +64,11 @@ class IssueStatusesController < ApplicationController
|
||||
|
||||
def destroy
|
||||
IssueStatus.find(params[:id]).destroy
|
||||
redirect_to issue_statuses_path
|
||||
redirect_to :action => 'index'
|
||||
rescue
|
||||
flash[:error] = l(:error_unable_delete_issue_status)
|
||||
redirect_to issue_statuses_path
|
||||
end
|
||||
redirect_to :action => 'index'
|
||||
end
|
||||
|
||||
def update_issue_done_ratio
|
||||
if request.post? && IssueStatus.update_issue_done_ratios
|
||||
@@ -76,6 +76,6 @@ class IssueStatusesController < ApplicationController
|
||||
else
|
||||
flash[:error] = l(:error_issue_done_ratios_not_updated)
|
||||
end
|
||||
redirect_to issue_statuses_path
|
||||
redirect_to :action => 'index'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -21,11 +21,11 @@ class IssuesController < ApplicationController
|
||||
|
||||
before_filter :find_issue, :only => [:show, :edit, :update]
|
||||
before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :destroy]
|
||||
before_filter :find_project, :only => [:new, :create, :update_form]
|
||||
before_filter :find_project, :only => [:new, :create]
|
||||
before_filter :authorize, :except => [:index]
|
||||
before_filter :find_optional_project, :only => [:index]
|
||||
before_filter :check_for_default_issue_status, :only => [:new, :create]
|
||||
before_filter :build_new_issue_from_params, :only => [:new, :create, :update_form]
|
||||
before_filter :build_new_issue_from_params, :only => [:new, :create]
|
||||
accept_rss_auth :index, :show
|
||||
accept_api_auth :index, :show, :create, :update, :destroy
|
||||
|
||||
@@ -71,8 +71,8 @@ class IssuesController < ApplicationController
|
||||
end
|
||||
|
||||
@issue_count = @query.issue_count
|
||||
@issue_pages = Paginator.new @issue_count, @limit, params['page']
|
||||
@offset ||= @issue_pages.offset
|
||||
@issue_pages = Paginator.new self, @issue_count, @limit, params['page']
|
||||
@offset ||= @issue_pages.current.offset
|
||||
@issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version],
|
||||
:order => sort_clause,
|
||||
:offset => @offset,
|
||||
@@ -85,8 +85,8 @@ class IssuesController < ApplicationController
|
||||
Issue.load_visible_relations(@issues) if include_in_api_response?('relations')
|
||||
}
|
||||
format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
|
||||
format.csv { send_data(query_to_csv(@issues, @query, params), :type => 'text/csv; header=present', :filename => 'issues.csv') }
|
||||
format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'issues.pdf') }
|
||||
format.csv { send_data(issues_to_csv(@issues, @project, @query, params), :type => 'text/csv; header=present', :filename => 'export.csv') }
|
||||
format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }
|
||||
end
|
||||
else
|
||||
respond_to do |format|
|
||||
@@ -132,6 +132,7 @@ class IssuesController < ApplicationController
|
||||
def new
|
||||
respond_to do |format|
|
||||
format.html { render :action => 'new', :layout => !request.xhr? }
|
||||
format.js { render :partial => 'update_form' }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -144,12 +145,8 @@ class IssuesController < ApplicationController
|
||||
format.html {
|
||||
render_attachment_warning_if_needed(@issue)
|
||||
flash[:notice] = l(:notice_issue_successful_create, :id => view_context.link_to("##{@issue.id}", issue_path(@issue), :title => @issue.subject))
|
||||
if params[:continue]
|
||||
attrs = {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?}
|
||||
redirect_to new_project_issue_path(@issue.project, :issue => attrs)
|
||||
else
|
||||
redirect_to issue_path(@issue)
|
||||
end
|
||||
redirect_to(params[:continue] ? { :action => 'new', :project_id => @issue.project, :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } :
|
||||
{ :action => 'show', :id => @issue })
|
||||
}
|
||||
format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) }
|
||||
end
|
||||
@@ -190,7 +187,7 @@ class IssuesController < ApplicationController
|
||||
flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record?
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_back_or_default issue_path(@issue) }
|
||||
format.html { redirect_back_or_default({:action => 'show', :id => @issue}) }
|
||||
format.api { render_api_ok }
|
||||
end
|
||||
else
|
||||
@@ -201,11 +198,6 @@ class IssuesController < ApplicationController
|
||||
end
|
||||
end
|
||||
|
||||
# Updates the issue form when changing the project, status or tracker
|
||||
# on issue creation/update
|
||||
def update_form
|
||||
end
|
||||
|
||||
# Bulk edit/copy a set of issues
|
||||
def bulk_edit
|
||||
@issues.sort!
|
||||
@@ -278,12 +270,12 @@ class IssuesController < ApplicationController
|
||||
|
||||
if params[:follow]
|
||||
if @issues.size == 1 && moved_issues.size == 1
|
||||
redirect_to issue_path(moved_issues.first)
|
||||
redirect_to :controller => 'issues', :action => 'show', :id => moved_issues.first
|
||||
elsif moved_issues.map(&:project).uniq.size == 1
|
||||
redirect_to project_issues_path(moved_issues.map(&:project).first)
|
||||
redirect_to :controller => 'issues', :action => 'index', :project_id => moved_issues.map(&:project).first
|
||||
end
|
||||
else
|
||||
redirect_back_or_default _project_issues_path(@project)
|
||||
redirect_back_or_default({:controller => 'issues', :action => 'index', :project_id => @project})
|
||||
end
|
||||
end
|
||||
|
||||
@@ -316,7 +308,7 @@ class IssuesController < ApplicationController
|
||||
end
|
||||
end
|
||||
respond_to do |format|
|
||||
format.html { redirect_back_or_default _project_issues_path(@project) }
|
||||
format.html { redirect_back_or_default(:action => 'index', :project_id => @project) }
|
||||
format.api { render_api_ok }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -80,7 +80,7 @@ class JournalsController < ApplicationController
|
||||
@journal.destroy if @journal.details.empty? && @journal.notes.blank?
|
||||
call_hook(:controller_journals_edit_post, { :journal => @journal, :params => params})
|
||||
respond_to do |format|
|
||||
format.html { redirect_to issue_path(@journal.journalized) }
|
||||
format.html { redirect_to :controller => 'issues', :action => 'show', :id => @journal.journalized_id }
|
||||
format.js { render :action => 'update' }
|
||||
end
|
||||
else
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -26,8 +26,8 @@ class MembersController < ApplicationController
|
||||
def index
|
||||
@offset, @limit = api_offset_and_limit
|
||||
@member_count = @project.member_principals.count
|
||||
@member_pages = Paginator.new @member_count, @limit, params['page']
|
||||
@offset ||= @member_pages.offset
|
||||
@member_pages = Paginator.new self, @member_count, @limit, params['page']
|
||||
@offset ||= @member_pages.current.offset
|
||||
@members = @project.member_principals.all(
|
||||
:order => "#{Member.table_name}.id",
|
||||
:limit => @limit,
|
||||
@@ -63,7 +63,7 @@ class MembersController < ApplicationController
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to_settings_in_projects }
|
||||
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
|
||||
format.js { @members = members }
|
||||
format.api {
|
||||
@member = members.first
|
||||
@@ -82,7 +82,7 @@ class MembersController < ApplicationController
|
||||
end
|
||||
saved = @member.save
|
||||
respond_to do |format|
|
||||
format.html { redirect_to_settings_in_projects }
|
||||
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
|
||||
format.js
|
||||
format.api {
|
||||
if saved
|
||||
@@ -99,7 +99,7 @@ class MembersController < ApplicationController
|
||||
@member.destroy
|
||||
end
|
||||
respond_to do |format|
|
||||
format.html { redirect_to_settings_in_projects }
|
||||
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
|
||||
format.js
|
||||
format.api {
|
||||
if @member.destroyed?
|
||||
@@ -112,14 +112,7 @@ class MembersController < ApplicationController
|
||||
end
|
||||
|
||||
def autocomplete
|
||||
respond_to do |format|
|
||||
format.js
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def redirect_to_settings_in_projects
|
||||
redirect_to settings_project_path(@project, :tab => 'members')
|
||||
@principals = Principal.active.not_member_of(@project).like(params[:q]).all(:limit => 100)
|
||||
render :layout => false
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -19,7 +19,6 @@ class MessagesController < ApplicationController
|
||||
menu_item :boards
|
||||
default_search_scope :messages
|
||||
before_filter :find_board, :only => [:new, :preview]
|
||||
before_filter :find_attachments, :only => [:preview]
|
||||
before_filter :find_message, :except => [:new, :preview]
|
||||
before_filter :authorize, :except => [:preview, :edit, :destroy]
|
||||
|
||||
@@ -40,13 +39,11 @@ class MessagesController < ApplicationController
|
||||
end
|
||||
|
||||
@reply_count = @topic.children.count
|
||||
@reply_pages = Paginator.new @reply_count, REPLIES_PER_PAGE, page
|
||||
@replies = @topic.children.
|
||||
includes(:author, :attachments, {:board => :project}).
|
||||
reorder("#{Message.table_name}.created_on ASC").
|
||||
limit(@reply_pages.per_page).
|
||||
offset(@reply_pages.offset).
|
||||
all
|
||||
@reply_pages = Paginator.new self, @reply_count, REPLIES_PER_PAGE, page
|
||||
@replies = @topic.children.find(:all, :include => [:author, :attachments, {:board => :project}],
|
||||
:order => "#{Message.table_name}.created_on ASC",
|
||||
:limit => @reply_pages.items_per_page,
|
||||
:offset => @reply_pages.current.offset)
|
||||
|
||||
@reply = Message.new(:subject => "RE: #{@message.subject}")
|
||||
render :action => "show", :layout => false if request.xhr?
|
||||
@@ -118,6 +115,7 @@ class MessagesController < ApplicationController
|
||||
|
||||
def preview
|
||||
message = @board.messages.find_by_id(params[:id])
|
||||
@attachements = message.attachments if message
|
||||
@text = (params[:message] || params[:reply])[:content]
|
||||
@previewed = message
|
||||
render :partial => 'common/preview'
|
||||
@@ -125,7 +123,7 @@ class MessagesController < ApplicationController
|
||||
|
||||
private
|
||||
def find_message
|
||||
return unless find_board
|
||||
find_board
|
||||
@message = @board.messages.find(params[:id], :include => :parent)
|
||||
@topic = @message.root
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
@@ -137,6 +135,5 @@ private
|
||||
@project = @board.project
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
render_404
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -59,7 +59,7 @@ class MyController < ApplicationController
|
||||
@user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : [])
|
||||
set_language_if_valid @user.language
|
||||
flash[:notice] = l(:notice_account_updated)
|
||||
redirect_to my_account_path
|
||||
redirect_to :action => 'account'
|
||||
return
|
||||
end
|
||||
end
|
||||
@@ -69,7 +69,7 @@ class MyController < ApplicationController
|
||||
def destroy
|
||||
@user = User.current
|
||||
unless @user.own_account_deletable?
|
||||
redirect_to my_account_path
|
||||
redirect_to :action => 'account'
|
||||
return
|
||||
end
|
||||
|
||||
@@ -88,7 +88,7 @@ class MyController < ApplicationController
|
||||
@user = User.current
|
||||
unless @user.change_password_allowed?
|
||||
flash[:error] = l(:notice_can_t_change_password)
|
||||
redirect_to my_account_path
|
||||
redirect_to :action => 'account'
|
||||
return
|
||||
end
|
||||
if request.post?
|
||||
@@ -96,7 +96,7 @@ class MyController < ApplicationController
|
||||
@user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
|
||||
if @user.save
|
||||
flash[:notice] = l(:notice_account_password_updated)
|
||||
redirect_to my_account_path
|
||||
redirect_to :action => 'account'
|
||||
end
|
||||
else
|
||||
flash[:error] = l(:notice_account_wrong_password)
|
||||
@@ -114,7 +114,7 @@ class MyController < ApplicationController
|
||||
User.current.rss_key
|
||||
flash[:notice] = l(:notice_feeds_access_key_reseted)
|
||||
end
|
||||
redirect_to my_account_path
|
||||
redirect_to :action => 'account'
|
||||
end
|
||||
|
||||
# Create a new API key
|
||||
@@ -127,7 +127,7 @@ class MyController < ApplicationController
|
||||
User.current.api_key
|
||||
flash[:notice] = l(:notice_api_access_key_reseted)
|
||||
end
|
||||
redirect_to my_account_path
|
||||
redirect_to :action => 'account'
|
||||
end
|
||||
|
||||
# User's page layout configuration
|
||||
@@ -147,17 +147,16 @@ class MyController < ApplicationController
|
||||
# params[:block] : id of the block to add
|
||||
def add_block
|
||||
block = params[:block].to_s.underscore
|
||||
if block.present? && BLOCKS.key?(block)
|
||||
@user = User.current
|
||||
layout = @user.pref[:my_page_layout] || {}
|
||||
# remove if already present in a group
|
||||
%w(top left right).each {|f| (layout[f] ||= []).delete block }
|
||||
# add it on top
|
||||
layout['top'].unshift block
|
||||
@user.pref[:my_page_layout] = layout
|
||||
@user.pref.save
|
||||
end
|
||||
redirect_to my_page_layout_path
|
||||
(render :nothing => true; return) unless block && (BLOCKS.keys.include? block)
|
||||
@user = User.current
|
||||
layout = @user.pref[:my_page_layout] || {}
|
||||
# remove if already present in a group
|
||||
%w(top left right).each {|f| (layout[f] ||= []).delete block }
|
||||
# add it on top
|
||||
layout['top'].unshift block
|
||||
@user.pref[:my_page_layout] = layout
|
||||
@user.pref.save
|
||||
redirect_to :action => 'page_layout'
|
||||
end
|
||||
|
||||
# Remove a block to user's page
|
||||
@@ -170,7 +169,7 @@ class MyController < ApplicationController
|
||||
%w(top left right).each {|f| (layout[f] ||= []).delete block }
|
||||
@user.pref[:my_page_layout] = layout
|
||||
@user.pref.save
|
||||
redirect_to my_page_layout_path
|
||||
redirect_to :action => 'page_layout'
|
||||
end
|
||||
|
||||
# Change blocks order on user's page
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -40,8 +40,8 @@ class NewsController < ApplicationController
|
||||
scope = @project ? @project.news.visible : News.visible
|
||||
|
||||
@news_count = scope.count
|
||||
@news_pages = Paginator.new @news_count, @limit, params['page']
|
||||
@offset ||= @news_pages.offset
|
||||
@news_pages = Paginator.new self, @news_count, @limit, params['page']
|
||||
@offset ||= @news_pages.current.offset
|
||||
@newss = scope.all(:include => [:author, :project],
|
||||
:order => "#{News.table_name}.created_on DESC",
|
||||
:offset => @offset,
|
||||
@@ -73,7 +73,7 @@ class NewsController < ApplicationController
|
||||
if @news.save
|
||||
render_attachment_warning_if_needed(@news)
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
redirect_to project_news_index_path(@project)
|
||||
redirect_to :controller => 'news', :action => 'index', :project_id => @project
|
||||
else
|
||||
render :action => 'new'
|
||||
end
|
||||
@@ -88,7 +88,7 @@ class NewsController < ApplicationController
|
||||
if @news.save
|
||||
render_attachment_warning_if_needed(@news)
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to news_path(@news)
|
||||
redirect_to :action => 'show', :id => @news
|
||||
else
|
||||
render :action => 'edit'
|
||||
end
|
||||
@@ -96,7 +96,7 @@ class NewsController < ApplicationController
|
||||
|
||||
def destroy
|
||||
@news.destroy
|
||||
redirect_to project_news_index_path(@project)
|
||||
redirect_to :action => 'index', :project_id => @project
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -16,11 +16,12 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
class PreviewsController < ApplicationController
|
||||
before_filter :find_project, :find_attachments
|
||||
before_filter :find_project
|
||||
|
||||
def issue
|
||||
@issue = @project.issues.find_by_id(params[:id]) unless params[:id].blank?
|
||||
if @issue
|
||||
@attachements = @issue.attachments
|
||||
@description = params[:issue] && params[:issue][:description]
|
||||
if @description && @description.gsub(/(\r?\n|\n\r?)/, "\n") == @issue.description.to_s.gsub(/(\r?\n|\n\r?)/, "\n")
|
||||
@description = nil
|
||||
@@ -36,6 +37,7 @@ class PreviewsController < ApplicationController
|
||||
def news
|
||||
if params[:id].present? && news = News.visible.find_by_id(params[:id])
|
||||
@previewed = news
|
||||
@attachments = news.attachments
|
||||
end
|
||||
@text = (params[:news] ? params[:news][:description] : nil)
|
||||
render :partial => 'common/preview'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -29,7 +29,7 @@ class ProjectEnumerationsController < ApplicationController
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
end
|
||||
|
||||
redirect_to settings_project_path(@project, :tab => 'activities')
|
||||
redirect_to :controller => 'projects', :action => 'settings', :tab => 'activities', :id => @project
|
||||
end
|
||||
|
||||
def destroy
|
||||
@@ -37,6 +37,7 @@ class ProjectEnumerationsController < ApplicationController
|
||||
time_entry_activity.destroy(time_entry_activity.parent)
|
||||
end
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to settings_project_path(@project, :tab => 'activities')
|
||||
redirect_to :controller => 'projects', :action => 'settings', :tab => 'activities', :id => @project
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -43,7 +43,6 @@ class ProjectsController < ApplicationController
|
||||
helper :repositories
|
||||
include RepositoriesHelper
|
||||
include ProjectsHelper
|
||||
helper :members
|
||||
|
||||
# Lists visible projects
|
||||
def index
|
||||
@@ -58,24 +57,25 @@ class ProjectsController < ApplicationController
|
||||
format.api {
|
||||
@offset, @limit = api_offset_and_limit
|
||||
@project_count = Project.visible.count
|
||||
@projects = Project.visible.offset(@offset).limit(@limit).order('lft').all
|
||||
@projects = Project.visible.all(:offset => @offset, :limit => @limit, :order => 'lft')
|
||||
}
|
||||
format.atom {
|
||||
projects = Project.visible.order('created_on DESC').limit(Setting.feeds_limit.to_i).all
|
||||
projects = Project.visible.find(:all, :order => 'created_on DESC',
|
||||
:limit => Setting.feeds_limit.to_i)
|
||||
render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}")
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def new
|
||||
@issue_custom_fields = IssueCustomField.sorted.all
|
||||
@issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
|
||||
@trackers = Tracker.sorted.all
|
||||
@project = Project.new
|
||||
@project.safe_attributes = params[:project]
|
||||
end
|
||||
|
||||
def create
|
||||
@issue_custom_fields = IssueCustomField.sorted.all
|
||||
@issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
|
||||
@trackers = Tracker.sorted.all
|
||||
@project = Project.new
|
||||
@project.safe_attributes = params[:project]
|
||||
@@ -91,12 +91,10 @@ class ProjectsController < ApplicationController
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
if params[:continue]
|
||||
attrs = {:parent_id => @project.parent_id}.reject {|k,v| v.nil?}
|
||||
redirect_to new_project_path(attrs)
|
||||
else
|
||||
redirect_to settings_project_path(@project)
|
||||
end
|
||||
redirect_to(params[:continue] ?
|
||||
{:controller => 'projects', :action => 'new', :project => {:parent_id => @project.parent_id}.reject {|k,v| v.nil?}} :
|
||||
{:controller => 'projects', :action => 'settings', :id => @project}
|
||||
)
|
||||
}
|
||||
format.api { render :action => 'show', :status => :created, :location => url_for(:controller => 'projects', :action => 'show', :id => @project.id) }
|
||||
end
|
||||
@@ -106,11 +104,15 @@ class ProjectsController < ApplicationController
|
||||
format.api { render_validation_errors(@project) }
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def copy
|
||||
@issue_custom_fields = IssueCustomField.sorted.all
|
||||
@issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
|
||||
@trackers = Tracker.sorted.all
|
||||
@root_projects = Project.find(:all,
|
||||
:conditions => "parent_id IS NULL AND status = #{Project::STATUS_ACTIVE}",
|
||||
:order => 'name')
|
||||
@source_project = Project.find(params[:id])
|
||||
if request.get?
|
||||
@project = Project.copy_from(@source_project)
|
||||
@@ -122,13 +124,13 @@ class ProjectsController < ApplicationController
|
||||
if validate_parent_id && @project.copy(@source_project, :only => params[:only])
|
||||
@project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
redirect_to settings_project_path(@project)
|
||||
redirect_to :controller => 'projects', :action => 'settings', :id => @project
|
||||
elsif !@project.new_record?
|
||||
# Project was created
|
||||
# But some objects were not copied due to validation failures
|
||||
# (eg. issues from disabled trackers)
|
||||
# TODO: inform about that
|
||||
redirect_to settings_project_path(@project)
|
||||
redirect_to :controller => 'projects', :action => 'settings', :id => @project
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -136,17 +138,17 @@ class ProjectsController < ApplicationController
|
||||
# source_project not found
|
||||
render_404
|
||||
end
|
||||
|
||||
|
||||
# Show @project
|
||||
def show
|
||||
# try to redirect to the requested menu item
|
||||
if params[:jump] && redirect_to_project_menu_item(@project, params[:jump])
|
||||
return
|
||||
if params[:jump]
|
||||
# try to redirect to the requested menu item
|
||||
redirect_to_project_menu_item(@project, params[:jump]) && return
|
||||
end
|
||||
|
||||
@users_by_role = @project.users_by_role
|
||||
@subprojects = @project.children.visible.all
|
||||
@news = @project.news.limit(5).includes(:author, :project).reorder("#{News.table_name}.created_on DESC").all
|
||||
@news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
|
||||
@trackers = @project.rolled_up_trackers
|
||||
|
||||
cond = @project.project_condition(Setting.display_subprojects_issues?)
|
||||
@@ -167,7 +169,7 @@ class ProjectsController < ApplicationController
|
||||
end
|
||||
|
||||
def settings
|
||||
@issue_custom_fields = IssueCustomField.sorted.all
|
||||
@issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
|
||||
@issue_category ||= IssueCategory.new
|
||||
@member ||= @project.members.new
|
||||
@trackers = Tracker.sorted.all
|
||||
@@ -184,7 +186,7 @@ class ProjectsController < ApplicationController
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to settings_project_path(@project)
|
||||
redirect_to :action => 'settings', :id => @project
|
||||
}
|
||||
format.api { render_api_ok }
|
||||
end
|
||||
@@ -202,7 +204,7 @@ class ProjectsController < ApplicationController
|
||||
def modules
|
||||
@project.enabled_module_names = params[:enabled_module_names]
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to settings_project_path(@project, :tab => 'modules')
|
||||
redirect_to :action => 'settings', :id => @project, :tab => 'modules'
|
||||
end
|
||||
|
||||
def archive
|
||||
@@ -211,12 +213,12 @@ class ProjectsController < ApplicationController
|
||||
flash[:error] = l(:error_can_not_archive_project)
|
||||
end
|
||||
end
|
||||
redirect_to admin_projects_path(:status => params[:status])
|
||||
redirect_to(url_for(:controller => 'admin', :action => 'projects', :status => params[:status]))
|
||||
end
|
||||
|
||||
def unarchive
|
||||
@project.unarchive if request.post? && !@project.active?
|
||||
redirect_to admin_projects_path(:status => params[:status])
|
||||
redirect_to(url_for(:controller => 'admin', :action => 'projects', :status => params[:status]))
|
||||
end
|
||||
|
||||
def close
|
||||
@@ -235,7 +237,7 @@ class ProjectsController < ApplicationController
|
||||
if api_request? || params[:confirm]
|
||||
@project_to_destroy.destroy
|
||||
respond_to do |format|
|
||||
format.html { redirect_to admin_projects_path }
|
||||
format.html { redirect_to :controller => 'admin', :action => 'projects' }
|
||||
format.api { render_api_ok }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -32,34 +32,35 @@ class QueriesController < ApplicationController
|
||||
@limit = per_page_option
|
||||
end
|
||||
|
||||
@query_count = IssueQuery.visible.count
|
||||
@query_pages = Paginator.new @query_count, @limit, params['page']
|
||||
@queries = IssueQuery.visible.all(:limit => @limit, :offset => @offset, :order => "#{Query.table_name}.name")
|
||||
@query_count = Query.visible.count
|
||||
@query_pages = Paginator.new self, @query_count, @limit, params['page']
|
||||
@queries = Query.visible.all(:limit => @limit, :offset => @offset, :order => "#{Query.table_name}.name")
|
||||
|
||||
respond_to do |format|
|
||||
format.html { render :nothing => true }
|
||||
format.api
|
||||
end
|
||||
end
|
||||
|
||||
def new
|
||||
@query = IssueQuery.new
|
||||
@query = Query.new
|
||||
@query.user = User.current
|
||||
@query.project = @project
|
||||
@query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
|
||||
@query.build_from_params(params)
|
||||
build_query_from_params
|
||||
end
|
||||
|
||||
def create
|
||||
@query = IssueQuery.new(params[:query])
|
||||
@query = Query.new(params[:query])
|
||||
@query.user = User.current
|
||||
@query.project = params[:query_is_for_all] ? nil : @project
|
||||
@query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
|
||||
@query.build_from_params(params)
|
||||
build_query_from_params
|
||||
@query.column_names = nil if params[:default_columns]
|
||||
|
||||
if @query.save
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
redirect_to _project_issues_path(@project, :query_id => @query)
|
||||
redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query
|
||||
else
|
||||
render :action => 'new', :layout => !request.xhr?
|
||||
end
|
||||
@@ -72,12 +73,12 @@ class QueriesController < ApplicationController
|
||||
@query.attributes = params[:query]
|
||||
@query.project = nil if params[:query_is_for_all]
|
||||
@query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
|
||||
@query.build_from_params(params)
|
||||
build_query_from_params
|
||||
@query.column_names = nil if params[:default_columns]
|
||||
|
||||
if @query.save
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to _project_issues_path(@project, :query_id => @query)
|
||||
redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query
|
||||
else
|
||||
render :action => 'edit'
|
||||
end
|
||||
@@ -85,12 +86,12 @@ class QueriesController < ApplicationController
|
||||
|
||||
def destroy
|
||||
@query.destroy
|
||||
redirect_to _project_issues_path(@project, :set_filter => 1)
|
||||
redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1
|
||||
end
|
||||
|
||||
private
|
||||
def find_query
|
||||
@query = IssueQuery.find(params[:id])
|
||||
@query = Query.find(params[:id])
|
||||
@project = @query.project
|
||||
render_403 unless @query.editable_by?(User.current)
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -90,6 +90,6 @@ class ReportsController < ApplicationController
|
||||
private
|
||||
|
||||
def find_issue_statuses
|
||||
@statuses = IssueStatus.sorted.all
|
||||
@statuses = IssueStatus.find(:all, :order => 'position')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -138,14 +138,13 @@ class RepositoriesController < ApplicationController
|
||||
|
||||
def revisions
|
||||
@changeset_count = @repository.changesets.count
|
||||
@changeset_pages = Paginator.new @changeset_count,
|
||||
@changeset_pages = Paginator.new self, @changeset_count,
|
||||
per_page_option,
|
||||
params['page']
|
||||
@changesets = @repository.changesets.
|
||||
limit(@changeset_pages.per_page).
|
||||
offset(@changeset_pages.offset).
|
||||
includes(:user, :repository, :parents).
|
||||
all
|
||||
@changesets = @repository.changesets.find(:all,
|
||||
:limit => @changeset_pages.items_per_page,
|
||||
:offset => @changeset_pages.current.offset,
|
||||
:include => [:user, :repository, :parents])
|
||||
|
||||
respond_to do |format|
|
||||
format.html { render :layout => false if request.xhr? }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -26,7 +26,7 @@ class RolesController < ApplicationController
|
||||
def index
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
@role_pages, @roles = paginate Role.sorted, :per_page => 25
|
||||
@role_pages, @roles = paginate :roles, :per_page => 25, :order => 'builtin, position'
|
||||
render :action => "index", :layout => false if request.xhr?
|
||||
}
|
||||
format.api {
|
||||
@@ -58,7 +58,7 @@ class RolesController < ApplicationController
|
||||
@role.workflow_rules.copy(copy_from)
|
||||
end
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
redirect_to roles_path
|
||||
redirect_to :action => 'index'
|
||||
else
|
||||
@roles = Role.sorted.all
|
||||
render :action => 'new'
|
||||
@@ -71,7 +71,7 @@ class RolesController < ApplicationController
|
||||
def update
|
||||
if request.put? and @role.update_attributes(params[:role])
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to roles_path
|
||||
redirect_to :action => 'index'
|
||||
else
|
||||
render :action => 'edit'
|
||||
end
|
||||
@@ -79,10 +79,10 @@ class RolesController < ApplicationController
|
||||
|
||||
def destroy
|
||||
@role.destroy
|
||||
redirect_to roles_path
|
||||
redirect_to :action => 'index'
|
||||
rescue
|
||||
flash[:error] = l(:error_can_not_remove_role)
|
||||
redirect_to roles_path
|
||||
redirect_to :action => 'index'
|
||||
end
|
||||
|
||||
def permissions
|
||||
@@ -94,7 +94,7 @@ class RolesController < ApplicationController
|
||||
role.save
|
||||
end
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to roles_path
|
||||
redirect_to :action => 'index'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -18,6 +18,9 @@
|
||||
class SearchController < ApplicationController
|
||||
before_filter :find_optional_project
|
||||
|
||||
helper :messages
|
||||
include MessagesHelper
|
||||
|
||||
def index
|
||||
@question = params[:q] || ""
|
||||
@question.strip!
|
||||
@@ -40,8 +43,8 @@ class SearchController < ApplicationController
|
||||
begin; offset = params[:offset].to_time if params[:offset]; rescue; end
|
||||
|
||||
# quick jump to an issue
|
||||
if (m = @question.match(/^#?(\d+)$/)) && (issue = Issue.visible.find_by_id(m[1].to_i))
|
||||
redirect_to issue_path(issue)
|
||||
if @question.match(/^#?(\d+)$/) && Issue.visible.find_by_id($1.to_i)
|
||||
redirect_to :controller => "issues", :action => "show", :id => $1
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -19,8 +19,6 @@ class SettingsController < ApplicationController
|
||||
layout 'admin'
|
||||
menu_item :plugins, :only => :plugin
|
||||
|
||||
helper :queries
|
||||
|
||||
before_filter :require_admin
|
||||
|
||||
def index
|
||||
@@ -38,7 +36,7 @@ class SettingsController < ApplicationController
|
||||
Setting[name] = value
|
||||
end
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to settings_path(:tab => params[:tab])
|
||||
redirect_to :action => 'edit', :tab => params[:tab]
|
||||
else
|
||||
@options = {}
|
||||
user_format = User::USER_FORMATS.collect{|key, value| [key, value[:setting_order]]}.sort{|a, b| a[1] <=> b[1]}
|
||||
@@ -54,15 +52,10 @@ class SettingsController < ApplicationController
|
||||
|
||||
def plugin
|
||||
@plugin = Redmine::Plugin.find(params[:id])
|
||||
unless @plugin.configurable?
|
||||
render_404
|
||||
return
|
||||
end
|
||||
|
||||
if request.post?
|
||||
Setting.send "plugin_#{@plugin.id}=", params[:settings]
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to plugin_settings_path(@plugin)
|
||||
redirect_to :action => 'plugin', :id => @plugin.id
|
||||
else
|
||||
@partial = @plugin.settings[:partial]
|
||||
@settings = Setting.send "plugin_#{@plugin.id}"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -30,34 +30,41 @@ class TimelogController < ApplicationController
|
||||
accept_rss_auth :index
|
||||
accept_api_auth :index, :show, :create, :update, :destroy
|
||||
|
||||
rescue_from Query::StatementInvalid, :with => :query_statement_invalid
|
||||
|
||||
helper :sort
|
||||
include SortHelper
|
||||
helper :issues
|
||||
include TimelogHelper
|
||||
helper :custom_fields
|
||||
include CustomFieldsHelper
|
||||
helper :queries
|
||||
include QueriesHelper
|
||||
|
||||
def index
|
||||
@query = TimeEntryQuery.build_from_params(params, :project => @project, :name => '_')
|
||||
scope = time_entry_scope
|
||||
sort_init 'spent_on', 'desc'
|
||||
sort_update 'spent_on' => ['spent_on', "#{TimeEntry.table_name}.created_on"],
|
||||
'user' => 'user_id',
|
||||
'activity' => 'activity_id',
|
||||
'project' => "#{Project.table_name}.name",
|
||||
'issue' => 'issue_id',
|
||||
'hours' => 'hours'
|
||||
|
||||
sort_init(@query.sort_criteria.empty? ? [['spent_on', 'desc']] : @query.sort_criteria)
|
||||
sort_update(@query.sortable_columns)
|
||||
retrieve_date_range
|
||||
|
||||
scope = TimeEntry.visible.spent_between(@from, @to)
|
||||
if @issue
|
||||
scope = scope.on_issue(@issue)
|
||||
elsif @project
|
||||
scope = scope.on_project(@project, Setting.display_subprojects_issues?)
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
# Paginate results
|
||||
@entry_count = scope.count
|
||||
@entry_pages = Paginator.new @entry_count, per_page_option, params['page']
|
||||
@entry_pages = Paginator.new self, @entry_count, per_page_option, params['page']
|
||||
@entries = scope.all(
|
||||
:include => [:project, :activity, :user, {:issue => :tracker}],
|
||||
:order => sort_clause,
|
||||
:limit => @entry_pages.per_page,
|
||||
:offset => @entry_pages.offset
|
||||
:limit => @entry_pages.items_per_page,
|
||||
:offset => @entry_pages.current.offset
|
||||
)
|
||||
@total_hours = scope.sum(:hours).to_f
|
||||
|
||||
@@ -87,16 +94,14 @@ class TimelogController < ApplicationController
|
||||
:include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}],
|
||||
:order => sort_clause
|
||||
)
|
||||
send_data(query_to_csv(@entries, @query, params), :type => 'text/csv; header=present', :filename => 'timelog.csv')
|
||||
send_data(entries_to_csv(@entries), :type => 'text/csv; header=present', :filename => 'timelog.csv')
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def report
|
||||
@query = TimeEntryQuery.build_from_params(params, :project => @project, :name => '_')
|
||||
scope = time_entry_scope
|
||||
|
||||
@report = Redmine::Helpers::TimeReport.new(@project, @issue, params[:criteria], params[:columns], scope)
|
||||
retrieve_date_range
|
||||
@report = Redmine::Helpers::TimeReport.new(@project, @issue, params[:criteria], params[:columns], @from, @to)
|
||||
|
||||
respond_to do |format|
|
||||
format.html { render :layout => !request.xhr? }
|
||||
@@ -129,24 +134,16 @@ class TimelogController < ApplicationController
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
if params[:continue]
|
||||
if params[:project_id]
|
||||
options = {
|
||||
redirect_to :action => 'new', :project_id => @time_entry.project, :issue_id => @time_entry.issue,
|
||||
:time_entry => {:issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id},
|
||||
:back_url => params[:back_url]
|
||||
}
|
||||
if @time_entry.issue
|
||||
redirect_to new_project_issue_time_entry_path(@time_entry.project, @time_entry.issue, options)
|
||||
else
|
||||
redirect_to new_project_time_entry_path(@time_entry.project, options)
|
||||
end
|
||||
else
|
||||
options = {
|
||||
redirect_to :action => 'new',
|
||||
:time_entry => {:project_id => @time_entry.project_id, :issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id},
|
||||
:back_url => params[:back_url]
|
||||
}
|
||||
redirect_to new_time_entry_path(options)
|
||||
end
|
||||
else
|
||||
redirect_back_or_default project_time_entries_path(@time_entry.project)
|
||||
redirect_back_or_default :action => 'index', :project_id => @time_entry.project
|
||||
end
|
||||
}
|
||||
format.api { render :action => 'show', :status => :created, :location => time_entry_url(@time_entry) }
|
||||
@@ -172,7 +169,7 @@ class TimelogController < ApplicationController
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_back_or_default project_time_entries_path(@time_entry.project)
|
||||
redirect_back_or_default :action => 'index', :project_id => @time_entry.project
|
||||
}
|
||||
format.api { render_api_ok }
|
||||
end
|
||||
@@ -203,7 +200,7 @@ class TimelogController < ApplicationController
|
||||
end
|
||||
end
|
||||
set_flash_from_bulk_time_entry_save(@time_entries, unsaved_time_entry_ids)
|
||||
redirect_back_or_default project_time_entries_path(@projects.first)
|
||||
redirect_back_or_default({:controller => 'timelog', :action => 'index', :project_id => @projects.first})
|
||||
end
|
||||
|
||||
def destroy
|
||||
@@ -222,7 +219,7 @@ class TimelogController < ApplicationController
|
||||
else
|
||||
flash[:error] = l(:notice_unable_delete_time_entry)
|
||||
end
|
||||
redirect_back_or_default project_time_entries_path(@projects.first)
|
||||
redirect_back_or_default(:action => 'index', :project_id => @projects.first)
|
||||
}
|
||||
format.api {
|
||||
if destroyed
|
||||
@@ -294,15 +291,51 @@ private
|
||||
end
|
||||
end
|
||||
|
||||
# Returns the TimeEntry scope for index and report actions
|
||||
def time_entry_scope
|
||||
scope = TimeEntry.visible.where(@query.statement)
|
||||
if @issue
|
||||
scope = scope.on_issue(@issue)
|
||||
elsif @project
|
||||
scope = scope.on_project(@project, Setting.display_subprojects_issues?)
|
||||
# Retrieves the date range based on predefined ranges or specific from/to param dates
|
||||
def retrieve_date_range
|
||||
@free_period = false
|
||||
@from, @to = nil, nil
|
||||
|
||||
if params[:period_type] == '1' || (params[:period_type].nil? && !params[:period].nil?)
|
||||
case params[:period].to_s
|
||||
when 'today'
|
||||
@from = @to = Date.today
|
||||
when 'yesterday'
|
||||
@from = @to = Date.today - 1
|
||||
when 'current_week'
|
||||
@from = Date.today - (Date.today.cwday - 1)%7
|
||||
@to = @from + 6
|
||||
when 'last_week'
|
||||
@from = Date.today - 7 - (Date.today.cwday - 1)%7
|
||||
@to = @from + 6
|
||||
when 'last_2_weeks'
|
||||
@from = Date.today - 14 - (Date.today.cwday - 1)%7
|
||||
@to = @from + 13
|
||||
when '7_days'
|
||||
@from = Date.today - 7
|
||||
@to = Date.today
|
||||
when 'current_month'
|
||||
@from = Date.civil(Date.today.year, Date.today.month, 1)
|
||||
@to = (@from >> 1) - 1
|
||||
when 'last_month'
|
||||
@from = Date.civil(Date.today.year, Date.today.month, 1) << 1
|
||||
@to = (@from >> 1) - 1
|
||||
when '30_days'
|
||||
@from = Date.today - 30
|
||||
@to = Date.today
|
||||
when 'current_year'
|
||||
@from = Date.civil(Date.today.year, 1, 1)
|
||||
@to = Date.civil(Date.today.year, 12, 31)
|
||||
end
|
||||
elsif params[:period_type] == '2' || (params[:period_type].nil? && (!params[:from].nil? || !params[:to].nil?))
|
||||
begin; @from = params[:from].to_s.to_date unless params[:from].blank?; rescue; end
|
||||
begin; @to = params[:to].to_s.to_date unless params[:to].blank?; rescue; end
|
||||
@free_period = true
|
||||
else
|
||||
# default
|
||||
end
|
||||
scope
|
||||
|
||||
@from, @to = @to, @from if @from && @to && @from > @to
|
||||
end
|
||||
|
||||
def parse_params_for_bulk_time_entry_attributes(params)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -25,7 +25,7 @@ class TrackersController < ApplicationController
|
||||
def index
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
@tracker_pages, @trackers = paginate Tracker.sorted, :per_page => 25
|
||||
@tracker_pages, @trackers = paginate :trackers, :per_page => 10, :order => 'position'
|
||||
render :action => "index", :layout => false if request.xhr?
|
||||
}
|
||||
format.api {
|
||||
@@ -36,19 +36,19 @@ class TrackersController < ApplicationController
|
||||
|
||||
def new
|
||||
@tracker ||= Tracker.new(params[:tracker])
|
||||
@trackers = Tracker.sorted.all
|
||||
@projects = Project.all
|
||||
@trackers = Tracker.find :all, :order => 'position'
|
||||
@projects = Project.find(:all)
|
||||
end
|
||||
|
||||
def create
|
||||
@tracker = Tracker.new(params[:tracker])
|
||||
if @tracker.save
|
||||
if request.post? and @tracker.save
|
||||
# workflow copy
|
||||
if !params[:copy_workflow_from].blank? && (copy_from = Tracker.find_by_id(params[:copy_workflow_from]))
|
||||
@tracker.workflow_rules.copy(copy_from)
|
||||
end
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
redirect_to trackers_path
|
||||
redirect_to :action => 'index'
|
||||
return
|
||||
end
|
||||
new
|
||||
@@ -57,14 +57,14 @@ class TrackersController < ApplicationController
|
||||
|
||||
def edit
|
||||
@tracker ||= Tracker.find(params[:id])
|
||||
@projects = Project.all
|
||||
@projects = Project.find(:all)
|
||||
end
|
||||
|
||||
def update
|
||||
@tracker = Tracker.find(params[:id])
|
||||
if @tracker.update_attributes(params[:tracker])
|
||||
if request.put? and @tracker.update_attributes(params[:tracker])
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to trackers_path
|
||||
redirect_to :action => 'index'
|
||||
return
|
||||
end
|
||||
edit
|
||||
@@ -78,7 +78,7 @@ class TrackersController < ApplicationController
|
||||
else
|
||||
@tracker.destroy
|
||||
end
|
||||
redirect_to trackers_path
|
||||
redirect_to :action => 'index'
|
||||
end
|
||||
|
||||
def fields
|
||||
@@ -92,7 +92,7 @@ class TrackersController < ApplicationController
|
||||
end
|
||||
end
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to fields_trackers_path
|
||||
redirect_to :action => 'fields'
|
||||
return
|
||||
end
|
||||
@trackers = Tracker.sorted.all
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -45,9 +45,12 @@ class UsersController < ApplicationController
|
||||
scope = scope.in_group(params[:group_id]) if params[:group_id].present?
|
||||
|
||||
@user_count = scope.count
|
||||
@user_pages = Paginator.new @user_count, @limit, params['page']
|
||||
@offset ||= @user_pages.offset
|
||||
@users = scope.order(sort_clause).limit(@limit).offset(@offset).all
|
||||
@user_pages = Paginator.new self, @user_count, @limit, params['page']
|
||||
@offset ||= @user_pages.current.offset
|
||||
@users = scope.find :all,
|
||||
:order => sort_clause,
|
||||
:limit => @limit,
|
||||
:offset => @offset
|
||||
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
@@ -55,7 +58,7 @@ class UsersController < ApplicationController
|
||||
render :layout => !request.xhr?
|
||||
}
|
||||
format.api
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
@@ -80,7 +83,7 @@ class UsersController < ApplicationController
|
||||
|
||||
def new
|
||||
@user = User.new(:language => Setting.default_language, :mail_notification => Setting.default_notification_option)
|
||||
@auth_sources = AuthSource.all
|
||||
@auth_sources = AuthSource.find(:all)
|
||||
end
|
||||
|
||||
def create
|
||||
@@ -101,16 +104,15 @@ class UsersController < ApplicationController
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
flash[:notice] = l(:notice_user_successful_create, :id => view_context.link_to(@user.login, user_path(@user)))
|
||||
if params[:continue]
|
||||
redirect_to new_user_path
|
||||
else
|
||||
redirect_to edit_user_path(@user)
|
||||
end
|
||||
redirect_to(params[:continue] ?
|
||||
{:controller => 'users', :action => 'new'} :
|
||||
{:controller => 'users', :action => 'edit', :id => @user}
|
||||
)
|
||||
}
|
||||
format.api { render :action => 'show', :status => :created, :location => user_url(@user) }
|
||||
end
|
||||
else
|
||||
@auth_sources = AuthSource.all
|
||||
@auth_sources = AuthSource.find(:all)
|
||||
# Clear password input
|
||||
@user.password = @user.password_confirmation = nil
|
||||
|
||||
@@ -122,7 +124,7 @@ class UsersController < ApplicationController
|
||||
end
|
||||
|
||||
def edit
|
||||
@auth_sources = AuthSource.all
|
||||
@auth_sources = AuthSource.find(:all)
|
||||
@membership ||= Member.new
|
||||
end
|
||||
|
||||
@@ -157,7 +159,7 @@ class UsersController < ApplicationController
|
||||
format.api { render_api_ok }
|
||||
end
|
||||
else
|
||||
@auth_sources = AuthSource.all
|
||||
@auth_sources = AuthSource.find(:all)
|
||||
@membership ||= Member.new
|
||||
# Clear password input
|
||||
@user.password = @user.password_confirmation = nil
|
||||
@@ -172,7 +174,7 @@ class UsersController < ApplicationController
|
||||
def destroy
|
||||
@user.destroy
|
||||
respond_to do |format|
|
||||
format.html { redirect_back_or_default(users_path) }
|
||||
format.html { redirect_back_or_default(users_url) }
|
||||
format.api { render_api_ok }
|
||||
end
|
||||
end
|
||||
@@ -181,7 +183,7 @@ class UsersController < ApplicationController
|
||||
@membership = Member.edit_membership(params[:membership_id], params[:membership], @user)
|
||||
@membership.save
|
||||
respond_to do |format|
|
||||
format.html { redirect_to edit_user_path(@user, :tab => 'memberships') }
|
||||
format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' }
|
||||
format.js
|
||||
end
|
||||
end
|
||||
@@ -192,7 +194,7 @@ class UsersController < ApplicationController
|
||||
@membership.destroy
|
||||
end
|
||||
respond_to do |format|
|
||||
format.html { redirect_to edit_user_path(@user, :tab => 'memberships') }
|
||||
format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' }
|
||||
format.js
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -31,7 +31,7 @@ class VersionsController < ApplicationController
|
||||
def index
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
@trackers = @project.trackers.sorted.all
|
||||
@trackers = @project.trackers.find(:all, :order => 'position')
|
||||
retrieve_selected_tracker_ids(@trackers, @trackers.select {|t| t.is_in_roadmap?})
|
||||
@with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
|
||||
project_ids = @with_subprojects ? @project.self_and_descendants.collect(&:id) : [@project.id]
|
||||
@@ -64,10 +64,9 @@ class VersionsController < ApplicationController
|
||||
def show
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
@issues = @version.fixed_issues.visible.
|
||||
includes(:status, :tracker, :priority).
|
||||
reorder("#{Tracker.table_name}.position, #{Issue.table_name}.id").
|
||||
all
|
||||
@issues = @version.fixed_issues.visible.find(:all,
|
||||
:include => [:status, :tracker, :priority],
|
||||
:order => "#{Tracker.table_name}.position, #{Issue.table_name}.id")
|
||||
}
|
||||
format.api
|
||||
end
|
||||
@@ -96,7 +95,7 @@ class VersionsController < ApplicationController
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
redirect_back_or_default settings_project_path(@project, :tab => 'versions')
|
||||
redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
|
||||
end
|
||||
format.js
|
||||
format.api do
|
||||
@@ -125,7 +124,7 @@ class VersionsController < ApplicationController
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_back_or_default settings_project_path(@project, :tab => 'versions')
|
||||
redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
|
||||
}
|
||||
format.api { render_api_ok }
|
||||
end
|
||||
@@ -142,21 +141,21 @@ class VersionsController < ApplicationController
|
||||
if request.put?
|
||||
@project.close_completed_versions
|
||||
end
|
||||
redirect_to settings_project_path(@project, :tab => 'versions')
|
||||
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
|
||||
end
|
||||
|
||||
def destroy
|
||||
if @version.fixed_issues.empty?
|
||||
@version.destroy
|
||||
respond_to do |format|
|
||||
format.html { redirect_back_or_default settings_project_path(@project, :tab => 'versions') }
|
||||
format.html { redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project }
|
||||
format.api { render_api_ok }
|
||||
end
|
||||
else
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
flash[:error] = l(:notice_unable_delete_version)
|
||||
redirect_to settings_project_path(@project, :tab => 'versions')
|
||||
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
|
||||
}
|
||||
format.api { head :unprocessable_entity }
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -16,36 +16,35 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
class WatchersController < ApplicationController
|
||||
before_filter :require_login, :find_watchables, :only => [:watch, :unwatch]
|
||||
before_filter :find_project
|
||||
before_filter :require_login, :check_project_privacy, :only => [:watch, :unwatch]
|
||||
before_filter :authorize, :only => [:new, :destroy]
|
||||
|
||||
def watch
|
||||
set_watcher(@watchables, User.current, true)
|
||||
if @watched.respond_to?(:visible?) && !@watched.visible?(User.current)
|
||||
render_403
|
||||
else
|
||||
set_watcher(User.current, true)
|
||||
end
|
||||
end
|
||||
|
||||
def unwatch
|
||||
set_watcher(@watchables, User.current, false)
|
||||
set_watcher(User.current, false)
|
||||
end
|
||||
|
||||
before_filter :find_project, :authorize, :only => [:new, :create, :append, :destroy, :autocomplete_for_user]
|
||||
accept_api_auth :create, :destroy
|
||||
|
||||
def new
|
||||
end
|
||||
|
||||
def create
|
||||
user_ids = []
|
||||
if params[:watcher].is_a?(Hash)
|
||||
user_ids << (params[:watcher][:user_ids] || params[:watcher][:user_id])
|
||||
else
|
||||
user_ids << params[:user_id]
|
||||
end
|
||||
user_ids.flatten.compact.uniq.each do |user_id|
|
||||
Watcher.create(:watchable => @watched, :user_id => user_id)
|
||||
if params[:watcher].is_a?(Hash) && request.post?
|
||||
user_ids = params[:watcher][:user_ids] || [params[:watcher][:user_id]]
|
||||
user_ids.each do |user_id|
|
||||
Watcher.create(:watchable => @watched, :user_id => user_id)
|
||||
end
|
||||
end
|
||||
respond_to do |format|
|
||||
format.html { redirect_to_referer_or {render :text => 'Watcher added.', :layout => true}}
|
||||
format.js
|
||||
format.api { render_api_ok }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -57,24 +56,22 @@ class WatchersController < ApplicationController
|
||||
end
|
||||
|
||||
def destroy
|
||||
@watched.set_watcher(User.find(params[:user_id]), false)
|
||||
@watched.set_watcher(User.find(params[:user_id]), false) if request.post?
|
||||
respond_to do |format|
|
||||
format.html { redirect_to :back }
|
||||
format.js
|
||||
format.api { render_api_ok }
|
||||
end
|
||||
end
|
||||
|
||||
def autocomplete_for_user
|
||||
@users = User.active.sorted.like(params[:q]).limit(100).all
|
||||
@users = User.active.like(params[:q]).find(:all, :limit => 100)
|
||||
if @watched
|
||||
@users -= @watched.watcher_users
|
||||
end
|
||||
render :layout => false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
private
|
||||
def find_project
|
||||
if params[:object_type] && params[:object_id]
|
||||
klass = Object.const_get(params[:object_type].camelcase)
|
||||
@@ -88,22 +85,11 @@ class WatchersController < ApplicationController
|
||||
render_404
|
||||
end
|
||||
|
||||
def find_watchables
|
||||
klass = Object.const_get(params[:object_type].camelcase) rescue nil
|
||||
if klass && klass.respond_to?('watched_by')
|
||||
@watchables = klass.find_all_by_id(Array.wrap(params[:object_id]))
|
||||
raise Unauthorized if @watchables.any? {|w| w.respond_to?(:visible?) && !w.visible?}
|
||||
end
|
||||
render_404 unless @watchables.present?
|
||||
end
|
||||
|
||||
def set_watcher(watchables, user, watching)
|
||||
watchables.each do |watchable|
|
||||
watchable.set_watcher(user, watching)
|
||||
end
|
||||
def set_watcher(user, watching)
|
||||
@watched.set_watcher(user, watching)
|
||||
respond_to do |format|
|
||||
format.html { redirect_to_referer_or {render :text => (watching ? 'Watcher added.' : 'Watcher removed.'), :layout => true}}
|
||||
format.js { render :partial => 'set_watcher', :locals => {:user => user, :watched => watchables} }
|
||||
format.js { render :partial => 'set_watcher', :locals => {:user => user, :watched => @watched} }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -37,7 +37,6 @@ class WikiController < ApplicationController
|
||||
before_filter :find_existing_or_new_page, :only => [:show, :edit, :update]
|
||||
before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy, :destroy_version]
|
||||
accept_api_auth :index, :show, :update, :destroy
|
||||
before_filter :find_attachments, :only => [:preview]
|
||||
|
||||
helper :attachments
|
||||
include AttachmentsHelper
|
||||
@@ -160,10 +159,10 @@ class WikiController < ApplicationController
|
||||
call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page})
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to project_wiki_page_path(@project, @page.title) }
|
||||
format.html { redirect_to :action => 'show', :project_id => @project, :id => @page.title }
|
||||
format.api {
|
||||
if was_new_page
|
||||
render :action => 'show', :status => :created, :location => project_wiki_page_path(@project, @page.title)
|
||||
render :action => 'show', :status => :created, :location => url_for(:controller => 'wiki', :action => 'show', :project_id => @project, :id => @page.title)
|
||||
else
|
||||
render_api_ok
|
||||
end
|
||||
@@ -200,26 +199,25 @@ class WikiController < ApplicationController
|
||||
@original_title = @page.pretty_title
|
||||
if request.post? && @page.update_attributes(params[:wiki_page])
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to project_wiki_page_path(@project, @page.title)
|
||||
redirect_to :action => 'show', :project_id => @project, :id => @page.title
|
||||
end
|
||||
end
|
||||
|
||||
def protect
|
||||
@page.update_attribute :protected, params[:protected]
|
||||
redirect_to project_wiki_page_path(@project, @page.title)
|
||||
redirect_to :action => 'show', :project_id => @project, :id => @page.title
|
||||
end
|
||||
|
||||
# show page history
|
||||
def history
|
||||
@version_count = @page.content.versions.count
|
||||
@version_pages = Paginator.new @version_count, per_page_option, params['page']
|
||||
@version_pages = Paginator.new self, @version_count, per_page_option, params['page']
|
||||
# don't load text
|
||||
@versions = @page.content.versions.
|
||||
select("id, author_id, comments, updated_on, version").
|
||||
reorder('version DESC').
|
||||
limit(@version_pages.per_page + 1).
|
||||
offset(@version_pages.offset).
|
||||
all
|
||||
@versions = @page.content.versions.find :all,
|
||||
:select => "id, author_id, comments, updated_on, version",
|
||||
:order => 'version DESC',
|
||||
:limit => @version_pages.items_per_page + 1,
|
||||
:offset => @version_pages.current.offset
|
||||
|
||||
render :layout => false if request.xhr?
|
||||
end
|
||||
@@ -262,7 +260,7 @@ class WikiController < ApplicationController
|
||||
end
|
||||
@page.destroy
|
||||
respond_to do |format|
|
||||
format.html { redirect_to project_wiki_index_path(@project) }
|
||||
format.html { redirect_to :action => 'index', :project_id => @project }
|
||||
format.api { render_api_ok }
|
||||
end
|
||||
end
|
||||
@@ -272,7 +270,7 @@ class WikiController < ApplicationController
|
||||
|
||||
@content = @page.content_for_version(params[:version])
|
||||
@content.destroy
|
||||
redirect_to_referer_or history_project_wiki_page_path(@project, @page.title)
|
||||
redirect_to_referer_or :action => 'history', :id => @page.title, :project_id => @project
|
||||
end
|
||||
|
||||
# Export wiki to a single pdf or html file
|
||||
@@ -294,7 +292,7 @@ class WikiController < ApplicationController
|
||||
# page is nil when previewing a new page
|
||||
return render_403 unless page.nil? || editable?(page)
|
||||
if page
|
||||
@attachments += page.attachments
|
||||
@attachements = page.attachments
|
||||
@previewed = page.content
|
||||
end
|
||||
@text = params[:content][:text]
|
||||
@@ -351,6 +349,6 @@ private
|
||||
end
|
||||
|
||||
def load_pages_for_index
|
||||
@pages = @wiki.pages.with_updated_on.reorder("#{WikiPage.table_name}.title").includes(:wiki => :project).includes(:parent).all
|
||||
@pages = @wiki.pages.with_updated_on.order("#{WikiPage.table_name}.title").includes(:wiki => :project).includes(:parent).all
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -30,7 +30,7 @@ class WikisController < ApplicationController
|
||||
def destroy
|
||||
if request.post? && params[:confirm] && @project.wiki
|
||||
@project.wiki.destroy
|
||||
redirect_to settings_project_path(@project, :tab => 'wiki')
|
||||
redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'wiki'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -38,7 +38,7 @@ class WorkflowsController < ApplicationController
|
||||
}
|
||||
}
|
||||
if @role.save
|
||||
redirect_to workflows_edit_path(:role_id => @role, :tracker_id => @tracker, :used_statuses_only => params[:used_statuses_only])
|
||||
redirect_to :action => 'edit', :role_id => @role, :tracker_id => @tracker, :used_statuses_only => params[:used_statuses_only]
|
||||
return
|
||||
end
|
||||
end
|
||||
@@ -64,7 +64,7 @@ class WorkflowsController < ApplicationController
|
||||
|
||||
if request.post? && @role && @tracker
|
||||
WorkflowPermission.replace_permissions(@tracker, @role, params[:permissions] || {})
|
||||
redirect_to workflows_permissions_path(:role_id => @role, :tracker_id => @tracker, :used_statuses_only => params[:used_statuses_only])
|
||||
redirect_to :action => 'permissions', :role_id => @role, :tracker_id => @tracker, :used_statuses_only => params[:used_statuses_only]
|
||||
return
|
||||
end
|
||||
|
||||
@@ -106,12 +106,12 @@ class WorkflowsController < ApplicationController
|
||||
if request.post?
|
||||
if params[:source_tracker_id].blank? || params[:source_role_id].blank? || (@source_tracker.nil? && @source_role.nil?)
|
||||
flash.now[:error] = l(:error_workflow_copy_source)
|
||||
elsif @target_trackers.blank? || @target_roles.blank?
|
||||
elsif @target_trackers.nil? || @target_roles.nil?
|
||||
flash.now[:error] = l(:error_workflow_copy_target)
|
||||
else
|
||||
WorkflowRule.copy(@source_tracker, @source_role, @target_trackers, @target_roles)
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to workflows_copy_path(:source_tracker_id => @source_tracker, :source_role_id => @source_role)
|
||||
redirect_to :action => 'copy', :source_tracker_id => @source_tracker, :source_role_id => @source_role
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
module ActivitiesHelper
|
||||
def sort_activity_events(events)
|
||||
events_by_group = events.group_by(&:event_group)
|
||||
sorted_events = []
|
||||
events.sort {|x, y| y.event_datetime <=> x.event_datetime}.each do |event|
|
||||
if group_events = events_by_group.delete(event.event_group)
|
||||
group_events.sort {|x, y| y.event_datetime <=> x.event_datetime}.each_with_index do |e, i|
|
||||
sorted_events << [e, i > 0]
|
||||
end
|
||||
end
|
||||
end
|
||||
sorted_events
|
||||
end
|
||||
end
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -24,7 +24,6 @@ module ApplicationHelper
|
||||
include Redmine::WikiFormatting::Macros::Definitions
|
||||
include Redmine::I18n
|
||||
include GravatarHelper::PublicMethods
|
||||
include Redmine::Pagination::Helper
|
||||
|
||||
extend Forwardable
|
||||
def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter
|
||||
@@ -91,10 +90,14 @@ module ApplicationHelper
|
||||
# * :download - Force download (default: false)
|
||||
def link_to_attachment(attachment, options={})
|
||||
text = options.delete(:text) || attachment.filename
|
||||
route_method = options.delete(:download) ? :download_named_attachment_path : :named_attachment_path
|
||||
html_options = options.slice!(:only_path)
|
||||
url = send(route_method, attachment, attachment.filename, options)
|
||||
link_to text, url, html_options
|
||||
action = options.delete(:download) ? 'download' : 'show'
|
||||
opt_only_path = {}
|
||||
opt_only_path[:only_path] = (options[:only_path] == false ? false : true)
|
||||
options.delete(:only_path)
|
||||
link_to(h(text),
|
||||
{:controller => 'attachments', :action => action,
|
||||
:id => attachment, :filename => attachment.filename}.merge(opt_only_path),
|
||||
options)
|
||||
end
|
||||
|
||||
# Generates a link to a SCM revision
|
||||
@@ -116,11 +119,13 @@ module ApplicationHelper
|
||||
# Generates a link to a message
|
||||
def link_to_message(message, options={}, html_options = nil)
|
||||
link_to(
|
||||
truncate(message.subject, :length => 60),
|
||||
board_message_path(message.board_id, message.parent_id || message.id, {
|
||||
h(truncate(message.subject, :length => 60)),
|
||||
{ :controller => 'messages', :action => 'show',
|
||||
:board_id => message.board_id,
|
||||
:id => (message.parent_id || message.id),
|
||||
:r => (message.parent_id && message.id),
|
||||
:anchor => (message.parent_id ? "message-#{message.id}" : nil)
|
||||
}.merge(options)),
|
||||
}.merge(options),
|
||||
html_options
|
||||
)
|
||||
end
|
||||
@@ -129,29 +134,16 @@ module ApplicationHelper
|
||||
# Examples:
|
||||
#
|
||||
# link_to_project(project) # => link to the specified project overview
|
||||
# link_to_project(project, :action=>'settings') # => link to project settings
|
||||
# link_to_project(project, {:only_path => false}, :class => "project") # => 3rd arg adds html options
|
||||
# link_to_project(project, {}, :class => "project") # => html options with default url (project overview)
|
||||
#
|
||||
def link_to_project(project, options={}, html_options = nil)
|
||||
if project.archived?
|
||||
h(project.name)
|
||||
elsif options.key?(:action)
|
||||
ActiveSupport::Deprecation.warn "#link_to_project with :action option is deprecated and will be removed in Redmine 3.0."
|
||||
h(project)
|
||||
else
|
||||
url = {:controller => 'projects', :action => 'show', :id => project}.merge(options)
|
||||
link_to project.name, url, html_options
|
||||
else
|
||||
link_to project.name, project_path(project, options), html_options
|
||||
end
|
||||
end
|
||||
|
||||
# Generates a link to a project settings if active
|
||||
def link_to_project_settings(project, options={}, html_options=nil)
|
||||
if project.active?
|
||||
link_to project.name, settings_project_path(project, options), html_options
|
||||
elsif project.archived?
|
||||
h(project.name)
|
||||
else
|
||||
link_to project.name, project_path(project, options), html_options
|
||||
link_to(h(project), url, html_options)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -160,8 +152,8 @@ module ApplicationHelper
|
||||
end
|
||||
|
||||
def thumbnail_tag(attachment)
|
||||
link_to image_tag(thumbnail_path(attachment)),
|
||||
named_attachment_path(attachment, attachment.filename),
|
||||
link_to image_tag(url_for(:controller => 'attachments', :action => 'thumbnail', :id => attachment)),
|
||||
{:controller => 'attachments', :action => 'show', :id => attachment, :filename => attachment.filename},
|
||||
:title => attachment.filename
|
||||
end
|
||||
|
||||
@@ -195,7 +187,7 @@ module ApplicationHelper
|
||||
|
||||
def format_version_name(version)
|
||||
if version.project == @project
|
||||
h(version)
|
||||
h(version)
|
||||
else
|
||||
h("#{version.project} - #{version}")
|
||||
end
|
||||
@@ -316,8 +308,8 @@ module ApplicationHelper
|
||||
|
||||
def principals_check_box_tags(name, principals)
|
||||
s = ''
|
||||
principals.each do |principal|
|
||||
s << "<label>#{ check_box_tag name, principal.id, false, :id => nil } #{h principal}</label>\n"
|
||||
principals.sort.each do |principal|
|
||||
s << "<label>#{ check_box_tag name, principal.id, false } #{h principal}</label>\n"
|
||||
end
|
||||
s.html_safe
|
||||
end
|
||||
@@ -343,7 +335,7 @@ module ApplicationHelper
|
||||
def options_for_membership_project_select(principal, projects)
|
||||
options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---")
|
||||
options << project_tree_options_for_select(projects) do |p|
|
||||
{:disabled => principal.projects.to_a.include?(p)}
|
||||
{:disabled => principal.projects.include?(p)}
|
||||
end
|
||||
options
|
||||
end
|
||||
@@ -399,6 +391,59 @@ module ApplicationHelper
|
||||
str.blank? ? nil : str
|
||||
end
|
||||
|
||||
def pagination_links_full(paginator, count=nil, options={})
|
||||
page_param = options.delete(:page_param) || :page
|
||||
per_page_links = options.delete(:per_page_links)
|
||||
url_param = params.dup
|
||||
|
||||
html = ''
|
||||
if paginator.current.previous
|
||||
# \xc2\xab(utf-8) = «
|
||||
html << link_to_content_update(
|
||||
"\xc2\xab " + l(:label_previous),
|
||||
url_param.merge(page_param => paginator.current.previous)) + ' '
|
||||
end
|
||||
|
||||
html << (pagination_links_each(paginator, options) do |n|
|
||||
link_to_content_update(n.to_s, url_param.merge(page_param => n))
|
||||
end || '')
|
||||
|
||||
if paginator.current.next
|
||||
# \xc2\xbb(utf-8) = »
|
||||
html << ' ' + link_to_content_update(
|
||||
(l(:label_next) + " \xc2\xbb"),
|
||||
url_param.merge(page_param => paginator.current.next))
|
||||
end
|
||||
|
||||
unless count.nil?
|
||||
html << " (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})"
|
||||
if per_page_links != false && links = per_page_links(paginator.items_per_page, count)
|
||||
html << " | #{links}"
|
||||
end
|
||||
end
|
||||
|
||||
html.html_safe
|
||||
end
|
||||
|
||||
def per_page_links(selected=nil, item_count=nil)
|
||||
values = Setting.per_page_options_array
|
||||
if item_count && values.any?
|
||||
if item_count > values.first
|
||||
max = values.detect {|value| value >= item_count} || item_count
|
||||
else
|
||||
max = item_count
|
||||
end
|
||||
values = values.select {|value| value <= max || value == selected}
|
||||
end
|
||||
if values.empty? || (values.size == 1 && values.first == selected)
|
||||
return nil
|
||||
end
|
||||
links = values.collect do |n|
|
||||
n == selected ? n : link_to_content_update(n, params.merge(:per_page => n))
|
||||
end
|
||||
l(:label_display_per_page, links.join(', '))
|
||||
end
|
||||
|
||||
def reorder_links(name, url, method = :post)
|
||||
link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)),
|
||||
url.merge({"#{name}[move_to]" => 'highest'}),
|
||||
@@ -552,14 +597,14 @@ module ApplicationHelper
|
||||
|
||||
def parse_inline_attachments(text, project, obj, attr, only_path, options)
|
||||
# when using an image link, try to use an attachment, if possible
|
||||
attachments = options[:attachments] || []
|
||||
attachments += obj.attachments if obj.respond_to?(:attachments)
|
||||
if attachments.present?
|
||||
if options[:attachments] || (obj && obj.respond_to?(:attachments))
|
||||
attachments = options[:attachments] || obj.attachments
|
||||
text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m|
|
||||
filename, ext, alt, alttext = $1.downcase, $2, $3, $4
|
||||
# search for the picture in attachments
|
||||
if found = Attachment.latest_attach(attachments, filename)
|
||||
image_url = download_named_attachment_path(found, found.filename, :only_path => only_path)
|
||||
image_url = url_for :only_path => only_path, :controller => 'attachments',
|
||||
:action => 'download', :id => found
|
||||
desc = found.description.to_s.gsub('"', '')
|
||||
if !desc.blank? && alttext.blank?
|
||||
alt = " title=\"#{desc}\" alt=\"#{desc}\""
|
||||
@@ -588,9 +633,9 @@ module ApplicationHelper
|
||||
esc, all, page, title = $1, $2, $3, $5
|
||||
if esc.nil?
|
||||
if page =~ /^([^\:]+)\:(.*)$/
|
||||
identifier, page = $1, $2
|
||||
link_project = Project.find_by_identifier(identifier) || Project.find_by_name(identifier)
|
||||
title ||= identifier if page.blank?
|
||||
link_project = Project.find_by_identifier($1) || Project.find_by_name($1)
|
||||
page = $2
|
||||
title ||= $1 if page.blank?
|
||||
end
|
||||
|
||||
if link_project && link_project.wiki
|
||||
@@ -658,11 +703,10 @@ module ApplicationHelper
|
||||
# identifier:document:"Some document"
|
||||
# identifier:version:1.0.0
|
||||
# identifier:source:some/file
|
||||
def parse_redmine_links(text, default_project, obj, attr, only_path, options)
|
||||
text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-_]+):)?(attachment|document|version|forum|news|message|project|commit|source|export)?(((#)|((([a-z0-9\-_]+)\|)?(r)))((\d+)((#note)?-(\d+))?)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]][^A-Za-z0-9_/])|,|\s|\]|<|$)}) do |m|
|
||||
def parse_redmine_links(text, project, obj, attr, only_path, options)
|
||||
text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-_]+):)?(attachment|document|version|forum|news|message|project|commit|source|export)?(((#)|((([a-z0-9\-]+)\|)?(r)))((\d+)((#note)?-(\d+))?)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]][^A-Za-z0-9_/])|,|\s|\]|<|$)}) do |m|
|
||||
leading, esc, project_prefix, project_identifier, prefix, repo_prefix, repo_identifier, sep, identifier, comment_suffix, comment_id = $1, $2, $3, $4, $5, $10, $11, $8 || $12 || $18, $14 || $19, $15, $17
|
||||
link = nil
|
||||
project = default_project
|
||||
if project_identifier
|
||||
project = Project.visible.find_by_identifier(project_identifier)
|
||||
end
|
||||
@@ -748,21 +792,21 @@ module ApplicationHelper
|
||||
when 'commit', 'source', 'export'
|
||||
if project
|
||||
repository = nil
|
||||
if name =~ %r{^(([a-z0-9\-_]+)\|)(.+)$}
|
||||
if name =~ %r{^(([a-z0-9\-]+)\|)(.+)$}
|
||||
repo_prefix, repo_identifier, name = $1, $2, $3
|
||||
repository = project.repositories.detect {|repo| repo.identifier == repo_identifier}
|
||||
else
|
||||
repository = project.repository
|
||||
end
|
||||
if prefix == 'commit'
|
||||
if repository && (changeset = Changeset.visible.where("repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%").first)
|
||||
if repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%"]))
|
||||
link = link_to h("#{project_prefix}#{repo_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.identifier},
|
||||
:class => 'changeset',
|
||||
:title => truncate_single_line(h(changeset.comments), :length => 100)
|
||||
end
|
||||
else
|
||||
if repository && User.current.allowed_to?(:browse_repository, project)
|
||||
name =~ %r{^[/\\]*(.*?)(@([^/\\@]+?))?(#(L\d+))?$}
|
||||
name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
|
||||
path, rev, anchor = $1, $3, $5
|
||||
link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:controller => 'repositories', :action => (prefix == 'export' ? 'raw' : 'entry'), :id => project, :repository_id => repository.identifier_param,
|
||||
:path => to_path_param(path),
|
||||
@@ -775,11 +819,12 @@ module ApplicationHelper
|
||||
end
|
||||
when 'attachment'
|
||||
attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil)
|
||||
if attachments && attachment = Attachment.latest_attach(attachments, name)
|
||||
link = link_to_attachment(attachment, :only_path => only_path, :download => true, :class => 'attachment')
|
||||
if attachments && attachment = attachments.detect {|a| a.filename == name }
|
||||
link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment},
|
||||
:class => 'attachment'
|
||||
end
|
||||
when 'project'
|
||||
if p = Project.visible.where("identifier = :s OR LOWER(name) = :s", :s => name.downcase).first
|
||||
if p = Project.visible.find(:first, :conditions => ["identifier = :s OR LOWER(name) = :s", {:s => name.downcase}])
|
||||
link = link_to_project(p, {:only_path => only_path}, :class => 'project')
|
||||
end
|
||||
end
|
||||
@@ -1032,7 +1077,7 @@ module ApplicationHelper
|
||||
(pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : ''.html_safe) +
|
||||
(pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : ''.html_safe)
|
||||
), :class => 'progress', :style => "width: #{width};").html_safe +
|
||||
content_tag('p', legend, :class => 'percent').html_safe
|
||||
content_tag('p', legend, :class => 'pourcent').html_safe
|
||||
end
|
||||
|
||||
def checked_image(checked=true)
|
||||
@@ -1076,7 +1121,7 @@ module ApplicationHelper
|
||||
"var datepickerOptions={dateFormat: 'yy-mm-dd', firstDay: #{start_of_week}, " +
|
||||
"showOn: 'button', buttonImageOnly: true, buttonImage: '" +
|
||||
path_to_image('/images/calendar.png') +
|
||||
"', showButtonPanel: true, showWeek: true, showOtherMonths: true, selectOtherMonths: true};")
|
||||
"', showButtonPanel: true};")
|
||||
jquery_locale = l('jquery.locale', :default => current_language.to_s)
|
||||
unless jquery_locale == 'en'
|
||||
tags << javascript_include_tag("i18n/jquery.ui.datepicker-#{jquery_locale}.js")
|
||||
@@ -1180,7 +1225,7 @@ module ApplicationHelper
|
||||
|
||||
def sanitize_anchor_name(anchor)
|
||||
if ''.respond_to?(:encoding) || RUBY_PLATFORM == 'java'
|
||||
anchor.gsub(%r{[^\s\-\p{Word}]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
|
||||
anchor.gsub(%r{[^\p{Word}\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
|
||||
else
|
||||
# TODO: remove when ruby1.8 is no longer supported
|
||||
anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
|
||||
@@ -1189,7 +1234,7 @@ module ApplicationHelper
|
||||
|
||||
# Returns the javascript tags that are included in the html layout head
|
||||
def javascript_heads
|
||||
tags = javascript_include_tag('jquery-1.8.3-ui-1.9.2-ujs-2.0.3', 'application')
|
||||
tags = javascript_include_tag('jquery-1.7.2-ui-1.8.21-ujs-2.0.3', 'application')
|
||||
unless User.current.pref.warn_on_leaving_unsaved == '0'
|
||||
tags << "\n".html_safe + javascript_tag("$(window).load(function(){ warnLeavingUnsaved('#{escape_javascript l(:text_warn_on_leaving_unsaved)}'); });")
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -36,7 +36,7 @@ module ContextMenusHelper
|
||||
|
||||
def bulk_update_custom_field_context_menu_link(field, text, value)
|
||||
context_menu_link h(text),
|
||||
bulk_update_issues_path(:ids => @issue_ids, :issue => {'custom_field_values' => {field.id => value}}, :back_url => @back),
|
||||
{:controller => 'issues', :action => 'bulk_update', :ids => @issue_ids, :issue => {'custom_field_values' => {field.id => value}}, :back_url => @back},
|
||||
:method => :post,
|
||||
:selected => (@issue && @issue.custom_field_value(field) == value)
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -24,7 +24,7 @@ module CustomFieldsHelper
|
||||
end
|
||||
|
||||
# Return custom field html tag corresponding to its format
|
||||
def custom_field_tag(name, custom_value)
|
||||
def custom_field_tag(name, custom_value)
|
||||
custom_field = custom_value.custom_field
|
||||
field_name = "#{name}[custom_field_values][#{custom_field.id}]"
|
||||
field_name << "[]" if custom_field.multiple?
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -24,19 +24,19 @@ module GanttHelper
|
||||
when :in
|
||||
if gantt.zoom < 4
|
||||
link_to_content_update l(:text_zoom_in),
|
||||
params.merge(gantt.params.merge(:zoom => (gantt.zoom + 1))),
|
||||
params.merge(gantt.params.merge(:zoom => (gantt.zoom+1))),
|
||||
:class => 'icon icon-zoom-in'
|
||||
else
|
||||
content_tag(:span, l(:text_zoom_in), :class => 'icon icon-zoom-in').html_safe
|
||||
content_tag('span', l(:text_zoom_in), :class => 'icon icon-zoom-in').html_safe
|
||||
end
|
||||
|
||||
when :out
|
||||
if gantt.zoom > 1
|
||||
link_to_content_update l(:text_zoom_out),
|
||||
params.merge(gantt.params.merge(:zoom => (gantt.zoom - 1))),
|
||||
params.merge(gantt.params.merge(:zoom => (gantt.zoom-1))),
|
||||
:class => 'icon icon-zoom-out'
|
||||
else
|
||||
content_tag(:span, l(:text_zoom_out), :class => 'icon icon-zoom-out').html_safe
|
||||
content_tag('span', l(:text_zoom_out), :class => 'icon icon-zoom-out').html_safe
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -24,19 +24,4 @@ module GroupsHelper
|
||||
{:name => 'memberships', :partial => 'groups/memberships', :label => :label_project_plural}
|
||||
]
|
||||
end
|
||||
|
||||
def render_principals_for_new_group_users(group)
|
||||
scope = User.active.sorted.not_in_group(group).like(params[:q])
|
||||
principal_count = scope.count
|
||||
principal_pages = Redmine::Pagination::Paginator.new principal_count, 100, params['page']
|
||||
principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).all
|
||||
|
||||
s = content_tag('div', principals_check_box_tags('user_ids[]', principals), :id => 'principals')
|
||||
|
||||
links = pagination_links_full(principal_pages, principal_count, :per_page_links => false) {|text, parameters, options|
|
||||
link_to text, autocomplete_for_user_group_path(group, parameters.merge(:q => params[:q], :format => 'js')), :remote => true
|
||||
}
|
||||
|
||||
s + content_tag('p', links, :class => 'pagination')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -184,7 +184,7 @@ module IssuesHelper
|
||||
|
||||
def sidebar_queries
|
||||
unless @sidebar_queries
|
||||
@sidebar_queries = IssueQuery.visible.all(
|
||||
@sidebar_queries = Query.visible.all(
|
||||
:order => "#{Query.table_name}.name ASC",
|
||||
# Project specific queries and global queries
|
||||
:conditions => (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id])
|
||||
@@ -347,16 +347,10 @@ module IssuesHelper
|
||||
|
||||
# Find the name of an associated record stored in the field attribute
|
||||
def find_name_by_reflection(field, id)
|
||||
unless id.present?
|
||||
return nil
|
||||
end
|
||||
association = Issue.reflect_on_association(field.to_sym)
|
||||
if association
|
||||
record = association.class_name.constantize.find_by_id(id)
|
||||
if record
|
||||
record.name.force_encoding('UTF-8') if record.name.respond_to?(:force_encoding)
|
||||
return record.name
|
||||
end
|
||||
return record.name if record
|
||||
end
|
||||
end
|
||||
|
||||
@@ -373,4 +367,44 @@ module IssuesHelper
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def issues_to_csv(issues, project, query, options={})
|
||||
decimal_separator = l(:general_csv_decimal_separator)
|
||||
encoding = l(:general_csv_encoding)
|
||||
columns = (options[:columns] == 'all' ? query.available_inline_columns : query.inline_columns)
|
||||
if options[:description]
|
||||
if description = query.available_columns.detect {|q| q.name == :description}
|
||||
columns << description
|
||||
end
|
||||
end
|
||||
|
||||
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
|
||||
# csv header fields
|
||||
csv << [ "#" ] + columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) }
|
||||
|
||||
# csv lines
|
||||
issues.each do |issue|
|
||||
col_values = columns.collect do |column|
|
||||
s = if column.is_a?(QueryCustomFieldColumn)
|
||||
cv = issue.custom_field_values.detect {|v| v.custom_field_id == column.custom_field.id}
|
||||
show_value(cv)
|
||||
else
|
||||
value = column.value(issue)
|
||||
if value.is_a?(Date)
|
||||
format_date(value)
|
||||
elsif value.is_a?(Time)
|
||||
format_time(value)
|
||||
elsif value.is_a?(Float)
|
||||
("%.2f" % value).gsub('.', decimal_separator)
|
||||
else
|
||||
value
|
||||
end
|
||||
end
|
||||
s.to_s
|
||||
end
|
||||
csv << [ issue.id.to_s ] + col_values.collect {|c| Redmine::CodesetUtil.from_utf8(c.to_s, encoding) }
|
||||
end
|
||||
end
|
||||
export
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -18,18 +18,4 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
module MembersHelper
|
||||
def render_principals_for_new_members(project)
|
||||
scope = Principal.active.sorted.not_member_of(project).like(params[:q])
|
||||
principal_count = scope.count
|
||||
principal_pages = Redmine::Pagination::Paginator.new principal_count, 100, params['page']
|
||||
principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).all
|
||||
|
||||
s = content_tag('div', principals_check_box_tags('membership[user_ids][]', principals), :id => 'principals')
|
||||
|
||||
links = pagination_links_full(principal_pages, principal_count, :per_page_links => false) {|text, parameters, options|
|
||||
link_to text, autocomplete_project_memberships_path(project, parameters.merge(:q => params[:q], :format => 'js')), :remote => true
|
||||
}
|
||||
|
||||
s + content_tag('p', links, :class => 'pagination')
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -18,54 +18,4 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
module MyHelper
|
||||
def calendar_items(startdt, enddt)
|
||||
Issue.visible.
|
||||
where(:project_id => User.current.projects.map(&:id)).
|
||||
where("(start_date>=? and start_date<=?) or (due_date>=? and due_date<=?)", startdt, enddt, startdt, enddt).
|
||||
includes(:project, :tracker, :priority, :assigned_to).
|
||||
all
|
||||
end
|
||||
|
||||
def documents_items
|
||||
Document.visible.order("#{Document.table_name}.created_on DESC").limit(10).all
|
||||
end
|
||||
|
||||
def issuesassignedtome_items
|
||||
Issue.visible.open.
|
||||
where(:assigned_to_id => ([User.current.id] + User.current.group_ids)).
|
||||
limit(10).
|
||||
includes(:status, :project, :tracker, :priority).
|
||||
order("#{IssuePriority.table_name}.position DESC, #{Issue.table_name}.updated_on DESC").
|
||||
all
|
||||
end
|
||||
|
||||
def issuesreportedbyme_items
|
||||
Issue.visible.
|
||||
where(:author_id => User.current.id).
|
||||
limit(10).
|
||||
includes(:status, :project, :tracker).
|
||||
order("#{Issue.table_name}.updated_on DESC").
|
||||
all
|
||||
end
|
||||
|
||||
def issueswatched_items
|
||||
Issue.visible.on_active_project.watched_by(User.current.id).recently_updated.limit(10).all
|
||||
end
|
||||
|
||||
def news_items
|
||||
News.visible.
|
||||
where(:project_id => User.current.projects.map(&:id)).
|
||||
limit(10).
|
||||
includes(:project, :author).
|
||||
order("#{News.table_name}.created_on DESC").
|
||||
all
|
||||
end
|
||||
|
||||
def timelog_items
|
||||
TimeEntry.
|
||||
where("#{TimeEntry.table_name}.user_id = ? AND #{TimeEntry.table_name}.spent_on BETWEEN ? AND ?", User.current.id, Date.today - 6, Date.today).
|
||||
includes(:activity, :project, {:issue => [:tracker, :status]}).
|
||||
order("#{TimeEntry.table_name}.spent_on DESC, #{Project.table_name}.name ASC, #{Tracker.table_name}.position ASC, #{Issue.table_name}.id ASC").
|
||||
all
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -24,7 +24,28 @@ module QueriesHelper
|
||||
|
||||
def filters_options(query)
|
||||
options = [[]]
|
||||
options += query.available_filters.map do |field, field_options|
|
||||
sorted_options = query.available_filters.sort do |a, b|
|
||||
ord = 0
|
||||
if !(a[1][:order] == 20 && b[1][:order] == 20)
|
||||
ord = a[1][:order] <=> b[1][:order]
|
||||
else
|
||||
cn = (CustomField::CUSTOM_FIELDS_NAMES.index(a[1][:field].class.name) <=>
|
||||
CustomField::CUSTOM_FIELDS_NAMES.index(b[1][:field].class.name))
|
||||
if cn != 0
|
||||
ord = cn
|
||||
else
|
||||
f = (a[1][:field] <=> b[1][:field])
|
||||
if f != 0
|
||||
ord = f
|
||||
else
|
||||
# assigned_to or author
|
||||
ord = (a[0] <=> b[0])
|
||||
end
|
||||
end
|
||||
end
|
||||
ord
|
||||
end
|
||||
options += sorted_options.map do |field, field_options|
|
||||
[field_options[:name], field]
|
||||
end
|
||||
end
|
||||
@@ -37,19 +58,6 @@ module QueriesHelper
|
||||
tags
|
||||
end
|
||||
|
||||
def query_available_inline_columns_options(query)
|
||||
(query.available_inline_columns - query.columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}
|
||||
end
|
||||
|
||||
def query_selected_inline_columns_options(query)
|
||||
(query.inline_columns & query.available_inline_columns).reject(&:frozen?).collect {|column| [column.caption, column.name]}
|
||||
end
|
||||
|
||||
def render_query_columns_selection(query, options={})
|
||||
tag_name = (options[:name] || 'c') + '[]'
|
||||
render :partial => 'queries/columns', :locals => {:query => query, :tag_name => tag_name}
|
||||
end
|
||||
|
||||
def column_header(column)
|
||||
column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption,
|
||||
:default_order => column.default_order) :
|
||||
@@ -79,16 +87,14 @@ module QueriesHelper
|
||||
format_time(value)
|
||||
when 'Date'
|
||||
format_date(value)
|
||||
when 'Fixnum'
|
||||
if column.name == :id
|
||||
link_to value, issue_path(issue)
|
||||
elsif column.name == :done_ratio
|
||||
when 'Fixnum', 'Float'
|
||||
if column.name == :done_ratio
|
||||
progress_bar(value, :width => '80px')
|
||||
elsif column.name == :spent_hours
|
||||
sprintf "%.2f", value
|
||||
else
|
||||
value.to_s
|
||||
h(value.to_s)
|
||||
end
|
||||
when 'Float'
|
||||
sprintf "%.2f", value
|
||||
when 'User'
|
||||
link_to_user value
|
||||
when 'Project'
|
||||
@@ -100,7 +106,7 @@ module QueriesHelper
|
||||
when 'FalseClass'
|
||||
l(:general_text_No)
|
||||
when 'Issue'
|
||||
value.visible? ? link_to_issue(value) : "##{value.id}"
|
||||
link_to_issue(value, :subject => false)
|
||||
when 'IssueRelation'
|
||||
other = value.other_issue(issue)
|
||||
content_tag('span',
|
||||
@@ -111,71 +117,26 @@ module QueriesHelper
|
||||
end
|
||||
end
|
||||
|
||||
def csv_content(column, issue)
|
||||
value = column.value(issue)
|
||||
if value.is_a?(Array)
|
||||
value.collect {|v| csv_value(column, issue, v)}.compact.join(', ')
|
||||
else
|
||||
csv_value(column, issue, value)
|
||||
end
|
||||
end
|
||||
|
||||
def csv_value(column, issue, value)
|
||||
case value.class.name
|
||||
when 'Time'
|
||||
format_time(value)
|
||||
when 'Date'
|
||||
format_date(value)
|
||||
when 'Float'
|
||||
sprintf("%.2f", value).gsub('.', l(:general_csv_decimal_separator))
|
||||
when 'IssueRelation'
|
||||
other = value.other_issue(issue)
|
||||
l(value.label_for(issue)) + " ##{other.id}"
|
||||
else
|
||||
value.to_s
|
||||
end
|
||||
end
|
||||
|
||||
def query_to_csv(items, query, options={})
|
||||
encoding = l(:general_csv_encoding)
|
||||
columns = (options[:columns] == 'all' ? query.available_inline_columns : query.inline_columns)
|
||||
query.available_block_columns.each do |column|
|
||||
if options[column.name].present?
|
||||
columns << column
|
||||
end
|
||||
end
|
||||
|
||||
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
|
||||
# csv header fields
|
||||
csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) }
|
||||
# csv lines
|
||||
items.each do |item|
|
||||
csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(csv_content(c, item), encoding) }
|
||||
end
|
||||
end
|
||||
export
|
||||
end
|
||||
|
||||
# Retrieve query from session or build a new query
|
||||
def retrieve_query
|
||||
if !params[:query_id].blank?
|
||||
cond = "project_id IS NULL"
|
||||
cond << " OR project_id = #{@project.id}" if @project
|
||||
@query = IssueQuery.find(params[:query_id], :conditions => cond)
|
||||
@query = Query.find(params[:query_id], :conditions => cond)
|
||||
raise ::Unauthorized unless @query.visible?
|
||||
@query.project = @project
|
||||
session[:query] = {:id => @query.id, :project_id => @query.project_id}
|
||||
sort_clear
|
||||
elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil)
|
||||
# Give it a name, required to be valid
|
||||
@query = IssueQuery.new(:name => "_")
|
||||
@query = Query.new(:name => "_")
|
||||
@query.project = @project
|
||||
@query.build_from_params(params)
|
||||
build_query_from_params
|
||||
session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names}
|
||||
else
|
||||
# retrieve from session
|
||||
@query = IssueQuery.find_by_id(session[:query][:id]) if session[:query][:id]
|
||||
@query ||= IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
|
||||
@query = Query.find_by_id(session[:query][:id]) if session[:query][:id]
|
||||
@query ||= Query.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
|
||||
@query.project = @project
|
||||
end
|
||||
end
|
||||
@@ -183,10 +144,10 @@ module QueriesHelper
|
||||
def retrieve_query_from_session
|
||||
if session[:query]
|
||||
if session[:query][:id]
|
||||
@query = IssueQuery.find_by_id(session[:query][:id])
|
||||
@query = Query.find_by_id(session[:query][:id])
|
||||
return unless @query
|
||||
else
|
||||
@query = IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
|
||||
@query = Query.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
|
||||
end
|
||||
if session[:query].has_key?(:project_id)
|
||||
@query.project_id = session[:query][:project_id]
|
||||
@@ -196,4 +157,17 @@ module QueriesHelper
|
||||
@query
|
||||
end
|
||||
end
|
||||
|
||||
def build_query_from_params
|
||||
if params[:fields] || params[:f]
|
||||
@query.filters = {}
|
||||
@query.add_filters(params[:fields] || params[:f], params[:operators] || params[:op], params[:values] || params[:v])
|
||||
else
|
||||
@query.available_filters.keys.each do |field|
|
||||
@query.add_short_filter(field, params[field]) if params[field]
|
||||
end
|
||||
end
|
||||
@query.group_by = params[:group_by] || (params[:query] && params[:query][:group_by])
|
||||
@query.column_names = params[:c] || (params[:query] && params[:query][:column_names])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -35,9 +35,4 @@ module ReportsHelper
|
||||
a = aggregate data, criteria
|
||||
a > 0 ? link_to(h(a), *args) : '-'
|
||||
end
|
||||
|
||||
def aggregate_path(project, field, row, options={})
|
||||
parameters = {:set_filter => 1, :subproject_id => '!*', field => row.id}.merge(options)
|
||||
project_issues_path(row.is_a?(Project) ? row : project, parameters)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -43,7 +43,7 @@ module RepositoriesHelper
|
||||
end
|
||||
|
||||
def render_changeset_changes
|
||||
changes = @changeset.filechanges.limit(1000).reorder('path').all.collect do |change|
|
||||
changes = @changeset.filechanges.find(:all, :limit => 1000, :order => 'path').collect do |change|
|
||||
case change.action
|
||||
when 'A'
|
||||
# Detects moved/copied files
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
module RoutesHelper
|
||||
|
||||
# Returns the path to project issues or to the cross-project
|
||||
# issue list if project is nil
|
||||
def _project_issues_path(project, *args)
|
||||
if project
|
||||
project_issues_path(project, *args)
|
||||
else
|
||||
issues_path(*args)
|
||||
end
|
||||
end
|
||||
|
||||
def _project_calendar_path(project, *args)
|
||||
project ? project_calendar_path(project, *args) : issues_calendar_path(*args)
|
||||
end
|
||||
|
||||
def _project_gantt_path(project, *args)
|
||||
project ? project_gantt_path(project, *args) : issues_gantt_path(*args)
|
||||
end
|
||||
end
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -53,7 +53,7 @@ module SettingsHelper
|
||||
check_box_tag(
|
||||
"settings[#{setting}][]",
|
||||
value,
|
||||
setting_values.include?(value),
|
||||
Setting.send(setting).include?(value),
|
||||
:id => nil
|
||||
) + text.to_s,
|
||||
:class => (options[:inline] ? 'inline' : 'block')
|
||||
|
||||
@@ -80,13 +80,12 @@ module SortHelper
|
||||
@criteria.collect {|k,o| k + (o ? '' : ':desc')}.join(',')
|
||||
end
|
||||
|
||||
# Returns an array of SQL fragments used to sort the list
|
||||
def to_sql
|
||||
sql = @criteria.collect do |k,o|
|
||||
if s = @available_criteria[k]
|
||||
(o ? s.to_a : s.to_a.collect {|c| append_desc(c)})
|
||||
(o ? s.to_a : s.to_a.collect {|c| append_desc(c)}).join(', ')
|
||||
end
|
||||
end.flatten.compact
|
||||
end.compact.join(', ')
|
||||
sql.blank? ? nil : sql
|
||||
end
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -56,10 +56,10 @@ module TimelogHelper
|
||||
end
|
||||
|
||||
def select_hours(data, criteria, value)
|
||||
if value.to_s.empty?
|
||||
data.select {|row| row[criteria].blank? }
|
||||
if value.to_s.empty?
|
||||
data.select {|row| row[criteria].blank? }
|
||||
else
|
||||
data.select {|row| row[criteria].to_s == value.to_s}
|
||||
data.select {|row| row[criteria].to_s == value.to_s}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -86,6 +86,49 @@ module TimelogHelper
|
||||
value)
|
||||
end
|
||||
|
||||
def entries_to_csv(entries)
|
||||
decimal_separator = l(:general_csv_decimal_separator)
|
||||
custom_fields = TimeEntryCustomField.find(:all)
|
||||
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
|
||||
# csv header fields
|
||||
headers = [l(:field_spent_on),
|
||||
l(:field_user),
|
||||
l(:field_activity),
|
||||
l(:field_project),
|
||||
l(:field_issue),
|
||||
l(:field_tracker),
|
||||
l(:field_subject),
|
||||
l(:field_hours),
|
||||
l(:field_comments)
|
||||
]
|
||||
# Export custom fields
|
||||
headers += custom_fields.collect(&:name)
|
||||
|
||||
csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8(
|
||||
c.to_s,
|
||||
l(:general_csv_encoding) ) }
|
||||
# csv lines
|
||||
entries.each do |entry|
|
||||
fields = [format_date(entry.spent_on),
|
||||
entry.user,
|
||||
entry.activity,
|
||||
entry.project,
|
||||
(entry.issue ? entry.issue.id : nil),
|
||||
(entry.issue ? entry.issue.tracker : nil),
|
||||
(entry.issue ? entry.issue.subject : nil),
|
||||
entry.hours.to_s.gsub('.', decimal_separator),
|
||||
entry.comments
|
||||
]
|
||||
fields += custom_fields.collect {|f| show_value(entry.custom_field_values.detect {|v| v.custom_field_id == f.id}) }
|
||||
|
||||
csv << fields.collect {|c| Redmine::CodesetUtil.from_utf8(
|
||||
c.to_s,
|
||||
l(:general_csv_encoding) ) }
|
||||
end
|
||||
end
|
||||
export
|
||||
end
|
||||
|
||||
def format_criteria_value(criteria_options, value)
|
||||
if value.blank?
|
||||
"[#{l(:label_none)}]"
|
||||
@@ -107,14 +150,14 @@ module TimelogHelper
|
||||
# Column headers
|
||||
headers = report.criteria.collect {|criteria| l(report.available_criteria[criteria][:label]) }
|
||||
headers += report.periods
|
||||
headers << l(:label_total_time)
|
||||
headers << l(:label_total)
|
||||
csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8(
|
||||
c.to_s,
|
||||
l(:general_csv_encoding) ) }
|
||||
# Content
|
||||
report_criteria_to_csv(csv, report.available_criteria, report.columns, report.criteria, report.periods, report.hours)
|
||||
# Total row
|
||||
str_total = Redmine::CodesetUtil.from_utf8(l(:label_total_time), l(:general_csv_encoding))
|
||||
str_total = Redmine::CodesetUtil.from_utf8(l(:label_total), l(:general_csv_encoding))
|
||||
row = [ str_total ] + [''] * (report.criteria.size - 1)
|
||||
total = 0
|
||||
report.periods.each do |period|
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -20,31 +20,24 @@
|
||||
module WatchersHelper
|
||||
|
||||
def watcher_tag(object, user, options={})
|
||||
ActiveSupport::Deprecation.warn "#watcher_tag is deprecated and will be removed in Redmine 3.0. Use #watcher_link instead."
|
||||
watcher_link(object, user)
|
||||
content_tag("span", watcher_link(object, user), :class => watcher_css(object))
|
||||
end
|
||||
|
||||
def watcher_link(objects, user)
|
||||
return '' unless user && user.logged?
|
||||
objects = Array.wrap(objects)
|
||||
def watcher_link(object, user)
|
||||
return '' unless user && user.logged? && object.respond_to?('watched_by?')
|
||||
watched = object.watched_by?(user)
|
||||
url = {:controller => 'watchers',
|
||||
:action => (watched ? 'unwatch' : 'watch'),
|
||||
:object_type => object.class.to_s.underscore,
|
||||
:object_id => object.id}
|
||||
link_to((watched ? l(:button_unwatch) : l(:button_watch)), url,
|
||||
:remote => true, :method => 'post', :class => (watched ? 'icon icon-fav' : 'icon icon-fav-off'))
|
||||
|
||||
watched = objects.any? {|object| object.watched_by?(user)}
|
||||
css = [watcher_css(objects), watched ? 'icon icon-fav' : 'icon icon-fav-off'].join(' ')
|
||||
text = watched ? l(:button_unwatch) : l(:button_watch)
|
||||
url = watch_path(
|
||||
:object_type => objects.first.class.to_s.underscore,
|
||||
:object_id => (objects.size == 1 ? objects.first.id : objects.map(&:id).sort)
|
||||
)
|
||||
method = watched ? 'delete' : 'post'
|
||||
|
||||
link_to text, url, :remote => true, :method => method, :class => css
|
||||
end
|
||||
|
||||
# Returns the css class used to identify watch links for a given +object+
|
||||
def watcher_css(objects)
|
||||
objects = Array.wrap(objects)
|
||||
id = (objects.size == 1 ? objects.first.id : 'bulk')
|
||||
"#{objects.first.class.to_s.underscore}-#{id}-watcher"
|
||||
def watcher_css(object)
|
||||
"#{object.class.to_s.underscore}-#{object.id}-watcher"
|
||||
end
|
||||
|
||||
# Returns a comma separated list of users watching the given object
|
||||
@@ -63,11 +56,11 @@ module WatchersHelper
|
||||
:user_id => user}
|
||||
s << ' '
|
||||
s << link_to(image_tag('delete.png'), url,
|
||||
:remote => true, :method => 'delete', :class => "delete")
|
||||
:remote => true, :method => 'post', :style => "vertical-align: middle", :class => "delete")
|
||||
end
|
||||
content << content_tag('li', s, :class => "user-#{user.id}")
|
||||
content << content_tag('li', s)
|
||||
end
|
||||
content.present? ? content_tag('ul', content, :class => 'watchers') : content
|
||||
content.present? ? content_tag('ul', content) : content
|
||||
end
|
||||
|
||||
def watchers_checkboxes(object, users, checked=nil)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# encoding: utf-8
|
||||
#
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -16,7 +16,6 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
require "digest/md5"
|
||||
require "fileutils"
|
||||
|
||||
class Attachment < ActiveRecord::Base
|
||||
belongs_to :container, :polymorphic => true
|
||||
@@ -93,6 +92,9 @@ class Attachment < ActiveRecord::Base
|
||||
|
||||
def filename=(arg)
|
||||
write_attribute :filename, sanitize_filename(arg.to_s)
|
||||
if new_record? && disk_filename.blank?
|
||||
self.disk_filename = Attachment.disk_filename(filename)
|
||||
end
|
||||
filename
|
||||
end
|
||||
|
||||
@@ -100,13 +102,7 @@ class Attachment < ActiveRecord::Base
|
||||
# and computes its MD5 hash
|
||||
def files_to_final_location
|
||||
if @temp_file && (@temp_file.size > 0)
|
||||
self.disk_directory = target_directory
|
||||
self.disk_filename = Attachment.disk_filename(filename, disk_directory)
|
||||
logger.info("Saving attachment '#{self.diskfile}' (#{@temp_file.size} bytes)")
|
||||
path = File.dirname(diskfile)
|
||||
unless File.directory?(path)
|
||||
FileUtils.mkdir_p(path)
|
||||
end
|
||||
md5 = Digest::MD5.new
|
||||
File.open(diskfile, "wb") do |f|
|
||||
if @temp_file.respond_to?(:read)
|
||||
@@ -138,7 +134,7 @@ class Attachment < ActiveRecord::Base
|
||||
|
||||
# Returns file's location on disk
|
||||
def diskfile
|
||||
File.join(self.class.storage_path, disk_directory.to_s, disk_filename.to_s)
|
||||
File.join(self.class.storage_path, disk_filename.to_s)
|
||||
end
|
||||
|
||||
def title
|
||||
@@ -158,19 +154,11 @@ class Attachment < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def visible?(user=User.current)
|
||||
if container_id
|
||||
container && container.attachments_visible?(user)
|
||||
else
|
||||
author == user
|
||||
end
|
||||
container && container.attachments_visible?(user)
|
||||
end
|
||||
|
||||
def deletable?(user=User.current)
|
||||
if container_id
|
||||
container && container.attachments_deletable?(user)
|
||||
else
|
||||
author == user
|
||||
end
|
||||
container && container.attachments_deletable?(user)
|
||||
end
|
||||
|
||||
def image?
|
||||
@@ -263,26 +251,6 @@ class Attachment < ActiveRecord::Base
|
||||
Attachment.where("created_on < ? AND (container_type IS NULL OR container_type = '')", Time.now - age).destroy_all
|
||||
end
|
||||
|
||||
# Moves an existing attachment to its target directory
|
||||
def move_to_target_directory!
|
||||
if !new_record? & readable?
|
||||
src = diskfile
|
||||
self.disk_directory = target_directory
|
||||
dest = diskfile
|
||||
if src != dest && FileUtils.mkdir_p(File.dirname(dest)) && FileUtils.mv(src, dest)
|
||||
update_column :disk_directory, disk_directory
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Moves existing attachments that are stored at the root of the files
|
||||
# directory (ie. created before Redmine 2.3) to their target subdirectories
|
||||
def self.move_from_root_to_target_directory
|
||||
Attachment.where("disk_directory IS NULL OR disk_directory = ''").find_each do |attachment|
|
||||
attachment.move_to_target_directory!
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Physically deletes the file from the file system
|
||||
@@ -300,15 +268,8 @@ class Attachment < ActiveRecord::Base
|
||||
@filename = just_filename.gsub(/[\/\?\%\*\:\|\"\'<>]+/, '_')
|
||||
end
|
||||
|
||||
# Returns the subdirectory in which the attachment will be saved
|
||||
def target_directory
|
||||
time = created_on || DateTime.now
|
||||
time.strftime("%Y/%m")
|
||||
end
|
||||
|
||||
# Returns an ASCII or hashed filename that do not
|
||||
# exists yet in the given subdirectory
|
||||
def self.disk_filename(filename, directory=nil)
|
||||
# Returns an ASCII or hashed filename
|
||||
def self.disk_filename(filename)
|
||||
timestamp = DateTime.now.strftime("%y%m%d%H%M%S")
|
||||
ascii = ''
|
||||
if filename =~ %r{^[a-zA-Z0-9_\.\-]*$}
|
||||
@@ -318,7 +279,7 @@ class Attachment < ActiveRecord::Base
|
||||
# keep the extension if any
|
||||
ascii << $1 if filename =~ %r{(\.[a-zA-Z0-9]+)$}
|
||||
end
|
||||
while File.exist?(File.join(storage_path, directory.to_s, "#{timestamp}_#{ascii}"))
|
||||
while File.exist?(File.join(@@storage_path, "#{timestamp}_#{ascii}"))
|
||||
timestamp.succ!
|
||||
end
|
||||
"#{timestamp}_#{ascii}"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -48,24 +48,6 @@ class AuthSource < ActiveRecord::Base
|
||||
write_ciphered_attribute(:account_password, arg)
|
||||
end
|
||||
|
||||
def searchable?
|
||||
false
|
||||
end
|
||||
|
||||
def self.search(q)
|
||||
results = []
|
||||
AuthSource.all.each do |source|
|
||||
begin
|
||||
if source.searchable?
|
||||
results += source.search(q)
|
||||
end
|
||||
rescue AuthSourceException => e
|
||||
logger.error "Error while searching users in #{source.name}: #{e.message}"
|
||||
end
|
||||
end
|
||||
results
|
||||
end
|
||||
|
||||
def allow_password_changes?
|
||||
self.class.allow_password_changes?
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -15,6 +15,7 @@
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
require 'iconv'
|
||||
require 'net/ldap'
|
||||
require 'net/ldap/dn'
|
||||
require 'timeout'
|
||||
@@ -63,32 +64,6 @@ class AuthSourceLdap < AuthSource
|
||||
"LDAP"
|
||||
end
|
||||
|
||||
# Returns true if this source can be searched for users
|
||||
def searchable?
|
||||
!account.to_s.include?("$login") && %w(login firstname lastname mail).all? {|a| send("attr_#{a}?")}
|
||||
end
|
||||
|
||||
# Searches the source for users and returns an array of results
|
||||
def search(q)
|
||||
q = q.to_s.strip
|
||||
return [] unless searchable? && q.present?
|
||||
|
||||
results = []
|
||||
search_filter = base_filter & Net::LDAP::Filter.begins(self.attr_login, q)
|
||||
ldap_con = initialize_ldap_con(self.account, self.account_password)
|
||||
ldap_con.search(:base => self.base_dn,
|
||||
:filter => search_filter,
|
||||
:attributes => ['dn', self.attr_login, self.attr_firstname, self.attr_lastname, self.attr_mail],
|
||||
:size => 10) do |entry|
|
||||
attrs = get_user_attributes_from_ldap_entry(entry)
|
||||
attrs[:login] = AuthSourceLdap.get_attr(entry, self.attr_login)
|
||||
results << attrs
|
||||
end
|
||||
results
|
||||
rescue Net::LDAP::LdapError => e
|
||||
raise AuthSourceException.new(e.message)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def with_timeout(&block)
|
||||
@@ -109,14 +84,6 @@ class AuthSourceLdap < AuthSource
|
||||
nil
|
||||
end
|
||||
|
||||
def base_filter
|
||||
filter = Net::LDAP::Filter.eq("objectClass", "*")
|
||||
if f = ldap_filter
|
||||
filter = filter & f
|
||||
end
|
||||
filter
|
||||
end
|
||||
|
||||
def validate_filter
|
||||
if filter.present? && ldap_filter.nil?
|
||||
errors.add(:filter, :invalid)
|
||||
@@ -173,8 +140,14 @@ class AuthSourceLdap < AuthSource
|
||||
else
|
||||
ldap_con = initialize_ldap_con(self.account, self.account_password)
|
||||
end
|
||||
login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
|
||||
object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )
|
||||
attrs = {}
|
||||
search_filter = base_filter & Net::LDAP::Filter.eq(self.attr_login, login)
|
||||
|
||||
search_filter = object_filter & login_filter
|
||||
if f = ldap_filter
|
||||
search_filter = search_filter & f
|
||||
end
|
||||
|
||||
ldap_con.search( :base => self.base_dn,
|
||||
:filter => search_filter,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -30,9 +30,8 @@ class Board < ActiveRecord::Base
|
||||
validates_length_of :description, :maximum => 255
|
||||
validate :validate_board
|
||||
|
||||
scope :visible, lambda {|*args|
|
||||
includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_messages, *args))
|
||||
}
|
||||
scope :visible, lambda {|*args| { :include => :project,
|
||||
:conditions => Project.allowed_to_condition(args.shift || User.current, :view_messages, *args) } }
|
||||
|
||||
safe_attributes 'name', 'description', 'parent_id', 'move_to'
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -15,6 +15,8 @@
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
require 'iconv'
|
||||
|
||||
class Changeset < ActiveRecord::Base
|
||||
belongs_to :repository
|
||||
belongs_to :user
|
||||
@@ -47,9 +49,9 @@ class Changeset < ActiveRecord::Base
|
||||
validates_uniqueness_of :revision, :scope => :repository_id
|
||||
validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true
|
||||
|
||||
scope :visible, lambda {|*args|
|
||||
includes(:repository => :project).where(Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args))
|
||||
}
|
||||
scope :visible,
|
||||
lambda {|*args| { :include => {:repository => :project},
|
||||
:conditions => Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args) } }
|
||||
|
||||
after_create :scan_for_issues
|
||||
before_create :before_create_cs
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -29,9 +29,6 @@ class CustomField < ActiveRecord::Base
|
||||
|
||||
validate :validate_custom_field
|
||||
before_validation :set_searchable
|
||||
after_save :handle_multiplicity_change
|
||||
|
||||
scope :sorted, lambda { order("#{table_name}.position ASC") }
|
||||
|
||||
CUSTOM_FIELDS_TABS = [
|
||||
{:name => 'IssueCustomField', :partial => 'custom_fields/index',
|
||||
@@ -172,7 +169,7 @@ class CustomField < ActiveRecord::Base
|
||||
keyword
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Returns a ORDER BY clause that can used to sort customized
|
||||
# objects by their value of the custom field.
|
||||
# Returns nil if the custom field can not be used for sorting.
|
||||
@@ -181,12 +178,18 @@ class CustomField < ActiveRecord::Base
|
||||
case field_format
|
||||
when 'string', 'text', 'list', 'date', 'bool'
|
||||
# COALESCE is here to make sure that blank and NULL values are sorted equally
|
||||
"COALESCE(#{join_alias}.value, '')"
|
||||
"COALESCE((SELECT cv_sort.value FROM #{CustomValue.table_name} cv_sort" +
|
||||
" WHERE cv_sort.customized_type='#{self.class.customized_class.base_class.name}'" +
|
||||
" AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" +
|
||||
" AND cv_sort.custom_field_id=#{id} LIMIT 1), '')"
|
||||
when 'int', 'float'
|
||||
# Make the database cast values into numeric
|
||||
# Postgresql will raise an error if a value can not be casted!
|
||||
# CustomValue validations should ensure that it doesn't occur
|
||||
"CAST(CASE #{join_alias}.value WHEN '' THEN '0' ELSE #{join_alias}.value END AS decimal(30,3))"
|
||||
"(SELECT CAST(cv_sort.value AS decimal(60,3)) FROM #{CustomValue.table_name} cv_sort" +
|
||||
" WHERE cv_sort.customized_type='#{self.class.customized_class.base_class.name}'" +
|
||||
" AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" +
|
||||
" AND cv_sort.custom_field_id=#{id} AND cv_sort.value <> '' AND cv_sort.value IS NOT NULL LIMIT 1)"
|
||||
when 'user', 'version'
|
||||
value_class.fields_for_order_statement(value_join_alias)
|
||||
else
|
||||
@@ -196,13 +199,16 @@ class CustomField < ActiveRecord::Base
|
||||
|
||||
# Returns a GROUP BY clause that can used to group by custom value
|
||||
# Returns nil if the custom field can not be used for grouping.
|
||||
def group_statement
|
||||
def group_statement
|
||||
return nil if multiple?
|
||||
case field_format
|
||||
when 'list', 'date', 'bool', 'int'
|
||||
order_statement
|
||||
when 'user', 'version'
|
||||
"COALESCE(#{join_alias}.value, '')"
|
||||
"COALESCE((SELECT cv_sort.value FROM #{CustomValue.table_name} cv_sort" +
|
||||
" WHERE cv_sort.customized_type='#{self.class.customized_class.base_class.name}'" +
|
||||
" AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" +
|
||||
" AND cv_sort.custom_field_id=#{id} LIMIT 1), '')"
|
||||
else
|
||||
nil
|
||||
end
|
||||
@@ -221,26 +227,7 @@ class CustomField < ActiveRecord::Base
|
||||
" AND #{join_alias}_2.customized_id = #{join_alias}.customized_id" +
|
||||
" AND #{join_alias}_2.custom_field_id = #{join_alias}.custom_field_id)" +
|
||||
" LEFT OUTER JOIN #{value_class.table_name} #{value_join_alias}" +
|
||||
" ON CAST(CASE #{join_alias}.value WHEN '' THEN '0' ELSE #{join_alias}.value END AS decimal(30,0)) = #{value_join_alias}.id"
|
||||
when 'int', 'float'
|
||||
"LEFT OUTER JOIN #{CustomValue.table_name} #{join_alias}" +
|
||||
" ON #{join_alias}.customized_type = '#{self.class.customized_class.base_class.name}'" +
|
||||
" AND #{join_alias}.customized_id = #{self.class.customized_class.table_name}.id" +
|
||||
" AND #{join_alias}.custom_field_id = #{id}" +
|
||||
" AND #{join_alias}.value <> ''" +
|
||||
" AND #{join_alias}.id = (SELECT max(#{join_alias}_2.id) FROM #{CustomValue.table_name} #{join_alias}_2" +
|
||||
" WHERE #{join_alias}_2.customized_type = #{join_alias}.customized_type" +
|
||||
" AND #{join_alias}_2.customized_id = #{join_alias}.customized_id" +
|
||||
" AND #{join_alias}_2.custom_field_id = #{join_alias}.custom_field_id)"
|
||||
when 'string', 'text', 'list', 'date', 'bool'
|
||||
"LEFT OUTER JOIN #{CustomValue.table_name} #{join_alias}" +
|
||||
" ON #{join_alias}.customized_type = '#{self.class.customized_class.base_class.name}'" +
|
||||
" AND #{join_alias}.customized_id = #{self.class.customized_class.table_name}.id" +
|
||||
" AND #{join_alias}.custom_field_id = #{id}" +
|
||||
" AND #{join_alias}.id = (SELECT max(#{join_alias}_2.id) FROM #{CustomValue.table_name} #{join_alias}_2" +
|
||||
" WHERE #{join_alias}_2.customized_type = #{join_alias}.customized_type" +
|
||||
" AND #{join_alias}_2.customized_id = #{join_alias}.customized_id" +
|
||||
" AND #{join_alias}_2.custom_field_id = #{join_alias}.custom_field_id)"
|
||||
" ON CAST(#{join_alias}.value as decimal(60,0)) = #{value_join_alias}.id"
|
||||
else
|
||||
nil
|
||||
end
|
||||
@@ -275,7 +262,7 @@ class CustomField < ActiveRecord::Base
|
||||
|
||||
# to move in project_custom_field
|
||||
def self.for_all
|
||||
where(:is_for_all => true).order('position').all
|
||||
find(:all, :conditions => ["is_for_all=?", true], :order => 'position')
|
||||
end
|
||||
|
||||
def type_name
|
||||
@@ -336,20 +323,4 @@ class CustomField < ActiveRecord::Base
|
||||
end
|
||||
errs
|
||||
end
|
||||
|
||||
# Removes multiple values for the custom field after setting the multiple attribute to false
|
||||
# We kepp the value with the highest id for each customized object
|
||||
def handle_multiplicity_change
|
||||
if !new_record? && multiple_was && !multiple
|
||||
ids = custom_values.
|
||||
where("EXISTS(SELECT 1 FROM #{CustomValue.table_name} cve WHERE cve.custom_field_id = #{CustomValue.table_name}.custom_field_id" +
|
||||
" AND cve.customized_type = #{CustomValue.table_name}.customized_type AND cve.customized_id = #{CustomValue.table_name}.customized_id" +
|
||||
" AND cve.id > #{CustomValue.table_name}.id)").
|
||||
pluck(:id)
|
||||
|
||||
if ids.any?
|
||||
custom_values.where(:id => ids).delete_all
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -19,20 +19,19 @@ class Document < ActiveRecord::Base
|
||||
include Redmine::SafeAttributes
|
||||
belongs_to :project
|
||||
belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id"
|
||||
acts_as_attachable :delete_permission => :delete_documents
|
||||
acts_as_attachable :delete_permission => :manage_documents
|
||||
|
||||
acts_as_searchable :columns => ['title', "#{table_name}.description"], :include => :project
|
||||
acts_as_event :title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"},
|
||||
:author => Proc.new {|o| o.attachments.reorder("#{Attachment.table_name}.created_on ASC").first.try(:author) },
|
||||
:author => Proc.new {|o| (a = o.attachments.find(:first, :order => "#{Attachment.table_name}.created_on ASC")) ? a.author : nil },
|
||||
:url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.id}}
|
||||
acts_as_activity_provider :find_options => {:include => :project}
|
||||
|
||||
validates_presence_of :project, :title, :category
|
||||
validates_length_of :title, :maximum => 60
|
||||
|
||||
scope :visible, lambda {|*args|
|
||||
includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_documents, *args))
|
||||
}
|
||||
scope :visible, lambda {|*args| { :include => :project,
|
||||
:conditions => Project.allowed_to_condition(args.shift || User.current, :view_documents, *args) } }
|
||||
|
||||
safe_attributes 'category_id', 'title', 'description'
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user