redmine_crm 0.0.23 → 0.0.25

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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/doc/CHANGELOG +4 -0
  4. data/lib/redmine_crm.rb +28 -20
  5. data/lib/redmine_crm/{rcrm_acts_as_taggable.rb → acts_as_taggable/rcrm_acts_as_taggable.rb} +93 -87
  6. data/lib/redmine_crm/acts_as_taggable/tag.rb +81 -0
  7. data/lib/redmine_crm/acts_as_taggable/tag_list.rb +111 -0
  8. data/lib/redmine_crm/acts_as_taggable/tagging.rb +16 -0
  9. data/lib/redmine_crm/acts_as_viewed/rcrm_acts_as_viewed.rb +274 -0
  10. data/lib/redmine_crm/{rcrm_acts_as_votable.rb → acts_as_votable/rcrm_acts_as_votable.rb} +8 -11
  11. data/lib/redmine_crm/acts_as_votable/rcrm_acts_as_voter.rb +20 -0
  12. data/lib/redmine_crm/{votable.rb → acts_as_votable/votable.rb} +36 -47
  13. data/lib/redmine_crm/{vote.rb → acts_as_votable/vote.rb} +7 -10
  14. data/lib/redmine_crm/{voter.rb → acts_as_votable/voter.rb} +29 -34
  15. data/lib/redmine_crm/currency/formatting.rb +0 -3
  16. data/lib/redmine_crm/currency/heuristics.rb +1 -1
  17. data/lib/redmine_crm/currency/loader.rb +1 -1
  18. data/lib/redmine_crm/helpers/tags_helper.rb +1 -3
  19. data/lib/redmine_crm/helpers/vote_helper.rb +29 -32
  20. data/lib/redmine_crm/liquid/drops/issues_drop.rb +66 -0
  21. data/lib/redmine_crm/liquid/drops/news_drop.rb +54 -0
  22. data/lib/redmine_crm/liquid/drops/projects_drop.rb +86 -0
  23. data/lib/redmine_crm/liquid/drops/users_drop.rb +72 -0
  24. data/lib/redmine_crm/liquid/filters/arrays.rb +178 -0
  25. data/lib/redmine_crm/liquid/filters/base.rb +208 -0
  26. data/lib/redmine_crm/version.rb +1 -1
  27. data/redmine_crm.gemspec +1 -1
  28. data/test/{acts_as_taggable_test.rb → acts_as_taggable/rcrm_acts_as_taggable_test.rb} +114 -151
  29. data/test/acts_as_taggable/tag_list_test.rb +38 -0
  30. data/test/acts_as_taggable/tag_test.rb +74 -0
  31. data/test/acts_as_taggable/tagging_test.rb +15 -0
  32. data/test/{viewed_test.rb → acts_as_viewed/rcrm_acts_as_viewed_test.rb} +17 -15
  33. data/test/{votable_test.rb → acts_as_votable/rcrm_acts_as_votable_test.rb} +3 -3
  34. data/test/acts_as_votable/rcrm_acts_as_voter_test.rb +12 -0
  35. data/test/{votable_model_test.rb → acts_as_votable/votable_test.rb} +4 -4
  36. data/test/{voter_model_test.rb → acts_as_votable/voter_test.rb} +7 -7
  37. data/test/currency_test.rb +10 -10
  38. data/test/fixtures/issue.rb +6 -2
  39. data/test/fixtures/issues.yml +13 -1
  40. data/test/fixtures/news.rb +3 -0
  41. data/test/fixtures/news.yml +8 -0
  42. data/test/fixtures/project.rb +8 -0
  43. data/test/fixtures/projects.yml +10 -0
  44. data/test/fixtures/user.rb +5 -1
  45. data/test/fixtures/users.yml +3 -2
  46. data/test/fixtures/vote_classes.rb +2 -3
  47. data/test/liquid/drops/issues_drop_test.rb +34 -0
  48. data/test/liquid/drops/liquid_test.rb +52 -0
  49. data/test/liquid/drops/news_drop_test.rb +38 -0
  50. data/test/liquid/drops/projects_drop_test.rb +44 -0
  51. data/test/liquid/drops/uses_drop_test.rb +36 -0
  52. data/test/liquid/filters/arrays_filter_test.rb +24 -0
  53. data/test/liquid/filters/base_filter_test.rb +63 -0
  54. data/test/liquid/liquid_helper.rb +32 -0
  55. data/test/money_helper_test.rb +5 -5
  56. data/test/schema.rb +21 -9
  57. data/test/test_helper.rb +26 -25
  58. metadata +76 -28
  59. data/lib/redmine_crm/rcrm_acts_as_viewed.rb +0 -287
  60. data/lib/redmine_crm/rcrm_acts_as_voter.rb +0 -27
  61. data/lib/redmine_crm/tag.rb +0 -81
  62. data/lib/redmine_crm/tag_list.rb +0 -112
  63. data/lib/redmine_crm/tagging.rb +0 -20
  64. data/test/tag_test.rb +0 -64
  65. data/test/tagging_test.rb +0 -14
