Redmine 4.1.1
This commit is contained in:
parent
33e7b881a5
commit
3d976f1b3b
1593 changed files with 36180 additions and 19489 deletions
|
@ -1,5 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2017 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2019 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
@ -15,9 +17,12 @@
|
|||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
module Redmine #:nodoc:
|
||||
module Redmine
|
||||
|
||||
# Exception raised when a plugin cannot be found given its id.
|
||||
class PluginNotFound < StandardError; end
|
||||
|
||||
# Exception raised when a plugin requirement is not met.
|
||||
class PluginRequirementError < StandardError; end
|
||||
|
||||
# Base class for Redmine plugins.
|
||||
|
@ -42,10 +47,14 @@ module Redmine #:nodoc:
|
|||
# In this example, the settings partial will be found here in the plugin directory: <tt>app/views/settings/_settings.rhtml</tt>.
|
||||
#
|
||||
# When rendered, the plugin settings value is available as the local variable +settings+
|
||||
#
|
||||
# See: http://www.redmine.org/projects/redmine/wiki/Plugin_Tutorial
|
||||
class Plugin
|
||||
# Absolute path to the directory where plugins are located
|
||||
cattr_accessor :directory
|
||||
self.directory = File.join(Rails.root, 'plugins')
|
||||
|
||||
# Absolute path to the plublic directory where plugins assets are copied
|
||||
cattr_accessor :public_directory
|
||||
self.public_directory = File.join(Rails.root, 'public', 'plugin_assets')
|
||||
|
||||
|
@ -69,7 +78,17 @@ module Redmine #:nodoc:
|
|||
def_field :name, :description, :url, :author, :author_url, :version, :settings, :directory
|
||||
attr_reader :id
|
||||
|
||||
# Plugin constructor
|
||||
# Plugin constructor: instanciates a new Redmine::Plugin with given +id+
|
||||
# and make it evaluate the given +block+
|
||||
#
|
||||
# Example
|
||||
# Redmine::Plugin.register :example do
|
||||
# name 'Example plugin'
|
||||
# author 'John Smith'
|
||||
# description 'This is an example plugin for Redmine'
|
||||
# version '0.0.1'
|
||||
# requires_redmine version_or_higher: '3.0.0'
|
||||
# end
|
||||
def self.register(id, &block)
|
||||
p = new(id)
|
||||
p.instance_eval(&block)
|
||||
|
@ -79,6 +98,10 @@ module Redmine #:nodoc:
|
|||
# Set a default directory if it was not provided during registration
|
||||
p.directory(File.join(self.directory, id.to_s)) if p.directory.nil?
|
||||
|
||||
unless File.directory?(p.directory)
|
||||
raise PluginNotFound, "Plugin not found. The directory for plugin #{p.id} should be #{p.directory}."
|
||||
end
|
||||
|
||||
# Adds plugin locales if any
|
||||
# YAML translation files should be found under <plugin>/config/locales/
|
||||
Rails.application.config.i18n.load_path += Dir.glob(File.join(p.directory, 'config', 'locales', '*.yml'))
|
||||
|
@ -90,10 +113,13 @@ module Redmine #:nodoc:
|
|||
ActionMailer::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
|
||||
# Add the plugin directories to rails autoload paths
|
||||
engine_cfg = Rails::Engine::Configuration.new(p.directory)
|
||||
engine_cfg.paths.add 'lib', eager_load: true
|
||||
Rails.application.config.eager_load_paths += engine_cfg.eager_load_paths
|
||||
Rails.application.config.autoload_once_paths += engine_cfg.autoload_once_paths
|
||||
Rails.application.config.autoload_paths += engine_cfg.autoload_paths
|
||||
ActiveSupport::Dependencies.autoload_paths += engine_cfg.eager_load_paths + engine_cfg.autoload_once_paths + engine_cfg.autoload_paths
|
||||
|
||||
# Defines plugin setting if present
|
||||
if p.settings
|
||||
|
@ -170,6 +196,7 @@ module Redmine #:nodoc:
|
|||
id
|
||||
end
|
||||
|
||||
# Returns the absolute path to the plugin assets directory
|
||||
def assets_directory
|
||||
File.join(directory, 'assets')
|
||||
end
|
||||
|
@ -248,7 +275,11 @@ module Redmine #:nodoc:
|
|||
arg = { :version_or_higher => arg } unless arg.is_a?(Hash)
|
||||
arg.assert_valid_keys(:version, :version_or_higher)
|
||||
|
||||
plugin = Plugin.find(plugin_name)
|
||||
begin
|
||||
plugin = Plugin.find(plugin_name)
|
||||
rescue PluginNotFound
|
||||
raise PluginRequirementError.new("#{id} plugin requires the #{plugin_name} plugin")
|
||||
end
|
||||
current = plugin.version.split('.').collect(&:to_i)
|
||||
|
||||
arg.each do |k, v|
|
||||
|
@ -311,7 +342,7 @@ module Redmine #:nodoc:
|
|||
# permission :say_hello, { :example => :say_hello }, :require => :member
|
||||
def permission(name, actions, options = {})
|
||||
if @project_module
|
||||
Redmine::AccessControl.map {|map| map.project_module(@project_module) {|map|map.permission(name, actions, options)}}
|
||||
Redmine::AccessControl.map {|map| map.project_module(@project_module) {|map| map.permission(name, actions, options)}}
|
||||
else
|
||||
Redmine::AccessControl.map {|map| map.permission(name, actions, options)}
|
||||
end
|
||||
|
@ -367,7 +398,7 @@ module Redmine #:nodoc:
|
|||
# * :label - label for the formatter displayed in application settings
|
||||
#
|
||||
# Examples:
|
||||
# wiki_format_provider(:custom_formatter, CustomFormatter, :label => "My custom formatter")
|
||||
# wiki_format_provider(:custom_formatter, CustomFormatter, :label => "My custom formatter")
|
||||
#
|
||||
def wiki_format_provider(name, *args)
|
||||
Redmine::WikiFormatting.register(name, *args)
|
||||
|
@ -391,7 +422,7 @@ module Redmine #:nodoc:
|
|||
base_target_dir = File.join(destination, File.dirname(source_files.first).gsub(source, ''))
|
||||
begin
|
||||
FileUtils.mkdir_p(base_target_dir)
|
||||
rescue Exception => e
|
||||
rescue => e
|
||||
raise "Could not create directory #{base_target_dir}: " + e.message
|
||||
end
|
||||
end
|
||||
|
@ -402,7 +433,7 @@ module Redmine #:nodoc:
|
|||
target_dir = File.join(destination, dir.gsub(source, ''))
|
||||
begin
|
||||
FileUtils.mkdir_p(target_dir)
|
||||
rescue Exception => e
|
||||
rescue => e
|
||||
raise "Could not create directory #{target_dir}: " + e.message
|
||||
end
|
||||
end
|
||||
|
@ -413,7 +444,7 @@ module Redmine #:nodoc:
|
|||
unless File.exist?(target) && FileUtils.identical?(file, target)
|
||||
FileUtils.cp(file, target)
|
||||
end
|
||||
rescue Exception => e
|
||||
rescue => e
|
||||
raise "Could not copy #{file} to #{target}: " + e.message
|
||||
end
|
||||
end
|
||||
|
@ -449,7 +480,6 @@ module Redmine #:nodoc:
|
|||
|
||||
# Migrate this plugin to the given version
|
||||
def migrate(version = nil)
|
||||
puts "Migrating #{id} (#{name})..."
|
||||
Redmine::Plugin::Migrator.migrate_plugin(self, version)
|
||||
end
|
||||
|
||||
|
@ -469,6 +499,36 @@ module Redmine #:nodoc:
|
|||
end
|
||||
end
|
||||
|
||||
class MigrationContext < ActiveRecord::MigrationContext
|
||||
def up(target_version = nil)
|
||||
selected_migrations =
|
||||
if block_given?
|
||||
migrations.select { |m| yield m }
|
||||
else
|
||||
migrations
|
||||
end
|
||||
Migrator.new(:up, selected_migrations, target_version).migrate
|
||||
end
|
||||
|
||||
def down(target_version = nil)
|
||||
selected_migrations =
|
||||
if block_given?
|
||||
migrations.select { |m| yield m }
|
||||
else
|
||||
migrations
|
||||
end
|
||||
Migrator.new(:down, selected_migrations, target_version).migrate
|
||||
end
|
||||
|
||||
def run(direction, target_version)
|
||||
Migrator.new(direction, migrations, target_version).run
|
||||
end
|
||||
|
||||
def open
|
||||
Migrator.new(:up, migrations, nil)
|
||||
end
|
||||
end
|
||||
|
||||
class Migrator < ActiveRecord::Migrator
|
||||
# We need to be able to set the 'current' plugin being migrated.
|
||||
cattr_accessor :current_plugin
|
||||
|
@ -478,22 +538,29 @@ module Redmine #:nodoc:
|
|||
def migrate_plugin(plugin, version)
|
||||
self.current_plugin = plugin
|
||||
return if current_version(plugin) == version
|
||||
migrate(plugin.migration_directory, version)
|
||||
|
||||
MigrationContext.new(plugin.migration_directory).migrate(version)
|
||||
end
|
||||
|
||||
def current_version(plugin=current_plugin)
|
||||
def get_all_versions(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
|
||||
@all_versions ||= {}
|
||||
@all_versions[plugin.id.to_s] ||= begin
|
||||
sm_table = ::ActiveRecord::SchemaMigration.table_name
|
||||
migration_versions = ActiveRecord::Base.connection.select_values("SELECT version FROM #{sm_table}")
|
||||
versions_by_plugins = migration_versions.group_by { |version| version.match(/-(.*)$/).try(:[], 1) }
|
||||
@all_versions = versions_by_plugins.transform_values! {|versions| versions.map!(&:to_i).sort! }
|
||||
@all_versions[plugin.id.to_s] || []
|
||||
end
|
||||
end
|
||||
|
||||
def current_version(plugin = current_plugin)
|
||||
get_all_versions(plugin).last || 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
|
||||
def load_migrated
|
||||
@migrated_versions = Set.new(self.class.get_all_versions(current_plugin))
|
||||
end
|
||||
|
||||
def record_version_state_after_migrating(version)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue