redmineup 1.0.10 → 1.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.gitlab-ci.yml +33 -0
- data/README.md +74 -153
- data/app/assets/javascripts/consumer.js +53 -0
- data/app/assets/javascripts/consumer_worker.js +219 -0
- data/app/assets/javascripts/jquery.colorPicker.min.js +26 -0
- data/app/assets/javascripts/select2_helpers.js +10 -0
- data/app/assets/stylesheets/redmineup.css +509 -0
- data/app/views/redmineup/_additional_assets.html.erb +1 -0
- data/config/locales/en.yml +1 -0
- data/config/locales/ru.yml +1 -0
- data/config/routes.rb +4 -0
- data/doc/CHANGELOG +99 -16
- data/doc/active-record-mixins.md +156 -0
- data/doc/assets-money-and-utilities.md +71 -0
- data/doc/tagging-and-select2.md +108 -0
- data/lib/action_cable/connection/rup_connection.rb +17 -0
- data/lib/action_cable/server/rup_configuration.rb +17 -0
- data/lib/action_cable/server/rup_server.rb +17 -0
- data/lib/redmineup/acts_as_taggable/tag.rb +26 -2
- data/lib/redmineup/acts_as_taggable/up_acts_as_taggable.rb +42 -2
- data/lib/redmineup/acts_as_viewed/up_acts_as_viewed.rb +1 -1
- data/lib/redmineup/engine.rb +12 -2
- data/lib/redmineup/helpers/datetime_helper.rb +23 -0
- data/lib/redmineup/helpers/external_assets_helper.rb +14 -6
- data/lib/redmineup/helpers/form_tag_helper.rb +43 -0
- data/lib/redmineup/helpers/tags_helper.rb +41 -0
- data/lib/redmineup/helpers/test_helper.rb +12 -0
- data/lib/redmineup/hooks/views_layouts_hook.rb +1 -4
- data/lib/redmineup/liquid/drops/version_drop.rb +0 -2
- data/lib/redmineup/money_helper.rb +10 -2
- data/lib/redmineup/patches/action_cable_base_patch.rb +25 -0
- data/lib/redmineup/patches/action_cable_patch.rb +19 -0
- data/lib/redmineup/patches/auto_completes_controller_patch.rb +17 -0
- data/lib/redmineup/patches/compatibility/routing_mapper_patch.rb +5 -18
- data/lib/redmineup/patches/compatibility/sprite_patch.rb +3 -11
- data/lib/redmineup/patches/compatibility_patch.rb +0 -6
- data/lib/redmineup/patches/liquid_patch.rb +13 -22
- data/lib/redmineup/version.rb +1 -1
- data/lib/redmineup.rb +47 -42
- data/test/acts_as_taggable/tag_test.rb +16 -0
- data/test/acts_as_votable/votable_test.rb +9 -9
- data/test/acts_as_votable/voter_test.rb +4 -4
- data/test/database.yml +3 -3
- data/test/fixtures/tags.yml +2 -0
- data/test/liquid/filters/additional_filter_test.rb +5 -1
- data/test/liquid/filters/arrays_filter_test.rb +6 -3
- data/test/schema.rb +6 -1
- data/test/tags_helper_view_test.rb +41 -0
- data/test/test_helper.rb +13 -12
- metadata +21 -5
- data/bitbucket-pipelines.yml +0 -50
- data/lib/redmineup/patches/compatibility/application_controller_patch.rb +0 -32
- data/lib/redmineup/patches/compatibility/user_patch.rb +0 -21
|
@@ -9,5 +9,46 @@ module Redmineup
|
|
|
9
9
|
yield tag, classes[index]
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
|
+
|
|
13
|
+
def tag_link(url, tag_name, options = {})
|
|
14
|
+
count = options.delete(:count)
|
|
15
|
+
inner = link_to(tag_name, url, options)
|
|
16
|
+
inner << content_tag('span', "(#{count})", class: 'tag-count') if count
|
|
17
|
+
css = monochrome? ? 'tag-label' : 'tag-label-color'
|
|
18
|
+
style = monochrome? ? {} : { style: "background-color: #{Redmineup::ActsAsTaggable::Tag.color_from_name(tag_name)}" }
|
|
19
|
+
content_tag(:span, inner, { class: css }.merge(style))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def tag_separator
|
|
23
|
+
monochrome? ? ', ' : ' '
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def monochrome?
|
|
27
|
+
@monochrome ||= defined?(RedmineupTags) && !RedmineupTags.use_colors?
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def tag_links(tag_list, options = {}, &url_block)
|
|
31
|
+
return if tag_list.blank?
|
|
32
|
+
content_tag(:span, class: 'tag_list') do
|
|
33
|
+
safe_join(tag_list.map { |tag| tag_link(url_block.call(tag), tag, options.dup) }, tag_separator)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Renders span.tag_list from an array of tag objects (respond to .name and .count).
|
|
38
|
+
# Resolves URL via `{key}_tag_url(name)` in the current view context.
|
|
39
|
+
#
|
|
40
|
+
# tag_cloud_links(contact.available_tags, :contact) # → contact_tag_url(name)
|
|
41
|
+
# tag_cloud_links(tags_cloud, :people) # → people_tag_url(name)
|
|
42
|
+
def tag_cloud_links(tags, key, options = {})
|
|
43
|
+
return if tags.blank?
|
|
44
|
+
url_method = :"#{key}_tag_url"
|
|
45
|
+
raise NoMethodError, "#{url_method} is not defined in view context" unless respond_to?(url_method, true)
|
|
46
|
+
content_tag(:span, class: 'tag_list') do
|
|
47
|
+
safe_join(tags.map { |tag|
|
|
48
|
+
tag_link(send(url_method, tag.name), tag.name, options.merge(count: tag.count).dup)
|
|
49
|
+
}, tag_separator)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
12
53
|
end
|
|
13
54
|
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module Redmineup
|
|
2
|
+
module TestHelper
|
|
3
|
+
module ClassMethods
|
|
4
|
+
def load_plugin_fixtures(plugin_name, *names)
|
|
5
|
+
fixtures_dir = File.join(Redmine::Plugin.find(plugin_name).directory, 'test', 'fixtures')
|
|
6
|
+
ActiveRecord::FixtureSet.create_fixtures(fixtures_dir, names)
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
ActiveSupport::TestCase.extend Redmineup::TestHelper::ClassMethods
|
|
@@ -3,10 +3,7 @@
|
|
|
3
3
|
module Redmineup
|
|
4
4
|
module Hooks
|
|
5
5
|
class ViewsLayoutsHook < Redmine::Hook::ViewListener
|
|
6
|
-
|
|
7
|
-
stylesheet_link_tag(:calendars, plugin: 'redmineup') +
|
|
8
|
-
stylesheet_link_tag(:money, plugin: 'redmineup')
|
|
9
|
-
end
|
|
6
|
+
render_on :view_layouts_base_html_head, partial: 'redmineup/additional_assets'
|
|
10
7
|
end
|
|
11
8
|
end
|
|
12
9
|
end
|
|
@@ -11,7 +11,6 @@ module Redmineup
|
|
|
11
11
|
:sharing,
|
|
12
12
|
:default_project_version,
|
|
13
13
|
:start_date,
|
|
14
|
-
:due_date,
|
|
15
14
|
:estimated_hours,
|
|
16
15
|
:spent_hours,
|
|
17
16
|
:closed?,
|
|
@@ -28,7 +27,6 @@ module Redmineup
|
|
|
28
27
|
:to_s_with_project,
|
|
29
28
|
:shared?,
|
|
30
29
|
:deletable?,
|
|
31
|
-
:default_project_version,
|
|
32
30
|
:to_s,
|
|
33
31
|
to: :@version
|
|
34
32
|
|
|
@@ -8,11 +8,19 @@ module Redmineup
|
|
|
8
8
|
price_to_currency(obj.try(price_field), obj.currency, options).to_s if obj.respond_to?(:currency)
|
|
9
9
|
end
|
|
10
10
|
|
|
11
|
-
def
|
|
11
|
+
def prices_formatted_collection(prices_collection, options = {})
|
|
12
12
|
return [] if prices_collection.blank? || prices_collection == 0
|
|
13
13
|
prices = prices_collection
|
|
14
14
|
prices.reject!{|k, v| v.to_i == 0} if options[:hide_zeros]
|
|
15
|
-
prices.
|
|
15
|
+
prices.map { |k, v| price_to_currency(v, k, symbol: true) }.compact
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def prices_collection_by_currency(prices_collection, options = {})
|
|
19
|
+
formatted_prices = prices_formatted_collection(prices_collection, options)
|
|
20
|
+
|
|
21
|
+
formatted_prices.map do |formatted_price|
|
|
22
|
+
content_tag(:span, formatted_price, :style => "white-space: nowrap;")
|
|
23
|
+
end
|
|
16
24
|
end
|
|
17
25
|
|
|
18
26
|
def deal_currency_icon(currency)
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Redmineup
|
|
2
|
+
module Patches
|
|
3
|
+
module ActionCableBasePatch
|
|
4
|
+
def self.prepended(base)
|
|
5
|
+
base.extend(ClassMethods)
|
|
6
|
+
base.delegate :rup_broadcast_to, to: :class
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
module ClassMethods
|
|
10
|
+
def rup_broadcast_to(*args)
|
|
11
|
+
# TODO: Remove to 2 args after plugins update
|
|
12
|
+
if args.length == 3
|
|
13
|
+
klass, model, message = args
|
|
14
|
+
ActionCable.rup_server(klass).broadcast(broadcasting_for(model), message)
|
|
15
|
+
else
|
|
16
|
+
model, message = args
|
|
17
|
+
ActionCable.rup_server.broadcast(broadcasting_for(model), message)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
ActionCable::Channel::Base.prepend(Redmineup::Patches::ActionCableBasePatch)
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Redmineup
|
|
2
|
+
module Patches
|
|
3
|
+
module ActionCablePatch
|
|
4
|
+
def self.prepended(base)
|
|
5
|
+
base.class_eval do
|
|
6
|
+
module_function def rup_server(klass = 'ActionCable::Connection::RupConnection')
|
|
7
|
+
@rup_servers ||= {}
|
|
8
|
+
return @rup_servers[klass] if @rup_servers[klass]
|
|
9
|
+
|
|
10
|
+
config = ActionCable::Server::RupConfiguration.new(connection_klass: klass)
|
|
11
|
+
@rup_servers[klass] = ActionCable::Server::RupServer.new(config: config)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
ActionCable.prepend(Redmineup::Patches::ActionCablePatch)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Redmineup
|
|
2
|
+
module Patches
|
|
3
|
+
module AutoCompletesControllerPatch
|
|
4
|
+
DEFAULT_TAGS_LIMIT = 10
|
|
5
|
+
|
|
6
|
+
def taggable_tags
|
|
7
|
+
limit = params.delete(:limit) || DEFAULT_TAGS_LIMIT
|
|
8
|
+
klass = Object.const_get(params[:taggable_type].camelcase) if params[:taggable_type].present?
|
|
9
|
+
|
|
10
|
+
tags = klass && klass.available_tags(params.merge(limit: limit, name_like: params[:q])) || Redmineup::ActsAsTaggable::Tag.limit(limit)
|
|
11
|
+
render json: tags.map { |tag| { id: tag.name, text: tag.name } }
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
AutoCompletesController.prepend(Redmineup::Patches::AutoCompletesControllerPatch)
|
|
@@ -2,28 +2,15 @@ module Redmineup
|
|
|
2
2
|
module Patches
|
|
3
3
|
module Compatibility
|
|
4
4
|
module RoutingMapperPatch
|
|
5
|
-
def
|
|
6
|
-
|
|
5
|
+
def constraints(options = {}, &block)
|
|
6
|
+
return super(options, &block) unless options.is_a?(Hash)
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
alias_method :constraints, :constraints_with_redmineup
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
module InstanceMethods
|
|
15
|
-
def constraints_with_redmineup(options = {}, &block)
|
|
16
|
-
return constraints_without_redmineup(options, &block) unless options.is_a?(Hash)
|
|
17
|
-
|
|
18
|
-
options[:object_type] = /.+/ if options[:object_type] && options[:object_type].is_a?(Regexp)
|
|
19
|
-
constraints_without_redmineup(options, &block)
|
|
20
|
-
end
|
|
8
|
+
options[:object_type] = /.+/ if options[:object_type] && options[:object_type].is_a?(Regexp)
|
|
9
|
+
super(options, &block)
|
|
21
10
|
end
|
|
22
11
|
end
|
|
23
12
|
end
|
|
24
13
|
end
|
|
25
14
|
end
|
|
26
15
|
|
|
27
|
-
|
|
28
|
-
ActionDispatch::Routing::Mapper.send(:include, Redmineup::Patches::Compatibility::RoutingMapperPatch)
|
|
29
|
-
end
|
|
16
|
+
ActionDispatch::Routing::Mapper.prepend(Redmineup::Patches::Compatibility::RoutingMapperPatch)
|
|
@@ -2,20 +2,12 @@ module Redmineup
|
|
|
2
2
|
module Patches
|
|
3
3
|
module Compatibility
|
|
4
4
|
module SpritePatch
|
|
5
|
-
def
|
|
6
|
-
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
module InstanceMethods
|
|
10
|
-
def sprite_icon(icon_name, label = nil, icon_only: false, size: '18', css_class: nil, sprite: "icons", plugin: nil)
|
|
11
|
-
label
|
|
12
|
-
end
|
|
5
|
+
def sprite_icon(icon_name, label = '', icon_only: false, size: '18', css_class: nil, sprite: "icons", plugin: nil, rtl: false)
|
|
6
|
+
label
|
|
13
7
|
end
|
|
14
8
|
end
|
|
15
9
|
end
|
|
16
10
|
end
|
|
17
11
|
end
|
|
18
12
|
|
|
19
|
-
|
|
20
|
-
ActionView::Base.send(:include, Redmineup::Patches::Compatibility::SpritePatch)
|
|
21
|
-
end
|
|
13
|
+
ApplicationHelper.prepend(Redmineup::Patches::Compatibility::SpritePatch)
|
|
@@ -1,9 +1,3 @@
|
|
|
1
|
-
if Redmine::VERSION.to_s < "4"
|
|
2
|
-
require 'redmineup/patches/compatibility/application_controller_patch'
|
|
3
|
-
end
|
|
4
|
-
if Redmine::VERSION.to_s < "5"
|
|
5
|
-
require 'redmineup/patches/compatibility/user_patch'
|
|
6
|
-
end
|
|
7
1
|
if Redmine::VERSION.to_s < "6"
|
|
8
2
|
require 'redmineup/patches/compatibility/sprite_patch'
|
|
9
3
|
end
|
|
@@ -2,32 +2,23 @@ module Redmineup
|
|
|
2
2
|
module Patches
|
|
3
3
|
module LiquidPatch
|
|
4
4
|
module StandardFilters
|
|
5
|
+
private
|
|
5
6
|
|
|
6
|
-
def
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
obj
|
|
17
|
-
when String
|
|
18
|
-
(obj.strip =~ /^\d+\.\d+$/) ? BigDecimal(obj) : obj.to_i
|
|
19
|
-
else
|
|
20
|
-
0
|
|
21
|
-
end
|
|
22
|
-
end
|
|
7
|
+
def to_number(obj)
|
|
8
|
+
case obj
|
|
9
|
+
when Float
|
|
10
|
+
BigDecimal(obj.to_s)
|
|
11
|
+
when Numeric
|
|
12
|
+
obj
|
|
13
|
+
when String
|
|
14
|
+
(obj.strip =~ /^\d+\.\d+$/) ? BigDecimal(obj) : obj.to_i
|
|
15
|
+
else
|
|
16
|
+
0
|
|
23
17
|
end
|
|
24
18
|
end
|
|
25
|
-
|
|
26
19
|
end
|
|
27
20
|
end
|
|
28
21
|
end
|
|
29
22
|
end
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
Liquid::StandardFilters.send(:include, Redmineup::Patches::LiquidPatch::StandardFilters)
|
|
33
|
-
end
|
|
23
|
+
|
|
24
|
+
Liquid::StandardFilters.prepend(Redmineup::Patches::LiquidPatch::StandardFilters)
|
data/lib/redmineup/version.rb
CHANGED
data/lib/redmineup.rb
CHANGED
|
@@ -44,6 +44,8 @@ require 'redmineup/liquid/drops/custom_field_enumeration_drop'
|
|
|
44
44
|
require 'redmineup/helpers/external_assets_helper'
|
|
45
45
|
require 'redmineup/helpers/form_tag_helper'
|
|
46
46
|
require 'redmineup/helpers/calendars_helper'
|
|
47
|
+
require 'redmineup/helpers/datetime_helper'
|
|
48
|
+
require 'redmineup/helpers/test_helper'
|
|
47
49
|
require 'redmineup/assets_manager'
|
|
48
50
|
|
|
49
51
|
require 'redmineup/patches/liquid_patch'
|
|
@@ -54,9 +56,21 @@ module Redmineup
|
|
|
54
56
|
def self.plugin_installed?(plugin_id)
|
|
55
57
|
Rails.root.join("plugins/#{plugin_id}/init.rb").exist?
|
|
56
58
|
end
|
|
59
|
+
|
|
60
|
+
def self.cable_available?
|
|
61
|
+
Rails.version > '4.0'
|
|
62
|
+
end
|
|
57
63
|
end
|
|
58
64
|
|
|
59
|
-
require 'application_record'
|
|
65
|
+
require 'application_record' if !defined?(ApplicationRecord) && Rails.version < '7.2.2'
|
|
66
|
+
|
|
67
|
+
if Redmineup.cable_available?
|
|
68
|
+
require 'action_cable/server/rup_configuration'
|
|
69
|
+
require 'action_cable/server/rup_server'
|
|
70
|
+
require 'action_cable/connection/rup_connection'
|
|
71
|
+
require 'redmineup/patches/action_cable_base_patch'
|
|
72
|
+
require 'redmineup/patches/action_cable_patch'
|
|
73
|
+
end
|
|
60
74
|
|
|
61
75
|
if defined?(ActiveRecord::Base)
|
|
62
76
|
ActiveRecord::Base.send :include, Redmineup::ActsAsList::List
|
|
@@ -66,13 +80,25 @@ end
|
|
|
66
80
|
|
|
67
81
|
if defined?(Propshaft::Assembly)
|
|
68
82
|
Propshaft::Assembly.prepend(Module.new do
|
|
69
|
-
def
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
83
|
+
def self.prepended(base)
|
|
84
|
+
base.class_eval do
|
|
85
|
+
cattr_accessor :redmineup_patched
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def config
|
|
90
|
+
return super if self.class.redmineup_patched
|
|
73
91
|
|
|
74
|
-
|
|
75
|
-
|
|
92
|
+
original_config = super
|
|
93
|
+
if defined?(Redmine::AssetPath)
|
|
94
|
+
base_dir = Pathname.new(Redmineup::AssetsManager.base_path)
|
|
95
|
+
paths = Redmineup::AssetsManager.assets_paths.map { |path| Pathname.new(path)}
|
|
96
|
+
asset_prefix = "plugin_assets/#{Redmineup::GEM_NAME}"
|
|
97
|
+
|
|
98
|
+
original_config[:redmine_extension_paths] << Redmine::AssetPath.new(base_dir, paths, asset_prefix)
|
|
99
|
+
self.class.redmineup_patched = true
|
|
100
|
+
end
|
|
101
|
+
original_config
|
|
76
102
|
end
|
|
77
103
|
end)
|
|
78
104
|
else
|
|
@@ -83,47 +109,26 @@ if defined?(ActionView::Base)
|
|
|
83
109
|
ActionView::Base.send :include, Redmineup::CalendarsHelper
|
|
84
110
|
ActionView::Base.send :include, Redmineup::ExternalAssetsHelper
|
|
85
111
|
ActionView::Base.send :include, Redmineup::FormTagHelper
|
|
112
|
+
ActionView::Base.send :include, Redmineup::TagsHelper
|
|
86
113
|
end
|
|
87
114
|
|
|
88
115
|
def requires_redmineup(arg)
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
requirement = requirement.split('.').collect(&:to_i)
|
|
93
|
-
requirement <=> current.slice(0, requirement.size)
|
|
94
|
-
end
|
|
116
|
+
arg = { version_or_higher: arg } unless arg.is_a?(Hash)
|
|
117
|
+
arg.assert_valid_keys(:version_or_higher)
|
|
95
118
|
|
|
96
|
-
|
|
97
|
-
|
|
119
|
+
requirement = arg[:version_or_higher]
|
|
120
|
+
unless requirement.is_a?(String)
|
|
121
|
+
raise ArgumentError, ':version_or_higher accepts a version string only'
|
|
98
122
|
end
|
|
99
123
|
|
|
100
|
-
|
|
101
|
-
|
|
124
|
+
current = Gem::Version.new(Redmineup::VERSION)
|
|
125
|
+
required = Gem::Version.new(requirement)
|
|
102
126
|
|
|
103
|
-
|
|
104
|
-
arg.each do |k, req|
|
|
105
|
-
case k
|
|
106
|
-
when :version_or_higher
|
|
107
|
-
raise ArgumentError.new(':version_or_higher accepts a version string only') unless req.is_a?(String)
|
|
127
|
+
return true if required <= current
|
|
108
128
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
req = [req] if req.is_a?(String)
|
|
115
|
-
if req.is_a?(Array)
|
|
116
|
-
unless req.detect { |ver| compare_versions(ver, current) == 0 }
|
|
117
|
-
abort "\033[31mRedmine requires redmineup gem version #{req} (you're using #{Redmineup::VERSION}).\nPlease update with 'bundle update redmineup'.\033[0m"
|
|
118
|
-
end
|
|
119
|
-
elsif req.is_a?(Range)
|
|
120
|
-
unless compare_versions(req.first, current) <= 0 && compare_versions(req.last, current) >= 0
|
|
121
|
-
abort "\033[31mRedmine requires redmineup gem version between #{req.first} and #{req.last} (you're using #{Redmineup::VERSION}).\nPlease update with 'bundle update redmineup'.\033[0m"
|
|
122
|
-
end
|
|
123
|
-
else
|
|
124
|
-
raise ArgumentError.new(':version option accepts a version string, an array or a range of versions')
|
|
125
|
-
end
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
true
|
|
129
|
+
message = "Redmine requires redmineup gem version #{requirement} or higher " \
|
|
130
|
+
"(you're using #{Redmineup::VERSION}).\n" \
|
|
131
|
+
"Please update with 'bundle update redmineup --conservative'."
|
|
132
|
+
Rails.logger&.error("\033[31m[ERROR]\033[0m #{message}")
|
|
133
|
+
abort "\033[31m#{message}\033[0m"
|
|
129
134
|
end
|
|
@@ -33,6 +33,22 @@ class TagTest < ActiveSupport::TestCase
|
|
|
33
33
|
assert_equal tags(:error).name, tags(:error).to_s
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
+
def test_color
|
|
37
|
+
assert_equal '#aaaaaa', tags(:feature).color # 11184810 = 0xaaaaaa
|
|
38
|
+
assert_equal '#bbbbbb', tags(:bug).color # 12303291 = 0xbbbbbb
|
|
39
|
+
# no DB color — falls back to color_from_name, not nil
|
|
40
|
+
assert_equal Redmineup::ActsAsTaggable::Tag.color_from_name('error'), tags(:error).color
|
|
41
|
+
assert_equal Redmineup::ActsAsTaggable::Tag.color_from_name('question'), tags(:question).color
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def test_color_from_name
|
|
45
|
+
color = Redmineup::ActsAsTaggable::Tag.color_from_name('error')
|
|
46
|
+
assert_match(/\A#[0-9a-f]{6}\z/, color)
|
|
47
|
+
assert_equal color, Redmineup::ActsAsTaggable::Tag.color_from_name('error') # deterministic
|
|
48
|
+
assert_not_equal color, Redmineup::ActsAsTaggable::Tag.color_from_name('other')
|
|
49
|
+
assert_match(/\A#[0-9a-f]{6}\z/, Redmineup::ActsAsTaggable::Tag.color_from_name(nil))
|
|
50
|
+
end
|
|
51
|
+
|
|
36
52
|
def test_tag_is_equal_to_itself
|
|
37
53
|
tag = tags(:error)
|
|
38
54
|
assert_equal tag, tag
|
|
@@ -67,7 +67,7 @@ class VotableTest < ActiveSupport::TestCase
|
|
|
67
67
|
assert_equal votable.find_votes_for(:vote_scope => 'rank').size, 1
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
-
def
|
|
70
|
+
def test_two_votes_for_when_voting_on_two_diff_scopes_dup
|
|
71
71
|
votable.vote_by(:voter => voters(:voter), :vote => 'yes', :vote_scope => 'weekly_rank')
|
|
72
72
|
votable.vote_by(:voter => voters(:voter), :vote => 'yes', :vote_scope => 'monthly_rank')
|
|
73
73
|
assert_equal votable.votes_for.size, 2
|
|
@@ -404,7 +404,7 @@ class VotableTest < ActiveSupport::TestCase
|
|
|
404
404
|
assert_equal votable_cache.cached_scoped_test_votes_total, 1
|
|
405
405
|
end
|
|
406
406
|
|
|
407
|
-
def
|
|
407
|
+
def test_update_cached_total_votes_for_when_a_vote_up_is_removed_dup
|
|
408
408
|
votable_cache.vote_by(:voter => voter, :vote => 'true', :vote_scope => "test")
|
|
409
409
|
votable_cache.unvote(:voter => voter, :vote_scope => "test")
|
|
410
410
|
assert_equal votable_cache.cached_scoped_test_votes_total, 0
|
|
@@ -440,44 +440,44 @@ class VotableTest < ActiveSupport::TestCase
|
|
|
440
440
|
assert_equal votable_cache.cached_scoped_test_votes_score, 0
|
|
441
441
|
end
|
|
442
442
|
|
|
443
|
-
def
|
|
443
|
+
def test_update_cached_up_votes_for_if_there_is_an_up_vote_column_dup
|
|
444
444
|
votable_cache.cached_scoped_test_votes_up = 50
|
|
445
445
|
votable_cache.vote_by(:voter => voter, :vote_scope => "test")
|
|
446
446
|
votable_cache.vote_by(:voter => voter, :vote_scope => "test")
|
|
447
447
|
assert_equal votable_cache.cached_scoped_test_votes_up, 1
|
|
448
448
|
end
|
|
449
449
|
|
|
450
|
-
def
|
|
450
|
+
def test_update_cached_down_votes_for_if_there_is_a_down_vote_column_dup
|
|
451
451
|
votable_cache.cached_scoped_test_votes_down = 50
|
|
452
452
|
votable_cache.vote_by(:voter => voter, :vote => 'false', :vote_scope => "test")
|
|
453
453
|
assert_equal votable_cache.cached_scoped_test_votes_down, 1
|
|
454
454
|
end
|
|
455
455
|
|
|
456
|
-
def
|
|
456
|
+
def test_update_cached_up_votes_for_when_a_vote_up_is_removed_dup
|
|
457
457
|
votable_cache.vote_by :voter => voter, :vote => 'true', :vote_scope => "test"
|
|
458
458
|
votable_cache.unvote :voter => voter, :vote_scope => "test"
|
|
459
459
|
assert_equal votable_cache.cached_scoped_test_votes_up, 0
|
|
460
460
|
end
|
|
461
461
|
|
|
462
|
-
def
|
|
462
|
+
def test_update_cached_down_votes_for_when_a_vote_down_is_removed_dup
|
|
463
463
|
votable_cache.vote_by(:voter => voter, :vote => 'false', :vote_scope => "test")
|
|
464
464
|
votable_cache.unvote(:voter => voter, :vote_scope => "test")
|
|
465
465
|
assert_equal votable_cache.cached_scoped_test_votes_down, 0
|
|
466
466
|
end
|
|
467
467
|
|
|
468
|
-
def
|
|
468
|
+
def test_select_from_cached_total_votes_for_if_there_a_total_column_dup
|
|
469
469
|
votable_cache.vote_by(:voter => voter, :vote_scope => "test")
|
|
470
470
|
votable_cache.cached_scoped_test_votes_total = 50
|
|
471
471
|
assert_equal votable_cache.count_votes_total(false, "test"), 50
|
|
472
472
|
end
|
|
473
473
|
|
|
474
|
-
def
|
|
474
|
+
def test_select_from_cached_up_votes_for_if_there_is_an_up_vote_column_dup
|
|
475
475
|
votable_cache.vote_by(:voter => voter, :vote_scope => "test")
|
|
476
476
|
votable_cache.cached_scoped_test_votes_up = 50
|
|
477
477
|
assert_equal votable_cache.count_votes_up(false, "test"), 50
|
|
478
478
|
end
|
|
479
479
|
|
|
480
|
-
def
|
|
480
|
+
def test_select_from_cached_down_votes_for_if_there_is_a_down_vote_column_dup
|
|
481
481
|
votable_cache.vote_by(:voter => voter, :vote => 'false', :vote_scope => "test")
|
|
482
482
|
votable_cache.cached_scoped_test_votes_down = 50
|
|
483
483
|
assert_equal votable_cache.count_votes_down(false, "test"), 50
|
|
@@ -188,7 +188,7 @@ class VoterTest < ActiveSupport::TestCase
|
|
|
188
188
|
end
|
|
189
189
|
|
|
190
190
|
# describe '#find_up_voted_items
|
|
191
|
-
def
|
|
191
|
+
def test_returns_objects_that_a_user_has_upvoted_for_dup
|
|
192
192
|
votable.vote_by(:voter => voter)
|
|
193
193
|
votables(:votable2).vote_by :voter => voters(:voter2)
|
|
194
194
|
assert voter.find_up_voted_items.include? votable
|
|
@@ -197,7 +197,7 @@ class VoterTest < ActiveSupport::TestCase
|
|
|
197
197
|
assert_equal voter.find_liked_items.size, 1
|
|
198
198
|
end
|
|
199
199
|
|
|
200
|
-
def
|
|
200
|
+
def test_returns_objects_that_a_user_has_upvoted_for_using_scope_dup
|
|
201
201
|
votable.vote_by(:voter => voter, :vote_scope => 'rank')
|
|
202
202
|
votables(:votable2).vote_by(:voter => voters(:voter2), :vote_scope => 'rank')
|
|
203
203
|
assert voter.find_up_voted_items(:vote_scope => 'rank').include? votable
|
|
@@ -226,7 +226,7 @@ class VoterTest < ActiveSupport::TestCase
|
|
|
226
226
|
assert_equal voter.find_down_voted_items(:vote_scope => 'rank').size, 0
|
|
227
227
|
end
|
|
228
228
|
|
|
229
|
-
def
|
|
229
|
+
def test_returns_objects_that_a_user_has_downvoted_for_dup
|
|
230
230
|
votable.vote_down voter
|
|
231
231
|
votables(:votable2).vote_down voters(:voter2)
|
|
232
232
|
assert voter.find_down_voted_items.include? votable
|
|
@@ -235,7 +235,7 @@ class VoterTest < ActiveSupport::TestCase
|
|
|
235
235
|
assert_equal voter.find_disliked_items.size, 1
|
|
236
236
|
end
|
|
237
237
|
|
|
238
|
-
def
|
|
238
|
+
def test_returns_objects_that_a_user_has_downvoted_for_using_scope_dup
|
|
239
239
|
votable.vote_down voter, :vote_scope => 'rank'
|
|
240
240
|
votables(:votable2).vote_down voters(:voter2), :vote_scope => 'rank'
|
|
241
241
|
assert voter.find_down_voted_items(:vote_scope => 'rank').include? votable
|
data/test/database.yml
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
sqlite:
|
|
2
2
|
adapter: sqlite3
|
|
3
|
-
database:
|
|
3
|
+
database: ":memory:"
|
|
4
4
|
|
|
5
5
|
mysql:
|
|
6
6
|
adapter: mysql2
|
|
7
7
|
database: redmineup_test
|
|
8
8
|
username: root
|
|
9
9
|
password: password
|
|
10
|
-
host:
|
|
10
|
+
host: mysql
|
|
11
11
|
|
|
12
12
|
postgresql:
|
|
13
13
|
adapter: postgresql
|
|
14
14
|
database: redmineup_test
|
|
15
15
|
user: postgres
|
|
16
16
|
password: password
|
|
17
|
-
host:
|
|
17
|
+
host: postgres
|
data/test/fixtures/tags.yml
CHANGED
|
@@ -15,7 +15,9 @@ module Redmineup
|
|
|
15
15
|
attachments = [attachment]
|
|
16
16
|
@issue_drop.define_singleton_method(:attachments) { attachments }
|
|
17
17
|
Attachment.stub(:latest_attach, attachment) do
|
|
18
|
-
|
|
18
|
+
expected_string = '<p>description with image ' \
|
|
19
|
+
'<img src=\'data:image/content_type;base64,to_base64_string\' title="attach_image" alt="attach_image" /></p>'
|
|
20
|
+
assert_equal expected_string, @strainer.parse_inline_attachments(text, @issue_drop)
|
|
19
21
|
end
|
|
20
22
|
end
|
|
21
23
|
|
|
@@ -25,6 +27,8 @@ module Redmineup
|
|
|
25
27
|
attachment = Minitest::Mock.new
|
|
26
28
|
attachment.expect(:url, 'mock_url')
|
|
27
29
|
attachment.expect(:description, "attach_image")
|
|
30
|
+
attachment.expect(:content_type, "content_type")
|
|
31
|
+
attachment.expect(:to_base64_string, "to_base64_string")
|
|
28
32
|
attachment
|
|
29
33
|
end
|
|
30
34
|
end
|
|
@@ -17,9 +17,9 @@ module Redmineup
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def test_where_filter
|
|
20
|
-
assert_match '{"name"=>"two", "value"=>5}', @liquid_render.render("{{ objects_arr | where: 'name', 'two' }}")
|
|
21
|
-
assert_match '{"name"=>"one", "value"=>10}', @liquid_render.render("{{ objects_arr | where: 'value', 6, '>' }}")
|
|
22
|
-
assert_match '{"name"=>"one", "value"=>10}', @liquid_render.render("{{ objects_arr | where: 'name', 'on', 'match' }}")
|
|
20
|
+
assert_match ws('{"name"=>"two", "value"=>5}'), ws(@liquid_render.render("{{ objects_arr | where: 'name', 'two' }}"))
|
|
21
|
+
assert_match ws('{"name"=>"one", "value"=>10}'), ws(@liquid_render.render("{{ objects_arr | where: 'value', 6, '>' }}"))
|
|
22
|
+
assert_match ws('{"name"=>"one", "value"=>10}'), ws(@liquid_render.render("{{ objects_arr | where: 'name', 'on', 'match' }}"))
|
|
23
23
|
assert_match '3', @liquid_render.render("{{ objects_arr | where: 'value', '', 'any' | size }}")
|
|
24
24
|
assert_match '1', @liquid_render.render("{{ objects_arr | where: 'value', '', 'none' | size }}")
|
|
25
25
|
assert_match '2', @liquid_render.render("{{ issues.all | where: 'author.name', 'Jonathan', '==' | size }}")
|
|
@@ -27,5 +27,8 @@ module Redmineup
|
|
|
27
27
|
assert_match '0', @liquid_render.render("{{ issues.all | where: 'author.name', '', 'none' | size }}")
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
def ws(string)
|
|
31
|
+
string.delete(' ')
|
|
32
|
+
end
|
|
30
33
|
end
|
|
31
34
|
end
|