redmine_crm 0.0.36 → 0.0.37

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/README.md +160 -33
  4. data/Rakefile +3 -12
  5. data/bitbucket-pipelines.yml +20 -6
  6. data/doc/CHANGELOG +5 -0
  7. data/lib/redmine_crm.rb +5 -0
  8. data/lib/redmine_crm/acts_as_draftable/draft.rb +40 -0
  9. data/lib/redmine_crm/acts_as_draftable/rcrm_acts_as_draftable.rb +154 -0
  10. data/lib/redmine_crm/acts_as_taggable/rcrm_acts_as_taggable.rb +1 -1
  11. data/lib/redmine_crm/acts_as_viewed/rcrm_acts_as_viewed.rb +0 -1
  12. data/lib/redmine_crm/acts_as_votable/votable.rb +6 -10
  13. data/lib/redmine_crm/helpers/form_tag_helper.rb +31 -0
  14. data/lib/redmine_crm/money_helper.rb +0 -2
  15. data/lib/redmine_crm/version.rb +1 -1
  16. data/redmine_crm.gemspec +6 -1
  17. data/test/acts_as_draftable/draft_test.rb +29 -0
  18. data/test/acts_as_draftable/rcrm_acts_as_draftable_test.rb +185 -0
  19. data/test/acts_as_taggable/rcrm_acts_as_taggable_test.rb +9 -11
  20. data/test/acts_as_taggable/tag_list_test.rb +25 -29
  21. data/test/acts_as_taggable/tag_test.rb +58 -51
  22. data/test/acts_as_votable/rcrm_acts_as_votable_test.rb +6 -4
  23. data/test/acts_as_votable/rcrm_acts_as_voter_test.rb +7 -5
  24. data/test/acts_as_votable/votable_test.rb +1 -1
  25. data/test/database.yml +14 -18
  26. data/test/models/issue.rb +14 -0
  27. data/test/{fixtures → models}/news.rb +0 -0
  28. data/test/{fixtures → models}/project.rb +0 -0
  29. data/test/{fixtures → models}/user.rb +0 -0
  30. data/test/{fixtures → models}/vote_classes.rb +0 -20
  31. data/test/schema.rb +9 -1
  32. data/test/test_helper.rb +5 -57
  33. data/vendor/assets/javascripts/select2_helpers.js +39 -0
  34. metadata +75 -14
  35. data/test/fixtures/issue.rb +0 -22
  36. data/test/liquid/drops/liquid_test.rb +0 -52
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f2ae8872b72b3265c1ae6e6993a8b3e0ca78f920
4
- data.tar.gz: c8364d112ed92618726af3ef54b16ffc23090abd
3
+ metadata.gz: 4b0ba370b2cc56fc7a7573ba6e7fa65f63a739a9
4
+ data.tar.gz: 2e257839a165ba3ac9a35f1735d25721dd7ab4a6
5
5
  SHA512:
6
- metadata.gz: 7a623433baaf7d77bf346e0a04e0a0052eeee082d063d13b073b20d487208bf1ac0183d03380b18e109d7ddfbc88405f5c8afde7d05c4b3a2c65241f50ff1b67
7
- data.tar.gz: 4004698fa8ee608d219a319142708253de3dc0770bba5d856715ffb9c49d7753c0c41320321bf8a9a6296b87a2767249727d215077487972088a58889b07389c
6
+ metadata.gz: 8166cb752f502d9b172c30bf781ea30313f2a2fc5b2d37b9eb2a7585f8bd5e169509e6ceeee2703def216331ce00ad391ffc2ddf1571773dd0ba6adea658a45c
7
+ data.tar.gz: b2763d0e87a531654ce8fb73937becf3ddb1fb53a5702452c8ce83bcdfc7172a95a16e429e26192d8e2fff00cb97dd3ac8fdd95ec68c5752418090e7064e67ed
data/.gitignore CHANGED
@@ -4,6 +4,8 @@
4
4
  /_yardoc/
5
5
  /coverage/
6
6
  /pkg/
7
+ /public/
8
+ /test/public/
7
9
  /spec/reports/
8
10
  /tmp/
9
11
  *.bundle
data/README.md CHANGED
@@ -1,71 +1,198 @@
1
1
  # RedmineCrm
