Compare commits

..
16 Commits
Author SHA1 Message Date
Jean-Philippe Lang 1faf02c9f5 tagged version 1.2.0
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/tags/1.2.0@5968 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-05-30 16:41:28 +00:00
Jean-Philippe Lang 1be21f2413 Merged r5965 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@5967 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-05-30 16:40:52 +00:00
Jean-Philippe Lang eaf430b630 Merged r5964 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@5966 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-05-30 16:40:17 +00:00
Toshi MARUYAMA d2789248f7 Merged r5962 from trunk.
Bulgarian translation updated by Ivan Cenov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@5963 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-05-29 14:54:06 +00:00
Jean-Philippe Lang f08f09a9d3 Merged r5950 to r5960 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@5961 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-05-29 12:06:05 +00:00
Toshi MARUYAMA 2c2760d041 Merged r5887 from trunk.
scm: replace a tab to two spaces in app/views/settings/_repositories.rhtml.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@5959 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-05-29 11:32:16 +00:00
Toshi MARUYAMA 218e2f32ee Merged r5886 from trunk.
scm: remove trailing white-spaces from app/views/settings/_repositories.rhtml.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@5958 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-05-29 11:31:48 +00:00
Jean-Philippe Lang f2b01aeb4d Merged r5948 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@5949 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-05-29 08:15:18 +00:00
Jean-Philippe Lang fabf54a368 Merged r5944 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@5947 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-05-29 07:47:25 +00:00
Jean-Philippe Lang 6b07f86883 Merged r5881 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@5946 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-05-29 07:24:15 +00:00
Jean-Philippe Lang 36d2ea9a6c Merged r5880 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@5945 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-05-29 07:18:05 +00:00
Toshi MARUYAMA 2dca48be53 Merged r5940 from trunk.
remove trailing white-spaces from rake redmine:email:test task source.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@5943 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-05-28 03:34:47 +00:00
Toshi MARUYAMA 7678aa9445 Merged r5939 from trunk.
handle a nil user in rake redmine:email:test task.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@5942 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-05-28 03:34:23 +00:00
Toshi MARUYAMA 9c355ee6c3 Merged r5938 from trunk.
use rake task parameter style message if redmine:email:test parameter is blank.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@5941 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-05-28 03:33:55 +00:00
Jean-Philippe Lang 723030e40a Set version to stable.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@5879 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-05-22 09:20:14 +00:00
Jean-Philippe Lang e6ed112d9d 1.2-stable branch added.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@5878 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-05-22 09:17:45 +00:00
985 changed files with 25485 additions and 23786 deletions

No files matched your search

