redmineup 1.0.2

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 (118) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/Gemfile +4 -0
  4. data/README.md +204 -0
  5. data/Rakefile +11 -0
  6. data/app/controllers/redmineup_controller.rb +26 -0
  7. data/app/views/redmine_crm/redmineup_calendar/_calendar.html.erb +34 -0
  8. data/app/views/redmineup/_money.html.erb +44 -0
  9. data/app/views/redmineup/settings.html.erb +10 -0
  10. data/bitbucket-pipelines.yml +50 -0
  11. data/config/currency_iso.json +2544 -0
  12. data/config/locales/cs.yml +13 -0
  13. data/config/locales/de.yml +13 -0
  14. data/config/locales/en.yml +13 -0
  15. data/config/locales/es.yml +13 -0
  16. data/config/locales/ru.yml +13 -0
  17. data/config/routes.rb +5 -0
  18. data/doc/CHANGELOG +14 -0
  19. data/doc/LICENSE.txt +339 -0
  20. data/lib/redmineup/acts_as_draftable/draft.rb +40 -0
  21. data/lib/redmineup/acts_as_draftable/up_acts_as_draftable.rb +172 -0
  22. data/lib/redmineup/acts_as_list/list.rb +282 -0
  23. data/lib/redmineup/acts_as_priceable/up_acts_as_priceable.rb +33 -0
  24. data/lib/redmineup/acts_as_taggable/tag.rb +81 -0
  25. data/lib/redmineup/acts_as_taggable/tag_list.rb +111 -0
  26. data/lib/redmineup/acts_as_taggable/tagging.rb +16 -0
  27. data/lib/redmineup/acts_as_taggable/up_acts_as_taggable.rb +357 -0
  28. data/lib/redmineup/acts_as_viewed/up_acts_as_viewed.rb +274 -0
  29. data/lib/redmineup/acts_as_votable/up_acts_as_votable.rb +80 -0
  30. data/lib/redmineup/acts_as_votable/up_acts_as_voter.rb +20 -0
  31. data/lib/redmineup/acts_as_votable/votable.rb +323 -0
  32. data/lib/redmineup/acts_as_votable/vote.rb +28 -0
  33. data/lib/redmineup/acts_as_votable/voter.rb +131 -0
  34. data/lib/redmineup/assets_manager.rb +43 -0
  35. data/lib/redmineup/colors_helper.rb +192 -0
  36. data/lib/redmineup/compatibility/application_controller_patch.rb +33 -0
  37. data/lib/redmineup/compatibility/routing_mapper_patch.rb +25 -0
  38. data/lib/redmineup/currency/formatting.rb +224 -0
  39. data/lib/redmineup/currency/heuristics.rb +151 -0
  40. data/lib/redmineup/currency/loader.rb +23 -0
  41. data/lib/redmineup/currency.rb +450 -0
  42. data/lib/redmineup/engine.rb +4 -0
  43. data/lib/redmineup/helpers/external_assets_helper.rb +20 -0
  44. data/lib/redmineup/helpers/form_tag_helper.rb +88 -0
  45. data/lib/redmineup/helpers/rup_calendar_helper.rb +146 -0
  46. data/lib/redmineup/helpers/tags_helper.rb +13 -0
  47. data/lib/redmineup/helpers/vote_helper.rb +35 -0
  48. data/lib/redmineup/hooks/views_layouts_hook.rb +11 -0
  49. data/lib/redmineup/liquid/drops/attachment_drop.rb +47 -0
  50. data/lib/redmineup/liquid/drops/issue_relations_drop.rb +41 -0
  51. data/lib/redmineup/liquid/drops/issues_drop.rb +217 -0
  52. data/lib/redmineup/liquid/drops/news_drop.rb +54 -0
  53. data/lib/redmineup/liquid/drops/projects_drop.rb +86 -0
  54. data/lib/redmineup/liquid/drops/time_entries_drop.rb +65 -0
  55. data/lib/redmineup/liquid/drops/users_drop.rb +68 -0
  56. data/lib/redmineup/liquid/filters/arrays.rb +254 -0
  57. data/lib/redmineup/liquid/filters/base.rb +249 -0
  58. data/lib/redmineup/liquid/filters/colors.rb +31 -0
  59. data/lib/redmineup/money_helper.rb +66 -0
  60. data/lib/redmineup/patches/liquid_patch.rb +33 -0
  61. data/lib/redmineup/settings/money.rb +46 -0
  62. data/lib/redmineup/settings.rb +53 -0
  63. data/lib/redmineup/version.rb +3 -0
  64. data/lib/redmineup.rb +108 -0
  65. data/redmineup.gemspec +29 -0
  66. data/test/acts_as_draftable/draft_test.rb +29 -0
  67. data/test/acts_as_draftable/rup_acts_as_draftable_test.rb +178 -0
  68. data/test/acts_as_taggable/rup_acts_as_taggable_test.rb +350 -0
  69. data/test/acts_as_taggable/tag_list_test.rb +34 -0
  70. data/test/acts_as_taggable/tag_test.rb +72 -0
  71. data/test/acts_as_taggable/tagging_test.rb +15 -0
  72. data/test/acts_as_viewed/rup_acts_as_viewed_test.rb +47 -0
  73. data/test/acts_as_votable/rup_acts_as_votable_test.rb +19 -0
  74. data/test/acts_as_votable/rup_acts_as_voter_test.rb +14 -0
  75. data/test/acts_as_votable/votable_test.rb +507 -0
  76. data/test/acts_as_votable/voter_test.rb +296 -0
  77. data/test/currency_test.rb +292 -0
  78. data/test/database.yml +17 -0
  79. data/test/fixtures/attachments.yml +14 -0
  80. data/test/fixtures/issues.yml +24 -0
  81. data/test/fixtures/news.yml +8 -0
  82. data/test/fixtures/projects.yml +10 -0
  83. data/test/fixtures/taggings.yml +32 -0
  84. data/test/fixtures/tags.yml +11 -0
  85. data/test/fixtures/users.yml +9 -0
  86. data/test/fixtures/votable_caches.yml +2 -0
  87. data/test/fixtures/votables.yml +4 -0
  88. data/test/fixtures/voters.yml +6 -0
  89. data/test/liquid/drops/attachment_drop_test.rb +15 -0
  90. data/test/liquid/drops/issue_relations_drop_test.rb +24 -0
  91. data/test/liquid/drops/issues_drop_test.rb +38 -0
  92. data/test/liquid/drops/news_drop_test.rb +38 -0
  93. data/test/liquid/drops/projects_drop_test.rb +44 -0
  94. data/test/liquid/drops/uses_drop_test.rb +36 -0
  95. data/test/liquid/filters/arrays_filter_test.rb +31 -0
  96. data/test/liquid/filters/base_filter_test.rb +67 -0
  97. data/test/liquid/filters/colors_filter_test.rb +33 -0
  98. data/test/liquid/liquid_helper.rb +34 -0
  99. data/test/models/attachment.rb +3 -0
  100. data/test/models/issue.rb +21 -0
  101. data/test/models/issue_relation.rb +10 -0
  102. data/test/models/news.rb +3 -0
  103. data/test/models/project.rb +8 -0
  104. data/test/models/user.rb +11 -0
  105. data/test/models/vote_classes.rb +33 -0
  106. data/test/money_helper_test.rb +12 -0
  107. data/test/schema.rb +144 -0
  108. data/test/tags_helper_test.rb +29 -0
  109. data/test/test_helper.rb +66 -0
  110. data/test/vote_helper_test.rb +28 -0
  111. data/vendor/assets/images/money.png +0 -0
  112. data/vendor/assets/images/vcard.png +0 -0
  113. data/vendor/assets/javascripts/Chart.bundle.min.js +16 -0
  114. data/vendor/assets/javascripts/select2.js +2 -0
  115. data/vendor/assets/javascripts/select2_helpers.js +192 -0
  116. data/vendor/assets/stylesheets/money.css +96 -0
  117. data/vendor/assets/stylesheets/select2.css +424 -0
  118. metadata +295 -0