2
2
 
3
- Gem include next functional for Redmine plugins:
4
- * rcrm_acts_as_taggable
5
- * rcrm_acts_as_votable
6
- * rcrm_acts_as_viewable
3
+ This gem is used at RedmineUP as a general place for shared functionality and
4
+ assets. It contains **Chart.js** and **select2** JS libraries, various mixins
5
+ for ActiveRecord models and other things you might find useful.
7
6
 
8
- ## Installation
7
+ Among mixins there are:
8
+
9
+ * rcrm_acts_as_draftable
10
+ * rcrm_acts_as_taggable
11
+ * rcrm_acts_as_viewable
12
+ * rcrm_acts_as_votable
9
13
 
10
- Add this line to your application's Gemfile:
11
14
 
15
+ ## Installation
16
+
17
+ Add it to your plugin's Gemfile:
12
18
  ```ruby
13
- gem "redmine_crm"
19
+ gem 'redmine_crm'
20
+ ```
21
+
22
+ Then invoke the following command in your plugin's or Redmine directory:
23
+ ```
24
+ $ bundle install
14
25
  ```
15
26
 
16
- And then execute:
27
+ And now you can start using it.
17
28
 
18
- $ bundle
19
29
 
20
- Or install it yourself as:
30
+ ## Usage
31
+ ### Drafts
32
+ This module allows saving and restoring drafts for different models. To be
33
+ saved as a draft, an instance does not need to pass the validations. Drafts
34
+ store not only model attributes, but also associations and virtual attributes.
35
+ A draft could be linked to a given user, so every user can manage his/her own
36
+ drafts independent of others. A draft might have a parent instance.
37
+
38
+ First of all, drafts need to be saved somewhere, so let's create a migration:
39
+ ```ruby
40
+ class CreateDrafts < Rails.version > '5' ? ActiveRecord::Migration[5.0] : ActiveRecord::Migration
41
+ def change
42
+ ActiveRecord::Base.create_drafts_table
43
+ end
44
+ end
45
+ ```
46
+
47
+ Then in the Redmine directory run:
48
+ ```
49
+ $ rake redmine:plugins:migrate
50
+ ```
21
51
 
22
- $ gem install redmine_crm
52
+ Next, add `rcrm_acts_as_draftable` to a model for which you want to save drafts:
53
+ ```ruby
54
+ class Message < ActiveRecord::Base
55
+ rcrm_acts_as_draftable
56
+ end
57
+ ```
23
58
 
24
- Create migration with next code:
59
+ And that's it for the preparation, now you're ready to make use of drafts:
25
60
  ```ruby
26
- require 'redmine_crm/rcrm_acts_as_taggable'
61
+ # You can save message as a draft.
62
+ Message.new(subject: 'foo').save_draft
63
+
64
+ # And later restore message from the draft.
65
+ draft = Message.drafts(nil).last
66
+ message = draft.restore
67
+ puts message.subject
68
+ # => foo
69
+
70
+ # Draft can be overwritten.
71
+ message.content = 'bar'
72
+ puts message.save_draft
73
+ # => true
74
+
75
+ # You can also save draft linked to a particular user.
76
+ Message.new(subject: 'baz').save_draft(current_user)
77
+
78
+ # And restore message from some user's draft.
79
+ user_draft = Message.drafts(current_user).last
80
+ user_message = user_draft.restore
81
+ puts user_message.subject
82
+ # => baz
83
+
84
+ # It's also possible to restore a bunch of messages at once.
85
+ messages = Message.drafts(current_user).restore_all
86
+ p messages.map(&:subject)
87
+ # => ["baz"]
88
+
89
+ # When a model instance is saved, corresponding draft is removed.
90
+ puts Message.drafts(current_user).count
91
+ # => 1
92
+ user_message.board_id = Board.first.id
93
+ user_message.save!
94
+ puts Message.drafts(current_user).count
95
+ # => 0
96
+
97
+ # Draft won't be saved for a persisted instance.
98
+ puts user_message.save_draft
99
+ # => false
100
+ ```
27
101
 
28
- def self.up
29
- ActiveRecord::Base.create_taggable_table
30
- end
102
+ ### Tags
103
+ This module makes it possible to tag objects.
31
104
 
