redmineup 1.0.2 → 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 (83) 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/images/icons.svg +8 -0
  6. data/app/assets/javascripts/chart.min.js +13 -0
  7. data/app/assets/javascripts/consumer.js +53 -0
  8. data/app/assets/javascripts/consumer_worker.js +219 -0
  9. data/app/assets/javascripts/jquery.colorPicker.min.js +26 -0
  10. data/{vendor → app}/assets/javascripts/select2_helpers.js +11 -1
  11. data/app/assets/stylesheets/calendars.css +15 -0
  12. data/{vendor → app}/assets/stylesheets/money.css +1 -2
  13. data/app/assets/stylesheets/redmineup.css +509 -0
  14. data/{vendor → app}/assets/stylesheets/select2.css +1 -1
  15. data/app/views/redmineup/_additional_assets.html.erb +1 -0
  16. data/config/locales/en.yml +1 -0
  17. data/config/locales/ru.yml +1 -0
  18. data/config/routes.rb +4 -0
  19. data/doc/CHANGELOG +116 -7
  20. data/doc/active-record-mixins.md +156 -0
  21. data/doc/assets-money-and-utilities.md +71 -0
  22. data/doc/tagging-and-select2.md +108 -0
  23. data/lib/action_cable/connection/rup_connection.rb +17 -0
  24. data/lib/action_cable/server/rup_configuration.rb +17 -0
  25. data/lib/action_cable/server/rup_server.rb +17 -0
  26. data/lib/application_record.rb +3 -0
  27. data/lib/redmineup/acts_as_taggable/tag.rb +26 -2
  28. data/lib/redmineup/acts_as_taggable/up_acts_as_taggable.rb +42 -2
  29. data/lib/redmineup/acts_as_viewed/up_acts_as_viewed.rb +1 -1
  30. data/lib/redmineup/acts_as_votable/votable.rb +2 -5
  31. data/lib/redmineup/assets_manager.rb +12 -1
  32. data/lib/redmineup/currency.rb +3 -1
  33. data/lib/redmineup/engine.rb +12 -2
  34. data/lib/redmineup/helpers/calendars_helper.rb +22 -0
  35. data/lib/redmineup/helpers/datetime_helper.rb +23 -0
  36. data/lib/redmineup/helpers/external_assets_helper.rb +15 -7
  37. data/lib/redmineup/helpers/form_tag_helper.rb +43 -0
  38. data/lib/redmineup/helpers/tags_helper.rb +41 -0
  39. data/lib/redmineup/helpers/test_helper.rb +12 -0
  40. data/lib/redmineup/hooks/views_layouts_hook.rb +1 -3
  41. data/lib/redmineup/liquid/drops/attachment_drop.rb +8 -0
  42. data/lib/redmineup/liquid/drops/custom_field_enumeration_drop.rb +11 -0
  43. data/lib/redmineup/liquid/drops/issues_drop.rb +11 -19
  44. data/lib/redmineup/liquid/drops/users_drop.rb +2 -3
  45. data/lib/redmineup/liquid/drops/version_drop.rb +38 -0
  46. data/lib/redmineup/liquid/filters/additional.rb +31 -0
  47. data/lib/redmineup/liquid/filters/base.rb +16 -1
  48. data/lib/redmineup/money_helper.rb +10 -2
  49. data/lib/redmineup/patches/action_cable_base_patch.rb +25 -0
  50. data/lib/redmineup/patches/action_cable_patch.rb +19 -0
  51. data/lib/redmineup/patches/auto_completes_controller_patch.rb +17 -0
  52. data/lib/redmineup/patches/compatibility/routing_mapper_patch.rb +16 -0
  53. data/lib/redmineup/patches/compatibility/sprite_patch.rb +13 -0
  54. data/lib/redmineup/patches/compatibility_patch.rb +4 -0
  55. data/lib/redmineup/patches/liquid_patch.rb +13 -22
  56. data/lib/redmineup/version.rb +1 -1
  57. data/lib/redmineup.rb +66 -40
  58. data/test/acts_as_taggable/rup_acts_as_taggable_test.rb +1 -1
  59. data/test/acts_as_taggable/tag_test.rb +16 -0
  60. data/test/acts_as_votable/votable_test.rb +9 -9
  61. data/test/acts_as_votable/voter_test.rb +4 -4
  62. data/test/database.yml +3 -3
  63. data/test/fixtures/tags.yml +2 -0
  64. data/test/liquid/drops/issues_drop_test.rb +5 -0
  65. data/test/liquid/filters/additional_filter_test.rb +35 -0
  66. data/test/liquid/filters/arrays_filter_test.rb +6 -3
  67. data/test/liquid/liquid_helper.rb +1 -1
  68. data/test/models/attachment.rb +5 -0
  69. data/test/models/issue.rb +5 -0
  70. data/test/models/journal.rb +6 -0
  71. data/test/schema.rb +65 -53
  72. data/test/tags_helper_view_test.rb +41 -0
  73. data/test/test_helper.rb +13 -12
  74. metadata +43 -14
  75. data/app/views/redmine_crm/redmineup_calendar/_calendar.html.erb +0 -34
  76. data/bitbucket-pipelines.yml +0 -50
  77. data/lib/redmineup/compatibility/application_controller_patch.rb +0 -33
  78. data/lib/redmineup/compatibility/routing_mapper_patch.rb +0 -25
  79. data/lib/redmineup/helpers/rup_calendar_helper.rb +0 -146
  80. /data/{vendor → app}/assets/images/money.png +0 -0
  81. /data/{vendor → app}/assets/images/vcard.png +0 -0
  82. /data/{vendor/assets/javascripts/Chart.bundle.min.js → app/assets/javascripts/Chart.bundle.min.js.bak} +0 -0
  83. /data/{vendor → app}/assets/javascripts/select2.js +0 -0