@@ -0,0 +1,66 @@
1
+ require 'action_view'
2
+ require 'redmineup/settings/money'
3
+
4
+ module Redmineup
5
+ module MoneyHelper
6
+ def object_price(obj, price_field = :price, options = {})
7
+ options.merge!({:symbol => true})
8
+ price_to_currency(obj.try(price_field), obj.currency, options).to_s if obj.respond_to?(:currency)
9
+ end
10
+
11
+ def prices_collection_by_currency(prices_collection, options = {})
12
+ return [] if prices_collection.blank? || prices_collection == 0
13
+ prices = prices_collection
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
16
+ end
17
+
18
+ def deal_currency_icon(currency)
19
+ case currency.to_s.upcase
20
+ when 'EUR'
21
+ 'icon-money-euro'
22
+ when 'GBP'
23
+ 'icon-money-pound'
24
+ when 'JPY'
25
+ 'icon-money-yen'
26
+ else
27
+ 'icon-money-dollar'
28
+ end
29
+ end
30
+
31
+ def collection_for_currencies_select(default_currency = Redmineup::Settings::Money.default_currency, major_currencies = Redmineup::Settings::Money.major_currencies)
32
+ currencies = []
33
+ currencies << default_currency.to_s unless default_currency.blank?
34
+ currencies |= major_currencies
35
+ currencies.map do |c|
36
+ currency = Redmineup::Currency.find(c)
37
+ ["#{currency.iso_code} (#{currency.symbol})", currency.iso_code] if currency
38
+ end.compact.uniq
39
+ end
40
+
41
+ def all_currencies
42
+ Currency.table.inject([]) do |array, (_, attributes)|
43
+ array ||= []
44
+ array << [attributes[:name].to_s + (attributes[:symbol].blank? ? '' : " (#{attributes[:symbol]})"), attributes[:iso_code]]
45
+ array
46
+ end.sort{|x, y| x[0] <=> y[0]}
47
+ end
48
+
49
+ def price_to_currency(price, currency = Redmineup::Settings::Money.default_currency, options = {})
50
+ return '' if price.blank?
51
+
52
+ currency = 'USD' unless currency.is_a?(String)
53
+ default_options = {
54
+ decimal_mark: Redmineup::Settings::Money.decimal_separator,
55
+ thousands_separator: Redmineup::Settings::Money.thousands_delimiter
56
+ }.reject { |_k, v| v.nil? }
57
+
58
+ currency = Redmineup::Currency.find(currency)
59
+ Redmineup::Currency.format(price.to_f, currency, default_options.merge(options))
60
+ end
61
+ end
62
+ end
63
+
64
+ unless ActionView::Base.included_modules.include?(Redmineup::MoneyHelper)
65
+ ActionView::Base.send(:include, Redmineup::MoneyHelper)
66
+ end
@@ -0,0 +1,33 @@
1
+ module Redmineup
2
+ module Patches
3
+ module LiquidPatch
4
+ module StandardFilters
5
+
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
23
+ end
24
+ end
25
+
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ unless Liquid::StandardFilters.included_modules.include?(Redmineup::Patches::LiquidPatch::StandardFilters)
32
+ Liquid::StandardFilters.send(:include, Redmineup::Patches::LiquidPatch::StandardFilters)
33
+ end
@@ -0,0 +1,46 @@
1
+ require 'redmineup/settings'
2
+
3
+ module Redmineup
4
+ class Settings
5
+ class Money
6
+ TAX_TYPE_EXCLUSIVE = 1
7
+ TAX_TYPE_INCLUSIVE = 2
8
+
9
+ class << self
10
+ def default_currency
11
+ Redmineup::Settings['default_currency'] || 'USD'
12
+ end
13
+
14
+ def major_currencies
15
+ currencies = Redmineup::Settings['major_currencies'].to_s.split(',').select { |c| !c.blank? }.map(&:strip)
16
+ currencies = %w[USD EUR GBP RUB CHF] if currencies.blank?
17
+ currencies.compact.uniq
18
+ end
19
+
20
+ def default_tax
21
+ Redmineup::Settings['default_tax'].to_f
22
+ end
23
+
24
+ def tax_type
25
+ ((['1', '2'] & [Redmineup::Settings['tax_type'].to_s]).first || TAX_TYPE_EXCLUSIVE).to_i
26
+ end
27
+
28
+ def tax_exclusive?
29
+ tax_type == TAX_TYPE_EXCLUSIVE
30
+ end
31
+
32
+ def thousands_delimiter
33
+ ([' ', ',', '.'] & [Redmineup::Settings['thousands_delimiter']]).first
34
+ end
35
+
36
+ def decimal_separator
37
+ ([',', '.'] & [Redmineup::Settings['decimal_separator']]).first
38
+ end
39
+
40
+ def disable_taxes?
41
+ Redmineup::Settings['disable_taxes'].to_i > 0
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,53 @@
1
+ module Redmineup
2
+ class Settings
3
+ SECTIONS = {
4
+ 'money' => { id: :money, label: :label_redmineup_money, partial: 'money' }
5
+ }.freeze
6
+
7
+ class << self
8
+ def initialize_gem_settings
9
+ return if !Object.const_defined?('Setting') || Setting.respond_to?(:plugin_redmineup)
10
+
11
+ if Setting.respond_to?(:define_setting)
12
+ Setting.send(:define_setting, 'plugin_redmineup', 'default' => default_settings, 'serialized' => true)
13
+ elsif Setting.respond_to?(:available_settings)
14
+ Setting.available_settings['plugin_redmineup'] = { 'default' => default_settings, 'serialized' => true }
15
+ Setting.class.send(:define_method, 'plugin_redmineup', -> { Setting['plugin_redmineup'] })
16
+ Setting.class.send(:define_method, 'plugin_redmineup=', lambda do |val|
17
+ setting = find_or_default('plugin_redmineup')
18
+ setting.value = val || ''
19
+ @cached_settings['plugin_redmineup'] = nil
20
+ setting.save(validate: false)
21
+ setting.value
22
+ end)
23
+ end
24
+ @settings_initialized
25
+ end
26
+
27
+ # Use apply instead attrs assign because it can rewrite other attributes
28
+ def apply=(values)
29
+ initialize_gem_settings unless @settings_initialized
30
+
31
+ Setting.plugin_redmineup = Setting.plugin_redmineup.merge(values)
32
+ end
33
+
34
+ def values
35
+ initialize_gem_settings unless @settings_initialized
36
+ Object.const_defined?('Setting') ? Setting.plugin_redmineup : {}
37
+ end
38
+
39
+ def [](value)
40
+ initialize_gem_settings unless @settings_initialized
41
+ return Setting.plugin_redmineup[value] if Object.const_defined?('Setting')
42
+
43
+ nil
44
+ end
45
+
46
+ private
47
+
48
+ def default_settings
49
+ {}
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,3 @@
1
+ module Redmineup
2
+ VERSION = '1.0.2'
3
+ end
data/lib/redmineup.rb ADDED
@@ -0,0 +1,108 @@
1
+ require 'active_record'
2
+ require 'action_view'
3
+
4
+ require 'redmineup/version'
5
+ require 'redmineup/engine'
6
+
7
+ require 'redmineup/settings'
8
+ require 'redmineup/settings/money'
9
+
10
+ require 'redmineup/acts_as_list/list'
11
+ require 'redmineup/acts_as_taggable/tag'
12
+ require 'redmineup/acts_as_taggable/tag_list'
13
+ require 'redmineup/acts_as_taggable/tagging'
14
+ require 'redmineup/acts_as_taggable/up_acts_as_taggable'
15
+ require 'redmineup/acts_as_viewed/up_acts_as_viewed'
16
+ require 'redmineup/acts_as_votable/up_acts_as_votable'
17
+ require 'redmineup/acts_as_votable/up_acts_as_voter'
18
+ require 'redmineup/acts_as_votable/vote'
19
+ require 'redmineup/acts_as_votable/voter'
20
+ require 'redmineup/acts_as_draftable/up_acts_as_draftable'
21
+ require 'redmineup/acts_as_draftable/draft'
22
+ require 'redmineup/acts_as_priceable/up_acts_as_priceable'
23
+
24
+ require 'redmineup/currency'
25
+ require 'redmineup/helpers/tags_helper'
26
+ require 'redmineup/money_helper'
27
+ require 'redmineup/colors_helper'
28
+
29
+ require 'liquid'
30
+ require 'redmineup/liquid/filters/base'
31
+ require 'redmineup/liquid/filters/arrays'
32
+ require 'redmineup/liquid/filters/colors'
33
+ require 'redmineup/liquid/drops/issues_drop'
34
+ require 'redmineup/liquid/drops/news_drop'
35
+ require 'redmineup/liquid/drops/projects_drop'
36
+ require 'redmineup/liquid/drops/users_drop'
37
+ require 'redmineup/liquid/drops/time_entries_drop'
38
+ require 'redmineup/liquid/drops/attachment_drop'
39
+ require 'redmineup/liquid/drops/issue_relations_drop'
40
+
41
+ require 'redmineup/helpers/external_assets_helper'
42
+ require 'redmineup/helpers/form_tag_helper'
43
+ require 'redmineup/helpers/rup_calendar_helper'
44
+ require 'redmineup/assets_manager'
45
+
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)
49
+
50
+ module Redmineup
51
+ GEM_NAME = 'redmineup'.freeze
52
+ end
53
+
54
+ if defined?(ActiveRecord::Base)
55
+ ActiveRecord::Base.send :include, Redmineup::ActsAsList::List
56
+ ActiveRecord::Base.extend(Redmineup::ActsAsVotable::Voter)
57
+ ActiveRecord::Base.extend(Redmineup::ActsAsVotable::Votable)
58
+ end
59
+
60
+ Redmineup::AssetsManager.install_assets
61
+
62
+ if defined?(ActionView::Base)
63
+ ActionView::Base.send :include, Redmineup::ExternalAssetsHelper
64
+ ActionView::Base.send :include, Redmineup::FormTagHelper
65
+ end
66
+
67
+ def requires_redmineup(arg)
68
+ def compare_versions(requirement, current)
69
+ raise ArgumentError.new('wrong version format') unless check_version_format(requirement)
70
+
71
+ requirement = requirement.split('.').collect(&:to_i)
72
+ requirement <=> current.slice(0, requirement.size)
73
+ end
74
+
75
+ def check_version_format(version)
76
+ version =~ /^\d+.?\d*.?\d*$/m
77
+ end
78
+
79
+ arg = { version_or_higher: arg } unless arg.is_a?(Hash)
80
+ arg.assert_valid_keys(:version, :version_or_higher)
81
+
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
108
+ end
data/redmineup.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'redmineup/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "redmineup"
8
+ spec.version = Redmineup::VERSION
9
+ spec.authors = ["RedmineUP"]
10
+ spec.email = ["support@redmineup.com"]
11
+ spec.summary = %q{Common libraries for RedmineUP plugins for Redmine}
12
+ spec.description = %q{Common libraries for RedmineUP plugins (www.redmineup.com) for Redmine. Required Redmine from http://redmine.org}
13
+ spec.homepage = "https://www.redmineup.com"
14
+ spec.license = "GPL-2.0"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+ spec.required_ruby_version = ">= 2.0.0"
21
+
22
+ spec.add_runtime_dependency 'rails'
23
+ spec.add_runtime_dependency 'liquid', '> 4.0', '< 5.0'
24
+ spec.add_runtime_dependency 'rubyzip'
25
+
26
+ spec.add_development_dependency 'sqlite3'
27
+ spec.add_development_dependency 'mysql2'
28
+ spec.add_development_dependency 'pg'
29
+ end
@@ -0,0 +1,29 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ class DraftTest < ActiveSupport::TestCase
4
+ def test_restore
5
+ issue = Issue.new(subject: 'some subject', description: 'some description')
6
+
7
+ issue.save_draft
8
+ restored_issue = Redmineup::ActsAsDraftable::Draft.find(issue.draft_id).restore
9
+
10
+ assert_equal issue.subject, restored_issue.subject
11
+ assert_equal issue.description, restored_issue.description
12
+ end
13
+
14
+ def test_restore_all
15
+ first_issue = Issue.new(subject: 'first subject')
16
+ first_issue.save_draft
17
+ second_issue = Issue.new(subject: 'second subject')
18
+ second_issue.save_draft
19
+
20
+ restored_issues = Redmineup::ActsAsDraftable::Draft.restore_all
21
+ assert_equal [first_issue.subject, second_issue.subject], restored_issues.map(&:subject).sort
22
+ end
23
+
24
+ private
25
+
26
+ def current_user
27
+ users(:sam)
28
+ end
29
+ end
@@ -0,0 +1,178 @@
1
+ require File.expand_path('../../test_helper', __FILE__)
2
+
3
+ class RupActsAsDraftableTest < ActiveSupport::TestCase
4
+ def test_up_acts_as_draftable_without_arguments
5
+ assert_nothing_raised do
6
+ Project.up_acts_as_draftable
7
+ end
8
+ end
9
+
10
+ def test_up_acts_as_draftable_with_parent
11
+ assert_nothing_raised do
12
+ News.up_acts_as_draftable(parent: :author)
13
+ end
14
+ assert User.new.respond_to?(:drafts)
15
+ end
16
+
17
+ def test_up_acts_as_draftable_with_non_existing_parent
18
+ assert_raises do
19
+ Issue.up_acts_as_draftable(parent: :foo)
20
+ end
21
+ end
22
+
23
+ def test_up_acts_as_draftable_with_non_hash_argument
24
+ assert_raises do
25
+ Issue.up_acts_as_draftable('bar')
26
+ end
27
+ end
28
+
29
+ def test_up_acts_as_draftable_with_invalid_hash_key
30
+ assert_raises do
31
+ Issue.up_acts_as_draftable(baz: 'qux')
32
+ end
33
+ end
34
+
35
+ def test_drafts
36
+ Issue.up_acts_as_draftable parent: :project
37
+ issue = Issue.new
38
+ issue.save_draft
39
+
40
+ assert_equal 1, Issue.drafts(current_user).count
41
+ assert_equal Redmineup::ActsAsDraftable::Draft, Issue.drafts(current_user).first.class
42
+ end
43
+
44
+ def test_from_draft
45
+ Issue.up_acts_as_draftable parent: :project
46
+ issue = Issue.new(subject: 'subject')
47
+ issue.save_draft
48
+
49
+ issue_from_draft = Issue.from_draft(issue.draft_id)
50
+
51
+ assert_equal Issue, issue_from_draft.class
52
+ assert_equal true, issue_from_draft.new_record?
53
+ assert_equal issue.draft_id, issue_from_draft.draft_id
54
+
55
+ assert_equal issue.subject, issue_from_draft.subject
56
+ end
57
+
58
+ def test_draft_deleted_after_save
59
+ issue = Issue.new(subject: 'subject')
60
+ issue.save_draft
61
+
62
+ issue_from_draft = Issue.from_draft(issue.draft_id)
63
+
64
+ assert_difference 'Issue.count' do
65
+ assert_difference 'Redmineup::ActsAsDraftable::Draft.count', -1 do
66
+ issue_from_draft.save!
67
+ end
68
+ end
69
+ assert_nil issue_from_draft.draft_id
70
+ end
71
+
72
+ def test_from_draft_with_non_existing_draft_id
73
+ assert_raises do
74
+ Issue.from_draft(999)
75
+ end
76
+ end
77
+
78
+ def test_from_draft_with_wrong_type
79
+ Project.up_acts_as_draftable
80
+
81
+ project = Project.new
82
+ project.save_draft
83
+
84
+ assert_raises do
85
+ Issue.from_draft(project.draft_id)
86
+ end
87
+ end
88
+
89
+ def test_dump_to_draft
90
+ assert_equal String, Issue.new.dump_to_draft.class
91
+ end
92
+
93
+ def test_load_from_draft
94
+ attributes = {subject: 'subject', description: 'description'}
95
+ draft = Issue.new(attributes).dump_to_draft
96
+
97
+ issue = Issue.new
98
+ issue.load_from_draft(draft)
99
+
100
+ assert_equal attributes[:subject], issue.subject
101
+ assert_equal attributes[:description], issue.description
102
+ end
103
+
104
+ def test_save_draft
105
+ Issue.up_acts_as_draftable parent: :project
106
+ attributes = { subject: 'subject' }
107
+ issue = Issue.new(attributes)
108
+
109
+ assert_no_difference 'Issue.count' do
110
+ assert_difference 'Redmineup::ActsAsDraftable::Draft.count' do
111
+ result = issue.save_draft
112
+ assert_equal true, result
113
+ end
114
+ end
115
+ assert_not_nil issue.draft_id
116
+
117
+ draft = Redmineup::ActsAsDraftable::Draft.find(issue.draft_id)
118
+ assert_equal 'Issue', draft.target_type
119
+ assert_equal current_user.id, draft.user_id
120
+ assert_equal attributes[:subject], draft.restore.subject
121
+ end
122
+
123
+ def test_save_draft_with_associations
124
+ Issue.up_acts_as_draftable parent: :project
125
+ issue = Issue.new(project: projects(:second_project))
126
+ issue.save_draft
127
+
128
+ draft = Redmineup::ActsAsDraftable::Draft.find(issue.draft_id)
129
+ assert_equal issue.project.name, draft.restore.project.name
130
+ end
131
+
132
+ def test_save_draft_updates_existing_draft
133
+ Issue.up_acts_as_draftable parent: :project
134
+ issue = Issue.new
135
+ issue.save_draft
136
+
137
+ issue.subject = 'changed subject'
138
+ assert_no_difference 'Issue.count' do
139
+ assert_no_difference 'Redmineup::ActsAsDraftable::Draft.count' do
140
+ issue.save_draft
141
+ end
142
+ end
143
+
144
+ draft = Redmineup::ActsAsDraftable::Draft.find(issue.draft_id)
145
+ assert_equal issue.subject, draft.restore.subject
146
+ end
147
+
148
+ def test_save_draft_does_not_save_persisted_object
149
+ issue = issues(:second_issue)
150
+ assert_equal false, issue.save_draft
151
+ end
152
+
153
+ def test_save_draft_saves_persisted_but_changed_object
154
+ issue = issues(:second_issue)
155
+ issue.subject = 'changed subject'
156
+ assert_equal true, issue.save_draft
157
+ end
158
+
159
+ def test_update_draft
160
+ issue = Issue.new(subject: 'subject')
161
+ issue.save_draft
162
+
163
+ assert_no_difference 'Issue.count' do
164
+ assert_no_difference 'Redmineup::ActsAsDraftable::Draft.count' do
165
+ issue.update_draft(subject: 'updated_subject')
166
+ end
167
+ end
168
+
169
+ draft = Redmineup::ActsAsDraftable::Draft.find(issue.draft_id)
170
+ assert_equal issue.subject, draft.restore.subject
171
+ end
172
+
173
+ private
174
+
175
+ def current_user
176
+ users(:sam)
177
+ end
178
+ end