32
- def self.down
33
- ActiveRecord::Base.drop_taggable_table
105
+ First, create a migration:
106
+ ```ruby
107
+ class CreateTags < Rails.version > '5' ? ActiveRecord::Migration[5.0] : ActiveRecord::Migration
108
+ def change
109
+ ActiveRecord::Base.create_taggable_table
34
110
  end
35
111
  end
36
112
  ```
37
- For rcrm_acts_as_viewed You may add column for your model
38
- with help:
39
113
 
114
+ Then in the Redmine directory run:
115
+ ```
116
+ $ rake redmine:plugins:migrate
117
+ ```
118
+
119
+ Next, add `rcrm_acts_as_taggable` to a model for which you want to provide tags:
40
120
  ```ruby
121
+ class Contact < ActiveRecord::Base
122
+ rcrm_acts_as_taggable
123
+ end
124
+ ```
41
125
 
42
- YourModel.add_viewings_columns
126
+ TODO: Add examples of usage.
43
127
 
44
- ```
45
- It will add two column to your table (views and total_views)
46
- and view_count will return two number: total view and unique views.
47
- Without this migration you will get only unique views.
128
+ ### Viewings
129
+ This module allows you to count views for some ActiveRecord model instances.
48
130
 
49
- Run migration for plugin:
131
+ To count views you'll need to create a migration:
132
+ ```ruby
133
+ class CreateViewings < Rails.version > '5' ? ActiveRecord::Migration[5.0] : ActiveRecord::Migration
134
+ def change
135
+ ActiveRecord::Base.create_viewings_table
136
+ end
137
+ end
138
+ ```
50
139
 
140
+ To apply it, run the following in the Redmine directory:
51
141
  ```
52
- rake redmine:plugins:migrate
142
+ $ rake redmine:plugins:migrate
53
143
  ```
54
144
 
55
- ## Usage
145
+ Then add `rcrm_acts_as_viewed` to a model for which you want to count views.
146
+ ```ruby
147
+ class Question < ActiveRecord::Base
148
+ rcrm_acts_as_viewed
149
+ end
150
+ ```
151
+
152
+ TODO: Provide some usage examples.
56
153
 
57
- Add to model
154
+ ### Votes
155
+ With this module you can make your models votable and allow users to vote.
58
156
 
157
+ As always, create a migration first:
59
158
  ```ruby
60
- rcrm_acts_as_taggable
159
+ class CreateVotes < Rails.version > '5' ? ActiveRecord::Migration[5.0] : ActiveRecord::Migration
160
+ def change
161
+ ActiveRecord::Base.create_votable_table
162
+ end
163
+ end
164
+ ```
165
+
166
+ Then apply it by running the following command in the Redmine directory:
167
+ ```
168
+ $ rake redmine:plugins:migrate
169
+ ```
170
+
171
+ To make a model votable, add `rcrm_acts_as_votable` to it:
172
+ ```ruby
173
+ class Question < ActiveRecord::Base
61
174
  rcrm_acts_as_votable
175
+ end
62
176
  ```
63
177
 
178
+ TODO: Write about `rcrm_acts_as_voter` and add usage examples.
64
179
 
65
- ## Run test
66
180
 
181
+ ## Development
182
+
183
+ If you're planning to extend this gem, you will need to install development
184
+ dependencies. To do this, execute the following command in the project's
185
+ directory:
186
+ ```
187
+ $ bundle install
188
+ ```
189
+
190
+ After that you'll be able to run tests:
67
191
  ```
