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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.gitlab-ci.yml +33 -0
  4. data/README.md +74 -153
  5. data/app/assets/javascripts/consumer.js +53 -0
  6. data/app/assets/javascripts/consumer_worker.js +219 -0
  7. data/app/assets/javascripts/jquery.colorPicker.min.js +26 -0
  8. data/app/assets/javascripts/select2_helpers.js +10 -0
  9. data/app/assets/stylesheets/redmineup.css +509 -0
  10. data/app/views/redmineup/_additional_assets.html.erb +1 -0
  11. data/config/locales/en.yml +1 -0
  12. data/config/locales/ru.yml +1 -0
  13. data/config/routes.rb +4 -0
  14. data/doc/CHANGELOG +99 -16
  15. data/doc/active-record-mixins.md +156 -0
  16. data/doc/assets-money-and-utilities.md +71 -0
  17. data/doc/tagging-and-select2.md +108 -0
  18. data/lib/action_cable/connection/rup_connection.rb +17 -0
  19. data/lib/action_cable/server/rup_configuration.rb +17 -0
  20. data/lib/action_cable/server/rup_server.rb +17 -0
  21. data/lib/redmineup/acts_as_taggable/tag.rb +26 -2
  22. data/lib/redmineup/acts_as_taggable/up_acts_as_taggable.rb +42 -2
  23. data/lib/redmineup/acts_as_viewed/up_acts_as_viewed.rb +1 -1
  24. data/lib/redmineup/engine.rb +12 -2
  25. data/lib/redmineup/helpers/datetime_helper.rb +23 -0
  26. data/lib/redmineup/helpers/external_assets_helper.rb +14 -6
  27. data/lib/redmineup/helpers/form_tag_helper.rb +43 -0
  28. data/lib/redmineup/helpers/tags_helper.rb +41 -0
  29. data/lib/redmineup/helpers/test_helper.rb +12 -0
  30. data/lib/redmineup/hooks/views_layouts_hook.rb +1 -4
  31. data/lib/redmineup/liquid/drops/version_drop.rb +0 -2
  32. data/lib/redmineup/money_helper.rb +10 -2
  33. data/lib/redmineup/patches/action_cable_base_patch.rb +25 -0
  34. data/lib/redmineup/patches/action_cable_patch.rb +19 -0
  35. data/lib/redmineup/patches/auto_completes_controller_patch.rb +17 -0
  36. data/lib/redmineup/patches/compatibility/routing_mapper_patch.rb +5 -18
  37. data/lib/redmineup/patches/compatibility/sprite_patch.rb +3 -11
  38. data/lib/redmineup/patches/compatibility_patch.rb +0 -6
  39. data/lib/redmineup/patches/liquid_patch.rb +13 -22
  40. data/lib/redmineup/version.rb +1 -1
  41. data/lib/redmineup.rb +47 -42
  42. data/test/acts_as_taggable/tag_test.rb +16 -0
  43. data/test/acts_as_votable/votable_test.rb +9 -9
  44. data/test/acts_as_votable/voter_test.rb +4 -4
  45. data/test/database.yml +3 -3
  46. data/test/fixtures/tags.yml +2 -0
  47. data/test/liquid/filters/additional_filter_test.rb +5 -1
  48. data/test/liquid/filters/arrays_filter_test.rb +6 -3
  49. data/test/schema.rb +6 -1
  50. data/test/tags_helper_view_test.rb +41 -0
  51. data/test/test_helper.rb +13 -12
  52. metadata +21 -5
  53. data/bitbucket-pipelines.yml +0 -50
  54. data/lib/redmineup/patches/compatibility/application_controller_patch.rb +0 -32
  55. 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
- def view_layouts_base_html_head(_context = {})
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 prices_collection_by_currency(prices_collection, options = {})
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.collect{|k, v| content_tag(:span, price_to_currency(v, k, :symbol => true), :style => "white-space: nowrap;")}.compact
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 self.included(base)
6
- base.send(:include, InstanceMethods)
5
+ def constraints(options = {}, &block)
6
+ return super(options, &block) unless options.is_a?(Hash)
7
7
 