@@ -26,7 +26,6 @@ module RedmineCrm
26
26
  alias_method name, method
27
27
  end
28
28
 
29
-
30
29
  def format(value, currency, *rules)
31
30
  # support for old format parameters
32
31
  rules = normalize_formatting_rules(rules)
@@ -220,8 +219,6 @@ module RedmineCrm
220
219
  "\\1#{rules[:decimal_mark]}\\3")
221
220
  end
222
221
  end
223
-
224
222
  end
225
-
226
223
  end
227
224
  end
@@ -148,4 +148,4 @@ module RedmineCrm
148
148
  end
149
149
  end
150
150
  end
151
- end
151
+ end
@@ -21,4 +21,4 @@ module RedmineCrm
21
21
  end
22
22
  end
23
23
  end
24
- end
24
+ end
@@ -3,13 +3,11 @@ module RedmineCrm
3
3
  # See the README for an example using tag_cloud.
4
4
  def tag_cloud(tags, classes)
5
5
  return if tags.empty?
6
-
7
6
  max_count = tags.sort_by(&:count).last.count.to_f
8
-
9
7
  tags.each do |tag|
10
8
  index = ((tag.count / max_count) * (classes.size - 1)).round
11
9
  yield tag, classes[index]
12
10
  end
13
11
  end
14
12
  end
15
- end
13
+ end
@@ -1,38 +1,35 @@
1
1
  module RedmineCrm
2
- module ActsAsVotable::Helpers
3
-
4
- # this helper provides methods that help find what words are
5
- # up votes and what words are down votes
6
- #
7
- # It can be called
8
- #
9
- # votable_object.votable_words.that_mean_true
10
- #
11
- module Words
12
-
13
- def votable_words
14
- VotableWords
15
- end
16
-
17
- end
18
-
19
- class VotableWords
20
-
21
- def self.that_mean_true
22
- ['up', 'upvote', 'like', 'liked', 'positive', 'yes', 'good', 'true', 1, true]
2
+ module ActsAsVotable
3
+ module Helpers
4
+ # this helper provides methods that help find what words are
5
+ # up votes and what words are down votes
6
+ #
7
+ # It can be called
8
+ #
9
+ # votable_object.votable_words.that_mean_true
10
+ #
11
+ module Words
12
+ def votable_words
13
+ VotableWords
14
+ end
23
15
  end
24
16
 
25
- def self.that_mean_false
26
- ['down', 'downvote', 'dislike', 'disliked', 'negative', 'no', 'bad', 'false', 0, false]
17
+ class VotableWords
18
+ def self.that_mean_true
19
+ ['up', 'upvote', 'like', 'liked', 'positive', 'yes', 'good', 'true', 1, true]
20
+ end
21
+
22
+ def self.that_mean_false
23
+ ['down', 'downvote', 'dislike', 'disliked', 'negative', 'no', 'bad', 'false', 0, false]
24
+ end
25
+
26
+ # check is word is a true or bad vote
27
+ # if the word is unknown, then it counts it as a true/good
28
+ # vote. this exists to allow all voting to be good by default
29
+ def self.meaning_of(word)
30
+ !that_mean_false.include?(word)
31
+ end
27
32
  end
28
-
29
- # check is word is a true or bad vote
30
- # if the word is unknown, then it counts it as a true/good
31
- # vote. this exists to allow all voting to be good by default
32
- def self.meaning_of word
33
- !that_mean_false.include?(word)
34
- end
35
-
36
33
  end
37
34
  end