data/lib/redmineup.rb CHANGED
@@ -27,6 +27,7 @@ require 'redmineup/money_helper'
27
27
  require 'redmineup/colors_helper'
28
28
 
29
29
  require 'liquid'
30
+ require 'redmineup/liquid/filters/additional'
30
31
  require 'redmineup/liquid/filters/base'
31
32
  require 'redmineup/liquid/filters/arrays'
32
33
  require 'redmineup/liquid/filters/colors'
@@ -37,18 +38,38 @@ require 'redmineup/liquid/drops/users_drop'
37
38
  require 'redmineup/liquid/drops/time_entries_drop'
38
39
  require 'redmineup/liquid/drops/attachment_drop'
39
40
  require 'redmineup/liquid/drops/issue_relations_drop'
41
+ require 'redmineup/liquid/drops/version_drop'
42
+ require 'redmineup/liquid/drops/custom_field_enumeration_drop'
40
43
 
41
44
  require 'redmineup/helpers/external_assets_helper'
42
45
  require 'redmineup/helpers/form_tag_helper'
43
- require 'redmineup/helpers/rup_calendar_helper'
46
+ require 'redmineup/helpers/calendars_helper'
47
+ require 'redmineup/helpers/datetime_helper'
48
+ require 'redmineup/helpers/test_helper'
44
49
  require 'redmineup/assets_manager'
45
50
 
46
- require 'redmineup/compatibility/application_controller_patch'
47
- require 'redmineup/compatibility/routing_mapper_patch'
48
- require 'redmineup/patches/liquid_patch' unless BigDecimal.respond_to?(:new)
51
+ require 'redmineup/patches/liquid_patch'
49
52
 
50
53
  module Redmineup
51
54
  GEM_NAME = 'redmineup'.freeze
55
+
56
+ def self.plugin_installed?(plugin_id)
57
+ Rails.root.join("plugins/#{plugin_id}/init.rb").exist?
58
+ end
59
+
60
+ def self.cable_available?
61
+ Rails.version > '4.0'
62
+ end
63
+ end
64
+
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'
52
73
  end