68
- rake test
192
+ $ bundle exec rake test
69
193
  ```
70
194
 
71
- For test for mysql set enviroment variable DB to value 'mysql' and run test.
195
+ SQLite in-memory database will be used by default, which is the fastest way to run tests. To run them using different database adapters, set `DB` environment variable to one of the available values — `mysql`, `postgresql`, `sqlite`. For example, to use PostgreSQL, invoke tests like so:
196
+ ```
197
+ $ bundle exec rake test DB=postgresql
198
+ ```
data/Rakefile CHANGED
@@ -1,20 +1,11 @@
1
- require "bundler/gem_tasks"
2
-
3
- require 'rake'
1
+ require 'bundler/gem_tasks'
4
2
  require 'rake/testtask'
5
- # require 'rake/rdoctask'
6
3
 
7
- desc 'Default: run unit tests.'
8
- task :default => :test
4
+ task default: :test
9
5
 
10
- desc 'Test the acts_as_taggable_on_steroids plugin.'
6
+ desc 'Run tests'
11
7
  Rake::TestTask.new(:test) do |t|
12
8
  t.libs << 'test'
13
9
  t.pattern = 'test/**/*_test.rb'
14
10
  t.verbose = true
15
11
  end
16
-
17
- desc 'Copy migration file to db/migration of plugin'
18
- file 'copy_migration' do
19
- cp "generators/redmine_crm_migration/templates/migration.rb", "db/migrate/redmine_crm.rb"
20
- end
@@ -8,10 +8,24 @@ image: ruby:2.3.0
8
8
  pipelines:
9
9
  default:
10
10
  - step:
11
- script: # Modify the commands below to build your repository.
12
- - bundler --version
11
+ script:
13
12
  - bundle install
14
- - gem install byebug
15
- - gem install rails -v 5.1.2
16
- - gem install sqlite3
17
- - rake test
13
+ - bundle exec rake test DB=sqlite
14
+ - bundle exec rake test DB=postgresql
15
+ - bundle exec rake test DB=mysql
16
+ services:
17
+ - mysql
18
+ - postgres
19
+
20
+ definitions:
21
+ services:
22
+ mysql:
23
+ image: mysql
24
+ environment:
25
+ MYSQL_DATABASE: redmine_crm_test
26
+ MYSQL_ROOT_PASSWORD: password
27
+ postgres:
28
+ image: postgres
29
+ environment:
30
+ POSTGRES_DB: redmine_crm_test
31
+ POSTGRES_PASSWORD: password
data/doc/CHANGELOG CHANGED
@@ -4,6 +4,11 @@ Redmine crm gem - general functions for plugins (tags, vote, viewing, currency)
4
4
  Copyright (C) 2011-2018 RedmineUP
5
5
  https://www.redmineup.com/
6
6
 
7
+ == 2018-03-28 v0.0.37
8
+
9
+ * Added rcrm_acts_as_draftable
10
+ * Added transform_to_select2 helper
11
+
7
12
  == 2018-03-22 v0.0.36
8
13
 
9
14
  * select2_tag improvements
data/lib/redmine_crm.rb CHANGED
@@ -1,3 +1,6 @@
1
+ require 'active_record'
2
+ require 'action_view'
3
+
1
4
  require 'redmine_crm/version'
2
5
 
3
6
  require 'redmine_crm/acts_as_list/list'
@@ -10,6 +13,8 @@ require 'redmine_crm/acts_as_votable/rcrm_acts_as_votable'
10
13
  require 'redmine_crm/acts_as_votable/rcrm_acts_as_voter'
11
14
  require 'redmine_crm/acts_as_votable/vote'
12
15
  require 'redmine_crm/acts_as_votable/voter'
16
+ require 'redmine_crm/acts_as_draftable/rcrm_acts_as_draftable'
17
+ require 'redmine_crm/acts_as_draftable/draft'
13
18
 
14
19
  require 'redmine_crm/currency'
15
20
  require 'redmine_crm/helpers/tags_helper'
@@ -0,0 +1,40 @@
1
+ # The MIT License (MIT)
2
+
3
+ # Copyright (c) 2016-2018 Georg Ledermann
4
+
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ module RedmineCrm
24
+ module ActsAsDraftable
25
+ class Draft < ActiveRecord::Base
26
+ belongs_to :user
27
+ belongs_to :parent, polymorphic: true
28
+
29
+ validates_presence_of :data, :target_type
30
+
31
+ def restore
32
+ target_type.constantize.from_draft(self)
33
+ end
34
+
35
+ def self.restore_all
36
+ find_each.map(&:restore)
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,154 @@
1
+ # The MIT License (MIT)
2
+
3
+ # Copyright (c) 2016-2018 Georg Ledermann
4
+
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+
23
+ module RedmineCrm
24
+ module ActsAsDraftable #:nodoc: all
25
+ module Base
26
+ ALLOWED_DRAFT_OPTIONS = [:parent]
27
+
28
+ def draftable?
29
+ false
30
+ end
31
+
32
+ def rcrm_acts_as_draftable(options = {})
33
+ raise ArgumentError unless options.is_a?(Hash)
34
+ raise ArgumentError unless options.keys.all? { |k| ALLOWED_DRAFT_OPTIONS.include?(k) }
35
+
36
+ class_attribute :draft_parent
37
+
38
+ if options[:parent]
39
+ parent_class = self.reflect_on_all_associations(:belongs_to).find { |a| a.name == options[:parent] }.try(:klass)
40
+ raise ArgumentError unless parent_class
41
+
42
+ unless parent_class.method_defined?(:drafts)
43
+ parent_class.class_eval do
44
+ def drafts(user)
45
+ Draft.where(user: user, parent: self)
46
+ end
47
+
48
+ def self.child_drafts(user)
49
+ Draft.where(user: user, parent_type: self.base_class.name)
50
+ end
51
+ end
52
+ end
53
+
54
+ self.draft_parent = options[:parent]
55
+ end
56
+
57
+ attr_accessor :draft_id
58
+ after_create :clear_draft
59
+
60
+ extend RedmineCrm::ActsAsDraftable::ClassMethods
61
+ include RedmineCrm::ActsAsDraftable::InstanceMethods
62
+ end
63
+ end # Base
64
+
65
+ module ClassMethods
66
+ def draftable?
67
+ true
68
+ end
69
+
70
+ def from_draft(draft_or_id)
71
+ draft = draft_or_id.is_a?(Draft) ? draft_or_id : Draft.find(draft_or_id)
72
+ raise ArgumentError unless draft.target_type == name
73
+
74
+ target = draft.target_type.constantize.new
75
+ target.load_from_draft(draft.data)
76
+
77
+ target.send("#{draft_parent}=", draft.parent) if draft_parent
78
+ target.draft_id = draft.id
79
+ target
80
+ end
81
+
82
+ def drafts(user)
83
+ Draft.where(user: user, target_type: name)
84
+ end
85
+ end # ClassMethods
86
+
87
+ module InstanceMethods
88
+ def save_draft(user = nil)
89
+ return false unless self.new_record?
90
+
91
+ draft = Draft.find_by_id(self.draft_id) || Draft.new
92
+
93
+ draft.data = dump_to_draft
94
+ draft.target_type = self.class.name
95
+ draft.user = user
96
+ draft.parent = self.send(self.class.draft_parent) if self.class.draft_parent
97
+
98
+ result = draft.save
99
+ self.draft_id = draft.id if result
100
+ result
101
+ end
102
+
103
+ def update_draft(user, attributes)
104
+ with_transaction_returning_status do
105
+ assign_attributes(attributes)
106
+ save_draft(user)
107
+ end
108
+ end
109
+
110
+ def dump_to_draft
111
+ Marshal.dump(instance_values)
112
+ end
113
+
114
+ def load_from_draft(string)
115
+ values = Marshal.load(string)
116
+
117
+ values.each do |name, value|
118
+ instance_variable_set("@#{name}", value)
119
+ end
120
+ end
121
+
122
+ private
123
+
124
+ def clear_draft
125
+ if draft = Draft.find_by_id(self.draft_id)
126
+ self.draft_id = nil if draft.destroy
127
+ end
128
+ end
129
+ end # InstanceMethods
130
+
131
+ module Migration
132
+ def create_drafts_table
133
+ return if connection.table_exists?(:drafts)
134
+
135
+ connection.create_table :drafts do |t|
136
+ t.string :target_type, limit: 150, null: false
137
+ t.references :user
138
+ t.references :parent, polymorphic: true, index: true
139
+ t.binary :data, limit: 16777215, null: false
140
+ t.datetime :updated_at, null: false
141
+ end
142
+
143
+ connection.add_index :drafts, [:user_id, :target_type]
144
+ end
145
+
146
+ def drop_drafts_table
147
+ connection.drop_table :drafts if connection.table_exists?(:drafts)
148
+ end
149
+ end # Migration
150
+ end
151
+ end
152
+
153
+ ActiveRecord::Base.extend RedmineCrm::ActsAsDraftable::Base
154
+ ActiveRecord::Base.extend RedmineCrm::ActsAsDraftable::Migration