38
- end
35
+ end
@@ -0,0 +1,66 @@
1
+ module RedmineCrm
2
+ module Liquid
3
+ class IssuesDrop < ::Liquid::Drop
4
+ def initialize(issues)
5
+ @issues = issues
6
+ end
7
+
8
+ def before_method(id)
9
+ issue = @issues.where(:id => id).first || Issue.new
10
+ IssueDrop.new issue
11
+ end
12
+
13
+ def all
14
+ @all ||= @issues.map do |issue|
15
+ IssueDrop.new issue
16
+ end
17
+ end
18
+
19
+ def each(&block)
20
+ all.each(&block)
21
+ end
22
+
23
+ def size
24
+ @issues.size
25
+ end
26
+ end
27
+
28
+ class IssueDrop < ::Liquid::Drop
29
+ include ActionView::Helpers::UrlHelper
30
+
31
+ delegate :id,
32
+ :subject,
33
+ :description,
34
+ :visible?,
35
+ :open?,
36
+ :start_date,
37
+ :due_date,
38
+ :overdue?,
39
+ :completed_percent,
40
+ :updated_on,
41
+ :created_on,
42
+ :to => :@issue
43
+
44
+ def initialize(issue)
45
+ @issue = issue
46
+ end
47
+
48
+ def link
49
+ link_to @issue.subject, self.url
50
+ end
51
+
52
+ def url
53
+ Rails.application.routes.url_helpers.issue_path(@issue)
54
+ end
55
+
56
+ def author
57
+ @user ||= UserDrop.new(@issue.author)
58
+ end
59
+
60
+ def custom_field_values
61
+ @issue.custom_field_values
62
+ end
63
+
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,54 @@
1
+ module RedmineCrm
2
+ module Liquid
3
+ class NewssDrop < ::Liquid::Drop
4
+
5
+ def self.default_drop
6
+ self.new News.visible.order("#{News.table_name}.created_on")
7
+ end
8
+
9
+ def initialize(newss)
10
+ @newss = newss
11
+ end
12
+
13
+ def before_method(id)
14
+ news = @newss.where(:id => id).first || News.new
15
+ NewsDrop.new news
16
+ end
17
+
18
+ def last
19
+ NewsDrop.new News.last
20
+ end
21
+
22
+ def all
23
+ @all ||= @newss.map do |news|
24
+ NewsDrop.new news
25
+ end
26
+ end
27
+
28
+ def each(&block)
29
+ all.each(&block)
30
+ end
31
+
32
+ def size
33
+ @newss.size
34
+ end
35
+ end
36
+
37
+ class NewsDrop < ::Liquid::Drop
38
+ delegate :id, :title, :summary, :description, :visible?, :commentable?, :to => :@news
39
+
40
+ def initialize(news)
41
+ @news = news
42
+ end
43
+
44
+ def author
45
+ UserDrop.new @news.author
46
+ end
47
+
48
+ def custom_field_values
49
+ @news.custom_field_values
50
+ end
51
+
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,86 @@
1
+ module RedmineCrm
2
+ module Liquid
3
+ class ProjectsDrop < ::Liquid::Drop
4
+
5
+ def self.default_drop
6
+ self.new Project.visible.order(:name)
7
+ end
8
+
9
+ def initialize(projects)
10
+ @projects = projects
11
+ end
12
+
13
+ def before_method(identifier)
14
+ project = @projects.where(:identifier => identifier).first || Project.new
15
+ ProjectDrop.new project
16
+ end
17
+
18
+ def all
19
+ @all ||= @projects.map do |project|
20
+ ProjectDrop.new project
21
+ end
22
+ end
23
+
24
+ def active
25
+ @active ||= @projects.select(&:active?).map do |project|
26
+ ProjectDrop.new project
27
+ end
28
+ end
29
+
30
+ def each(&block)
31
+ all.each(&block)
32
+ end
33
+
34
+ def size
35
+ @projects.size
36
+ end
37
+ end
38
+
39
+ class ProjectDrop < ::Liquid::Drop
40
+ include ActionView::Helpers::UrlHelper
41
+
42
+ delegate :id,
43
+ :identifier,
44
+ :name,
45
+ :is_public,
46
+ :description,
47
+ :visible?,
48
+ :active?,
49
+ :archived?,
50
+ :short_description,
51
+ :start_date,
52
+ :due_date,
53
+ :overdue?,
54
+ :completed_percent,
55
+ :to => :@project
56
+
57
+ def initialize(project)
58
+ @project = project
59
+ end
60
+
61
+ def link
62
+ link_to @project.name, self.url
63
+ end
64
+
65
+ def url
66
+ Rails.application.routes.url_helpers.project_path(@project)
67
+ end
68
+
69
+ def issues
70
+ @issues ||= IssuesDrop.new @project.issues.visible
71
+ end
72
+
73
+ def users
74
+ @users ||= UsersDrop.new @project.users
75
+ end
76
+
77
+ def subprojects
78
+ @subprojects ||= ProjectsDrop.new @project.children
79
+ end
80
+
81
+ def custom_field_values
82
+ @project.custom_field_values
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,72 @@
1
+ module RedmineCrm
2
+ module Liquid
3
+ class UsersDrop < ::Liquid::Drop
4
+
5
+ def self.default_drop
6
+ self.new User.sorted
7
+ end
8
+
9
+ def initialize(users)
10
+ @users = users
11
+ end
12
+
13
+ def before_method(login)
14
+ user = @users.where(:login => login).first || User.new
15
+ UserDrop.new user
16
+ end
17
+
18
+ def current
19
+ UserDrop.new User.current
20
+ end
21
+
22
+ def all
23
+ @all ||= @users.map do |user|
24
+ UserDrop.new user
25
+ end
26
+ end
27
+
28
+ def each(&block)
29
+ all.each(&block)
30
+ end
31
+
32
+ def size
33
+ @users.size
34
+ end
35
+ end
36
+
37
+ class UserDrop < ::Liquid::Drop
38
+ delegate :id, :name, :firstname, :lastname, :mail, :active?, :admin?, :logged?, :language, :to => :@user
39
+
40
+ def initialize(user)
41
+ @user = user
42
+ end
43
+
44
+ def avatar
45
+ ApplicationController.helpers.avatar(@user)
46
+ end
47
+
48
+ def name
49
+ @user.name
50
+ end
51
+
52
+ def permissions
53
+ roles = @user.memberships.collect { |m| m.roles }.flatten.uniq
54
+ roles << (@user.logged? ? Role.non_member : Role.anonymous)
55
+ roles.map(&:permissions).flatten.uniq.map(&:to_s)
56
+ end
57
+
58
+ def groups
59
+ @user.groups.map(&:name)
60
+ end
61
+
62
+ def projects
63
+ ProjectsDrop.new @user.memberships.map(&:project).flatten.select(&:visible?).uniq
64
+ end
65
+
66
+ def custom_field_values
67
+ @user.custom_field_values
68
+ end
69
+
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,178 @@
1
+ module RedmineCrm
2
+ module Liquid
3
+ module Filters
4
+ module Arrays
5
+
6
+ # Get the first element of the passed in array
7
+ #
8
+ # Example:
9
+ # {{ product.images | first | to_img }}
10
+ #
11
+ # {{ product.images | first: 3 }}
12
+ #
13
+ def first(array, count=1)
14
+ (count > 1 ? array.first(count) : array.first) if array.respond_to?(:first)
15
+ end
16
+
17
+ # Convert the input into json string
18
+ #
19
+ # input - The Array or Hash to be converted
20
+ #
21
+ # Returns the converted json string
22
+ def jsonify(input)
23
+ as_liquid(input).to_json
24
+ end
25
+
26
+ # Group an array of items by a property
27
+ #
28
+ # input - the inputted Enumerable
29
+ # property - the property
30
+ #
31
+ # Returns an array of Hashes, each looking something like this:
32
+ # {"name" => "larry"
33
+ # "items" => [...] } # all the items where `property` == "larry"
34
+ def group_by(input, property)
35
+ if groupable?(input)
36
+ input.group_by { |item| item_property(item, property).to_s }
37
+ .each_with_object([]) do |item, array|
38
+ array << {
39
+ "name" => item.first,
40
+ "items" => item.last,
41
+ "size" => item.last.size
42
+ }
43
+ end
44
+ else
45
+ input
46
+ end
47
+ end
48
+
49
+ # Filter an array of objects
50
+ #
51
+ # input - the object array
52
+ # property - property within each object to filter by
53
+ # value - desired value
54
+ #
55
+ # Returns the filtered array of objects
56
+ def where(input, property, value, operator='==')
57
+ return input unless input.respond_to?(:select)
58
+ input = input.values if input.is_a?(Hash)
59
+ if operator == '=='
60
+ input.select do |object|
61
+ Array(item_property(object, property)).map(&:to_s).include?(value.to_s)
62
+ end || []
63
+ elsif operator == '<>'
64
+ input.select do |object|
65
+ !Array(item_property(object, property)).map(&:to_s).include?(value.to_s)
66
+ end || []
67
+ elsif operator == '>'
68
+ input.select do |object|
69
+ item_property(object, property) > value
70
+ end || []
71
+ elsif operator == '<'
72
+ input.select do |object|
73
+ item_property(object, property) < value
74
+ end || []
75
+ elsif operator == 'match'
76
+ input.select do |object|
77
+ Array(item_property(object, property)).map(&:to_s).any?{|i| i.match(value.to_s)}
78
+ end || []
79
+ else
80
+ []
81
+ end
82
+ end
83
+
84
+ # Filter an array of objects by tags
85
+ #
86
+ # input - the object array
87
+ # tags - quoted tags list divided by comma
88
+ # match - (all- defaut, any, exclude)
89
+ #
90
+ # Returns the filtered array of objects
91
+ def tagged_with(input, tags, match='all')
92
+ return input unless input.respond_to?(:select)
93
+ input = input.values if input.is_a?(Hash)
94
+ tag_list = input.is_a?(Array) ? tags.sort : tags.split(',').map(&:strip).sort
95
+ case match
96
+ when "all"
97
+ input.select do |object|
98
+ object.respond_to?(:tag_list) &&
99
+ (tag_list - Array(item_property(object, 'tag_list')).map(&:to_s).sort).empty?
100
+ end || []
101
+ when "any"
102
+ input.select do |object|
103
+ object.respond_to?(:tag_list) &&
104
+ (tag_list & Array(item_property(object, 'tag_list')).map(&:to_s).sort).any?
105
+ end || []
106
+ when "exclude"
107
+ input.select do |object|
108
+ object.respond_to?(:tag_list) &&
109
+ (tag_list & Array(item_property(object, 'tag_list')).map(&:to_s).sort).empty?
110
+ end || []
111
+ else
112
+ []
113
+ end
114
+ end
115
+
116
+ # Sort an array of objects
117
+ #
118
+ # input - the object array
119
+ # property - property within each object to filter by
120
+ # nils ('first' | 'last') - nils appear before or after non-nil values
121
+ #
122
+ # Returns the filtered array of objects
123
+ def sort(input, property = nil, nils = "first")
124
+ if input.nil?
125
+ raise ArgumentError, "Cannot sort a null object."
126
+ end
127
+ if property.nil?
128
+ input.sort
129
+ else
130
+ if nils == "first"
131
+ order = - 1
132
+ elsif nils == "last"
133
+ order = + 1
134
+ else
135
+ raise ArgumentError, "Invalid nils order: " \
136
+ "'#{nils}' is not a valid nils order. It must be 'first' or 'last'."
137
+ end
138
+
139
+ sort_input(input, property, order)
140
+ end
141
+ end
142
+
143
+ def pop(array, input = 1)
144
+ return array unless array.is_a?(Array)
145
+ new_ary = array.dup
146
+ new_ary.pop(input.to_i || 1)
147
+ new_ary
148
+ end
149
+
150
+ def push(array, input)
151
+ return array unless array.is_a?(Array)
152
+ new_ary = array.dup
153
+ new_ary.push(input)
154
+ new_ary
155
+ end
156
+
157
+ def shift(array, input = 1)
158
+ return array unless array.is_a?(Array)
159
+ new_ary = array.dup
160
+ new_ary.shift(input.to_i || 1)
161
+ new_ary
162
+ end
163
+
164
+ def unshift(array, input)
165
+ return array unless array.is_a?(Array)
166
+ new_ary = array.dup
167
+ new_ary.unshift(input)
168
+ new_ary
169
+ end
170
+
171
+ private
172
+
173
+ end # module ArrayFilters
174
+ end
175
+ end
176
+
177
+ ::Liquid::Template.register_filter(RedmineCrm::Liquid::Filters::Arrays)
178
+ end