53
74
 
54
75
  if defined?(ActiveRecord::Base)
@@ -57,52 +78,57 @@ if defined?(ActiveRecord::Base)
57
78
  ActiveRecord::Base.extend(Redmineup::ActsAsVotable::Votable)
58
79
  end
59
80
 
60
- Redmineup::AssetsManager.install_assets
81
+ if defined?(Propshaft::Assembly)
82
+ Propshaft::Assembly.prepend(Module.new do
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
91
+
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
102
+ end
103
+ end)
104
+ else
105
+ Redmineup::AssetsManager.install_assets
106
+ end
61
107
 
62
108
  if defined?(ActionView::Base)
109
+ ActionView::Base.send :include, Redmineup::CalendarsHelper
63
110
  ActionView::Base.send :include, Redmineup::ExternalAssetsHelper
64
111
  ActionView::Base.send :include, Redmineup::FormTagHelper
112
+ ActionView::Base.send :include, Redmineup::TagsHelper
65
113
  end
66
114
 
67
115
  def requires_redmineup(arg)
68
- def compare_versions(requirement, current)
69
- raise ArgumentError.new('wrong version format') unless check_version_format(requirement)
116
+ arg = { version_or_higher: arg } unless arg.is_a?(Hash)
117
+ arg.assert_valid_keys(:version_or_higher)
70
118
 
71
- requirement = requirement.split('.').collect(&:to_i)
72
- requirement <=> current.slice(0, requirement.size)
119
+ requirement = arg[:version_or_higher]
120
+ unless requirement.is_a?(String)
121
+ raise ArgumentError, ':version_or_higher accepts a version string only'
73
122
  end
74
123
 
75
- def check_version_format(version)
76
- version =~ /^\d+.?\d*.?\d*$/m
77
- end
124
+ current = Gem::Version.new(Redmineup::VERSION)
125
+ required = Gem::Version.new(requirement)
78
126
 
79
- arg = { version_or_higher: arg } unless arg.is_a?(Hash)
80
- arg.assert_valid_keys(:version, :version_or_higher)
127
+ return true if required <= current
81
128
 
82
- current = Redmineup::VERSION.split('.').map { |x| x.to_i }
83
- arg.each do |k, req|
84
- case k
85
- when :version_or_higher
86
- raise ArgumentError.new(':version_or_higher accepts a version string only') unless req.is_a?(String)
87
-
88
- unless compare_versions(req, current) <= 0
89
- 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
90
- abort "\033[31mRedmine requires redmineup gem version #{req} or higher (you're using #{Redmineup::VERSION}).\nPlease update with 'bundle update redmineup'.\033[0m"
91
- end
92
- when :version
93
- req = [req] if req.is_a?(String)
94
- if req.is_a?(Array)
95
- unless req.detect { |ver| compare_versions(ver, current) == 0 }
96
- abort "\033[31mRedmine requires redmineup gem version #{req} (you're using #{Redmineup::VERSION}).\nPlease update with 'bundle update redmineup'.\033[0m"
97
- end
98
- elsif req.is_a?(Range)
99
- unless compare_versions(req.first, current) <= 0 && compare_versions(req.last, current) >= 0
100
- 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"
101
- end
102
- else
103
- raise ArgumentError.new(':version option accepts a version string, an array or a range of versions')
104
- end
105
- end
106
- end
107
- 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"
108
134
  end
@@ -338,7 +338,7 @@ class RupActsAsTaggableTest < ActiveSupport::TestCase
338
338
 
339
339
  def test_tags_condition
340
340
  assert_equal "(tags_TABLE.name LIKE #{tags(:feature).id} OR tags_TABLE.name LIKE #{tags(:bug).id})",
341
- Issue.send(:tags_condition, [tags(:feature), tags(:bug)], 'tags_TABLE')
341
+ Issue.send(:tags_condition, [tags(:feature), tags(:bug)], 'tags_TABLE').gsub("'", "")
342
342
  end