8
- base.class_eval do
9
- alias_method :constraints_without_redmineup, :constraints
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
- unless ActionDispatch::Routing::Mapper.included_modules.include?(Redmineup::Patches::Compatibility::RoutingMapperPatch)
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 self.included(base)
6
- base.send(:include, InstanceMethods)
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
- unless ActionView::Base.included_modules.include?(Redmineup::Patches::Compatibility::SpritePatch)
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 self.included(base)
7
- base.class_eval do
8
-
9
- private
10
-
11
- def to_number(obj)
12
- case obj
13
- when Float
14
- BigDecimal(obj.to_s)
15
- when Numeric
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
- unless Liquid::StandardFilters.included_modules.include?(Redmineup::Patches::LiquidPatch::StandardFilters)
32
- Liquid::StandardFilters.send(:include, Redmineup::Patches::LiquidPatch::StandardFilters)
33
- end
23
+
24
+ Liquid::StandardFilters.prepend(Redmineup::Patches::LiquidPatch::StandardFilters)
@@ -1,3 +1,3 @@
1
1
  module Redmineup
2
- VERSION = '1.0.10'
2
+ VERSION = '1.1.13'
3
3
  end
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' unless defined?(ApplicationRecord)
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 initialize(config)
70
- base_dir = Pathname.new(Redmineup::AssetsManager.base_path)
71
- paths = Redmineup::AssetsManager.assets_paths.map { |path| Pathname.new(path)}
72
- asset_prefix = "plugin_assets/#{Redmineup::GEM_NAME}"
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
- config[:redmine_extension_paths] << Redmine::AssetPath.new(base_dir, paths, asset_prefix)
75
- super
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
- def compare_versions(requirement, current)
90
- raise ArgumentError.new('wrong version format') unless check_version_format(requirement)
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
- def check_version_format(version)
97
- version =~ /^\d+.?\d*.?\d*$/m
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
- arg = { version_or_higher: arg } unless arg.is_a?(Hash)
101
- arg.assert_valid_keys(:version, :version_or_higher)
124
+ current = Gem::Version.new(Redmineup::VERSION)
125
+ required = Gem::Version.new(requirement)
102
126
 
103
- current = Redmineup::VERSION.split('.').map { |x| x.to_i }
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
- unless compare_versions(req, current) <= 0
110
- Rails.logger.error "\033[31m[ERROR]\033[0m Redmine requires redmineup gem version #{req} or higher (you're using #{Redmineup::VERSION}).\n\033[31m[ERROR]\033[0m Please update with 'bundle update redmineup'." if Rails.logger
111
- abort "\033[31mRedmine requires redmineup gem version #{req} or higher (you're using #{Redmineup::VERSION}).\nPlease update with 'bundle update redmineup'.\033[0m"
112
- end
113
- when :version
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 test_two_votes_for_when_voting_on_two_diff_scopes
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 test_update_cached_total_votes_for_when_a_vote_up_is_removed
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 test_update_cached_up_votes_for_if_there_is_an_up_vote_column
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 test_update_cached_down_votes_for_if_there_is_a_down_vote_column
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 test_update_cached_up_votes_for_when_a_vote_up_is_removed
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 test_update_cached_down_votes_for_when_a_vote_down_is_removed
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 test_select_from_cached_total_votes_for_if_there_a_total_column
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 test_select_from_cached_up_votes_for_if_there_is_an_up_vote_column
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 test_select_from_cached_down_votes_for_if_there_is_a_down_vote_column
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 test_returns_objects_that_a_user_has_upvoted_for
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 test_returns_objects_that_a_user_has_upvoted_for_using_scope
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 test_returns_objects_that_a_user_has_downvoted_for
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 test_returns_objects_that_a_user_has_downvoted_for_using_scope
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: ':memory:'
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: 127.0.0.1
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: 127.0.0.1
17
+ host: postgres
@@ -3,9 +3,11 @@ error:
3
3
 
4
4
  feature:
5
5
  name: New feature
6
+ color: 11184810
6
7
 
7
8
  bug:
8
9
  name: bug
10
+ color: 12303291
9
11
 
10
12
  question:
11
13
  name: question
@@ -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
- assert_equal '<p>description with image <img src="mock_url" title="attach_image" alt="attach_image" loading="lazy" /></p>', @strainer.parse_inline_attachments(text, @issue_drop)
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