-5
View File
@@ -23,8 +23,3 @@
/tmp/test/* /tmp/test/*
/vendor/rails /vendor/rails
*.rbc *.rbc
/.bundle
/Gemfile.lock
/Gemfile.local
-6
View File
@@ -25,11 +25,5 @@ tmp/sockets/*
tmp/test/* tmp/test/*
vendor/rails vendor/rails
*.rbc *.rbc
.svn/ .svn/
.git/ .git/
.bundle
Gemfile.lock
Gemfile.local
+1 -1
View File
@@ -2,4 +2,4 @@
Redmine is a flexible project management web application written using Ruby on Rails framework. Redmine is a flexible project management web application written using Ruby on Rails framework.
More details can be found in the doc directory or on the official website http://www.redmine.org More details can be found at in the doc directory or on the official website http://www.redmine.org
+1 -6
View File
@@ -5,11 +5,6 @@ require(File.join(File.dirname(__FILE__), 'config', 'boot'))
require 'rake' require 'rake'
require 'rake/testtask' require 'rake/testtask'
require 'rake/rdoctask'
begin
require 'rdoc/task'
rescue LoadError
# RDoc is not available
end
require 'tasks/rails' require 'tasks/rails'
+2 -1
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2009 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -156,6 +156,7 @@ class AccountController < ApplicationController
end end
end end
def open_id_authenticate(openid_url) def open_id_authenticate(openid_url)
authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => signin_url) do |result, identity_url, registration| authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => signin_url) do |result, identity_url, registration|
if result.successful? if result.successful?
+1 -18
View File
@@ -1,24 +1,7 @@
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class ActivitiesController < ApplicationController class ActivitiesController < ApplicationController
menu_item :activity menu_item :activity
before_filter :find_optional_project before_filter :find_optional_project
accept_rss_auth :index accept_key_auth :index
def index def index
@days = Setting.activity_days_default.to_i @days = Setting.activity_days_default.to_i
+2 -2
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+18 -57
View File
@@ -18,19 +18,12 @@
require 'uri' require 'uri'
require 'cgi' require 'cgi'
class Unauthorized < Exception; end
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
include Redmine::I18n include Redmine::I18n
layout 'base' layout 'base'
exempt_from_layout 'builder', 'rsb' exempt_from_layout 'builder', 'rsb'
protect_from_forgery
def handle_unverified_request
super
cookies.delete(:autologin)
end
# Remove broken cookie after upgrade from 0.8.x (#4292) # Remove broken cookie after upgrade from 0.8.x (#4292)
# See https://rails.lighthouseapp.com/projects/8994/tickets/3360 # See https://rails.lighthouseapp.com/projects/8994/tickets/3360
# TODO: remove it when Rails is fixed # TODO: remove it when Rails is fixed
@@ -45,9 +38,9 @@ class ApplicationController < ActionController::Base
before_filter :user_setup, :check_if_login_required, :set_localization before_filter :user_setup, :check_if_login_required, :set_localization
filter_parameter_logging :password filter_parameter_logging :password
protect_from_forgery
rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token
rescue_from ::Unauthorized, :with => :deny_access
include Redmine::Search::Controller include Redmine::Search::Controller
include Redmine::MenuManager::MenuController include Redmine::MenuManager::MenuController
@@ -75,11 +68,11 @@ class ApplicationController < ActionController::Base
user = User.try_to_autologin(cookies[:autologin]) user = User.try_to_autologin(cookies[:autologin])
session[:user_id] = user.id if user session[:user_id] = user.id if user
user user
elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth? elsif params[:format] == 'atom' && params[:key] && accept_key_auth_actions.include?(params[:action])
# RSS key authentication does not start a session # RSS key authentication does not start a session
User.find_by_rss_key(params[:key]) User.find_by_rss_key(params[:key])
elsif Setting.rest_api_enabled? && accept_api_auth? elsif Setting.rest_api_enabled? && api_request?
if (key = api_key_from_request) if (key = api_key_from_request) && accept_key_auth_actions.include?(params[:action])
# Use API key # Use API key
User.find_by_api_key(key) User.find_by_api_key(key)
else else
@@ -206,6 +199,8 @@ class ApplicationController < ActionController::Base
render_404 unless @object.present? render_404 unless @object.present?
@project = @object.project @project = @object.project
rescue ActiveRecord::RecordNotFound
render_404
end end
def find_model_object def find_model_object
@@ -252,7 +247,7 @@ class ApplicationController < ActionController::Base
if @project.is_public? || User.current.member_of?(@project) || User.current.admin? if @project.is_public? || User.current.member_of?(@project) || User.current.admin?
true true
else else
deny_access User.current.logged? ? render_403 : require_login
end end
else else
@project = nil @project = nil
@@ -313,19 +308,6 @@ class ApplicationController < ActionController::Base
end end
end end
# Filter for actions that provide an API response
# but have no HTML representation for non admin users
def require_admin_or_api_request
return true if api_request?
if User.current.admin?
true
elsif User.current.logged?
render_error(:status => 406)
else
deny_access
end
end
# Picks which layout to use based on the request # Picks which layout to use based on the request
# #
# @return [boolean, string] name of the layout to use or false for no layout # @return [boolean, string] name of the layout to use or false for no layout
@@ -345,44 +327,16 @@ class ApplicationController < ActionController::Base
@items.sort! {|x,y| y.event_datetime <=> x.event_datetime } @items.sort! {|x,y| y.event_datetime <=> x.event_datetime }
@items = @items.slice(0, Setting.feeds_limit.to_i) @items = @items.slice(0, Setting.feeds_limit.to_i)
@title = options[:title] || Setting.app_title @title = options[:title] || Setting.app_title
render :template => "common/feed.atom", :layout => false, render :template => "common/feed.atom.rxml", :layout => false, :content_type => 'application/atom+xml'
:content_type => 'application/atom+xml'
end end
# TODO: remove in Redmine 1.4
def self.accept_key_auth(*actions) def self.accept_key_auth(*actions)
ActiveSupport::Deprecation.warn "ApplicationController.accept_key_auth is deprecated and will be removed in Redmine 1.4. Use accept_rss_auth (or accept_api_auth) instead." actions = actions.flatten.map(&:to_s)
accept_rss_auth(*actions) write_inheritable_attribute('accept_key_auth_actions', actions)
end end
# TODO: remove in Redmine 1.4
def accept_key_auth_actions def accept_key_auth_actions
ActiveSupport::Deprecation.warn "ApplicationController.accept_key_auth_actions is deprecated and will be removed in Redmine 1.4. Use accept_rss_auth (or accept_api_auth) instead." self.class.read_inheritable_attribute('accept_key_auth_actions') || []
self.class.accept_rss_auth
end
def self.accept_rss_auth(*actions)
if actions.any?
write_inheritable_attribute('accept_rss_auth_actions', actions)
else
read_inheritable_attribute('accept_rss_auth_actions') || []
end
end
def accept_rss_auth?(action=action_name)
self.class.accept_rss_auth.include?(action.to_sym)
end
def self.accept_api_auth(*actions)
if actions.any?
write_inheritable_attribute('accept_api_auth_actions', actions)
else
read_inheritable_attribute('accept_api_auth_actions') || []
end
end
def accept_api_auth?(action=action_name)
self.class.accept_api_auth.include?(action.to_sym)
end end
# Returns the number of objects that should be displayed # Returns the number of objects that should be displayed
@@ -491,6 +445,13 @@ class ApplicationController < ActionController::Base
render_error "An error occurred while executing the query and has been logged. Please report this error to your Redmine administrator." render_error "An error occurred while executing the query and has been logged. Please report this error to your Redmine administrator."
end end
# Converts the errors on an ActiveRecord object into a common JSON format
def object_errors_to_json(object)
object.errors.collect do |attribute, error|
{ attribute => error }
end.to_json
end
# Renders API response on validation failure # Renders API response on validation failure
def render_validation_errors(object) def render_validation_errors(object)
options = { :status => :unprocessable_entity, :layout => false } options = { :status => :unprocessable_entity, :layout => false }
+1 -14
View File
@@ -20,20 +20,11 @@ class AttachmentsController < ApplicationController
before_filter :file_readable, :read_authorize, :except => :destroy before_filter :file_readable, :read_authorize, :except => :destroy
before_filter :delete_authorize, :only => :destroy before_filter :delete_authorize, :only => :destroy
accept_api_auth :show, :download verify :method => :post, :only => :destroy
def show def show
respond_to do |format|
format.html {
if @attachment.is_diff? if @attachment.is_diff?
@diff = File.new(@attachment.diskfile, "rb").read @diff = File.new(@attachment.diskfile, "rb").read
@diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
@diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
# Save diff type as user preference
if User.current.logged? && @diff_type != User.current.pref[:diff_type]
User.current.pref[:diff_type] = @diff_type
User.current.preference.save
end
render :action => 'diff' render :action => 'diff'
elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte
@content = File.new(@attachment.diskfile, "rb").read @content = File.new(@attachment.diskfile, "rb").read
@@ -41,9 +32,6 @@ class AttachmentsController < ApplicationController
else else
download download
end end
}
format.api
end
end end
def download def download
@@ -58,7 +46,6 @@ class AttachmentsController < ApplicationController
end end
verify :method => :delete, :only => :destroy
def destroy def destroy
# Make sure association callbacks are called # Make sure association callbacks are called
@attachment.container.attachments.delete(@attachment) @attachment.container.attachments.delete(@attachment)
+2 -2
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+5 -7
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2007 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -18,7 +18,7 @@
class BoardsController < ApplicationController class BoardsController < ApplicationController
default_search_scope :messages default_search_scope :messages
before_filter :find_project, :find_board_if_available, :authorize before_filter :find_project, :find_board_if_available, :authorize
accept_rss_auth :index, :show accept_key_auth :index, :show
helper :messages helper :messages
include MessagesHelper include MessagesHelper
@@ -65,8 +65,7 @@ class BoardsController < ApplicationController
verify :method => :post, :only => [ :destroy ], :redirect_to => { :action => :index } verify :method => :post, :only => [ :destroy ], :redirect_to => { :action => :index }
def new def new
@board = Board.new @board = Board.new(params[:board])
@board.safe_attributes = params[:board]
@board.project = @project @board.project = @project
if request.post? && @board.save if request.post? && @board.save
flash[:notice] = l(:notice_successful_create) flash[:notice] = l(:notice_successful_create)
@@ -75,8 +74,7 @@ class BoardsController < ApplicationController
end end
def edit def edit
@board.safe_attributes = params[:board] if request.post? && @board.update_attributes(params[:board])
if request.post? && @board.save
redirect_to_settings_in_projects redirect_to_settings_in_projects
end end
end end
+1 -2
View File
@@ -7,8 +7,7 @@ class CommentsController < ApplicationController
verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
def create def create
@comment = Comment.new @comment = Comment.new(params[:comment])
@comment.safe_attributes = params[:comment]
@comment.author = User.current @comment.author = User.current
if @news.comments << @comment if @news.comments << @comment
flash[:notice] = l(:label_comment_added) flash[:notice] = l(:label_comment_added)
+5 -7
View File
@@ -26,11 +26,8 @@ class ContextMenusController < ApplicationController
:delete => User.current.allowed_to?(:delete_issues, @projects) :delete => User.current.allowed_to?(:delete_issues, @projects)
} }
if @project if @project
if @issue
@assignables = @issue.assignable_users
else
@assignables = @project.assignable_users @assignables = @project.assignable_users
end @assignables << @issue.assigned_to if @issue && @issue.assigned_to && !@assignables.include?(@issue.assigned_to)
@trackers = @project.trackers @trackers = @project.trackers
else else
#when multiple projects, we only keep the intersection of each set #when multiple projects, we only keep the intersection of each set
@@ -38,7 +35,7 @@ class ContextMenusController < ApplicationController
@trackers = @projects.map(&:trackers).inject{|memo,t| memo & t} @trackers = @projects.map(&:trackers).inject{|memo,t| memo & t}
end end
@priorities = IssuePriority.active.reverse @priorities = IssuePriority.all.reverse
@statuses = IssueStatus.find(:all, :order => 'position') @statuses = IssueStatus.find(:all, :order => 'position')
@back = back_url @back = back_url
@@ -51,8 +48,9 @@ class ContextMenusController < ApplicationController
@projects = @time_entries.collect(&:project).compact.uniq @projects = @time_entries.collect(&:project).compact.uniq
@project = @projects.first if @projects.size == 1 @project = @projects.first if @projects.size == 1
@activities = TimeEntryActivity.shared.active @activities = TimeEntryActivity.shared.active
@can = {:edit => User.current.allowed_to?(:edit_time_entries, @projects), @can = {:edit => User.current.allowed_to?(:log_time, @projects),
:delete => User.current.allowed_to?(:edit_time_entries, @projects) :update => User.current.allowed_to?(:log_time, @projects),
:delete => User.current.allowed_to?(:log_time, @projects)
} }
@back = back_url @back = back_url
render :layout => false render :layout => false
+1 -1
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2009 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+5 -7
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2007 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -47,8 +47,7 @@ class DocumentsController < ApplicationController
end end
def new def new
@document = @project.documents.build @document = @project.documents.build(params[:document])
@document.safe_attributes = params[:document]
if request.post? and @document.save if request.post? and @document.save
attachments = Attachment.attach_files(@document, params[:attachments]) attachments = Attachment.attach_files(@document, params[:attachments])
render_attachment_warning_if_needed(@document) render_attachment_warning_if_needed(@document)
@@ -58,9 +57,8 @@ class DocumentsController < ApplicationController
end end
def edit def edit
@categories = DocumentCategory.active #TODO: use it in the views @categories = DocumentCategory.all
@document.safe_attributes = params[:document] if request.post? and @document.update_attributes(params[:document])
if request.post? and @document.save
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'show', :id => @document redirect_to :action => 'show', :id => @document
end end
+11 -5
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -24,10 +24,16 @@ class EnumerationsController < ApplicationController
include CustomFieldsHelper include CustomFieldsHelper
def index def index
list
render :action => 'list'
end end
# GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
verify :method => :post, :only => [ :destroy, :create, :update ], verify :method => :post, :only => [ :destroy, :create, :update ],
:redirect_to => { :action => :index } :redirect_to => { :action => :list }
def list
end
def new def new
begin begin
@@ -42,7 +48,7 @@ class EnumerationsController < ApplicationController
@enumeration.type = params[:enumeration][:type] @enumeration.type = params[:enumeration][:type]
if @enumeration.save if @enumeration.save
flash[:notice] = l(:notice_successful_create) flash[:notice] = l(:notice_successful_create)
redirect_to :action => 'index', :type => @enumeration.type redirect_to :action => 'list', :type => @enumeration.type
else else
render :action => 'new' render :action => 'new'
end end
@@ -57,7 +63,7 @@ class EnumerationsController < ApplicationController
@enumeration.type = params[:enumeration][:type] if params[:enumeration][:type] @enumeration.type = params[:enumeration][:type] if params[:enumeration][:type]
if @enumeration.update_attributes(params[:enumeration]) if @enumeration.update_attributes(params[:enumeration])
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'index', :type => @enumeration.type redirect_to :action => 'list', :type => @enumeration.type
else else
render :action => 'edit' render :action => 'edit'
end end
+3 -5
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2009 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -67,10 +67,8 @@ class GroupsController < ApplicationController
respond_to do |format| respond_to do |format|
if @group.save if @group.save
format.html {
flash[:notice] = l(:notice_successful_create) flash[:notice] = l(:notice_successful_create)
redirect_to(params[:continue] ? new_group_path : groups_path) format.html { redirect_to(groups_path) }
}
format.xml { render :xml => @group, :status => :created, :location => @group } format.xml { render :xml => @group, :status => :created, :location => @group }
else else
format.html { render :action => "new" } format.html { render :action => "new" }
@@ -125,7 +123,7 @@ class GroupsController < ApplicationController
def remove_user def remove_user
@group = Group.find(params[:id]) @group = Group.find(params[:id])
@group.users.delete(User.find(params[:user_id])) if request.delete? @group.users.delete(User.find(params[:user_id])) if request.post?
respond_to do |format| respond_to do |format|
format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'users' } format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'users' }
format.js { render(:update) {|page| page.replace_html "tab-content-users", :partial => 'groups/users'} } format.js { render(:update) {|page| page.replace_html "tab-content-users", :partial => 'groups/users'} }
+19 -56
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -18,35 +18,16 @@
class IssueCategoriesController < ApplicationController class IssueCategoriesController < ApplicationController
menu_item :settings menu_item :settings
model_object IssueCategory model_object IssueCategory
before_filter :find_model_object, :except => [:index, :new, :create] before_filter :find_model_object, :except => :new
before_filter :find_project_from_association, :except => [:index, :new, :create] before_filter :find_project_from_association, :except => :new
before_filter :find_project, :only => [:index, :new, :create] before_filter :find_project, :only => :new
before_filter :authorize before_filter :authorize
accept_api_auth :index, :show, :create, :update, :destroy
def index verify :method => :post, :only => :destroy
respond_to do |format|
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project }
format.api { @categories = @project.issue_categories.all }
end
end
def show
respond_to do |format|
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project }
format.api
end
end
def new def new
@category = @project.issue_categories.build @category = @project.issue_categories.build(params[:category])
@category.safe_attributes = params[:issue_category] if request.post?
end
verify :method => :post, :only => :create
def create
@category = @project.issue_categories.build
@category.safe_attributes = params[:issue_category]
if @category.save if @category.save
respond_to do |format| respond_to do |format|
format.html do format.html do
@@ -59,54 +40,36 @@ class IssueCategoriesController < ApplicationController
content_tag('select', '<option></option>' + options_from_collection_for_select(@project.issue_categories, 'id', 'name', @category.id), :id => 'issue_category_id', :name => 'issue[category_id]') content_tag('select', '<option></option>' + options_from_collection_for_select(@project.issue_categories, 'id', 'name', @category.id), :id => 'issue_category_id', :name => 'issue[category_id]')
} }
end end
format.api { render :action => 'show', :status => :created, :location => issue_category_path(@category) }
end end
else else
respond_to do |format| respond_to do |format|
format.html { render :action => 'new'} format.html
format.js do format.js do
render(:update) {|page| page.alert(@category.errors.full_messages.join('\n')) } render(:update) {|page| page.alert(@category.errors.full_messages.join('\n')) }
end end
format.api { render_validation_errors(@category) } end
end end
end end
end end
def edit def edit
end if request.post? and @category.update_attributes(params[:category])
verify :method => :put, :only => :update
def update
@category.safe_attributes = params[:issue_category]
if @category.save
respond_to do |format|
format.html {
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
}
format.api { head :ok }
end
else
respond_to do |format|
format.html { render :action => 'edit' }
format.api { render_validation_errors(@category) }
end
end end
end end
verify :method => :delete, :only => :destroy
def destroy def destroy
@issue_count = @category.issues.size @issue_count = @category.issues.size
if @issue_count == 0 || params[:todo] || api_request? if @issue_count == 0
reassign_to = nil # No issue assigned to this category
if params[:reassign_to_id] && (params[:todo] == 'reassign' || params[:todo].blank?) @category.destroy
reassign_to = @project.issue_categories.find_by_id(params[:reassign_to_id]) redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories'
end return
elsif params[:todo]
reassign_to = @project.issue_categories.find_by_id(params[:reassign_to_id]) if params[:todo] == 'reassign'
@category.destroy(reassign_to) @category.destroy(reassign_to)
respond_to do |format| redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories'
format.html { redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories' }
format.api { head :ok }
end
return return
end end
@categories = @project.issue_categories - [@category] @categories = @project.issue_categories - [@category]
-19
View File
@@ -1,23 +1,4 @@
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class IssueMovesController < ApplicationController class IssueMovesController < ApplicationController
menu_item :issues
default_search_scope :issues default_search_scope :issues
before_filter :find_issues, :check_project_uniqueness before_filter :find_issues, :check_project_uniqueness
before_filter :authorize before_filter :authorize
+14 -47
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2007 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -16,38 +16,15 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class IssueRelationsController < ApplicationController class IssueRelationsController < ApplicationController
before_filter :find_issue, :find_project_from_association, :authorize, :only => [:index, :create] before_filter :find_issue, :find_project_from_association, :authorize
before_filter :find_relation, :except => [:index, :create]
accept_api_auth :index, :show, :create, :destroy def new
def index
@relations = @issue.relations
respond_to do |format|
format.html { render :nothing => true }
format.api
end
end
def show
raise Unauthorized unless @relation.visible?
respond_to do |format|
format.html { render :nothing => true }
format.api
end
end
verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
def create
@relation = IssueRelation.new(params[:relation]) @relation = IssueRelation.new(params[:relation])
@relation.issue_from = @issue @relation.issue_from = @issue
if params[:relation] && m = params[:relation][:issue_to_id].to_s.match(/^#?(\d+)$/) if params[:relation] && m = params[:relation][:issue_to_id].to_s.match(/^#?(\d+)$/)
@relation.issue_to = Issue.visible.find_by_id(m[1].to_i) @relation.issue_to = Issue.visible.find_by_id(m[1].to_i)
end end
saved = @relation.save @relation.save if request.post?
respond_to do |format| respond_to do |format|
format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue } format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue }
format.js do format.js do
@@ -60,25 +37,21 @@ class IssueRelationsController < ApplicationController
end end
end end
end end
format.api {
if saved
render :action => 'show', :status => :created, :location => relation_url(@relation)
else
render_validation_errors(@relation)
end
}
end end
end end
verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed }
def destroy def destroy
raise Unauthorized unless @relation.deletable? relation = IssueRelation.find(params[:id])
@relation.destroy if request.post? && @issue.relations.include?(relation)
relation.destroy
@issue.reload
end
respond_to do |format| respond_to do |format|
format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue } format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue }
format.js { render(:update) {|page| page.remove "relation-#{@relation.id}"} } format.js {
format.api { head :ok } @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
render(:update) {|page| page.replace_html "relations", :partial => 'issues/relations'}
}
end end
end end
@@ -88,10 +61,4 @@ private
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render_404 render_404
end end
def find_relation
@relation = IssueRelation.find(params[:id])
rescue ActiveRecord::RecordNotFound
render_404
end
end end
+9 -16
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -18,20 +18,14 @@
class IssueStatusesController < ApplicationController class IssueStatusesController < ApplicationController
layout 'admin' layout 'admin'
before_filter :require_admin, :except => :index before_filter :require_admin
before_filter :require_admin_or_api_request, :only => :index
accept_api_auth :index verify :method => :post, :only => [ :destroy, :create, :update, :move, :update_issue_done_ratio ],
:redirect_to => { :action => :index }
def index def index
respond_to do |format|
format.html {
@issue_status_pages, @issue_statuses = paginate :issue_statuses, :per_page => 25, :order => "position" @issue_status_pages, @issue_statuses = paginate :issue_statuses, :per_page => 25, :order => "position"
render :action => "index", :layout => false if request.xhr? render :action => "index", :layout => false if request.xhr?
}
format.api {
@issue_statuses = IssueStatus.all(:order => 'position')
}
end
end end
def new def new
@@ -40,7 +34,7 @@ class IssueStatusesController < ApplicationController
def create def create
@issue_status = IssueStatus.new(params[:issue_status]) @issue_status = IssueStatus.new(params[:issue_status])
if request.post? && @issue_status.save if @issue_status.save
flash[:notice] = l(:notice_successful_create) flash[:notice] = l(:notice_successful_create)
redirect_to :action => 'index' redirect_to :action => 'index'
else else
@@ -54,7 +48,7 @@ class IssueStatusesController < ApplicationController
def update def update
@issue_status = IssueStatus.find(params[:id]) @issue_status = IssueStatus.find(params[:id])
if request.put? && @issue_status.update_attributes(params[:issue_status]) if @issue_status.update_attributes(params[:issue_status])
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'index' redirect_to :action => 'index'
else else
@@ -62,7 +56,6 @@ class IssueStatusesController < ApplicationController
end end
end end
verify :method => :delete, :only => :destroy, :redirect_to => { :action => :index }
def destroy def destroy
IssueStatus.find(params[:id]).destroy IssueStatus.find(params[:id]).destroy
redirect_to :action => 'index' redirect_to :action => 'index'
@@ -72,7 +65,7 @@ class IssueStatusesController < ApplicationController
end end
def update_issue_done_ratio def update_issue_done_ratio
if request.post? && IssueStatus.update_issue_done_ratios if IssueStatus.update_issue_done_ratios
flash[:notice] = l(:notice_issue_done_ratios_updated) flash[:notice] = l(:notice_issue_done_ratios_updated)
else else
flash[:error] = l(:error_issue_done_ratios_not_updated) flash[:error] = l(:error_issue_done_ratios_not_updated)
+14 -20
View File
@@ -27,8 +27,7 @@ class IssuesController < ApplicationController
before_filter :find_optional_project, :only => [:index] before_filter :find_optional_project, :only => [:index]
before_filter :check_for_default_issue_status, :only => [:new, :create] before_filter :check_for_default_issue_status, :only => [:new, :create]
before_filter :build_new_issue_from_params, :only => [:new, :create] before_filter :build_new_issue_from_params, :only => [:new, :create]
accept_rss_auth :index, :show accept_key_auth :index, :show, :create, :update, :destroy
accept_api_auth :index, :show, :create, :update, :destroy
rescue_from Query::StatementInvalid, :with => :query_statement_invalid rescue_from Query::StatementInvalid, :with => :query_statement_invalid
@@ -89,20 +88,15 @@ class IssuesController < ApplicationController
@issue_count_by_group = @query.issue_count_by_group @issue_count_by_group = @query.issue_count_by_group
respond_to do |format| respond_to do |format|
format.html { render :template => 'issues/index', :layout => !request.xhr? } format.html { render :template => 'issues/index.rhtml', :layout => !request.xhr? }
format.api { format.api
Issue.load_relations(@issues) if include_in_api_response?('relations')
}
format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") } format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
format.csv { send_data(issues_to_csv(@issues, @project, @query, params), :type => 'text/csv; header=present', :filename => 'export.csv') } format.csv { send_data(issues_to_csv(@issues, @project), :type => 'text/csv; header=present', :filename => 'export.csv') }
format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') } format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') }
end end
else else
respond_to do |format| # Send html if the query is not valid
format.html { render(:template => 'issues/index', :layout => !request.xhr?) } render(:template => 'issues/index.rhtml', :layout => !request.xhr?)
format.any(:atom, :csv, :pdf) { render(:nothing => true) }
format.api { render_validation_errors(@query) }
end
end end
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render_404 render_404
@@ -121,10 +115,10 @@ class IssuesController < ApplicationController
@relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? } @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
@allowed_statuses = @issue.new_statuses_allowed_to(User.current) @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
@edit_allowed = User.current.allowed_to?(:edit_issues, @project) @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
@priorities = IssuePriority.active @priorities = IssuePriority.all
@time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project) @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
respond_to do |format| respond_to do |format|
format.html { render :template => 'issues/show' } format.html { render :template => 'issues/show.rhtml' }
format.api format.api
format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' } format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' }
format.pdf { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") } format.pdf { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") }
@@ -144,11 +138,11 @@ class IssuesController < ApplicationController
call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue }) call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
if @issue.save if @issue.save
attachments = Attachment.attach_files(@issue, params[:attachments]) attachments = Attachment.attach_files(@issue, params[:attachments])
render_attachment_warning_if_needed(@issue)
flash[:notice] = l(:notice_successful_create)
call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue}) call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue})
respond_to do |format| respond_to do |format|
format.html { format.html {
render_attachment_warning_if_needed(@issue)
flash[:notice] = l(:notice_issue_successful_create, :id => "<a href='#{issue_path(@issue)}'>##{@issue.id}</a>")
redirect_to(params[:continue] ? { :action => 'new', :project_id => @project, :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } : redirect_to(params[:continue] ? { :action => 'new', :project_id => @project, :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } :
{ :action => 'show', :id => @issue }) { :action => 'show', :id => @issue })
} }
@@ -285,7 +279,7 @@ private
# TODO: Refactor, not everything in here is needed by #edit # TODO: Refactor, not everything in here is needed by #edit
def update_issue_from_params def update_issue_from_params
@allowed_statuses = @issue.new_statuses_allowed_to(User.current) @allowed_statuses = @issue.new_statuses_allowed_to(User.current)
@priorities = IssuePriority.active @priorities = IssuePriority.all
@edit_allowed = User.current.allowed_to?(:edit_issues, @project) @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
@time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project) @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
@time_entry.attributes = params[:time_entry] @time_entry.attributes = params[:time_entry]
@@ -307,21 +301,21 @@ private
end end
@issue.project = @project @issue.project = @project
@issue.author = User.current
# Tracker must be set before custom field values # Tracker must be set before custom field values
@issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first) @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
if @issue.tracker.nil? if @issue.tracker.nil?
render_error l(:error_no_tracker_in_project) render_error l(:error_no_tracker_in_project)
return false return false
end end
@issue.start_date ||= Date.today if Setting.default_issue_start_date_to_creation_date? @issue.start_date ||= Date.today
if params[:issue].is_a?(Hash) if params[:issue].is_a?(Hash)
@issue.safe_attributes = params[:issue] @issue.safe_attributes = params[:issue]
if User.current.allowed_to?(:add_issue_watchers, @project) && @issue.new_record? if User.current.allowed_to?(:add_issue_watchers, @project) && @issue.new_record?
@issue.watcher_user_ids = params[:issue]['watcher_user_ids'] @issue.watcher_user_ids = params[:issue]['watcher_user_ids']
end end
end end
@priorities = IssuePriority.active @issue.author = User.current
@priorities = IssuePriority.all
@allowed_statuses = @issue.new_statuses_allowed_to(User.current, true) @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true)
end end
+1 -1
View File
@@ -20,7 +20,7 @@ class JournalsController < ApplicationController
before_filter :find_issue, :only => [:new] before_filter :find_issue, :only => [:new]
before_filter :find_optional_project, :only => [:index] before_filter :find_optional_project, :only => [:index]
before_filter :authorize, :only => [:new, :edit, :diff] before_filter :authorize, :only => [:new, :edit, :diff]
accept_rss_auth :index accept_key_auth :index
menu_item :issues menu_item :issues
helper :issues helper :issues
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+6 -9
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -28,10 +28,10 @@ class MembersController < ApplicationController
attrs = params[:member].dup attrs = params[:member].dup
if (user_ids = attrs.delete(:user_ids)) if (user_ids = attrs.delete(:user_ids))
user_ids.each do |user_id| user_ids.each do |user_id|
members << Member.new(:role_ids => params[:member][:role_ids], :user_id => user_id) members << Member.new(attrs.merge(:user_id => user_id))
end end
else else
members << Member.new(:role_ids => params[:member][:role_ids], :user_id => params[:member][:user_id]) members << Member.new(attrs)
end end
@project.members << members @project.members << members
end end
@@ -64,10 +64,7 @@ class MembersController < ApplicationController
end end
def edit def edit
if params[:member] if request.post? and @member.update_attributes(params[:member])
@member.role_ids = params[:member][:role_ids]
end
if request.post? and @member.save
respond_to do |format| respond_to do |format|
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project } format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
format.js { format.js {
@@ -96,7 +93,7 @@ class MembersController < ApplicationController
end end
def autocomplete_for_member def autocomplete_for_member
@principals = Principal.active.not_member_of(@project).like(params[:q]).all(:limit => 100) @principals = Principal.active.like(params[:q]).find(:all, :limit => 100) - @project.principals
render :layout => false render :layout => false
end end
+14 -9
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2007 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -53,10 +53,13 @@ class MessagesController < ApplicationController
# Create a new topic # Create a new topic
def new def new
@message = Message.new @message = Message.new(params[:message])
@message.author = User.current @message.author = User.current
@message.board = @board @message.board = @board
@message.safe_attributes = params[:message] if params[:message] && User.current.allowed_to?(:edit_messages, @project)
@message.locked = params[:message]['locked']
@message.sticky = params[:message]['sticky']
end
if request.post? && @message.save if request.post? && @message.save
call_hook(:controller_messages_new_after_save, { :params => params, :message => @message}) call_hook(:controller_messages_new_after_save, { :params => params, :message => @message})
attachments = Attachment.attach_files(@message, params[:attachments]) attachments = Attachment.attach_files(@message, params[:attachments])
@@ -67,10 +70,9 @@ class MessagesController < ApplicationController
# Reply to a topic # Reply to a topic
def reply def reply
@reply = Message.new @reply = Message.new(params[:reply])
@reply.author = User.current @reply.author = User.current
@reply.board = @board @reply.board = @board
@reply.safe_attributes = params[:reply]
@topic.children << @reply @topic.children << @reply
if !@reply.new_record? if !@reply.new_record?
call_hook(:controller_messages_reply_after_save, { :params => params, :message => @reply}) call_hook(:controller_messages_reply_after_save, { :params => params, :message => @reply})
@@ -83,8 +85,11 @@ class MessagesController < ApplicationController
# Edit a message # Edit a message
def edit def edit
(render_403; return false) unless @message.editable_by?(User.current) (render_403; return false) unless @message.editable_by?(User.current)
@message.safe_attributes = params[:message] if params[:message]
if request.post? && @message.save @message.locked = params[:message]['locked']
@message.sticky = params[:message]['sticky']
end
if request.post? && @message.update_attributes(params[:message])
attachments = Attachment.attach_files(@message, params[:attachments]) attachments = Attachment.attach_files(@message, params[:attachments])
render_attachment_warning_if_needed(@message) render_attachment_warning_if_needed(@message)
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
@@ -110,7 +115,7 @@ class MessagesController < ApplicationController
content = "#{ll(Setting.default_language, :text_user_wrote, user)}\\n> " content = "#{ll(Setting.default_language, :text_user_wrote, user)}\\n> "
content << text.to_s.strip.gsub(%r{<pre>((.|\s)*?)</pre>}m, '[...]').gsub('"', '\"').gsub(/(\r?\n|\r\n?)/, "\\n> ") + "\\n\\n" content << text.to_s.strip.gsub(%r{<pre>((.|\s)*?)</pre>}m, '[...]').gsub('"', '\"').gsub(/(\r?\n|\r\n?)/, "\\n> ") + "\\n\\n"
render(:update) { |page| render(:update) { |page|
page << "$('message_subject').value = \"#{subject}\";" page << "$('reply_subject').value = \"#{subject}\";"
page.<< "$('message_content').value = \"#{content}\";" page.<< "$('message_content').value = \"#{content}\";"
page.show 'reply' page.show 'reply'
page << "Form.Element.focus('message_content');" page << "Form.Element.focus('message_content');"
+1 -1
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2009 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+4 -9
View File
@@ -23,8 +23,7 @@ class NewsController < ApplicationController
before_filter :find_project, :only => [:new, :create] before_filter :find_project, :only => [:new, :create]
before_filter :authorize, :except => [:index] before_filter :authorize, :except => [:index]
before_filter :find_optional_project, :only => :index before_filter :find_optional_project, :only => :index
accept_rss_auth :index accept_key_auth :index
accept_api_auth :index
helper :watchers helper :watchers
@@ -47,10 +46,7 @@ class NewsController < ApplicationController
:limit => @limit) :limit => @limit)
respond_to do |format| respond_to do |format|
format.html { format.html { render :layout => false if request.xhr? }
@news = News.new # for adding news inline
render :layout => false if request.xhr?
}
format.api format.api
format.atom { render_feed(@newss, :title => (@project ? @project.name : Setting.app_title) + ": #{l(:label_news_plural)}") } format.atom { render_feed(@newss, :title => (@project ? @project.name : Setting.app_title) + ": #{l(:label_news_plural)}") }
end end
@@ -67,8 +63,8 @@ class NewsController < ApplicationController
def create def create
@news = News.new(:project => @project, :author => User.current) @news = News.new(:project => @project, :author => User.current)
@news.safe_attributes = params[:news]
if request.post? if request.post?
@news.attributes = params[:news]
if @news.save if @news.save
flash[:notice] = l(:notice_successful_create) flash[:notice] = l(:notice_successful_create)
redirect_to :controller => 'news', :action => 'index', :project_id => @project redirect_to :controller => 'news', :action => 'index', :project_id => @project
@@ -82,8 +78,7 @@ class NewsController < ApplicationController
end end
def update def update
@news.safe_attributes = params[:news] if request.put? and @news.update_attributes(params[:news])
if request.put? and @news.save
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'show', :id => @news redirect_to :action => 'show', :id => @news
else else
+3 -8
View File
@@ -24,8 +24,7 @@ class ProjectsController < ApplicationController
before_filter :authorize, :except => [ :index, :list, :new, :create, :copy, :archive, :unarchive, :destroy] before_filter :authorize, :except => [ :index, :list, :new, :create, :copy, :archive, :unarchive, :destroy]
before_filter :authorize_global, :only => [:new, :create] before_filter :authorize_global, :only => [:new, :create]
before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ] before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ]
accept_rss_auth :index accept_key_auth :index, :show, :create, :update, :destroy
accept_api_auth :index, :show, :create, :update, :destroy
after_filter :only => [:create, :edit, :update, :archive, :unarchive, :destroy] do |controller| after_filter :only => [:create, :edit, :update, :archive, :unarchive, :destroy] do |controller|
if controller.request.post? if controller.request.post?
@@ -66,8 +65,7 @@ class ProjectsController < ApplicationController
def new def new
@issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position") @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
@trackers = Tracker.all @trackers = Tracker.all
@project = Project.new @project = Project.new(params[:project])
@project.safe_attributes = params[:project]
end end
verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
@@ -88,10 +86,7 @@ class ProjectsController < ApplicationController
respond_to do |format| respond_to do |format|
format.html { format.html {
flash[:notice] = l(:notice_successful_create) flash[:notice] = l(:notice_successful_create)
redirect_to(params[:continue] ? redirect_to :controller => 'projects', :action => 'settings', :id => @project
{:controller => 'projects', :action => 'new', :project => {:parent_id => @project.parent_id}.reject {|k,v| v.nil?}} :
{:controller => 'projects', :action => 'settings', :id => @project}
)
} }
format.api { render :action => 'show', :status => :created, :location => url_for(:controller => 'projects', :action => 'show', :id => @project.id) } format.api { render :action => 'show', :status => :created, :location => url_for(:controller => 'projects', :action => 'show', :id => @project.id) }
end end
+19 -49
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2007 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -17,78 +17,48 @@
class QueriesController < ApplicationController class QueriesController < ApplicationController
menu_item :issues menu_item :issues
before_filter :find_query, :except => [:new, :create, :index] before_filter :find_query, :except => :new
before_filter :find_optional_project, :only => [:new, :create] before_filter :find_optional_project, :only => :new
accept_api_auth :index
include QueriesHelper
def index
case params[:format]
when 'xml', 'json'
@offset, @limit = api_offset_and_limit
else
@limit = per_page_option
end
@query_count = Query.visible.count
@query_pages = Paginator.new self, @query_count, @limit, params['page']
@queries = Query.visible.all(:limit => @limit, :offset => @offset, :order => "#{Query.table_name}.name")
respond_to do |format|
format.html { render :nothing => true }
format.api
end
end
def new def new
@query = Query.new
@query.user = User.current
@query.project = @project
@query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
build_query_from_params
end
verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
def create
@query = Query.new(params[:query]) @query = Query.new(params[:query])
@query.user = User.current
@query.project = params[:query_is_for_all] ? nil : @project @query.project = params[:query_is_for_all] ? nil : @project
@query.user = User.current
@query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
build_query_from_params
@query.add_filters(params[:fields] || params[:f], params[:operators] || params[:op], params[:values] || params[:v]) if params[:fields] || params[:f]
@query.group_by ||= params[:group_by]
@query.column_names = params[:c] if params[:c]
@query.column_names = nil if params[:default_columns] @query.column_names = nil if params[:default_columns]
if @query.save if request.post? && params[:confirm] && @query.save
flash[:notice] = l(:notice_successful_create) flash[:notice] = l(:notice_successful_create)
redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query
else return
render :action => 'new', :layout => !request.xhr?
end end
render :layout => false if request.xhr?
end end
def edit def edit
end if request.post?
@query.filters = {}
verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed } @query.add_filters(params[:fields] || params[:f], params[:operators] || params[:op], params[:values] || params[:v]) if params[:fields] || params[:f]
def update
@query.attributes = params[:query] @query.attributes = params[:query]
@query.project = nil if params[:query_is_for_all] @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.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
build_query_from_params @query.group_by ||= params[:group_by]
@query.column_names = params[:c] if params[:c]
@query.column_names = nil if params[:default_columns] @query.column_names = nil if params[:default_columns]
if @query.save if @query.save
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query
else end
render :action => 'edit'
end end
end end
verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed }
def destroy def destroy
@query.destroy @query.destroy if request.post?
redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1 redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1
end end
+6 -6
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -24,8 +24,8 @@ class ReportsController < ApplicationController
@versions = @project.shared_versions.sort @versions = @project.shared_versions.sort
@priorities = IssuePriority.all @priorities = IssuePriority.all
@categories = @project.issue_categories @categories = @project.issue_categories
@assignees = (Setting.issue_group_assignment? ? @project.principals : @project.users).sort @assignees = @project.members.collect { |m| m.user }.sort
@authors = @project.users.sort @authors = @project.members.collect { |m| m.user }.sort
@subprojects = @project.descendants.visible @subprojects = @project.descendants.visible
@issues_by_tracker = Issue.by_tracker(@project) @issues_by_tracker = Issue.by_tracker(@project)
@@ -63,12 +63,12 @@ class ReportsController < ApplicationController
@report_title = l(:field_category) @report_title = l(:field_category)
when "assigned_to" when "assigned_to"
@field = "assigned_to_id" @field = "assigned_to_id"
@rows = (Setting.issue_group_assignment? ? @project.principals : @project.users).sort @rows = @project.members.collect { |m| m.user }.sort
@data = Issue.by_assigned_to(@project) @data = Issue.by_assigned_to(@project)
@report_title = l(:field_assigned_to) @report_title = l(:field_assigned_to)
when "author" when "author"
@field = "author_id" @field = "author_id"
@rows = @project.users.sort @rows = @project.members.collect { |m| m.user }.sort
@data = Issue.by_author(@project) @data = Issue.by_author(@project)
@report_title = l(:field_author) @report_title = l(:field_author)
when "subproject" when "subproject"
+5 -14
View File
@@ -30,7 +30,7 @@ class RepositoriesController < ApplicationController
before_filter :find_repository, :except => :edit before_filter :find_repository, :except => :edit
before_filter :find_project, :only => :edit before_filter :find_project, :only => :edit
before_filter :authorize before_filter :authorize
accept_rss_auth :revisions accept_key_auth :revisions
rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed
@@ -121,7 +121,7 @@ class RepositoriesController < ApplicationController
@changesets = @repository.changesets.find(:all, @changesets = @repository.changesets.find(:all,
:limit => @changeset_pages.items_per_page, :limit => @changeset_pages.items_per_page,
:offset => @changeset_pages.current.offset, :offset => @changeset_pages.current.offset,
:include => [:user, :repository, :parents]) :include => [:user, :repository])
respond_to do |format| respond_to do |format|
format.html { render :layout => false if request.xhr? } format.html { render :layout => false if request.xhr? }
@@ -172,16 +172,7 @@ class RepositoriesController < ApplicationController
(show_error_not_found; return) unless @entry (show_error_not_found; return) unless @entry
@annotate = @repository.scm.annotate(@path, @rev) @annotate = @repository.scm.annotate(@path, @rev)
if @annotate.nil? || @annotate.empty? (render_error l(:error_scm_annotate); return) if @annotate.nil? || @annotate.empty?
(render_error l(:error_scm_annotate); return)
end
ann_buf_size = 0
@annotate.lines.each do |buf|
ann_buf_size += buf.size
end
if ann_buf_size > Setting.file_max_size_displayed.to_i.kilobyte
(render_error l(:error_scm_annotate_big_text_file); return)
end
@changeset = @repository.find_changeset_by_name(@rev) @changeset = @repository.find_changeset_by_name(@rev)
end end
@@ -217,7 +208,7 @@ class RepositoriesController < ApplicationController
User.current.preference.save User.current.preference.save
end end
@cache_key = "repositories/diff/#{@repository.id}/" + @cache_key = "repositories/diff/#{@repository.id}/" +
Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}-#{current_language}") Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}")
unless read_fragment(@cache_key) unless read_fragment(@cache_key)
@diff = @repository.diff(@path, @rev, @rev_to) @diff = @repository.diff(@path, @rev, @rev_to)
show_error_not_found unless @diff show_error_not_found unless @diff
@@ -258,7 +249,7 @@ class RepositoriesController < ApplicationController
(render_404; return false) unless @repository (render_404; return false) unless @repository
@path = params[:path].join('/') unless params[:path].nil? @path = params[:path].join('/') unless params[:path].nil?
@path ||= '' @path ||= ''
@rev = params[:rev].blank? ? @repository.default_branch : params[:rev].to_s.strip @rev = params[:rev].blank? ? @repository.default_branch : params[:rev].strip
@rev_to = params[:rev_to] @rev_to = params[:rev_to]
unless @rev.to_s.match(REV_PARAM_RE) && @rev_to.to_s.match(REV_PARAM_RE) unless @rev.to_s.match(REV_PARAM_RE) && @rev_to.to_s.match(REV_PARAM_RE)
+3 -3
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -20,7 +20,7 @@ class RolesController < ApplicationController
before_filter :require_admin before_filter :require_admin
verify :method => :post, :only => [ :destroy ], verify :method => :post, :only => [ :destroy, :move ],
:redirect_to => { :action => :index } :redirect_to => { :action => :index }
def index def index
+4 -4
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -24,8 +24,8 @@ class SearchController < ApplicationController
def index def index
@question = params[:q] || "" @question = params[:q] || ""
@question.strip! @question.strip!
@all_words = params[:all_words] ? params[:all_words].present? : true @all_words = params[:all_words] || (params[:submit] ? false : true)
@titles_only = params[:titles_only] ? params[:titles_only].present? : false @titles_only = !params[:titles_only].nil?
projects_to_search = projects_to_search =
case params[:scope] case params[:scope]
+3 -4
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2009 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -20,8 +20,7 @@ class SysController < ActionController::Base
def projects def projects
p = Project.active.has_module(:repository).find(:all, :include => :repository, :order => 'identifier') p = Project.active.has_module(:repository).find(:all, :include => :repository, :order => 'identifier')
# extra_info attribute from repository breaks activeresource client render :xml => p.to_xml(:include => :repository)
render :xml => p.to_xml(:only => [:id, :identifier, :name, :is_public, :status], :include => {:repository => {:only => [:id, :url]}})
end end
def create_project_repository def create_project_repository
@@ -32,7 +31,7 @@ class SysController < ActionController::Base
logger.info "Repository for #{project.name} was reported to be created by #{request.remote_ip}." logger.info "Repository for #{project.name} was reported to be created by #{request.remote_ip}."
project.repository = Repository.factory(params[:vendor], params[:repository]) project.repository = Repository.factory(params[:vendor], params[:repository])
if project.repository && project.repository.save if project.repository && project.repository.save
render :xml => project.repository.to_xml(:only => [:id, :url]), :status => 201 render :xml => project.repository, :status => 201
else else
render :nothing => true, :status => 422 render :nothing => true, :status => 422
end end
+7 -8
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2010 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -22,8 +22,7 @@ class TimelogController < ApplicationController
before_filter :find_time_entries, :only => [:bulk_edit, :bulk_update, :destroy] before_filter :find_time_entries, :only => [:bulk_edit, :bulk_update, :destroy]
before_filter :authorize, :except => [:index] before_filter :authorize, :except => [:index]
before_filter :find_optional_project, :only => [:index] before_filter :find_optional_project, :only => [:index]
accept_rss_auth :index accept_key_auth :index, :show, :create, :update, :destroy
accept_api_auth :index, :show, :create, :update, :destroy
helper :sort helper :sort
include SortHelper include SortHelper
@@ -105,7 +104,7 @@ class TimelogController < ApplicationController
def new def new
@time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today) @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today)
@time_entry.safe_attributes = params[:time_entry] @time_entry.attributes = params[:time_entry]
call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
render :action => 'edit' render :action => 'edit'
@@ -114,7 +113,7 @@ class TimelogController < ApplicationController
verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
def create def create
@time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today) @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today)
@time_entry.safe_attributes = params[:time_entry] @time_entry.attributes = params[:time_entry]
call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
@@ -135,14 +134,14 @@ class TimelogController < ApplicationController
end end
def edit def edit
@time_entry.safe_attributes = params[:time_entry] @time_entry.attributes = params[:time_entry]
call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
end end
verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed } verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
def update def update
@time_entry.safe_attributes = params[:time_entry] @time_entry.attributes = params[:time_entry]
call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
@@ -173,7 +172,7 @@ class TimelogController < ApplicationController
unsaved_time_entry_ids = [] unsaved_time_entry_ids = []
@time_entries.each do |time_entry| @time_entries.each do |time_entry|
time_entry.reload time_entry.reload
time_entry.safe_attributes = attributes time_entry.attributes = attributes
call_hook(:controller_time_entries_bulk_edit_before_save, { :params => params, :time_entry => time_entry }) call_hook(:controller_time_entries_bulk_edit_before_save, { :params => params, :time_entry => time_entry })
unless time_entry.save unless time_entry.save
# Keep unsaved time_entry ids to display them in flash error # Keep unsaved time_entry ids to display them in flash error
+8 -28
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2009 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -18,29 +18,16 @@
class TrackersController < ApplicationController class TrackersController < ApplicationController
layout 'admin' layout 'admin'
before_filter :require_admin, :except => :index before_filter :require_admin
before_filter :require_admin_or_api_request, :only => :index
accept_api_auth :index verify :method => :post, :only => :destroy, :redirect_to => { :action => :index }
def index def index
respond_to do |format|
format.html {
@tracker_pages, @trackers = paginate :trackers, :per_page => 10, :order => 'position' @tracker_pages, @trackers = paginate :trackers, :per_page => 10, :order => 'position'
render :action => "index", :layout => false if request.xhr? render :action => "index", :layout => false if request.xhr?
}
format.api {
@trackers = Tracker.all
}
end
end end
def new def new
@tracker ||= Tracker.new(params[:tracker])
@trackers = Tracker.find :all, :order => 'position'
@projects = Project.find(:all)
end
def create
@tracker = Tracker.new(params[:tracker]) @tracker = Tracker.new(params[:tracker])
if request.post? and @tracker.save if request.post? and @tracker.save
# workflow copy # workflow copy
@@ -51,27 +38,20 @@ class TrackersController < ApplicationController
redirect_to :action => 'index' redirect_to :action => 'index'
return return
end end
new @trackers = Tracker.find :all, :order => 'position'
render :action => 'new'
end
def edit
@tracker ||= Tracker.find(params[:id])
@projects = Project.find(:all) @projects = Project.find(:all)
end end
def update def edit
@tracker = Tracker.find(params[:id]) @tracker = Tracker.find(params[:id])
if request.put? and @tracker.update_attributes(params[:tracker]) if request.post? and @tracker.update_attributes(params[:tracker])
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'index' redirect_to :action => 'index'
return return
end end
edit @projects = Project.find(:all)
render :action => 'edit'
end end
verify :method => :delete, :only => :destroy, :redirect_to => { :action => :index }
def destroy def destroy
@tracker = Tracker.find(params[:id]) @tracker = Tracker.find(params[:id])
unless @tracker.issues.empty? unless @tracker.issues.empty?
+1 -1
View File
@@ -20,7 +20,7 @@ class UsersController < ApplicationController
before_filter :require_admin, :except => :show before_filter :require_admin, :except => :show
before_filter :find_user, :only => [:show, :edit, :update, :destroy, :edit_membership, :destroy_membership] before_filter :find_user, :only => [:show, :edit, :update, :destroy, :edit_membership, :destroy_membership]
accept_api_auth :index, :show, :create, :update, :destroy accept_key_auth :index, :show, :create, :update, :destroy
helper :sort helper :sort
include SortHelper include SortHelper
+8 -42
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -23,14 +23,10 @@ class VersionsController < ApplicationController
before_filter :find_project, :only => [:index, :new, :create, :close_completed] before_filter :find_project, :only => [:index, :new, :create, :close_completed]
before_filter :authorize before_filter :authorize
accept_api_auth :index, :show, :create, :update, :destroy
helper :custom_fields helper :custom_fields
helper :projects helper :projects
def index def index
respond_to do |format|
format.html {
@trackers = @project.trackers.find(:all, :order => 'position') @trackers = @project.trackers.find(:all, :order => 'position')
retrieve_selected_tracker_ids(@trackers, @trackers.select {|t| t.is_in_roadmap?}) 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') @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
@@ -52,22 +48,12 @@ class VersionsController < ApplicationController
end end
end end
@versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?} @versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?}
}
format.api {
@versions = @project.shared_versions.all
}
end
end end
def show def show
respond_to do |format|
format.html {
@issues = @version.fixed_issues.visible.find(:all, @issues = @version.fixed_issues.visible.find(:all,
:include => [:status, :tracker, :priority], :include => [:status, :tracker, :priority],
:order => "#{Tracker.table_name}.position, #{Issue.table_name}.id") :order => "#{Tracker.table_name}.position, #{Issue.table_name}.id")
}
format.api
end
end end
def new def new
@@ -75,7 +61,7 @@ class VersionsController < ApplicationController
if params[:version] if params[:version]
attributes = params[:version].dup attributes = params[:version].dup
attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing']) attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing'])
@version.safe_attributes = attributes @version.attributes = attributes
end end
end end
@@ -85,7 +71,7 @@ class VersionsController < ApplicationController
if params[:version] if params[:version]
attributes = params[:version].dup attributes = params[:version].dup
attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing']) attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing'])
@version.safe_attributes = attributes @version.attributes = attributes
end end
if request.post? if request.post?
@@ -93,7 +79,7 @@ class VersionsController < ApplicationController
respond_to do |format| respond_to do |format|
format.html do format.html do
flash[:notice] = l(:notice_successful_create) flash[:notice] = l(:notice_successful_create)
redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
end end
format.js do format.js do
# IE doesn't support the replace_html rjs method for select box options # IE doesn't support the replace_html rjs method for select box options
@@ -101,9 +87,6 @@ class VersionsController < ApplicationController
content_tag('select', '<option></option>' + version_options_for_select(@project.shared_versions.open, @version), :id => 'issue_fixed_version_id', :name => 'issue[fixed_version_id]') content_tag('select', '<option></option>' + version_options_for_select(@project.shared_versions.open, @version), :id => 'issue_fixed_version_id', :name => 'issue[fixed_version_id]')
} }
end end
format.api do
render :action => 'show', :status => :created, :location => version_url(@version)
end
end end
else else
respond_to do |format| respond_to do |format|
@@ -111,7 +94,6 @@ class VersionsController < ApplicationController
format.js do format.js do
render(:update) {|page| page.alert(@version.errors.full_messages.join('\n')) } render(:update) {|page| page.alert(@version.errors.full_messages.join('\n')) }
end end
format.api { render_validation_errors(@version) }
end end
end end
end end
@@ -124,19 +106,12 @@ class VersionsController < ApplicationController
if request.put? && params[:version] if request.put? && params[:version]
attributes = params[:version].dup attributes = params[:version].dup
attributes.delete('sharing') unless @version.allowed_sharings.include?(attributes['sharing']) attributes.delete('sharing') unless @version.allowed_sharings.include?(attributes['sharing'])
@version.safe_attributes = attributes if @version.update_attributes(attributes)
if @version.save
respond_to do |format|
format.html {
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
}
format.api { head :ok }
end
else else
respond_to do |format| respond_to do |format|
format.html { render :action => 'edit' } format.html { render :action => 'edit' }
format.api { render_validation_errors(@version) }
end end
end end
end end
@@ -149,22 +124,13 @@ class VersionsController < ApplicationController
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
end end
verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed }
def destroy def destroy
if @version.fixed_issues.empty? if @version.fixed_issues.empty?
@version.destroy @version.destroy
respond_to do |format| redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
format.html { redirect_back_or_default :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project }
format.api { head :ok }
end
else else
respond_to do |format|
format.html {
flash[:error] = l(:notice_unable_delete_version) flash[:error] = l(:notice_unable_delete_version)
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
}
format.api { head :unprocessable_entity }
end
end end
end end
+2 -2
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+3 -28
View File
@@ -40,7 +40,6 @@ class WikiController < ApplicationController
helper :attachments helper :attachments
include AttachmentsHelper include AttachmentsHelper
helper :watchers helper :watchers
include Redmine::Export::PDF
# List of pages, sorted alphabetically and by parent (hierarchy) # List of pages, sorted alphabetically and by parent (hierarchy)
def index def index
@@ -72,10 +71,7 @@ class WikiController < ApplicationController
end end
@content = @page.content_for_version(params[:version]) @content = @page.content_for_version(params[:version])
if User.current.allowed_to?(:export_wiki_pages, @project) if User.current.allowed_to?(:export_wiki_pages, @project)
if params[:format] == 'pdf' if params[:format] == 'html'
send_data(wiki_to_pdf(@page, @project), :type => 'application/pdf', :filename => "#{@page.title}.pdf")
return
elsif params[:format] == 'html'
export = render_to_string :action => 'export', :layout => false export = render_to_string :action => 'export', :layout => false
send_data(export, :type => 'text/html', :filename => "#{@page.title}.html") send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
return return
@@ -85,10 +81,6 @@ class WikiController < ApplicationController
end end
end end
@editable = editable? @editable = editable?
@sections_editable = @editable && User.current.allowed_to?(:edit_wiki_pages, @page.project) &&
@content.current_version? &&
Redmine::WikiFormatting.supports_section_edit?
render :action => 'show' render :action => 'show'
end end
@@ -104,13 +96,6 @@ class WikiController < ApplicationController
# To prevent StaleObjectError exception when reverting to a previous version # To prevent StaleObjectError exception when reverting to a previous version
@content.version = @page.content.version @content.version = @page.content.version
@text = @content.text
if params[:section].present? && Redmine::WikiFormatting.supports_section_edit?
@section = params[:section].to_i
@text, @section_hash = Redmine::WikiFormatting.formatter.new(@text).get_section(@section)
render_404 if @text.blank?
end
end end
verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed } verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
@@ -131,17 +116,7 @@ class WikiController < ApplicationController
redirect_to :action => 'show', :project_id => @project, :id => @page.title redirect_to :action => 'show', :project_id => @project, :id => @page.title
return return
end end
@content.attributes = params[:content]
@content.comments = params[:content][:comments]
@text = params[:content][:text]
if params[:section].present? && Redmine::WikiFormatting.supports_section_edit?
@section = params[:section].to_i
@section_hash = params[:section_hash]
@content.text = Redmine::WikiFormatting.formatter.new(@content.text).update_section(params[:section].to_i, @text, @section_hash)
else
@content.version = params[:content][:version]
@content.text = @text
end
@content.author = User.current @content.author = User.current
# if page is new @page.save will also save content, but not if page isn't a new record # if page is new @page.save will also save content, but not if page isn't a new record
if (@page.new_record? ? @page.save : @content.save) if (@page.new_record? ? @page.save : @content.save)
@@ -153,7 +128,7 @@ class WikiController < ApplicationController
render :action => 'edit' render :action => 'edit'
end end
rescue ActiveRecord::StaleObjectError, Redmine::WikiFormatting::StaleSectionError rescue ActiveRecord::StaleObjectError
# Optimistic locking exception # Optimistic locking exception
flash.now[:error] = l(:notice_locking_conflict) flash.now[:error] = l(:notice_locking_conflict)
render :action => 'edit' render :action => 'edit'
+3 -3
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2007 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -22,7 +22,7 @@ class WikisController < ApplicationController
# Create or update a project's wiki # Create or update a project's wiki
def edit def edit
@wiki = @project.wiki || Wiki.new(:project => @project) @wiki = @project.wiki || Wiki.new(:project => @project)
@wiki.safe_attributes = params[:wiki] @wiki.attributes = params[:wiki]
@wiki.save if request.post? @wiki.save if request.post?
render(:update) {|page| page.replace_html "tab-content-wiki", :partial => 'projects/settings/wiki'} render(:update) {|page| page.replace_html "tab-content-wiki", :partial => 'projects/settings/wiki'}
end end
+1 -1
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2008 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+2 -4
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+2 -4
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+63 -192
View File
@@ -1,5 +1,3 @@
# encoding: utf-8
#
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2011 Jean-Philippe Lang
# #
@@ -82,7 +80,7 @@ module ApplicationHelper
subject = truncate(subject, :length => options[:truncate]) subject = truncate(subject, :length => options[:truncate])
end end
end end
s = link_to "#{h(issue.tracker)} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue}, s = link_to "#{issue.tracker} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue},
:class => issue.css_classes, :class => issue.css_classes,
:title => title :title => title
s << ": #{h subject}" if subject s << ": #{h subject}" if subject
@@ -97,10 +95,8 @@ module ApplicationHelper
def link_to_attachment(attachment, options={}) def link_to_attachment(attachment, options={})
text = options.delete(:text) || attachment.filename text = options.delete(:text) || attachment.filename
action = options.delete(:download) ? 'download' : 'show' action = options.delete(:download) ? 'download' : 'show'
link_to(h(text),
{:controller => 'attachments', :action => action, link_to(h(text), {:controller => 'attachments', :action => action, :id => attachment, :filename => attachment.filename }, options)
:id => attachment, :filename => attachment.filename },
options)
end end
# Generates a link to a SCM revision # Generates a link to a SCM revision
@@ -110,7 +106,7 @@ module ApplicationHelper
text = options.delete(:text) || format_revision(revision) text = options.delete(:text) || format_revision(revision)
rev = revision.respond_to?(:identifier) ? revision.identifier : revision rev = revision.respond_to?(:identifier) ? revision.identifier : revision
link_to(h(text), {:controller => 'repositories', :action => 'revision', :id => project, :rev => rev}, link_to(text, {:controller => 'repositories', :action => 'revision', :id => project, :rev => rev},
:title => l(:label_revision_id, format_revision(revision))) :title => l(:label_revision_id, format_revision(revision)))
end end
@@ -204,7 +200,7 @@ module ApplicationHelper
end end
content << "</ul>\n" content << "</ul>\n"
end end
content.html_safe content
end end
# Renders flash messages # Renders flash messages
@@ -213,7 +209,7 @@ module ApplicationHelper
flash.each do |k,v| flash.each do |k,v|
s << content_tag('div', v, :class => "flash #{k}") s << content_tag('div', v, :class => "flash #{k}")
end end
s.html_safe s
end end
# Renders tabs and their content # Renders tabs and their content
@@ -237,7 +233,7 @@ module ApplicationHelper
{ :value => url_for(:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item) } { :value => url_for(:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item) }
end end
s << '</select>' s << '</select>'
s.html_safe s
end end
end end
@@ -254,7 +250,7 @@ module ApplicationHelper
tag_options.merge!(yield(project)) if block_given? tag_options.merge!(yield(project)) if block_given?
s << content_tag('option', name_prefix + h(project), tag_options) s << content_tag('option', name_prefix + h(project), tag_options)
end end
s.html_safe s
end end
# Yields the given block for each project with its level in the tree # Yields the given block for each project with its level in the tree
@@ -285,7 +281,7 @@ module ApplicationHelper
end end
s << ("</li></ul>\n" * ancestors.size) s << ("</li></ul>\n" * ancestors.size)
end end
s.html_safe s
end end
def principals_check_box_tags(name, principals) def principals_check_box_tags(name, principals)
@@ -293,20 +289,6 @@ module ApplicationHelper
principals.sort.each do |principal| principals.sort.each do |principal|
s << "<label>#{ check_box_tag name, principal.id, false } #{h principal}</label>\n" s << "<label>#{ check_box_tag name, principal.id, false } #{h principal}</label>\n"
end end
s.html_safe
end
# Returns a string for users/groups option tags
def principals_options_for_select(collection, selected=nil)
s = ''
groups = ''
collection.sort.each do |element|
selected_attribute = ' selected="selected"' if option_value_selected?(element, selected)
(element.is_a?(Group) ? groups : s) << %(<option value="#{element.id}"#{selected_attribute}>#{h element.name}</option>)
end
unless groups.empty?
s << %(<optgroup label="#{h(l(:label_group_plural))}">#{groups}</optgroup>)
end
s s
end end
@@ -326,11 +308,11 @@ module ApplicationHelper
end end
def html_hours(text) def html_hours(text)
text.gsub(%r{(\d+)\.(\d+)}, '<span class="hours hours-int">\1</span><span class="hours hours-dec">.\2</span>').html_safe text.gsub(%r{(\d+)\.(\d+)}, '<span class="hours hours-int">\1</span><span class="hours hours-dec">.\2</span>')
end end
def authoring(created, author, options={}) def authoring(created, author, options={})
l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created)).html_safe l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created))
end end
def time_tag(time) def time_tag(time)
@@ -357,10 +339,7 @@ module ApplicationHelper
html = '' html = ''
if paginator.current.previous if paginator.current.previous
# \xc2\xab(utf-8) = &#171; html << link_to_content_update('&#171; ' + l(:label_previous), url_param.merge(page_param => paginator.current.previous)) + ' '
html << link_to_content_update(
"\xc2\xab " + l(:label_previous),
url_param.merge(page_param => paginator.current.previous)) + ' '
end end
html << (pagination_links_each(paginator, options) do |n| html << (pagination_links_each(paginator, options) do |n|
@@ -368,10 +347,7 @@ module ApplicationHelper
end || '') end || '')
if paginator.current.next if paginator.current.next
# \xc2\xbb(utf-8) = &#187; html << ' ' + link_to_content_update((l(:label_next) + ' &#187;'), url_param.merge(page_param => paginator.current.next))
html << ' ' + link_to_content_update(
(l(:label_next) + " \xc2\xbb"),
url_param.merge(page_param => paginator.current.next))
end end
unless count.nil? unless count.nil?
@@ -381,7 +357,7 @@ module ApplicationHelper
end end
end end
html.html_safe html
end end
def per_page_links(selected=nil) def per_page_links(selected=nil)
@@ -391,30 +367,22 @@ module ApplicationHelper
links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil
end end
def reorder_links(name, url, method = :post) def reorder_links(name, url)
link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)), link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)), url.merge({"#{name}[move_to]" => 'highest'}), :method => :post, :title => l(:label_sort_highest)) +
url.merge({"#{name}[move_to]" => 'highest'}), link_to(image_tag('1uparrow.png', :alt => l(:label_sort_higher)), url.merge({"#{name}[move_to]" => 'higher'}), :method => :post, :title => l(:label_sort_higher)) +
:method => method, :title => l(:label_sort_highest)) + link_to(image_tag('1downarrow.png', :alt => l(:label_sort_lower)), url.merge({"#{name}[move_to]" => 'lower'}), :method => :post, :title => l(:label_sort_lower)) +
link_to(image_tag('1uparrow.png', :alt => l(:label_sort_higher)), link_to(image_tag('2downarrow.png', :alt => l(:label_sort_lowest)), url.merge({"#{name}[move_to]" => 'lowest'}), :method => :post, :title => l(:label_sort_lowest))
url.merge({"#{name}[move_to]" => 'higher'}),
:method => method, :title => l(:label_sort_higher)) +
link_to(image_tag('1downarrow.png', :alt => l(:label_sort_lower)),
url.merge({"#{name}[move_to]" => 'lower'}),
:method => method, :title => l(:label_sort_lower)) +
link_to(image_tag('2downarrow.png', :alt => l(:label_sort_lowest)),
url.merge({"#{name}[move_to]" => 'lowest'}),
:method => method, :title => l(:label_sort_lowest))
end end
def breadcrumb(*args) def breadcrumb(*args)
elements = args.flatten elements = args.flatten
elements.any? ? content_tag('p', (args.join(" \xc2\xbb ") + " \xc2\xbb ").html_safe, :class => 'breadcrumb') : nil elements.any? ? content_tag('p', args.join(' &#187; ') + ' &#187; ', :class => 'breadcrumb') : nil
end end
def other_formats_links(&block) def other_formats_links(&block)
concat('<p class="other-formats">'.html_safe + l(:label_export_to)) concat('<p class="other-formats">' + l(:label_export_to))
yield Redmine::Views::OtherFormatsBuilder.new(self) yield Redmine::Views::OtherFormatsBuilder.new(self)
concat('</p>'.html_safe) concat('</p>')
end end
def page_header_title def page_header_title
@@ -427,21 +395,22 @@ module ApplicationHelper
root = ancestors.shift root = ancestors.shift
b << link_to_project(root, {:jump => current_menu_item}, :class => 'root') b << link_to_project(root, {:jump => current_menu_item}, :class => 'root')
if ancestors.size > 2 if ancestors.size > 2
b << "\xe2\x80\xa6" b << '&#8230;'
ancestors = ancestors[-2, 2] ancestors = ancestors[-2, 2]
end end
b += ancestors.collect {|p| link_to_project(p, {:jump => current_menu_item}, :class => 'ancestor') } b += ancestors.collect {|p| link_to_project(p, {:jump => current_menu_item}, :class => 'ancestor') }
end end
b << h(@project) b << h(@project)
b.join(" \xc2\xbb ").html_safe b.join(' &#187; ')
end end
end end
def html_title(*args) def html_title(*args)
if args.empty? if args.empty?
title = @html_title || [] title = []
title << @project.name if @project title << @project.name if @project
title << Setting.app_title unless Setting.app_title == title.last title += @html_title if @html_title
title << Setting.app_title
title.select {|t| !t.blank? }.join(' - ') title.select {|t| !t.blank? }.join(' - ')
else else
@html_title ||= [] @html_title ||= []
@@ -487,19 +456,14 @@ module ApplicationHelper
project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil) project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil)
only_path = options.delete(:only_path) == false ? false : true only_path = options.delete(:only_path) == false ? false : true
text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) { |macro, args| exec_macro(macro, obj, args) }
@parsed_headings = [] @parsed_headings = []
@heading_anchors = {}
@current_section = 0 if options[:edit_section_links]
parse_sections(text, project, obj, attr, only_path, options)
text = parse_non_pre_blocks(text) do |text| text = parse_non_pre_blocks(text) do |text|
[:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_macros].each do |method_name| [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_headings].each do |method_name|
send method_name, text, project, obj, attr, only_path, options send method_name, text, project, obj, attr, only_path, options
end end
end end
parse_headings(text, project, obj, attr, only_path, options)
if @parsed_headings.any? if @parsed_headings.any?
replace_toc(text, @parsed_headings) replace_toc(text, @parsed_headings)
@@ -534,26 +498,26 @@ module ApplicationHelper
while tag = tags.pop while tag = tags.pop
parsed << "</#{tag}>" parsed << "</#{tag}>"
end end
parsed.html_safe parsed
end end
def parse_inline_attachments(text, project, obj, attr, only_path, options) def parse_inline_attachments(text, project, obj, attr, only_path, options)
# when using an image link, try to use an attachment, if possible # when using an image link, try to use an attachment, if possible
if options[:attachments] || (obj && obj.respond_to?(:attachments)) if options[:attachments] || (obj && obj.respond_to?(:attachments))
attachments = options[:attachments] || obj.attachments attachments = nil
text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m| text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m|
filename, ext, alt, alttext = $1.downcase, $2, $3, $4 filename, ext, alt, alttext = $1.downcase, $2, $3, $4
attachments ||= (options[:attachments] || obj.attachments).sort_by(&:created_on).reverse
# search for the picture in attachments # search for the picture in attachments
if found = Attachment.latest_attach(attachments, filename) if found = attachments.detect { |att| att.filename.downcase == filename }
image_url = url_for :only_path => only_path, :controller => 'attachments', image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found
:action => 'download', :id => found
desc = found.description.to_s.gsub('"', '') desc = found.description.to_s.gsub('"', '')
if !desc.blank? && alttext.blank? if !desc.blank? && alttext.blank?
alt = " title=\"#{desc}\" alt=\"#{desc}\"" alt = " title=\"#{desc}\" alt=\"#{desc}\""
end end
"src=\"#{image_url}\"#{alt}".html_safe "src=\"#{image_url}\"#{alt}"
else else
m.html_safe m
end end
end end
end end
@@ -586,27 +550,22 @@ module ApplicationHelper
if page =~ /^(.+?)\#(.+)$/ if page =~ /^(.+?)\#(.+)$/
page, anchor = $1, $2 page, anchor = $1, $2
end end
anchor = sanitize_anchor_name(anchor) if anchor.present?
# check if page exists # check if page exists
wiki_page = link_project.wiki.find_page(page) wiki_page = link_project.wiki.find_page(page)
url = if anchor.present? && wiki_page.present? && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)) && obj.page == wiki_page url = case options[:wiki_links]
"##{anchor}" when :local; "#{title}.html"
else when :anchor; "##{title}" # used for single-file wiki export
case options[:wiki_links]
when :local; "#{page.present? ? Wiki.titleize(page) : ''}.html" + (anchor.present? ? "##{anchor}" : '')
when :anchor; "##{page.present? ? Wiki.titleize(page) : title}" + (anchor.present? ? "_#{anchor}" : '') # used for single-file wiki export
else else
wiki_page_id = page.present? ? Wiki.titleize(page) : nil wiki_page_id = page.present? ? Wiki.titleize(page) : nil
url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project, :id => wiki_page_id, :anchor => anchor) url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project, :id => wiki_page_id, :anchor => anchor)
end end
end link_to((title || page), url, :class => ('wiki-page' + (wiki_page ? '' : ' new')))
link_to(title.present? ? title.html_safe : h(page), url, :class => ('wiki-page' + (wiki_page ? '' : ' new')))
else else
# project or wiki doesn't exist # project or wiki doesn't exist
all.html_safe all
end end
else else
all.html_safe all
end end
end end
end end
@@ -644,7 +603,7 @@ module ApplicationHelper
# identifier:version:1.0.0 # identifier:version:1.0.0
# identifier:source:some/file # identifier:source:some/file
def parse_redmine_links(text, project, obj, attr, only_path, options) def parse_redmine_links(text, project, obj, attr, only_path, options)
text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-]+):)?(attachment|document|version|forum|news|commit|source|export|message|project)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|\]|<|$)}) do |m| text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-]+):)?(attachment|document|version|commit|source|export|message|project)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|\]|<|$)}) do |m|
leading, esc, project_prefix, project_identifier, prefix, sep, identifier = $1, $2, $3, $4, $5, $7 || $9, $8 || $10 leading, esc, project_prefix, project_identifier, prefix, sep, identifier = $1, $2, $3, $4, $5, $7 || $9, $8 || $10
link = nil link = nil
if project_identifier if project_identifier
@@ -654,7 +613,7 @@ module ApplicationHelper
if prefix.nil? && sep == 'r' if prefix.nil? && sep == 'r'
# project.changesets.visible raises an SQL error because of a double join on repositories # project.changesets.visible raises an SQL error because of a double join on repositories
if project && project.repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(project.repository.id, identifier)) if project && project.repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(project.repository.id, identifier))
link = link_to(h("#{project_prefix}r#{identifier}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision}, link = link_to("#{project_prefix}r#{identifier}", {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision},
:class => 'changeset', :class => 'changeset',
:title => truncate_single_line(changeset.comments, :length => 100)) :title => truncate_single_line(changeset.comments, :length => 100))
end end
@@ -681,16 +640,6 @@ module ApplicationHelper
if message = Message.visible.find_by_id(oid, :include => :parent) if message = Message.visible.find_by_id(oid, :include => :parent)
link = link_to_message(message, {:only_path => only_path}, :class => 'message') link = link_to_message(message, {:only_path => only_path}, :class => 'message')
end end
when 'forum'
if board = Board.visible.find_by_id(oid)
link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project},
:class => 'board'
end
when 'news'
if news = News.visible.find_by_id(oid)
link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news},
:class => 'news'
end
when 'project' when 'project'
if p = Project.visible.find_by_id(oid) if p = Project.visible.find_by_id(oid)
link = link_to_project(p, {:only_path => only_path}, :class => 'project') link = link_to_project(p, {:only_path => only_path}, :class => 'project')
@@ -710,21 +659,11 @@ module ApplicationHelper
link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version}, link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version},
:class => 'version' :class => 'version'
end end
when 'forum'
if project && board = project.boards.visible.find_by_name(name)
link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project},
:class => 'board'
end
when 'news'
if project && news = project.news.visible.find_by_title(name)
link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news},
:class => 'news'
end
when 'commit' when 'commit'
if project && project.repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", project.repository.id, "#{name}%"])) if project && project.repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", project.repository.id, "#{name}%"]))
link = link_to h("#{project_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.identifier}, link = link_to h("#{project_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.identifier},
:class => 'changeset', :class => 'changeset',
:title => truncate_single_line(h(changeset.comments), :length => 100) :title => truncate_single_line(changeset.comments, :length => 100)
end end
when 'source', 'export' when 'source', 'export'
if project && project.repository && User.current.allowed_to?(:browse_repository, project) if project && project.repository && User.current.allowed_to?(:browse_repository, project)
@@ -750,26 +689,11 @@ module ApplicationHelper
end end
end end
end end
(leading + (link || "#{project_prefix}#{prefix}#{sep}#{identifier}")).html_safe leading + (link || "#{project_prefix}#{prefix}#{sep}#{identifier}")
end end
end end
HEADING_RE = /(<h(1|2|3|4)( [^>]+)?>(.+?)<\/h(1|2|3|4)>)/i unless const_defined?(:HEADING_RE) HEADING_RE = /<h(1|2|3|4)( [^>]+)?>(.+?)<\/h(1|2|3|4)>/i unless const_defined?(:HEADING_RE)
def parse_sections(text, project, obj, attr, only_path, options)
return unless options[:edit_section_links]
text.gsub!(HEADING_RE) do
@current_section += 1
if @current_section > 1
content_tag('div',
link_to(image_tag('edit.png'), options[:edit_section_links].merge(:section => @current_section)),
:class => 'contextual',
:title => l(:button_edit_section)) + $1
else
$1
end
end
end
# Headings and TOC # Headings and TOC
# Adds ids and links to headings unless options[:headings] is set to false # Adds ids and links to headings unless options[:headings] is set to false
@@ -777,48 +701,14 @@ module ApplicationHelper
return if options[:headings] == false return if options[:headings] == false
text.gsub!(HEADING_RE) do text.gsub!(HEADING_RE) do
level, attrs, content = $2.to_i, $3, $4 level, attrs, content = $1.to_i, $2, $3
item = strip_tags(content).strip item = strip_tags(content).strip
anchor = sanitize_anchor_name(item) anchor = item.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
# used for single-file wiki export
anchor = "#{obj.page.title}_#{anchor}" if options[:wiki_links] == :anchor && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version))
@heading_anchors[anchor] ||= 0
idx = (@heading_anchors[anchor] += 1)
if idx > 1
anchor = "#{anchor}-#{idx}"
end
@parsed_headings << [level, anchor, item] @parsed_headings << [level, anchor, item]
"<a name=\"#{anchor}\"></a>\n<h#{level} #{attrs}>#{content}<a href=\"##{anchor}\" class=\"wiki-anchor\">&para;</a></h#{level}>" "<a name=\"#{anchor}\"></a>\n<h#{level} #{attrs}>#{content}<a href=\"##{anchor}\" class=\"wiki-anchor\">&para;</a></h#{level}>"
end end
end end
MACROS_RE = /
(!)? # escaping
(
\{\{ # opening tag
([\w]+) # macro name
(\(([^\}]*)\))? # optional arguments
\}\} # closing tag
)
/x unless const_defined?(:MACROS_RE)
# Macros substitution
def parse_macros(text, project, obj, attr, only_path, options)
text.gsub!(MACROS_RE) do
esc, all, macro = $1, $2, $3.downcase
args = ($5 || '').split(',').each(&:strip)
if esc.nil?
begin
exec_macro(macro, obj, args)
rescue => e
"<div class=\"flash error\">Error executing the <strong>#{macro}</strong> macro (#{e})</div>"
end || all
else
all
end
end
end
TOC_RE = /<p>\{\{([<>]?)toc\}\}<\/p>/i unless const_defined?(:TOC_RE) TOC_RE = /<p>\{\{([<>]?)toc\}\}<\/p>/i unless const_defined?(:TOC_RE)
# Renders the TOC with given headings # Renders the TOC with given headings
@@ -857,8 +747,7 @@ module ApplicationHelper
text.to_s. text.to_s.
gsub(/\r\n?/, "\n"). # \r\n and \r -> \n gsub(/\r\n?/, "\n"). # \r\n and \r -> \n
gsub(/\n\n+/, "<br /><br />"). # 2+ newline -> 2 br gsub(/\n\n+/, "<br /><br />"). # 2+ newline -> 2 br
gsub(/([^\n]\n)(?=[^\n])/, '\1<br />'). # 1 newline -> br gsub(/([^\n]\n)(?=[^\n])/, '\1<br />') # 1 newline -> br
html_safe
end end
def lang_options_for_select(blank=true) def lang_options_for_select(blank=true)
@@ -871,20 +760,10 @@ module ApplicationHelper
content_tag("label", label_text) content_tag("label", label_text)
end end
def labelled_tabular_form_for(*args, &proc) def labelled_tabular_form_for(name, object, options, &proc)
args << {} unless args.last.is_a?(Hash)
options = args.last
options[:html] ||= {} options[:html] ||= {}
options[:html][:class] = 'tabular' unless options[:html].has_key?(:class) options[:html][:class] = 'tabular' unless options[:html].has_key?(:class)
options.merge!({:builder => TabularFormBuilder}) form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)
form_for(*args, &proc)
end
def labelled_form_for(*args, &proc)
args << {} unless args.last.is_a?(Hash)
options = args.last
options.merge!({:builder => TabularFormBuilder})
form_for(*args, &proc)
end end
def back_url_hidden_field_tag def back_url_hidden_field_tag
@@ -895,7 +774,7 @@ module ApplicationHelper
def check_all_links(form_name) def check_all_links(form_name)
link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") + link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
" | ".html_safe + " | " +
link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)") link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
end end
@@ -908,11 +787,11 @@ module ApplicationHelper
legend = options[:legend] || '' legend = options[:legend] || ''
content_tag('table', content_tag('table',
content_tag('tr', content_tag('tr',
(pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : ''.html_safe) + (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : '') +
(pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : ''.html_safe) + (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : '') +
(pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : ''.html_safe) (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : '')
), :class => 'progress', :style => "width: #{width};").html_safe + ), :class => 'progress', :style => "width: #{width};") +
content_tag('p', legend, :class => 'pourcent').html_safe content_tag('p', legend, :class => 'pourcent')
end end
def checked_image(checked=true) def checked_image(checked=true)
@@ -950,7 +829,7 @@ module ApplicationHelper
options[:class] << ' disabled' options[:class] << ' disabled'
url = '#' url = '#'
end end
link_to h(name), url, options link_to name, url, options
end end
def calendar_for(field_id) def calendar_for(field_id)
@@ -993,10 +872,6 @@ module ApplicationHelper
(@has_content && @has_content[name]) || false (@has_content && @has_content[name]) || false
end end
def email_delivery_enabled?
!!ActionMailer::Base.perform_deliveries
end
# Returns the avatar image tag for the given +user+ if avatars are enabled # Returns the avatar image tag for the given +user+ if avatars are enabled
# +user+ can be a User or a string that will be scanned for an email address (eg. 'joe <joe@foo.bar>') # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe <joe@foo.bar>')
def avatar(user, options = { }) def avatar(user, options = { })
@@ -1014,25 +889,21 @@ module ApplicationHelper
end end
end end
def sanitize_anchor_name(anchor)
anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
end
# Returns the javascript tags that are included in the html layout head # Returns the javascript tags that are included in the html layout head
def javascript_heads def javascript_heads
tags = javascript_include_tag(:defaults) tags = javascript_include_tag(:defaults)
unless User.current.pref.warn_on_leaving_unsaved == '0' unless User.current.pref.warn_on_leaving_unsaved == '0'
tags << "\n".html_safe + javascript_tag("Event.observe(window, 'load', function(){ new WarnLeavingUnsaved('#{escape_javascript( l(:text_warn_on_leaving_unsaved) )}'); });") tags << "\n" + javascript_tag("Event.observe(window, 'load', function(){ new WarnLeavingUnsaved('#{escape_javascript( l(:text_warn_on_leaving_unsaved) )}'); });")
end end
tags tags
end end
def favicon def favicon
"<link rel='shortcut icon' href='#{image_path('/favicon.ico')}' />".html_safe "<link rel='shortcut icon' href='#{image_path('/favicon.ico')}' />"
end end
def robot_exclusion_tag def robot_exclusion_tag
'<meta name="robots" content="noindex,follow,noarchive" />'.html_safe '<meta name="robots" content="noindex,follow,noarchive" />'
end end
# Returns true if arg is expected in the API response # Returns true if arg is expected in the API response
+13 -12
View File
@@ -1,5 +1,3 @@
# encoding: utf-8
#
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2011 Jean-Philippe Lang
# #
@@ -30,16 +28,19 @@ module AttachmentsHelper
end end
end end
def render_api_attachment(attachment, api) def to_utf8(str)
api.attachment do if str.respond_to?(:force_encoding)
api.id attachment.id str.force_encoding('UTF-8')
api.filename attachment.filename return str if str.valid_encoding?
api.filesize attachment.filesize else
api.content_type attachment.content_type return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii
api.description attachment.description end
api.content_url url_for(:controller => 'attachments', :action => 'download', :id => attachment, :filename => attachment.filename, :only_path => false)
api.author(:id => attachment.author.id, :name => attachment.author.name) if attachment.author begin
api.created_on attachment.created_on Iconv.conv('UTF-8//IGNORE', 'UTF-8', str + ' ')[0..-3]
rescue Iconv::InvalidEncoding
# "UTF-8//IGNORE" is not supported on some OS
str
end end
end end
end end
+2 -4
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+2 -4
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006-2007 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+3 -24
View File
@@ -1,22 +1,3 @@
# encoding: utf-8
#
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module CalendarsHelper module CalendarsHelper
def link_to_previous_month(year, month, options={}) def link_to_previous_month(year, month, options={})
target_year, target_month = if month == 1 target_year, target_month = if month == 1
@@ -31,8 +12,7 @@ module CalendarsHelper
"#{month_name(target_month)}" "#{month_name(target_month)}"
end end
# \xc2\xab(utf-8) = &#171; link_to_month(('&#171; ' + name), target_year, target_month, options)
link_to_month(("\xc2\xab " + name), target_year, target_month, options)
end end
def link_to_next_month(year, month, options={}) def link_to_next_month(year, month, options={})
@@ -48,11 +28,10 @@ module CalendarsHelper
"#{month_name(target_month)}" "#{month_name(target_month)}"
end end
# \xc2\xbb(utf-8) = &#187; link_to_month((name + ' &#187;'), target_year, target_month, options)
link_to_month((name + " \xc2\xbb"), target_year, target_month, options)
end end
def link_to_month(link_name, year, month, options={}) def link_to_month(link_name, year, month, options={})
link_to_content_update(h(link_name), params.merge(:year => year, :month => month)) link_to_content_update(link_name, params.merge(:year => year, :month => month))
end end
end end
+2 -4
View File
@@ -1,5 +1,3 @@
# encoding: utf-8
#
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2011 Jean-Philippe Lang
# #
@@ -59,8 +57,8 @@ module CustomFieldsHelper
# Return custom field label tag # Return custom field label tag
def custom_field_label_tag(name, custom_value) def custom_field_label_tag(name, custom_value)
content_tag "label", h(custom_value.custom_field.name) + content_tag "label", custom_value.custom_field.name +
(custom_value.custom_field.is_required? ? " <span class=\"required\">*</span>".html_safe : ""), (custom_value.custom_field.is_required? ? " <span class=\"required\">*</span>" : ""),
:for => "#{name}_custom_field_values_#{custom_value.custom_field.id}", :for => "#{name}_custom_field_values_#{custom_value.custom_field.id}",
:class => (custom_value.errors.empty? ? nil : "error" ) :class => (custom_value.errors.empty? ? nil : "error" )
end end
+2 -4
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+2 -4
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+2 -4
View File
@@ -1,5 +1,3 @@
# encoding: utf-8
#
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2011 Jean-Philippe Lang
# #
@@ -27,7 +25,7 @@ module GanttHelper
params.merge(gantt.params.merge(:zoom => (gantt.zoom+1))), params.merge(gantt.params.merge(:zoom => (gantt.zoom+1))),
:class => 'icon icon-zoom-in' :class => 'icon icon-zoom-in'
else else
content_tag('span', l(:text_zoom_in), :class => 'icon icon-zoom-in').html_safe content_tag('span', l(:text_zoom_in), :class => 'icon icon-zoom-in')
end end
when :out when :out
@@ -36,7 +34,7 @@ module GanttHelper
params.merge(gantt.params.merge(:zoom => (gantt.zoom-1))), params.merge(gantt.params.merge(:zoom => (gantt.zoom-1))),
:class => 'icon icon-zoom-out' :class => 'icon icon-zoom-out'
else else
content_tag('span', l(:text_zoom_out), :class => 'icon icon-zoom-out').html_safe content_tag('span', l(:text_zoom_out), :class => 'icon icon-zoom-out')
end end
end end
end end
+1 -3
View File
@@ -1,7 +1,5 @@
# encoding: utf-8
#
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2009 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+2 -4
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
-2
View File
@@ -1,4 +1,2 @@
# encoding: utf-8
#
module IssueMovesHelper module IssueMovesHelper
end end
+2 -4
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006-2007 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+2 -4
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+57 -38
View File
@@ -1,5 +1,3 @@
# encoding: utf-8
#
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2011 Jean-Philippe Lang
# #
@@ -48,13 +46,13 @@ module IssuesHelper
@cached_label_priority ||= l(:field_priority) @cached_label_priority ||= l(:field_priority)
@cached_label_project ||= l(:field_project) @cached_label_project ||= l(:field_project)
(link_to_issue(issue) + "<br /><br />" + link_to_issue(issue) + "<br /><br />" +
"<strong>#{@cached_label_project}</strong>: #{link_to_project(issue.project)}<br />" + "<strong>#{@cached_label_project}</strong>: #{link_to_project(issue.project)}<br />" +
"<strong>#{@cached_label_status}</strong>: #{h(issue.status.name)}<br />" + "<strong>#{@cached_label_status}</strong>: #{issue.status.name}<br />" +
"<strong>#{@cached_label_start_date}</strong>: #{format_date(issue.start_date)}<br />" + "<strong>#{@cached_label_start_date}</strong>: #{format_date(issue.start_date)}<br />" +
"<strong>#{@cached_label_due_date}</strong>: #{format_date(issue.due_date)}<br />" + "<strong>#{@cached_label_due_date}</strong>: #{format_date(issue.due_date)}<br />" +
"<strong>#{@cached_label_assigned_to}</strong>: #{h(issue.assigned_to)}<br />" + "<strong>#{@cached_label_assigned_to}</strong>: #{issue.assigned_to}<br />" +
"<strong>#{@cached_label_priority}</strong>: #{h(issue.priority.name)}").html_safe "<strong>#{@cached_label_priority}</strong>: #{issue.priority.name}"
end end
def issue_heading(issue) def issue_heading(issue)
@@ -74,7 +72,7 @@ module IssuesHelper
end end
s << content_tag('h3', subject) s << content_tag('h3', subject)
s << '</div>' * (ancestors.size + 1) s << '</div>' * (ancestors.size + 1)
s.html_safe s
end end
def render_descendants_tree(issue) def render_descendants_tree(issue)
@@ -89,7 +87,7 @@ module IssuesHelper
:class => "issue issue-#{child.id} hascontextmenu #{level > 0 ? "idnt idnt-#{level}" : nil}") :class => "issue issue-#{child.id} hascontextmenu #{level > 0 ? "idnt idnt-#{level}" : nil}")
end end
s << '</form></table>' s << '</form></table>'
s.html_safe s
end end
def render_custom_fields_rows(issue) def render_custom_fields_rows(issue)
@@ -108,7 +106,7 @@ module IssuesHelper
n += 1 n += 1
end end
s << "</tr>\n" s << "</tr>\n"
s.html_safe s
end end
def issues_destroy_confirmation_message(issues) def issues_destroy_confirmation_message(issues)
@@ -147,7 +145,7 @@ module IssuesHelper
# links to #index on issues/show # links to #index on issues/show
url_params = controller_name == 'issues' ? {:controller => 'issues', :action => 'index', :project_id => @project} : params url_params = controller_name == 'issues' ? {:controller => 'issues', :action => 'index', :project_id => @project} : params
content_tag('h3', h(title)) + content_tag('h3', title) +
queries.collect {|query| queries.collect {|query|
link_to(h(query.name), url_params.merge(:query_id => query)) link_to(h(query.name), url_params.merge(:query_id => query))
}.join('<br />') }.join('<br />')
@@ -208,7 +206,7 @@ module IssuesHelper
unless no_html unless no_html
label = content_tag('strong', label) label = content_tag('strong', label)
old_value = content_tag("i", h(old_value)) if detail.old_value old_value = content_tag("i", h(old_value)) if detail.old_value
old_value = content_tag("strike", old_value) if detail.old_value and detail.value.blank? old_value = content_tag("strike", old_value) if detail.old_value and (!detail.value or detail.value.empty?)
if detail.property == 'attachment' && !value.blank? && a = Attachment.find_by_id(detail.prop_key) if detail.property == 'attachment' && !value.blank? && a = Attachment.find_by_id(detail.prop_key)
# Link to the attachment if it has not been removed # Link to the attachment if it has not been removed
value = link_to_attachment(a) value = link_to_attachment(a)
@@ -265,38 +263,59 @@ module IssuesHelper
end end
end end
def issues_to_csv(issues, project, query, options={}) def issues_to_csv(issues, project = nil)
ic = Iconv.new(l(:general_csv_encoding), 'UTF-8')
decimal_separator = l(:general_csv_decimal_separator) decimal_separator = l(:general_csv_decimal_separator)
encoding = l(:general_csv_encoding)
columns = (options[:columns] == 'all' ? query.available_columns : query.columns)
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
# csv header fields # csv header fields
csv << [ "#" ] + columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) } + headers = [ "#",
(options[:description] ? [Redmine::CodesetUtil.from_utf8(l(:field_description), encoding)] : []) l(:field_status),
l(:field_project),
l(:field_tracker),
l(:field_priority),
l(:field_subject),
l(:field_assigned_to),
l(:field_category),
l(:field_fixed_version),
l(:field_author),
l(:field_start_date),
l(:field_due_date),
l(:field_done_ratio),
l(:field_estimated_hours),
l(:field_parent_issue),
l(:field_created_on),
l(:field_updated_on)
]
# Export project custom fields if project is given
# otherwise export custom fields marked as "For all projects"
custom_fields = project.nil? ? IssueCustomField.for_all : project.all_issue_custom_fields
custom_fields.each {|f| headers << f.name}
# Description in the last column
headers << l(:field_description)
csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
# csv lines # csv lines
issues.each do |issue| issues.each do |issue|
col_values = columns.collect do |column| fields = [issue.id,
s = if column.is_a?(QueryCustomFieldColumn) issue.status.name,
cv = issue.custom_values.detect {|v| v.custom_field_id == column.custom_field.id} issue.project.name,
show_value(cv) issue.tracker.name,
else issue.priority.name,
value = issue.send(column.name) issue.subject,
if value.is_a?(Date) issue.assigned_to,
format_date(value) issue.category,
elsif value.is_a?(Time) issue.fixed_version,
format_time(value) issue.author.name,
elsif value.is_a?(Float) format_date(issue.start_date),
value.to_s.gsub('.', decimal_separator) format_date(issue.due_date),
else issue.done_ratio,
value issue.estimated_hours.to_s.gsub('.', decimal_separator),
end issue.parent_id,
end format_time(issue.created_on),
s.to_s format_time(issue.updated_on)
end ]
csv << [ issue.id.to_s ] + col_values.collect {|c| Redmine::CodesetUtil.from_utf8(c.to_s, encoding) } + custom_fields.each {|f| fields << show_value(issue.custom_value_for(f)) }
(options[:description] ? [Redmine::CodesetUtil.from_utf8(issue.description, encoding)] : []) fields << issue.description
csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
end end
end end
export export
+2 -4
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006-2008 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+2 -4
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006-2008 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+2 -4
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+2 -4
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006-2007 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+2 -4
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+2 -4
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+2 -4
View File
@@ -1,5 +1,3 @@
# encoding: utf-8
#
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2011 Jean-Philippe Lang
# #
@@ -48,7 +46,7 @@ module ProjectsHelper
options = '' options = ''
options << "<option value=''></option>" if project.allowed_parents.include?(nil) options << "<option value=''></option>" if project.allowed_parents.include?(nil)
options << project_tree_options_for_select(project.allowed_parents.compact, :selected => selected) options << project_tree_options_for_select(project.allowed_parents.compact, :selected => selected)
content_tag('select', options.html_safe, :name => 'project[parent_id]', :id => 'project_parent_id') content_tag('select', options, :name => 'project[parent_id]', :id => 'project_parent_id')
end end
# Renders a tree of projects as a nested set of unordered lists # Renders a tree of projects as a nested set of unordered lists
@@ -82,7 +80,7 @@ module ProjectsHelper
s << ("</li></ul>\n" * ancestors.size) s << ("</li></ul>\n" * ancestors.size)
@project = original_project @project = original_project
end end
s.html_safe s
end end
# Returns a set of options for a select field, grouped by project. # Returns a set of options for a select field, grouped by project.
+12 -18
View File
@@ -1,5 +1,3 @@
# encoding: utf-8
#
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2011 Jean-Philippe Lang
# #
@@ -26,7 +24,7 @@ module QueriesHelper
def column_header(column) def column_header(column)
column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption, column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption,
:default_order => column.default_order) : :default_order => column.default_order) :
content_tag('th', h(column.caption)) content_tag('th', column.caption)
end end
def column_content(column, issue) def column_content(column, issue)
@@ -47,7 +45,7 @@ module QueriesHelper
if column.name == :done_ratio if column.name == :done_ratio
progress_bar(value, :width => '80px') progress_bar(value, :width => '80px')
else else
h(value.to_s) value.to_s
end end
when 'User' when 'User'
link_to_user value link_to_user value
@@ -72,25 +70,14 @@ module QueriesHelper
cond = "project_id IS NULL" cond = "project_id IS NULL"
cond << " OR project_id = #{@project.id}" if @project cond << " OR project_id = #{@project.id}" if @project
@query = Query.find(params[:query_id], :conditions => cond) @query = Query.find(params[:query_id], :conditions => cond)
raise ::Unauthorized unless @query.visible?
@query.project = @project @query.project = @project
session[:query] = {:id => @query.id, :project_id => @query.project_id} session[:query] = {:id => @query.id, :project_id => @query.project_id}
sort_clear sort_clear
elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil) else
if api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil)
# Give it a name, required to be valid # Give it a name, required to be valid
@query = Query.new(:name => "_") @query = Query.new(:name => "_")
@query.project = @project @query.project = @project
build_query_from_params
session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names}
else
# retrieve from session
@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
def build_query_from_params
if params[:fields] || params[:f] if params[:fields] || params[:f]
@query.filters = {} @query.filters = {}
@query.add_filters(params[:fields] || params[:f], params[:operators] || params[:op], params[:values] || params[:v]) @query.add_filters(params[:fields] || params[:f], params[:operators] || params[:op], params[:values] || params[:v])
@@ -99,7 +86,14 @@ module QueriesHelper
@query.add_short_filter(field, params[field]) if params[field] @query.add_short_filter(field, params[field]) if params[field]
end end
end end
@query.group_by = params[:group_by] || (params[:query] && params[:query][:group_by]) @query.group_by = params[:group_by]
@query.column_names = params[:c] || (params[:query] && params[:query][:column_names]) @query.column_names = params[:c] || (params[:query] && params[:query][:column_names])
session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names}
else
@query = Query.find_by_id(session[:query][:id]) if session[:query][:id]
@query ||= Query.new(:name => "_", :project => @project, :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names])
@query.project = @project
end
end
end end
end end
+1 -3
View File
@@ -1,5 +1,3 @@
# encoding: utf-8
#
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2011 Jean-Philippe Lang
# #
@@ -33,6 +31,6 @@ module ReportsHelper
def aggregate_link(data, criteria, *args) def aggregate_link(data, criteria, *args)
a = aggregate data, criteria a = aggregate data, criteria
a > 0 ? link_to(h(a), *args) : '-' a > 0 ? link_to(a, *args) : '-'
end end
end end
+47 -76
View File
@@ -1,5 +1,3 @@
# encoding: utf-8
#
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2011 Jean-Philippe Lang
# #
@@ -39,9 +37,9 @@ module RepositoriesHelper
unless properties.nil? || properties.empty? unless properties.nil? || properties.empty?
content = '' content = ''
properties.keys.sort.each do |property| properties.keys.sort.each do |property|
content << content_tag('li', "<b>#{h property}</b>: <span>#{h properties[property]}</span>".html_safe) content << content_tag('li', "<b>#{h property}</b>: <span>#{h properties[property]}</span>")
end end
content_tag('ul', content.html_safe, :class => 'properties') content_tag('ul', content, :class => 'properties')
end end
end end
@@ -89,7 +87,7 @@ module RepositoriesHelper
if s = tree[file][:s] if s = tree[file][:s]
style << ' folder' style << ' folder'
path_param = to_path_param(@repository.relative_path(file)) path_param = to_path_param(@repository.relative_path(file))
text = link_to(h(text), :controller => 'repositories', text = link_to(text, :controller => 'repositories',
:action => 'show', :action => 'show',
:id => @project, :id => @project,
:path => path_param, :path => path_param,
@@ -99,25 +97,56 @@ module RepositoriesHelper
elsif c = tree[file][:c] elsif c = tree[file][:c]
style << " change-#{c.action}" style << " change-#{c.action}"
path_param = to_path_param(@repository.relative_path(c.path)) path_param = to_path_param(@repository.relative_path(c.path))
text = link_to(h(text), :controller => 'repositories', text = link_to(text, :controller => 'repositories',
:action => 'entry', :action => 'entry',
:id => @project, :id => @project,
:path => path_param, :path => path_param,
:rev => @changeset.identifier) unless c.action == 'D' :rev => @changeset.identifier) unless c.action == 'D'
text << " - #{h(c.revision)}" unless c.revision.blank? text << " - #{c.revision}" unless c.revision.blank?
text << ' ('.html_safe + link_to(l(:label_diff), :controller => 'repositories', text << ' (' + link_to('diff', :controller => 'repositories',
:action => 'diff', :action => 'diff',
:id => @project, :id => @project,
:path => path_param, :path => path_param,
:rev => @changeset.identifier) + ') '.html_safe if c.action == 'M' :rev => @changeset.identifier) + ') ' if c.action == 'M'
text << ' '.html_safe + content_tag('span', h(c.from_path), :class => 'copied-from') unless c.from_path.blank? text << ' ' + content_tag('span', c.from_path, :class => 'copied-from') unless c.from_path.blank?
output << "<li class='#{style}'>#{text}</li>" output << "<li class='#{style}'>#{text}</li>"
end end
end end
output << '</ul>' output << '</ul>'
output.html_safe output
end end
def to_utf8(str)
return str if str.nil?
str = to_utf8_internal(str)
if str.respond_to?(:force_encoding)
str.force_encoding('UTF-8')
end
str
end
def to_utf8_internal(str)
return str if str.nil?
if str.respond_to?(:force_encoding)
str.force_encoding('ASCII-8BIT')
end
return str if str.empty?
return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii
if str.respond_to?(:force_encoding)
str.force_encoding('UTF-8')
end
@encodings ||= Setting.repositories_encodings.split(',').collect(&:strip)
@encodings.each do |encoding|
begin
return Iconv.conv('UTF-8', encoding, str)
rescue Iconv::Failure
# do nothing here and try the next encoding
end
end
str = Redmine::CodesetUtil.replace_invalid_utf8(str)
end
private :to_utf8_internal
def repository_field_tags(form, repository) def repository_field_tags(form, repository)
method = repository.class.name.demodulize.underscore + "_field_tags" method = repository.class.name.demodulize.underscore + "_field_tags"
if repository.is_a?(Repository) && if repository.is_a?(Repository) &&
@@ -159,8 +188,7 @@ module RepositoriesHelper
def subversion_field_tags(form, repository) def subversion_field_tags(form, repository)
content_tag('p', form.text_field(:url, :size => 60, :required => true, content_tag('p', form.text_field(:url, :size => 60, :required => true,
:disabled => (repository && !repository.root_url.blank?)) + :disabled => (repository && !repository.root_url.blank?)) +
'<br />'.html_safe + '<br />(file:///, http://, https://, svn://, svn+[tunnelscheme]://)') +
'(file:///, http://, https://, svn://, svn+[tunnelscheme]://)') +
content_tag('p', form.text_field(:login, :size => 30)) + content_tag('p', form.text_field(:login, :size => 30)) +
content_tag('p', form.password_field( content_tag('p', form.password_field(
:password, :size => 30, :name => 'ignore', :password, :size => 30, :name => 'ignore',
@@ -185,12 +213,12 @@ module RepositoriesHelper
:size => 60, :required => true, :size => 60, :required => true,
:disabled => (repository && !repository.root_url.blank?) :disabled => (repository && !repository.root_url.blank?)
) + ) +
'<br />'.html_safe + l(:text_mercurial_repository_note)) + '<br />' + l(:text_mercurial_repository_note)) +
content_tag('p', form.select( content_tag('p', form.select(
:path_encoding, [nil] + Setting::ENCODINGS, :path_encoding, [nil] + Setting::ENCODINGS,
:label => l(:field_scm_path_encoding) :label => l(:field_scm_path_encoding)
) + ) +
'<br />'.html_safe + l(:text_scm_path_encoding_note)) '<br />' + l(:text_scm_path_encoding_note))
end end
def git_field_tags(form, repository) def git_field_tags(form, repository)
@@ -199,13 +227,12 @@ module RepositoriesHelper
:size => 60, :required => true, :size => 60, :required => true,
:disabled => (repository && !repository.root_url.blank?) :disabled => (repository && !repository.root_url.blank?)
) + ) +
'<br />'.html_safe + '<br />' + l(:text_git_repository_note)) +
l(:text_git_repository_note)) +
content_tag('p', form.select( content_tag('p', form.select(
:path_encoding, [nil] + Setting::ENCODINGS, :path_encoding, [nil] + Setting::ENCODINGS,
:label => l(:field_scm_path_encoding) :label => l(:field_scm_path_encoding)
) + ) +
'<br />'.html_safe + l(:text_scm_path_encoding_note)) + '<br />' + l(:text_scm_path_encoding_note)) +
content_tag('p', form.check_box( content_tag('p', form.check_box(
:extra_report_last_commit, :extra_report_last_commit,
:label => l(:label_git_report_last_commit) :label => l(:label_git_report_last_commit)
@@ -230,7 +257,7 @@ module RepositoriesHelper
:path_encoding, [nil] + Setting::ENCODINGS, :path_encoding, [nil] + Setting::ENCODINGS,
:label => l(:field_scm_path_encoding) :label => l(:field_scm_path_encoding)
) + ) +
'<br />'.html_safe + l(:text_scm_path_encoding_note)) '<br />' + l(:text_scm_path_encoding_note))
end end
def bazaar_field_tags(form, repository) def bazaar_field_tags(form, repository)
@@ -252,62 +279,6 @@ module RepositoriesHelper
:path_encoding, [nil] + Setting::ENCODINGS, :path_encoding, [nil] + Setting::ENCODINGS,
:label => l(:field_scm_path_encoding) :label => l(:field_scm_path_encoding)
) + ) +
'<br />'.html_safe + l(:text_scm_path_encoding_note)) '<br />' + l(:text_scm_path_encoding_note))
end
def index_commits(commits, heads, href_proc = nil)
return nil if commits.nil? or commits.first.parents.nil?
map = {}
commit_hashes = []
refs_map = {}
href_proc ||= Proc.new {|x|x}
heads.each{|r| refs_map[r.scmid] ||= []; refs_map[r.scmid] << r}
commits.reverse.each_with_index do |c, i|
h = {}
h[:parents] = c.parents.collect do |p|
[p.scmid, 0, 0]
end
h[:rdmid] = i
h[:space] = 0
h[:refs] = refs_map[c.scmid].join(" ") if refs_map.include? c.scmid
h[:scmid] = c.scmid
h[:href] = href_proc.call(c.scmid)
commit_hashes << h
map[c.scmid] = h
end
heads.sort! do |a,b|
a.to_s <=> b.to_s
end
j = 0
heads.each do |h|
if map.include? h.scmid then
j = mark_chain(j += 1, map[h.scmid], map)
end
end
# when no head matched anything use first commit
if j == 0 then
mark_chain(j += 1, map.values.first, map)
end
map
end
def mark_chain(mark, commit, map)
stack = [[mark, commit]]
markmax = mark
until stack.empty?
current = stack.pop
m, commit = current
commit[:space] = m if commit[:space] == 0
m1 = m - 1
commit[:parents].each_with_index do |p, i|
psha = p[0]
if map.include? psha and map[psha][:space] == 0 then
stack << [m1 += 1, map[psha]] if i == 0
stack = [[m1 += 1, map[psha]]] + stack if i > 0
end
end
markmax = m1 if markmax < m1
end
markmax
end end
end end
+2 -4
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+3 -7
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006-2007 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -49,7 +47,6 @@ module SearchHelper
options << [l(:label_my_projects), 'my_projects'] unless User.current.memberships.empty? options << [l(:label_my_projects), 'my_projects'] unless User.current.memberships.empty?
options << [l(:label_and_its_subprojects, @project.name), 'subprojects'] unless @project.nil? || @project.descendants.active.empty? options << [l(:label_and_its_subprojects, @project.name), 'subprojects'] unless @project.nil? || @project.descendants.active.empty?
options << [@project.name, ''] unless @project.nil? options << [@project.name, ''] unless @project.nil?
label_tag("scope", l(:description_project_scope), :class => "hidden-for-sighted") +
select_tag('scope', options_for_select(options, params[:scope].to_s)) if options.size > 1 select_tag('scope', options_for_select(options, params[:scope].to_s)) if options.size > 1
end end
@@ -60,8 +57,7 @@ module SearchHelper
c = results_by_type[t] c = results_by_type[t]
next if c == 0 next if c == 0
text = "#{type_label(t)} (#{c})" text = "#{type_label(t)} (#{c})"
links << link_to(h(text), :q => params[:q], :titles_only => params[:titles_only], links << link_to(text, :q => params[:q], :titles_only => params[:title_only], :all_words => params[:all_words], :scope => params[:scope], t => 1)
:all_words => params[:all_words], :scope => params[:scope], t => 1)
end end
('<ul>' + links.map {|link| content_tag('li', link)}.join(' ') + '</ul>') unless links.empty? ('<ul>' + links.map {|link| content_tag('li', link)}.join(' ') + '</ul>') unless links.empty?
end end
+16 -18
View File
@@ -1,5 +1,3 @@
# encoding: utf-8
#
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2011 Jean-Philippe Lang
# #
@@ -34,18 +32,18 @@ module SettingsHelper
if blank_text = options.delete(:blank) if blank_text = options.delete(:blank)
choices = [[blank_text.is_a?(Symbol) ? l(blank_text) : blank_text, '']] + choices choices = [[blank_text.is_a?(Symbol) ? l(blank_text) : blank_text, '']] + choices
end end
setting_label(setting, options).html_safe + setting_label(setting, options) +
select_tag("settings[#{setting}]", select_tag("settings[#{setting}]",
options_for_select(choices, Setting.send(setting).to_s), options_for_select(choices, Setting.send(setting).to_s),
options).html_safe options)
end end
def setting_multiselect(setting, choices, options={}) def setting_multiselect(setting, choices, options={})
setting_values = Setting.send(setting) setting_values = Setting.send(setting)
setting_values = [] unless setting_values.is_a?(Array) setting_values = [] unless setting_values.is_a?(Array)
setting_label(setting, options).html_safe + setting_label(setting, options) +
hidden_field_tag("settings[#{setting}][]", '').html_safe + hidden_field_tag("settings[#{setting}][]", '') +
choices.collect do |choice| choices.collect do |choice|
text, value = (choice.is_a?(Array) ? choice : [choice, choice]) text, value = (choice.is_a?(Array) ? choice : [choice, choice])
content_tag( content_tag(
@@ -57,28 +55,28 @@ module SettingsHelper
) + text.to_s, ) + text.to_s,
:class => 'block' :class => 'block'
) )
end.join.html_safe end.join
end end
def setting_text_field(setting, options={}) def setting_text_field(setting, options={})
setting_label(setting, options).html_safe + setting_label(setting, options) +
text_field_tag("settings[#{setting}]", Setting.send(setting), options).html_safe text_field_tag("settings[#{setting}]", Setting.send(setting), options)
end end
def setting_text_area(setting, options={}) def setting_text_area(setting, options={})
setting_label(setting, options).html_safe + setting_label(setting, options) +
text_area_tag("settings[#{setting}]", Setting.send(setting), options).html_safe text_area_tag("settings[#{setting}]", Setting.send(setting), options)
end end
def setting_check_box(setting, options={}) def setting_check_box(setting, options={})
setting_label(setting, options).html_safe + setting_label(setting, options) +
hidden_field_tag("settings[#{setting}]", 0).html_safe + hidden_field_tag("settings[#{setting}]", 0) +
check_box_tag("settings[#{setting}]", 1, Setting.send("#{setting}?"), options).html_safe check_box_tag("settings[#{setting}]", 1, Setting.send("#{setting}?"), options)
end end
def setting_label(setting, options={}) def setting_label(setting, options={})
label = options.delete(:label) label = options.delete(:label)
label != false ? content_tag("label", l(label || "setting_#{setting}")).html_safe : '' label != false ? content_tag("label", l(label || "setting_#{setting}")) : ''
end end
# Renders a notification field for a Redmine::Notifiable option # Renders a notification field for a Redmine::Notifiable option
@@ -86,8 +84,8 @@ module SettingsHelper
return content_tag(:label, return content_tag(:label,
check_box_tag('settings[notified_events][]', check_box_tag('settings[notified_events][]',
notifiable.name, notifiable.name,
Setting.notified_events.include?(notifiable.name)).html_safe + Setting.notified_events.include?(notifiable.name)) +
l_or_humanize(notifiable.name, :prefix => 'label_').html_safe, l_or_humanize(notifiable.name, :prefix => 'label_'),
:class => notifiable.parent.present? ? "parent" : '').html_safe :class => notifiable.parent.present? ? "parent" : '')
end end
end end
+1 -3
View File
@@ -1,5 +1,3 @@
# encoding: utf-8
#
# Helpers to sort tables using clickable column headers. # Helpers to sort tables using clickable column headers.
# #
# Author: Stuart Rackham <srackham@methods.co.nz>, March 2005. # Author: Stuart Rackham <srackham@methods.co.nz>, March 2005.
@@ -207,7 +205,7 @@ module SortHelper
# Add project_id to url_options # Add project_id to url_options
url_options = url_options.merge(:project_id => params[:project_id]) if params.has_key?(:project_id) url_options = url_options.merge(:project_id => params[:project_id]) if params.has_key?(:project_id)
link_to_content_update(h(caption), url_options, :class => css) link_to_content_update(caption, url_options, :class => css)
end end
# Returns a table header <th> tag with a sort link for the named column # Returns a table header <th> tag with a sort link for the named column
+18 -24
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -86,6 +84,7 @@ module TimelogHelper
end end
def entries_to_csv(entries) def entries_to_csv(entries)
ic = Iconv.new(l(:general_csv_encoding), 'UTF-8')
decimal_separator = l(:general_csv_decimal_separator) decimal_separator = l(:general_csv_decimal_separator)
custom_fields = TimeEntryCustomField.find(:all) custom_fields = TimeEntryCustomField.find(:all)
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
@@ -103,9 +102,7 @@ module TimelogHelper
# Export custom fields # Export custom fields
headers += custom_fields.collect(&:name) headers += custom_fields.collect(&:name)
csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8( csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
c.to_s,
l(:general_csv_encoding) ) }
# csv lines # csv lines
entries.each do |entry| entries.each do |entry|
fields = [format_date(entry.spent_on), fields = [format_date(entry.spent_on),
@@ -120,9 +117,7 @@ module TimelogHelper
] ]
fields += custom_fields.collect {|f| show_value(entry.custom_value_for(f)) } fields += custom_fields.collect {|f| show_value(entry.custom_value_for(f)) }
csv << fields.collect {|c| Redmine::CodesetUtil.from_utf8( csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
c.to_s,
l(:general_csv_encoding) ) }
end end
end end
export export
@@ -144,53 +139,52 @@ module TimelogHelper
end end
def report_to_csv(criterias, periods, hours) def report_to_csv(criterias, periods, hours)
decimal_separator = l(:general_csv_decimal_separator)
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
# Column headers # Column headers
headers = criterias.collect {|criteria| l(@available_criterias[criteria][:label]) } headers = criterias.collect {|criteria| l(@available_criterias[criteria][:label]) }
headers += periods headers += periods
headers << l(:label_total) headers << l(:label_total)
csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8( csv << headers.collect {|c| to_utf8(c) }
c.to_s,
l(:general_csv_encoding) ) }
# Content # Content
report_criteria_to_csv(csv, criterias, periods, hours) report_criteria_to_csv(csv, criterias, periods, hours)
# Total row # Total row
str_total = Redmine::CodesetUtil.from_utf8(l(:label_total), l(:general_csv_encoding)) row = [ l(:label_total) ] + [''] * (criterias.size - 1)
row = [ str_total ] + [''] * (criterias.size - 1)
total = 0 total = 0
periods.each do |period| periods.each do |period|
sum = sum_hours(select_hours(hours, @columns, period.to_s)) sum = sum_hours(select_hours(hours, @columns, period.to_s))
total += sum total += sum
row << (sum > 0 ? ("%.2f" % sum).gsub('.',decimal_separator) : '') row << (sum > 0 ? "%.2f" % sum : '')
end end
row << ("%.2f" % total).gsub('.',decimal_separator) row << "%.2f" %total
csv << row csv << row
end end
export export
end end
def report_criteria_to_csv(csv, criterias, periods, hours, level=0) def report_criteria_to_csv(csv, criterias, periods, hours, level=0)
decimal_separator = l(:general_csv_decimal_separator)
hours.collect {|h| h[criterias[level]].to_s}.uniq.each do |value| hours.collect {|h| h[criterias[level]].to_s}.uniq.each do |value|
hours_for_value = select_hours(hours, criterias[level], value) hours_for_value = select_hours(hours, criterias[level], value)
next if hours_for_value.empty? next if hours_for_value.empty?
row = [''] * level row = [''] * level
row << Redmine::CodesetUtil.from_utf8( row << to_utf8(format_criteria_value(criterias[level], value))
format_criteria_value(criterias[level], value).to_s,
l(:general_csv_encoding) )
row += [''] * (criterias.length - level - 1) row += [''] * (criterias.length - level - 1)
total = 0 total = 0
periods.each do |period| periods.each do |period|
sum = sum_hours(select_hours(hours_for_value, @columns, period.to_s)) sum = sum_hours(select_hours(hours_for_value, @columns, period.to_s))
total += sum total += sum
row << (sum > 0 ? ("%.2f" % sum).gsub('.',decimal_separator) : '') row << (sum > 0 ? "%.2f" % sum : '')
end end
row << ("%.2f" % total).gsub('.',decimal_separator) row << "%.2f" %total
csv << row csv << row
if criterias.length > level + 1 if criterias.length > level + 1
report_criteria_to_csv(csv, criterias, periods, hours_for_value, level + 1) report_criteria_to_csv(csv, criterias, periods, hours_for_value, level + 1)
end end
end end
end end
def to_utf8(s)
@ic ||= Iconv.new(l(:general_csv_encoding), 'UTF-8')
begin; @ic.iconv(s.to_s); rescue; s.to_s; end
end
end end
+2 -4
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+2 -4
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
-2
View File
@@ -1,5 +1,3 @@
# encoding: utf-8
#
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2011 Jean-Philippe Lang
# #
-2
View File
@@ -1,5 +1,3 @@
# encoding: utf-8
#
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2011 Jean-Philippe Lang
# #
+2 -4
View File
@@ -1,7 +1,5 @@
# encoding: utf-8 # redMine - project management software
# # Copyright (C) 2006 Jean-Philippe Lang
# Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
-8
View File
@@ -1,5 +1,3 @@
# encoding: utf-8
#
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2011 Jean-Philippe Lang
# #
@@ -34,10 +32,4 @@ module WikiHelper
end end
s s
end end
def wiki_page_breadcrumb(page)
breadcrumb(page.ancestors.reverse.collect {|parent|
link_to(h(parent.pretty_title), {:controller => 'wiki', :action => 'show', :id => parent.title, :project_id => parent.project})
})
end
end end
+1 -3
View File
@@ -1,7 +1,5 @@
# encoding: utf-8
#
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2008 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+10 -20
View File
@@ -24,7 +24,6 @@ class Attachment < ActiveRecord::Base
validates_presence_of :container, :filename, :author validates_presence_of :container, :filename, :author
validates_length_of :filename, :maximum => 255 validates_length_of :filename, :maximum => 255
validates_length_of :disk_filename, :maximum => 255 validates_length_of :disk_filename, :maximum => 255
validate :validate_max_file_size
acts_as_event :title => :filename, acts_as_event :title => :filename,
:url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id, :filename => o.filename}} :url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id, :filename => o.filename}}
@@ -44,12 +43,9 @@ class Attachment < ActiveRecord::Base
"LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id"} "LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id"}
cattr_accessor :storage_path cattr_accessor :storage_path
@@storage_path = Redmine::Configuration['attachments_storage_path'] || "#{Rails.root}/files" @@storage_path = Redmine::Configuration['attachments_storage_path'] || "#{RAILS_ROOT}/files"
before_save :files_to_final_location def validate
after_destroy :delete_from_disk
def validate_max_file_size
if self.filesize > Setting.attachment_max_size.to_i.kilobytes if self.filesize > Setting.attachment_max_size.to_i.kilobytes
errors.add(:base, :too_long, :count => Setting.attachment_max_size.to_i.kilobytes) errors.add(:base, :too_long, :count => Setting.attachment_max_size.to_i.kilobytes)
end end
@@ -76,9 +72,9 @@ class Attachment < ActiveRecord::Base
# Copies the temporary file to its final location # Copies the temporary file to its final location
# and computes its MD5 hash # and computes its MD5 hash
def files_to_final_location def before_save
if @temp_file && (@temp_file.size > 0) if @temp_file && (@temp_file.size > 0)
logger.info("Saving attachment '#{self.diskfile}' (#{@temp_file.size} bytes)") logger.debug("saving '#{self.diskfile}'")
md5 = Digest::MD5.new md5 = Digest::MD5.new
File.open(diskfile, "wb") do |f| File.open(diskfile, "wb") do |f|
buffer = "" buffer = ""
@@ -89,7 +85,6 @@ class Attachment < ActiveRecord::Base
end end
self.digest = md5.hexdigest self.digest = md5.hexdigest
end end
@temp_file = nil
# Don't save the content type if it's longer than the authorized length # Don't save the content type if it's longer than the authorized length
if self.content_type && self.content_type.length > 255 if self.content_type && self.content_type.length > 255
self.content_type = nil self.content_type = nil
@@ -97,7 +92,7 @@ class Attachment < ActiveRecord::Base
end end
# Deletes file on the disk # Deletes file on the disk
def delete_from_disk def after_destroy
File.delete(diskfile) if !filename.blank? && File.exist?(diskfile) File.delete(diskfile) if !filename.blank? && File.exist?(diskfile)
end end
@@ -123,7 +118,7 @@ class Attachment < ActiveRecord::Base
end end
def image? def image?
self.filename =~ /\.(bmp|gif|jpg|jpe|jpeg|png)$/i self.filename =~ /\.(jpe?g|gif|png)$/i
end end
def is_text? def is_text?
@@ -154,7 +149,6 @@ class Attachment < ActiveRecord::Base
:file => file, :file => file,
:description => attachment['description'].to_s.strip, :description => attachment['description'].to_s.strip,
:author => User.current) :author => User.current)
obj.attachments << a
if a.new_record? if a.new_record?
obj.unsaved_attachments ||= [] obj.unsaved_attachments ||= []
@@ -167,19 +161,15 @@ class Attachment < ActiveRecord::Base
{:files => attached, :unsaved => obj.unsaved_attachments} {:files => attached, :unsaved => obj.unsaved_attachments}
end end
def self.latest_attach(attachments, filename)
attachments.sort_by(&:created_on).reverse.detect {
|att| att.filename.downcase == filename.downcase
}
end
private private
def sanitize_filename(value) def sanitize_filename(value)
# get only the filename, not the whole path # get only the filename, not the whole path
just_filename = value.gsub(/^.*(\\|\/)/, '') just_filename = value.gsub(/^.*(\\|\/)/, '')
# NOTE: File.basename doesn't work right with Windows paths on Unix
# INCORRECT: just_filename = File.basename(value.gsub('\\\\', '/'))
# Finally, replace invalid characters with underscore # Finally, replace all non alphanumeric, hyphens or periods with underscore
@filename = just_filename.gsub(/[\/\?\%\*\:\|\"\'<>]+/, '_') @filename = just_filename.gsub(/[^\w\.\-]/,'_')
end end
# Returns an ASCII or hashed filename # Returns an ASCII or hashed filename
+2 -2
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+2 -2
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+2 -8
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2007 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -16,7 +16,6 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Board < ActiveRecord::Base class Board < ActiveRecord::Base
include Redmine::SafeAttributes
belongs_to :project belongs_to :project
has_many :topics, :class_name => 'Message', :conditions => "#{Message.table_name}.parent_id IS NULL", :order => "#{Message.table_name}.created_on DESC" has_many :topics, :class_name => 'Message', :conditions => "#{Message.table_name}.parent_id IS NULL", :order => "#{Message.table_name}.created_on DESC"
has_many :messages, :dependent => :destroy, :order => "#{Message.table_name}.created_on DESC" has_many :messages, :dependent => :destroy, :order => "#{Message.table_name}.created_on DESC"
@@ -28,11 +27,6 @@ class Board < ActiveRecord::Base
validates_length_of :name, :maximum => 30 validates_length_of :name, :maximum => 30
validates_length_of :description, :maximum => 255 validates_length_of :description, :maximum => 255
named_scope :visible, lambda {|*args| { :include => :project,
:conditions => Project.allowed_to_condition(args.shift || User.current, :view_messages, *args) } }
safe_attributes 'name', 'description', 'move_to'
def visible?(user=User.current) def visible?(user=User.current)
!user.nil? && user.allowed_to?(:view_messages, project) !user.nil? && user.allowed_to?(:view_messages, project)
end end
+1 -2
View File
@@ -20,13 +20,12 @@ class Change < ActiveRecord::Base
validates_presence_of :changeset_id, :action, :path validates_presence_of :changeset_id, :action, :path
before_save :init_path before_save :init_path
before_validation :replace_invalid_utf8_of_path
def relative_path def relative_path
changeset.repository.relative_path(path) changeset.repository.relative_path(path)
end end
def replace_invalid_utf8_of_path def before_validation
self.path = Redmine::CodesetUtil.replace_invalid_utf8(self.path) self.path = Redmine::CodesetUtil.replace_invalid_utf8(self.path)
self.from_path = Redmine::CodesetUtil.replace_invalid_utf8(self.from_path) self.from_path = Redmine::CodesetUtil.replace_invalid_utf8(self.from_path)
end end
+41 -23
View File
@@ -22,14 +22,6 @@ class Changeset < ActiveRecord::Base
belongs_to :user belongs_to :user
has_many :changes, :dependent => :delete_all has_many :changes, :dependent => :delete_all
has_and_belongs_to_many :issues has_and_belongs_to_many :issues
has_and_belongs_to_many :parents,
:class_name => "Changeset",
:join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}",
:association_foreign_key => 'parent_id', :foreign_key => 'changeset_id'
has_and_belongs_to_many :children,
:class_name => "Changeset",
:join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}",
:association_foreign_key => 'changeset_id', :foreign_key => 'parent_id'
acts_as_event :title => Proc.new {|o| "#{l(:label_revision)} #{o.format_identifier}" + (o.short_comments.blank? ? '' : (': ' + o.short_comments))}, acts_as_event :title => Proc.new {|o| "#{l(:label_revision)} #{o.format_identifier}" + (o.short_comments.blank? ? '' : (': ' + o.short_comments))},
:description => :long_comments, :description => :long_comments,
@@ -52,9 +44,6 @@ class Changeset < ActiveRecord::Base
named_scope :visible, lambda {|*args| { :include => {:repository => :project}, named_scope :visible, lambda {|*args| { :include => {:repository => :project},
:conditions => Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args) } } :conditions => Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args) } }
after_create :scan_for_issues
before_create :before_create_cs
def revision=(r) def revision=(r)
write_attribute :revision, (r.nil? ? nil : r.to_s) write_attribute :revision, (r.nil? ? nil : r.to_s)
end end
@@ -90,14 +79,14 @@ class Changeset < ActiveRecord::Base
user || committer.to_s.split('<').first user || committer.to_s.split('<').first
end end
def before_create_cs def before_create
self.committer = self.class.to_utf8(self.committer, repository.repo_log_encoding) self.committer = self.class.to_utf8(self.committer, repository.repo_log_encoding)
self.comments = self.class.normalize_comments( self.comments = self.class.normalize_comments(
self.comments, repository.repo_log_encoding) self.comments, repository.repo_log_encoding)
self.user = repository.find_committer_user(self.committer) self.user = repository.find_committer_user(self.committer)
end end
def scan_for_issues def after_create
scan_comment_for_issue_ids scan_comment_for_issue_ids
end end
@@ -151,16 +140,12 @@ class Changeset < ActiveRecord::Base
@long_comments || split_comments.last @long_comments || split_comments.last
end end
def text_tag(ref_project=nil) def text_tag
tag = if scmid? if scmid?
"commit:#{scmid}" "commit:#{scmid}"
else else
"r#{revision}" "r#{revision}"
end end
if ref_project && project && ref_project != project
tag = "#{project.identifier}:#{tag}"
end
tag
end end
# Returns the previous changeset # Returns the previous changeset
@@ -208,7 +193,7 @@ class Changeset < ActiveRecord::Base
def fix_issue(issue) def fix_issue(issue)
status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i) status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i)
if status.nil? if status.nil?
logger.warn("No status matches commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger logger.warn("No status macthes commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger
return issue return issue
end end
@@ -217,7 +202,7 @@ class Changeset < ActiveRecord::Base
# don't change the status is the issue is closed # don't change the status is the issue is closed
return if issue.status && issue.status.is_closed? return if issue.status && issue.status.is_closed?
journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag(issue.project))) journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag))
issue.status = status issue.status = status
unless Setting.commit_fix_done_ratio.blank? unless Setting.commit_fix_done_ratio.blank?
issue.done_ratio = Setting.commit_fix_done_ratio.to_i issue.done_ratio = Setting.commit_fix_done_ratio.to_i
@@ -236,7 +221,7 @@ class Changeset < ActiveRecord::Base
:hours => hours, :hours => hours,
:issue => issue, :issue => issue,
:spent_on => commit_date, :spent_on => commit_date,
:comments => l(:text_time_logged_by_changeset, :value => text_tag(issue.project), :comments => l(:text_time_logged_by_changeset, :value => text_tag,
:locale => Setting.default_language) :locale => Setting.default_language)
) )
time_entry.activity = log_time_activity unless log_time_activity.nil? time_entry.activity = log_time_activity unless log_time_activity.nil?
@@ -268,6 +253,39 @@ class Changeset < ActiveRecord::Base
end end
def self.to_utf8(str, encoding) def self.to_utf8(str, encoding)
Redmine::CodesetUtil.to_utf8(str, encoding) return str if str.nil?
str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
if str.empty?
str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
return str
end
enc = encoding.blank? ? "UTF-8" : encoding
if str.respond_to?(:force_encoding)
if enc.upcase != "UTF-8"
str.force_encoding(enc)
str = str.encode("UTF-8", :invalid => :replace,
:undef => :replace, :replace => '?')
else
str.force_encoding("UTF-8")
if ! str.valid_encoding?
str = str.encode("US-ASCII", :invalid => :replace,
:undef => :replace, :replace => '?').encode("UTF-8")
end
end
else
ic = Iconv.new('UTF-8', enc)
txtar = ""
begin
txtar += ic.iconv(str)
rescue Iconv::IllegalSequence
txtar += $!.success
str = '?' + $!.failed[1,$!.failed.length]
retry
rescue
txtar += $!.success
end
str = txtar
end
str
end end
end end
+2 -5
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -16,11 +16,8 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Comment < ActiveRecord::Base class Comment < ActiveRecord::Base
include Redmine::SafeAttributes
belongs_to :commented, :polymorphic => true, :counter_cache => true belongs_to :commented, :polymorphic => true, :counter_cache => true
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
validates_presence_of :commented, :author, :comments validates_presence_of :commented, :author, :comments
safe_attributes 'comments'
end end
+2 -12
View File
@@ -25,8 +25,6 @@ class CustomField < ActiveRecord::Base
validates_length_of :name, :maximum => 30 validates_length_of :name, :maximum => 30
validates_inclusion_of :field_format, :in => Redmine::CustomFieldFormat.available_formats validates_inclusion_of :field_format, :in => Redmine::CustomFieldFormat.available_formats
validate :validate_values
def initialize(attributes = nil) def initialize(attributes = nil)
super super
self.possible_values ||= [] self.possible_values ||= []
@@ -38,20 +36,12 @@ class CustomField < ActiveRecord::Base
true true
end end
def validate_values def validate
if self.field_format == "list" if self.field_format == "list"
errors.add(:possible_values, :blank) if self.possible_values.nil? || self.possible_values.empty? errors.add(:possible_values, :blank) if self.possible_values.nil? || self.possible_values.empty?
errors.add(:possible_values, :invalid) unless self.possible_values.is_a? Array errors.add(:possible_values, :invalid) unless self.possible_values.is_a? Array
end end
if regexp.present?
begin
Regexp.new(regexp)
rescue
errors.add(:regexp, :invalid)
end
end
# validate default value # validate default value
v = CustomValue.new(:custom_field => self.clone, :value => default_value, :customized => nil) v = CustomValue.new(:custom_field => self.clone, :value => default_value, :customized => nil)
v.custom_field.is_required = false v.custom_field.is_required = false
@@ -66,7 +56,7 @@ class CustomField < ActiveRecord::Base
when 'user' when 'user'
obj.project.users.sort.collect {|u| [u.to_s, u.id.to_s]} obj.project.users.sort.collect {|u| [u.to_s, u.id.to_s]}
when 'version' when 'version'
obj.project.shared_versions.sort.collect {|u| [u.to_s, u.id.to_s]} obj.project.versions.sort.collect {|u| [u.to_s, u.id.to_s]}
end end
elsif obj.is_a?(Array) elsif obj.is_a?(Array)
obj.collect {|o| possible_values_options(o)}.inject {|memo, v| memo & v} obj.collect {|o| possible_values_options(o)}.inject {|memo, v| memo & v}
+4 -6
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -19,8 +19,6 @@ class CustomValue < ActiveRecord::Base
belongs_to :custom_field belongs_to :custom_field
belongs_to :customized, :polymorphic => true belongs_to :customized, :polymorphic => true
validate :validate_custom_value
def after_initialize def after_initialize
if new_record? && custom_field && (customized_type.blank? || (customized && customized.new_record?)) if new_record? && custom_field && (customized_type.blank? || (customized && customized.new_record?))
self.value ||= custom_field.default_value self.value ||= custom_field.default_value
@@ -49,7 +47,7 @@ class CustomValue < ActiveRecord::Base
end end
protected protected
def validate_custom_value def validate
if value.blank? if value.blank?
errors.add(:value, :blank) if custom_field.is_required? and value.blank? errors.add(:value, :blank) if custom_field.is_required? and value.blank?
else else
@@ -64,7 +62,7 @@ protected
when 'float' when 'float'
begin; Kernel.Float(value); rescue; errors.add(:value, :invalid) end begin; Kernel.Float(value); rescue; errors.add(:value, :invalid) end
when 'date' when 'date'
errors.add(:value, :not_a_date) unless value =~ /^\d{4}-\d{2}-\d{2}$/ && begin; value.to_date; rescue; false end errors.add(:value, :not_a_date) unless value =~ /^\d{4}-\d{2}-\d{2}$/
when 'list' when 'list'
errors.add(:value, :inclusion) unless custom_field.possible_values.include?(value) errors.add(:value, :inclusion) unless custom_field.possible_values.include?(value)
end end
-3
View File
@@ -16,7 +16,6 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Document < ActiveRecord::Base class Document < ActiveRecord::Base
include Redmine::SafeAttributes
belongs_to :project belongs_to :project
belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id" belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id"
acts_as_attachable :delete_permission => :manage_documents acts_as_attachable :delete_permission => :manage_documents
@@ -33,8 +32,6 @@ class Document < ActiveRecord::Base
named_scope :visible, lambda {|*args| { :include => :project, named_scope :visible, lambda {|*args| { :include => :project,
:conditions => Project.allowed_to_condition(args.shift || User.current, :view_documents, *args) } } :conditions => Project.allowed_to_condition(args.shift || User.current, :view_documents, *args) } }
safe_attributes 'category_id', 'title', 'description'
def visible?(user=User.current) def visible?(user=User.current)
!user.nil? && user.allowed_to?(:view_documents, project) !user.nil? && user.allowed_to?(:view_documents, project)
end end
+3 -5
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -25,7 +25,6 @@ class Enumeration < ActiveRecord::Base
acts_as_tree :order => 'position ASC' acts_as_tree :order => 'position ASC'
before_destroy :check_integrity before_destroy :check_integrity
before_save :check_default
validates_presence_of :name validates_presence_of :name
validates_uniqueness_of :name, :scope => [:type, :project_id] validates_uniqueness_of :name, :scope => [:type, :project_id]
@@ -33,7 +32,6 @@ class Enumeration < ActiveRecord::Base
named_scope :shared, :conditions => { :project_id => nil } named_scope :shared, :conditions => { :project_id => nil }
named_scope :active, :conditions => { :active => true } named_scope :active, :conditions => { :active => true }
named_scope :named, lambda {|arg| { :conditions => ["LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip]}}
def self.default def self.default
# Creates a fake default scope so Enumeration.default will check # Creates a fake default scope so Enumeration.default will check
@@ -52,7 +50,7 @@ class Enumeration < ActiveRecord::Base
nil nil
end end
def check_default def before_save
if is_default? && is_default_changed? if is_default? && is_default_changed?
Enumeration.update_all("is_default = #{connection.quoted_false}", {:type => type}) Enumeration.update_all("is_default = #{connection.quoted_false}", {:type => type})
end end
+1 -22
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2009 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -25,14 +25,10 @@ class Group < Principal
validates_uniqueness_of :lastname, :case_sensitive => false validates_uniqueness_of :lastname, :case_sensitive => false
validates_length_of :lastname, :maximum => 30 validates_length_of :lastname, :maximum => 30
before_destroy :remove_references_before_destroy
def to_s def to_s
lastname.to_s lastname.to_s
end end
alias :name :to_s
def user_added(user) def user_added(user)
members.each do |member| members.each do |member|
next if member.project.nil? next if member.project.nil?
@@ -50,21 +46,4 @@ class Group < Principal
:conditions => ["#{Member.table_name}.user_id = ? AND #{MemberRole.table_name}.inherited_from IN (?)", user.id, member.member_role_ids]).each(&:destroy) :conditions => ["#{Member.table_name}.user_id = ? AND #{MemberRole.table_name}.inherited_from IN (?)", user.id, member.member_role_ids]).each(&:destroy)
end end
end end
def self.human_attribute_name(attribute_key_name)
attr_name = attribute_key_name
if attr_name == 'lastname'
attr_name = "name"
end
super(attr_name)
end
private
# Removes references that are not handled by associations
def remove_references_before_destroy
return if self.id.nil?
Issue.update_all 'assigned_to_id = NULL', ['assigned_to_id = ?', id]
end
end end
+1 -1
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2009 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+15 -55
View File
@@ -22,7 +22,7 @@ class Issue < ActiveRecord::Base
belongs_to :tracker belongs_to :tracker
belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id' belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id'
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
belongs_to :assigned_to, :class_name => 'Principal', :foreign_key => 'assigned_to_id' belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id'
belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id' belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id'
belongs_to :priority, :class_name => 'IssuePriority', :foreign_key => 'priority_id' belongs_to :priority, :class_name => 'IssuePriority', :foreign_key => 'priority_id'
belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id' belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id'
@@ -35,7 +35,7 @@ class Issue < ActiveRecord::Base
has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all
acts_as_nested_set :scope => 'root_id', :dependent => :destroy acts_as_nested_set :scope => 'root_id', :dependent => :destroy
acts_as_attachable :after_add => :attachment_added, :after_remove => :attachment_removed acts_as_attachable :after_remove => :attachment_removed
acts_as_customizable acts_as_customizable
acts_as_watchable acts_as_watchable
acts_as_searchable :columns => ['subject', "#{table_name}.description", "#{Journal.table_name}.notes"], acts_as_searchable :columns => ['subject', "#{table_name}.description", "#{Journal.table_name}.notes"],
@@ -58,7 +58,6 @@ class Issue < ActiveRecord::Base
validates_length_of :subject, :maximum => 255 validates_length_of :subject, :maximum => 255
validates_inclusion_of :done_ratio, :in => 0..100 validates_inclusion_of :done_ratio, :in => 0..100
validates_numericality_of :estimated_hours, :allow_nil => true validates_numericality_of :estimated_hours, :allow_nil => true
validate :validate_issue
named_scope :visible, lambda {|*args| { :include => :project, named_scope :visible, lambda {|*args| { :include => :project,
:conditions => Issue.visible_condition(args.shift || User.current, *args) } } :conditions => Issue.visible_condition(args.shift || User.current, *args) } }
@@ -94,11 +93,9 @@ class Issue < ActiveRecord::Base
when 'all' when 'all'
nil nil
when 'default' when 'default'
user_ids = [user.id] + user.groups.map(&:id) "(#{table_name}.is_private = #{connection.quoted_false} OR #{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id = #{user.id})"
"(#{table_name}.is_private = #{connection.quoted_false} OR #{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))"
when 'own' when 'own'
user_ids = [user.id] + user.groups.map(&:id) "(#{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id = #{user.id})"
"(#{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))"
else else
'1=0' '1=0'
end end
@@ -112,9 +109,9 @@ class Issue < ActiveRecord::Base
when 'all' when 'all'
true true
when 'default' when 'default'
!self.is_private? || self.author == user || user.is_or_belongs_to?(assigned_to) !self.is_private? || self.author == user || self.assigned_to == user
when 'own' when 'own'
self.author == user || user.is_or_belongs_to?(assigned_to) self.author == user || self.assigned_to == user
else else
false false
end end
@@ -231,13 +228,6 @@ class Issue < ActiveRecord::Base
result result
end end
def description=(arg)
if arg.is_a?(String)
arg = arg.gsub(/(\r\n|\n|\r)/, "\r\n")
end
write_attribute(:description, arg)
end
# Overrides attributes= so that tracker_id gets assigned first # Overrides attributes= so that tracker_id gets assigned first
def attributes_with_tracker_first=(new_attributes, *args) def attributes_with_tracker_first=(new_attributes, *args)
return if new_attributes.nil? return if new_attributes.nil?
@@ -338,7 +328,7 @@ class Issue < ActiveRecord::Base
Setting.issue_done_ratio == 'issue_field' Setting.issue_done_ratio == 'issue_field'
end end
def validate_issue def validate
if self.due_date.nil? && @attributes['due_date'] && !@attributes['due_date'].empty? if self.due_date.nil? && @attributes['due_date'] && !@attributes['due_date'].empty?
errors.add :due_date, :not_a_date errors.add :due_date, :not_a_date
end end
@@ -355,7 +345,7 @@ class Issue < ActiveRecord::Base
if !assignable_versions.include?(fixed_version) if !assignable_versions.include?(fixed_version)
errors.add :fixed_version_id, :inclusion errors.add :fixed_version_id, :inclusion
elsif reopened? && fixed_version.closed? elsif reopened? && fixed_version.closed?
errors.add :base, I18n.t(:error_can_not_reopen_issue_on_closed_version) errors.add_to_base I18n.t(:error_can_not_reopen_issue_on_closed_version)
end end
end end
@@ -452,7 +442,6 @@ class Issue < ActiveRecord::Base
def assignable_users def assignable_users
users = project.assignable_users users = project.assignable_users
users << author if author users << author if author
users << assigned_to if assigned_to
users.uniq.sort users.uniq.sort
end end
@@ -486,13 +475,7 @@ class Issue < ActiveRecord::Base
# Author and assignee are always notified unless they have been # Author and assignee are always notified unless they have been
# locked or don't want to be notified # locked or don't want to be notified
notified << author if author && author.active? && author.notify_about?(self) notified << author if author && author.active? && author.notify_about?(self)
if assigned_to notified << assigned_to if assigned_to && assigned_to.active? && assigned_to.notify_about?(self)
if assigned_to.is_a?(Group)
notified += assigned_to.users.select {|u| u.active? && u.notify_about?(self)}
else
notified << assigned_to if assigned_to.active? && assigned_to.notify_about?(self)
end
end
notified.uniq! notified.uniq!
# Remove users that can not view the issue # Remove users that can not view the issue
notified.reject! {|user| !visible?(user)} notified.reject! {|user| !visible?(user)}
@@ -509,22 +492,7 @@ class Issue < ActiveRecord::Base
end end
def relations def relations
@relations ||= (relations_from + relations_to).sort (relations_from + relations_to).sort
end
# Preloads relations for a collection of issues
def self.load_relations(issues)
if issues.any?
relations = IssueRelation.all(:conditions => ["issue_from_id IN (:ids) OR issue_to_id IN (:ids)", {:ids => issues.map(&:id)}])
issues.each do |issue|
issue.instance_variable_set "@relations", relations.select {|r| r.issue_from_id == issue.id || r.issue_to_id == issue.id}
end
end
end
# Finds an issue relation given its id.
def find_relation(relation_id)
IssueRelation.find(relation_id, :conditions => ["issue_to_id = ? OR issue_from_id = ?", id, id])
end end
def all_dependent_issues(except=[]) def all_dependent_issues(except=[])
@@ -616,13 +584,15 @@ class Issue < ActiveRecord::Base
@time_entry.project = project @time_entry.project = project
@time_entry.issue = self @time_entry.issue = self
@time_entry.user = User.current @time_entry.user = User.current
@time_entry.spent_on = User.current.today @time_entry.spent_on = Date.today
@time_entry.attributes = params[:time_entry] @time_entry.attributes = params[:time_entry]
self.time_entries << @time_entry self.time_entries << @time_entry
end end
if valid? if valid?
attachments = Attachment.attach_files(self, params[:attachments]) attachments = Attachment.attach_files(self, params[:attachments])
attachments[:files].each {|a| @current_journal.details << JournalDetail.new(:property => 'attachment', :prop_key => a.id, :value => a.filename)}
# TODO: Rename hook # TODO: Rename hook
Redmine::Hook.call_hook(:controller_issues_edit_before_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => @current_journal}) Redmine::Hook.call_hook(:controller_issues_edit_before_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => @current_journal})
begin begin
@@ -634,7 +604,7 @@ class Issue < ActiveRecord::Base
end end
rescue ActiveRecord::StaleObjectError rescue ActiveRecord::StaleObjectError
attachments[:files].each(&:destroy) attachments[:files].each(&:destroy)
errors.add :base, l(:notice_locking_conflict) errors.add_to_base l(:notice_locking_conflict)
raise ActiveRecord::Rollback raise ActiveRecord::Rollback
end end
end end
@@ -852,13 +822,6 @@ class Issue < ActiveRecord::Base
end end
end end
# Callback on attachment deletion
def attachment_added(obj)
if @current_journal && !obj.new_record?
@current_journal.details << JournalDetail.new(:property => 'attachment', :prop_key => obj.id, :value => obj.filename)
end
end
# Callback on attachment deletion # Callback on attachment deletion
def attachment_removed(obj) def attachment_removed(obj)
journal = init_journal(User.current) journal = init_journal(User.current)
@@ -907,13 +870,10 @@ class Issue < ActiveRecord::Base
if @current_journal if @current_journal
# attributes changes # attributes changes
(Issue.column_names - %w(id root_id lft rgt lock_version created_on updated_on)).each {|c| (Issue.column_names - %w(id root_id lft rgt lock_version created_on updated_on)).each {|c|
before = @issue_before_change.send(c)
after = send(c)
next if before == after || (before.blank? && after.blank?)
@current_journal.details << JournalDetail.new(:property => 'attr', @current_journal.details << JournalDetail.new(:property => 'attr',
:prop_key => c, :prop_key => c,
:old_value => @issue_before_change.send(c), :old_value => @issue_before_change.send(c),
:value => send(c)) :value => send(c)) unless send(c)==@issue_before_change.send(c)
} }
# custom fields changes # custom fields changes
custom_values.each {|c| custom_values.each {|c|
+3 -8
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -16,19 +16,14 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class IssueCategory < ActiveRecord::Base class IssueCategory < ActiveRecord::Base
include Redmine::SafeAttributes
belongs_to :project belongs_to :project
belongs_to :assigned_to, :class_name => 'Principal', :foreign_key => 'assigned_to_id' belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id'
has_many :issues, :foreign_key => 'category_id', :dependent => :nullify has_many :issues, :foreign_key => 'category_id', :dependent => :nullify
validates_presence_of :name validates_presence_of :name
validates_uniqueness_of :name, :scope => [:project_id] validates_uniqueness_of :name, :scope => [:project_id]
validates_length_of :name, :maximum => 30 validates_length_of :name, :maximum => 30
safe_attributes 'name', 'assigned_to_id'
named_scope :named, lambda {|arg| { :conditions => ["LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip]}}
alias :destroy_without_reassign :destroy alias :destroy_without_reassign :destroy
# Destroy the category # Destroy the category
+2 -2
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+2 -2
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006-2007 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
+2 -2
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2011 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
Loaded 100 of 985 files, more files were not shown because too many files have changed in this diff. Show more