343
343
 
344
344
  def test_all_tags_list
@@ -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
@@ -26,6 +26,11 @@ module Redmineup
26
26
  assert_equal @user.name, @liquid_render.render('{{ issue.author.name }}')
27
27
  end
28
28
 
29
+ def test_issue_attachments
30
+ attachment_author = @issue.attachments.first.author.name
31
+ assert_equal attachment_author, @liquid_render.render('{% assign attach = issue.attachments | first %}{{ attach.author.name }}')
32
+ end
33
+
29
34
  def test_issue_delegated
30
35
  assert_equal [@issue.id, @issue.subject, @issue.description].join('|'),
31
36
  @liquid_render.render('{{ issue.id }}|{{ issue.subject }}|{{ issue.description }}')
@@ -0,0 +1,35 @@
1
+ require File.dirname(__FILE__) + '/../liquid_helper'
2
+ include LiquidHelperMethods
3
+
4
+ module Redmineup
5
+ class AdditionalFilterTest < ActiveSupport::TestCase
6
+ def setup
7
+ @issue = Issue.first
8
+ @issue_drop = Liquid::IssueDrop.new(@issue)
9
+ @strainer = ::Liquid::Context.new.strainer
10
+ end
11
+
12
+ def test_parse_inline_attachments
13
+ text = '<p>description with image <img src="screenshot.png" /></p>'
14
+ attachment = mock_attachment
15
+ attachments = [attachment]
16
+ @issue_drop.define_singleton_method(:attachments) { attachments }
17
+ Attachment.stub(:latest_attach, attachment) do
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)
21
+ end
22
+ end
23
+
24
+ private
25
+
26
+ def mock_attachment
27
+ attachment = Minitest::Mock.new
28
+ attachment.expect(:url, 'mock_url')
29
+ attachment.expect(:description, "attach_image")
30
+ attachment.expect(:content_type, "content_type")
31
+ attachment.expect(:to_base64_string, "to_base64_string")
32
+ attachment
33
+ end
34
+ end
35
+ 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
@@ -1,7 +1,7 @@
1
1
  require File.dirname(__FILE__) + '/../test_helper'
2
2
 
3
3
  class LiquidRender
4
-
4
+
5
5
  def initialize(drops = {})
