summaryrefslogtreecommitdiffstats
path: root/lib/redmine
diff options
context:
space:
mode:
Diffstat (limited to 'lib/redmine')
-rw-r--r--lib/redmine/ciphering.rb6
-rw-r--r--lib/redmine/core_ext/active_record.rb43
-rw-r--r--lib/redmine/core_ext/string.rb4
-rw-r--r--lib/redmine/hook.rb16
-rw-r--r--lib/redmine/plugin.rb137
-rw-r--r--lib/redmine/scm/adapters/cvs_adapter.rb4
-rw-r--r--lib/redmine/themes.rb8
-rw-r--r--lib/redmine/utils.rb6
-rw-r--r--lib/redmine/version.rb6
-rw-r--r--lib/redmine/views/api_template_handler.rb6
-rw-r--r--lib/redmine/views/builders/xml.rb4
-rw-r--r--lib/redmine/views/labelled_form_builder.rb4
-rw-r--r--lib/redmine/views/my_page/block.rb2
-rw-r--r--lib/redmine/wiki_formatting.rb7
14 files changed, 198 insertions, 55 deletions
diff --git a/lib/redmine/ciphering.rb b/lib/redmine/ciphering.rb
index 3dd5df826..186709016 100644
--- a/lib/redmine/ciphering.rb
+++ b/lib/redmine/ciphering.rb
@@ -72,7 +72,7 @@ module Redmine
all.each do |object|
clear = object.send(attribute)
object.send "#{attribute}=", clear
- raise(ActiveRecord::Rollback) unless object.save(false)
+ raise(ActiveRecord::Rollback) unless object.save(:validation => false)
end
end ? true : false
end
@@ -81,8 +81,8 @@ module Redmine
transaction do
all.each do |object|
clear = object.send(attribute)
- object.write_attribute attribute, clear
- raise(ActiveRecord::Rollback) unless object.save(false)
+ object.send :write_attribute, attribute, clear
+ raise(ActiveRecord::Rollback) unless object.save(:validation => false)
end
end
end ? true : false
diff --git a/lib/redmine/core_ext/active_record.rb b/lib/redmine/core_ext/active_record.rb
index f881f90a5..5f84e144f 100644
--- a/lib/redmine/core_ext/active_record.rb
+++ b/lib/redmine/core_ext/active_record.rb
@@ -16,38 +16,25 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module ActiveRecord
- class Base
- def self.find_ids(options={})
- find_ids_with_associations(options)
+ module FinderMethods
+ def find_ids(*args)
+ find_ids_with_associations
end
- end
- module Associations
- module ClassMethods
- def find_ids_with_associations(options = {})
- catch :invalid_query do
- join_dependency = ActiveRecord::Associations::ClassMethods::JoinDependency.new(self, merge_includes(scope(:find, :include), options[:include]), options[:joins])
- return connection.select_values(construct_ids_finder_sql_with_included_associations(options, join_dependency)).map(&:to_i)
- end
+ private
+
+ def find_ids_with_associations
+ join_dependency = construct_join_dependency_for_association_find
+ relation = construct_relation_for_association_find_ids(join_dependency)
+ rows = connection.select_all(relation, 'SQL', relation.bind_values)
+ rows.map {|row| row["id"].to_i}
+ rescue ThrowResult
[]
- end
-
- def construct_ids_finder_sql_with_included_associations(options, join_dependency)
- scope = scope(:find)
- sql = "SELECT #{table_name}.id FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} "
- sql << join_dependency.join_associations.collect{|join| join.association_join }.join
-
- add_joins!(sql, options[:joins], scope)
- add_conditions!(sql, options[:conditions], scope)
- add_limited_ids_condition!(sql, options, join_dependency) if !using_limitable_reflections?(join_dependency.reflections) && ((scope && scope[:limit]) || options[:limit])
-
- add_group!(sql, options[:group], options[:having], scope)
- add_order!(sql, options[:order], scope)
- add_limit!(sql, options, scope) if using_limitable_reflections?(join_dependency.reflections)
- add_lock!(sql, options, scope)
+ end
- return sanitize_sql(sql)
- end
+ def construct_relation_for_association_find_ids(join_dependency)
+ relation = except(:includes, :eager_load, :preload, :select).select("#{table_name}.id")
+ apply_join_dependency(relation, join_dependency)
end
end
end
diff --git a/lib/redmine/core_ext/string.rb b/lib/redmine/core_ext/string.rb
index 2da5ffef9..c865284ac 100644
--- a/lib/redmine/core_ext/string.rb
+++ b/lib/redmine/core_ext/string.rb
@@ -4,4 +4,8 @@ require File.dirname(__FILE__) + '/string/inflections'
class String #:nodoc:
include Redmine::CoreExtensions::String::Conversions
include Redmine::CoreExtensions::String::Inflections
+
+ def is_binary_data?
+ ( self.count( "^ -~", "^\r\n" ).fdiv(self.size) > 0.3 || self.index( "\x00" ) ) unless empty?
+ end
end
diff --git a/lib/redmine/hook.rb b/lib/redmine/hook.rb
index dba36a91a..f0a95f020 100644
--- a/lib/redmine/hook.rb
+++ b/lib/redmine/hook.rb
@@ -17,7 +17,7 @@
module Redmine
module Hook
- include ActionController::UrlWriter
+ #include ActionController::UrlWriter
@@listener_classes = []
@@listeners = nil
@@ -88,12 +88,12 @@ module Redmine
include ActionView::Helpers::FormTagHelper
include ActionView::Helpers::FormOptionsHelper
include ActionView::Helpers::JavaScriptHelper
- include ActionView::Helpers::PrototypeHelper
+ #include ActionView::Helpers::PrototypeHelper
include ActionView::Helpers::NumberHelper
include ActionView::Helpers::UrlHelper
include ActionView::Helpers::AssetTagHelper
include ActionView::Helpers::TextHelper
- include ActionController::UrlWriter
+ include Rails.application.routes.url_helpers
include ApplicationHelper
# Default to creating links using only the path. Subclasses can
@@ -113,6 +113,14 @@ module Redmine
context[:controller].send(:render_to_string, {:locals => context}.merge(options))
end
end
+
+ def controller
+ nil
+ end
+
+ def config
+ ActionController::Base.config
+ end
end
# Helper module included in ApplicationHelper and ActionController so that
@@ -143,7 +151,7 @@ module Redmine
default_context = { :project => @project }
default_context[:controller] = controller if respond_to?(:controller)
default_context[:request] = request if respond_to?(:request)
- Redmine::Hook.call_hook(hook, default_context.merge(context)).join(' ')
+ Redmine::Hook.call_hook(hook, default_context.merge(context)).join(' ').html_safe
end
end
end
diff --git a/lib/redmine/plugin.rb b/lib/redmine/plugin.rb
index 5c13e3d1f..1f57c4d0c 100644
--- a/lib/redmine/plugin.rb
+++ b/lib/redmine/plugin.rb
@@ -43,6 +43,9 @@ module Redmine #:nodoc:
#
# When rendered, the plugin settings value is available as the local variable +settings+
class Plugin
+ cattr_accessor :directory
+ self.directory = File.join(Rails.root, 'plugins')
+
cattr_accessor :public_directory
self.public_directory = File.join(Rails.root, 'public', 'plugin_assets')
@@ -70,9 +73,22 @@ module Redmine #:nodoc:
p.instance_eval(&block)
# Set a default name if it was not provided during registration
p.name(id.to_s.humanize) if p.name.nil?
+
# Adds plugin locales if any
# YAML translation files should be found under <plugin>/config/locales/
- ::I18n.load_path += Dir.glob(File.join(Rails.root, 'vendor', 'plugins', id.to_s, 'config', 'locales', '*.yml'))
+ ::I18n.load_path += Dir.glob(File.join(p.directory, 'config', 'locales', '*.yml'))
+
+ # Prepends the app/views directory of the plugin to the view path
+ view_path = File.join(p.directory, 'app', 'views')
+ if File.directory?(view_path)
+ ActionController::Base.prepend_view_path(view_path)
+ end
+
+ # Adds the app/{controllers,helpers,models} directories of the plugin to the autoload path
+ Dir.glob File.expand_path(File.join(p.directory, 'app', '{controllers,helpers,models}')) do |dir|
+ ActiveSupport::Dependencies.autoload_paths += [dir]
+ end
+
registered_plugins[id] = p
end
@@ -100,10 +116,38 @@ module Redmine #:nodoc:
registered_plugins[id.to_sym].present?
end
+ def self.load
+ Dir.glob(File.join(self.directory, '*')).sort.each do |directory|
+ if File.directory?(directory)
+ lib = File.join(directory, "lib")
+ if File.directory?(lib)
+ $:.unshift lib
+ ActiveSupport::Dependencies.autoload_paths += [lib]
+ end
+ initializer = File.join(directory, "init.rb")
+ if File.file?(initializer)
+ require initializer
+ end
+ end
+ end
+ end
+
def initialize(id)
@id = id.to_sym
end
+ def directory
+ File.join(self.class.directory, id.to_s)
+ end
+
+ def public_directory
+ File.join(self.class.public_directory, id.to_s)
+ end
+
+ def assets_directory
+ File.join(directory, 'assets')
+ end
+
def <=>(plugin)
self.id.to_s <=> plugin.id.to_s
end
@@ -277,5 +321,96 @@ module Redmine #:nodoc:
def configurable?
settings && settings.is_a?(Hash) && !settings[:partial].blank?
end
+
+ def mirror_assets
+ source = assets_directory
+ destination = public_directory
+ return unless File.directory?(source)
+
+ source_files = Dir[source + "/**/*"]
+ source_dirs = source_files.select { |d| File.directory?(d) }
+ source_files -= source_dirs
+
+ unless source_files.empty?
+ base_target_dir = File.join(destination, File.dirname(source_files.first).gsub(source, ''))
+ FileUtils.mkdir_p(base_target_dir)
+ end
+
+ source_dirs.each do |dir|
+ # strip down these paths so we have simple, relative paths we can
+ # add to the destination
+ target_dir = File.join(destination, dir.gsub(source, ''))
+ begin
+ FileUtils.mkdir_p(target_dir)
+ rescue Exception => e
+ raise "Could not create directory #{target_dir}: \n" + e
+ end
+ end
+
+ source_files.each do |file|
+ begin
+ target = File.join(destination, file.gsub(source, ''))
+ unless File.exist?(target) && FileUtils.identical?(file, target)
+ FileUtils.cp(file, target)
+ end
+ rescue Exception => e
+ raise "Could not copy #{file} to #{target}: \n" + e
+ end
+ end
+ end
+
+ # The directory containing this plugin's migrations (<tt>plugin/db/migrate</tt>)
+ def migration_directory
+ File.join(Rails.root, 'plugins', id.to_s, 'db', 'migrate')
+ end
+
+ # Returns the version number of the latest migration for this plugin. Returns
+ # nil if this plugin has no migrations.
+ def latest_migration
+ migrations.last
+ end
+
+ # Returns the version numbers of all migrations for this plugin.
+ def migrations
+ migrations = Dir[migration_directory+"/*.rb"]
+ migrations.map { |p| File.basename(p).match(/0*(\d+)\_/)[1].to_i }.sort
+ end
+
+ # Migrate this plugin to the given version
+ def migrate(version = nil)
+ Redmine::Plugin::Migrator.migrate_plugin(self, version)
+ end
+
+ class Migrator < ActiveRecord::Migrator
+ # We need to be able to set the 'current' plugin being migrated.
+ cattr_accessor :current_plugin
+
+ class << self
+ # Runs the migrations from a plugin, up (or down) to the version given
+ def migrate_plugin(plugin, version)
+ self.current_plugin = plugin
+ return if current_version(plugin) == version
+ migrate(plugin.migration_directory, version)
+ end
+
+ def current_version(plugin=current_plugin)
+ # Delete migrations that don't match .. to_i will work because the number comes first
+ ::ActiveRecord::Base.connection.select_values(
+ "SELECT version FROM #{schema_migrations_table_name}"
+ ).delete_if{ |v| v.match(/-#{plugin.id}/) == nil }.map(&:to_i).max || 0
+ end
+ end
+
+ def migrated
+ sm_table = self.class.schema_migrations_table_name
+ ::ActiveRecord::Base.connection.select_values(
+ "SELECT version FROM #{sm_table}"
+ ).delete_if{ |v| v.match(/-#{current_plugin.id}/) == nil }.map(&:to_i).sort
+ end
+
+ def record_version_state_after_migrating(version)
+ super(version.to_s + "-" + current_plugin.id.to_s)
+ end
+ end
end
end
diff --git a/lib/redmine/scm/adapters/cvs_adapter.rb b/lib/redmine/scm/adapters/cvs_adapter.rb
index 9bcee71a6..3a0d27c34 100644
--- a/lib/redmine/scm/adapters/cvs_adapter.rb
+++ b/lib/redmine/scm/adapters/cvs_adapter.rb
@@ -222,8 +222,8 @@ module Redmine
:author => author,
:message => commit_log.chomp,
:paths => [{
- :revision => revision,
- :branch => revBranch,
+ :revision => revision.dup,
+ :branch => revBranch.dup,
:path => scm_iconv('UTF-8', @path_encoding, entry_path),
:name => scm_iconv('UTF-8', @path_encoding, entry_name),
:kind => 'file',
diff --git a/lib/redmine/themes.rb b/lib/redmine/themes.rb
index 71d237e67..51b974fd7 100644
--- a/lib/redmine/themes.rb
+++ b/lib/redmine/themes.rb
@@ -118,6 +118,14 @@ module ApplicationHelper
stylesheet_path source
end
+ def stylesheet_link_tag(source, *args)
+ if current_theme && current_theme.stylesheets.include?(source)
+ super current_theme.stylesheet_path(source), *args
+ else
+ super
+ end
+ end
+
# Returns the header tags for the current theme
def heads_for_theme
if current_theme && current_theme.javascripts.include?('theme')
diff --git a/lib/redmine/utils.rb b/lib/redmine/utils.rb
index 96580168f..b04bbaa47 100644
--- a/lib/redmine/utils.rb
+++ b/lib/redmine/utils.rb
@@ -22,7 +22,7 @@ module Redmine
def relative_url_root
ActionController::Base.respond_to?('relative_url_root') ?
ActionController::Base.relative_url_root.to_s :
- ActionController::AbstractRequest.relative_url_root.to_s
+ ActionController::Base.config.relative_url_root.to_s
end
# Sets the relative root url of the application
@@ -30,7 +30,7 @@ module Redmine
if ActionController::Base.respond_to?('relative_url_root=')
ActionController::Base.relative_url_root=arg
else
- ActionController::AbstractRequest.relative_url_root=arg
+ ActionController::Base.config.relative_url_root = arg
end
end
@@ -38,7 +38,7 @@ module Redmine
# Example:
# random_hex(4) # => "89b8c729"
def random_hex(n)
- ActiveSupport::SecureRandom.hex(n)
+ SecureRandom.hex(n)
end
end
end
diff --git a/lib/redmine/version.rb b/lib/redmine/version.rb
index 45c405988..c473160db 100644
--- a/lib/redmine/version.rb
+++ b/lib/redmine/version.rb
@@ -2,9 +2,9 @@ require 'rexml/document'
module Redmine
module VERSION #:nodoc:
- MAJOR = 1
- MINOR = 4
- TINY = 1
+ MAJOR = 2
+ MINOR = 0
+ TINY = 0
# Branch values:
# * official release: nil
diff --git a/lib/redmine/views/api_template_handler.rb b/lib/redmine/views/api_template_handler.rb
index f603c433c..298a20d0b 100644
--- a/lib/redmine/views/api_template_handler.rb
+++ b/lib/redmine/views/api_template_handler.rb
@@ -17,10 +17,8 @@
module Redmine
module Views
- class ApiTemplateHandler < ActionView::TemplateHandler
- include ActionView::TemplateHandlers::Compilable
-
- def compile(template)
+ class ApiTemplateHandler
+ def self.call(template)
"Redmine::Views::Builders.for(params[:format]) do |api|; #{template.source}; self.output_buffer = api.output; end"
end
end
diff --git a/lib/redmine/views/builders/xml.rb b/lib/redmine/views/builders/xml.rb
index 5814d00cb..dc2707d66 100644
--- a/lib/redmine/views/builders/xml.rb
+++ b/lib/redmine/views/builders/xml.rb
@@ -15,6 +15,8 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+require 'builder'
+
module Redmine
module Views
module Builders
@@ -29,7 +31,7 @@ module Redmine
end
def method_missing(sym, *args, &block)
- if args.size == 1 && args.first.is_a?(Time)
+ if args.size == 1 && args.first.is_a?(::Time)
__send__ sym, args.first.xmlschema, &block
else
super
diff --git a/lib/redmine/views/labelled_form_builder.rb b/lib/redmine/views/labelled_form_builder.rb
index 857ac066a..bdf5ffb11 100644
--- a/lib/redmine/views/labelled_form_builder.rb
+++ b/lib/redmine/views/labelled_form_builder.rb
@@ -24,14 +24,14 @@ class Redmine::Views::LabelledFormBuilder < ActionView::Helpers::FormBuilder
%w(date_select)).each do |selector|
src = <<-END_SRC
def #{selector}(field, options = {})
- label_for_field(field, options) + super(field, options.except(:label))
+ label_for_field(field, options) + super(field, options.except(:label)).html_safe
end
END_SRC
class_eval src, __FILE__, __LINE__
end
def select(field, choices, options = {}, html_options = {})
- label_for_field(field, options) + super(field, choices, options, html_options.except(:label))
+ label_for_field(field, options) + super(field, choices, options, html_options.except(:label)).html_safe
end
# Returns a label tag for the given field
diff --git a/lib/redmine/views/my_page/block.rb b/lib/redmine/views/my_page/block.rb
index 06f532dde..793686755 100644
--- a/lib/redmine/views/my_page/block.rb
+++ b/lib/redmine/views/my_page/block.rb
@@ -20,7 +20,7 @@ module Redmine
module MyPage
module Block
def self.additional_blocks
- @@additional_blocks ||= Dir.glob("#{Rails.root}/vendor/plugins/*/app/views/my/blocks/_*.{rhtml,erb}").inject({}) do |h,file|
+ @@additional_blocks ||= Dir.glob("#{Redmine::Plugin.directory}/*/app/views/my/blocks/_*.{rhtml,erb}").inject({}) do |h,file|
name = File.basename(file).split('.').first.gsub(/^_/, '')
h[name] = name.to_sym
h
diff --git a/lib/redmine/wiki_formatting.rb b/lib/redmine/wiki_formatting.rb
index 63914e8ce..f1d8378f5 100644
--- a/lib/redmine/wiki_formatting.rb
+++ b/lib/redmine/wiki_formatting.rb
@@ -115,8 +115,9 @@ module Redmine
url=url[0..-2] # discard closing parenth from url
post = ")"+post # add closing parenth to post
end
- tag = content_tag('a', proto + url, :href => "#{proto=="www."?"http://www.":proto}#{url}", :class => 'external')
- %(#{leading}#{tag}#{post})
+ content = proto + url
+ href = "#{proto=="www."?"http://www.":proto}#{url}"
+ %(#{leading}<a class="external" href="#{ERB::Util.html_escape href}">#{ERB::Util.html_escape content}</a>#{post}).html_safe
end
end
end
@@ -128,7 +129,7 @@ module Redmine
if text.match(/<a\b[^>]*>(.*)(#{Regexp.escape(mail)})(.*)<\/a>/)
mail
else
- content_tag('a', mail, :href => "mailto:#{mail}", :class => "email")
+ %(<a class="email" href="mailto:#{ERB::Util.html_escape mail}">#{ERB::Util.html_escape mail}</a>).html_safe
end
end
end