6
6
  @objects_hash = [
7
7
  {'name' => 'one', "value" => 10},
@@ -1,3 +1,8 @@
1
1
  class Attachment < ActiveRecord::Base
2
2
  belongs_to :author, :class_name => "User"
3
+
4
+ def self.latest_attach(attachments, filename)
5
+ # stub method for test
6
+ # returned one attachment
7
+ end
3
8
  end
data/test/models/issue.rb CHANGED
@@ -8,6 +8,7 @@ class Issue < ActiveRecord::Base
8
8
 
9
9
  has_many :relations_from, class_name: 'IssueRelation', foreign_key: 'issue_from_id', dependent: :delete_all
10
10
  has_many :relations_to, class_name: 'IssueRelation', foreign_key: 'issue_to_id', dependent: :delete_all
11
+ has_many :journals, foreign_key: 'journalized_id'
11
12
 
12
13
  up_acts_as_draftable
13
14
  up_acts_as_taggable
@@ -18,4 +19,8 @@ class Issue < ActiveRecord::Base
18
19
  def visible?
19
20
  true
20
21
  end
22
+
23
+ def attachments
24
+ Attachment.all
25
+ end
21
26
  end
@@ -0,0 +1,6 @@
1
+ class Journal < ActiveRecord::Base
2
+ belongs_to :journalized, :polymorphic => true
3
+ belongs_to :issue, :foreign_key => :journalized_id
4
+
5
+ belongs_to :user
6
+ end
data/test/schema.rb CHANGED
@@ -25,97 +25,109 @@ ActiveRecord::Schema.define version: 0 do
25
25
  t.datetime :updated_at
26
26
  end
27
27
 
28
- create_table "tags", :force => true do |t|
29
- t.column "name", :string
28
+ create_table :journals, force: true do |t|
29
+ t.integer :journalized_id, default: 0, null: false
30
+ t.string :journalized_type, limit: 30, default: "", null: false
31
+ t.integer :user_id, default: 0, null: false
32
+ t.text :notes
33
+ t.datetime :created_on, null: false
34
+ t.boolean :private_notes, default: false, null: false
30
35
  end
31
36
 
32
- create_table "taggings", :force => true do |t|
33
- t.column "tag_id", :integer
34
- t.column "taggable_id", :integer
35
- t.column "taggable_type", :string
36
- t.column "created_at", :datetime
37
+ create_table :tags, force: true do |t|
38
+ t.string :name
39
+ t.string :color
37
40
  end
38
41
 
39
- create_table "users", :force => true do |t|
40
- t.column "name", :string
41
- t.column "language", :string
42
+ create_table :taggings, force: true do |t|
43
+ t.integer :tag_id
44
+ t.integer :taggable_id
45
+ t.string :taggable_type
46
+ t.datetime :created_at
42
47
  end
43
48
 
44
- create_table "issue_relations", :force => true do |t|
45
- t.column "issue_from_id", :integer
46
- t.column "issue_to_id", :integer
47
- t.column "relation_type", :string
48
- t.column "delay", :integer
49
+ create_table :users, force: true do |t|
50
+ t.string :name
51
+ t.string :language
49
52
  end
50
53
 
51
- create_table "issues", :force => true do |t|
52
- t.integer "project_id"
53
- t.column "subject", :string
54
- t.column "description", :string
55
- t.column "closed", :boolean
56
- t.column "cached_tag_list", :string
57
- t.column "user_id", :integer
58
- t.column "author_id", :integer
59
- t.column "views", :integer, :default => 0
60
- t.column "total_views", :integer, :default => 0
54
+ create_table :categories, force: true do |t|
55
+ t.string :name
61
56
  end
62
57
 
63
- create_table "votes", :force => true do |t|
64
- t.references "votable", :polymorphic => true
65
- t.references "voter", :polymorphic => true
66
-
67
- t.boolean "vote_flag"
68
- t.string "vote_scope"
69
- t.integer "vote_weight"
70
- t.string "vote_ip"
71
-
58
+ create_table :issue_relations, force: true do |t|
59
+ t.integer :issue_from_id
60
+ t.integer :issue_to_id
61
+ t.string :relation_type
62
+ t.integer :delay
63
+ end
64
+
65
+ create_table :issues, force: true do |t|
66
+ t.integer :project_id
67
+ t.string :subject
68
+ t.string :description
69
+ t.boolean :closed
70
+ t.string :cached_tag_list
71
+ t.integer :user_id
72
+ t.integer :author_id
73
+ t.integer :views, default: 0
74
+ t.integer :total_views, default: 0
75
+ end
76
+
77
+ create_table :votes, force: true do |t|
78
+ t.references :votable, polymorphic: true
79
+ t.references :voter, polymorphic: true
80
+ t.boolean :vote_flag
81
+ t.string :vote_scope
82
+ t.integer :vote_weight
83
+ t.string :vote_ip
72
84
  t.timestamps
73
85
  end
74
86
 
75
- create_table "news", :force => true do |t|
76
- t.string "title"
77
- t.text "description"
78
- t.integer "author_id"
87
+ create_table :news, force: true do |t|
88
+ t.string :title
89
+ t.text :description
90
+ t.integer :author_id
79
91
  end
80
92
 
81
- create_table "projects", :force => true do |t|
82
- t.string "name"
83
- t.text "description"
84
- t.string "identifier"
85
- t.integer "status"
93
+ create_table :projects, force: true do |t|
94
+ t.string :name
95
+ t.text :description
96
+ t.string :identifier
97
+ t.integer :status
86
98
  end
87
99
 
88
- create_table :voters, :force => true do |t|
100
+ create_table :voters, force: true do |t|
89
101
  t.string :name
90
102
  end
91
103
 
92
- create_table :not_voters, :force => true do |t|
104
+ create_table :not_voters, force: true do |t|
93
105
  t.string :name
94
106
  end
95
107
 
96
- create_table :votables, :force => true do |t|
108
+ create_table :votables, force: true do |t|
97
109
  t.string :name
98
110
  end
99
111
 
100
- create_table :votable_voters, :force => true do |t|
112
+ create_table :votable_voters, force: true do |t|
101
113
  t.string :name
102
114
  end
103
115
 
104
- create_table :sti_votables, :force => true do |t|
116
+ create_table :sti_votables, force: true do |t|
105
117
  t.string :name
106
118
  t.string :type
107
119
  end
108
120
 
109
- create_table :sti_not_votables, :force => true do |t|
121
+ create_table :sti_not_votables, force: true do |t|
110
122
  t.string :name
111
123
  t.string :type
112
124
  end
113
125
 
114
- create_table :not_votables, :force => true do |t|
126
+ create_table :not_votables, force: true do |t|
115
127
  t.string :name
116
128
  end
117
129
 
118
- create_table :votable_caches, :force => true do |t|
130
+ create_table :votable_caches, force: true do |t|
119
131
  t.string :name
120
132
  t.integer :cached_votes_total
121
133
  t.integer :cached_votes_score
@@ -134,11 +146,11 @@ ActiveRecord::Schema.define version: 0 do
134
146
  t.float :cached_scoped_weighted_average
135
147
  end
136
148
 
137
- create_table :viewings, :force => true do |t|
149
+ create_table :viewings, force: true do |t|
138
150
  t.column :viewer_id, :integer
139
151
  t.column :viewed_id, :integer
140
152
  t.column :viewed_type, :string
141
- t.column :ip, :string, :limit => '24'
153
+ t.column :ip, :string, limit: '45'
142
154
  t.column :created_at, :datetime
143
155
  end
144
156
  end
@@ -0,0 +1,41 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class TagsHelperViewTest < ActionView::TestCase
4
+ include Redmineup::TagsHelper
5
+ include Redmineup::FormTagHelper
6
+
7
+ def stub_tag_url(name)
8
+ "/stub_tags/#{name}" # URL stub for tag_cloud_links(tags, :stub)
9
+ end
10
+
11
+ def test_tag_link
12
+ result = tag_link('/tags/error', 'error', count: 3)
13
+ assert_includes result, 'tag-label-color'
14
+ assert_includes result, 'background-color: #'
15
+ assert_includes result, '(3)'
16
+ end
17
+
18
+ def test_tag_links
19
+ result = tag_links(['error', 'bug']) { |t| "/tags/#{t}" }
20
+ assert_includes result, 'class="tag_list"'
21
+ assert_nil tag_links([]) { |t| "/tags/#{t}" }
22
+ end
23
+
24
+ def test_tag_cloud_links
25
+ result = tag_cloud_links(Issue.tag_counts, :stub)
26
+ assert_includes result, 'class="tag_list"'
27
+ assert_includes result, '/stub_tags/'
28
+ assert_nil tag_cloud_links([], :stub)
29
+ assert_raises(NoMethodError) { tag_cloud_links(Issue.tag_counts, :unknown_xyz) }
30
+ end
31
+
32
+ def test_tag_list_field_tag
33
+ result = tag_list_field_tag('issue[tag_list]', ['bug'],
34
+ url: '/auto_completes/taggable_tags',
35
+ width: '60%', tags: false,
36
+ placeholder: '+ add tag')
37
+ assert_includes result, 'name="issue[tag_list][]"'
38
+ assert_includes result, '"width":"60%"'
39
+ assert_includes result, '"tags":false'
40
+ end
41
+ end