redmine_crm 0.0.23 → 0.0.53

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -1
  3. data/README.md +166 -33
  4. data/Rakefile +3 -12
  5. data/app/controllers/redmine_crm_controller.rb +26 -0
  6. data/app/views/redmine_crm/_money.html.erb +44 -0
  7. data/app/views/redmine_crm/settings.html.erb +10 -0
  8. data/bitbucket-pipelines.yml +54 -0
  9. data/config/currency_iso.json +12 -0
  10. data/config/locales/en.yml +13 -0
  11. data/config/locales/ru.yml +13 -0
  12. data/config/routes.rb +5 -0
  13. data/doc/CHANGELOG +123 -2
  14. data/lib/redmine_crm/acts_as_draftable/draft.rb +40 -0
  15. data/lib/redmine_crm/acts_as_draftable/rcrm_acts_as_draftable.rb +172 -0
  16. data/lib/redmine_crm/acts_as_list/list.rb +282 -0
  17. data/lib/redmine_crm/{rcrm_acts_as_taggable.rb → acts_as_taggable/rcrm_acts_as_taggable.rb} +112 -93
  18. data/lib/redmine_crm/acts_as_taggable/tag.rb +81 -0
  19. data/lib/redmine_crm/acts_as_taggable/tag_list.rb +111 -0
  20. data/lib/redmine_crm/acts_as_taggable/tagging.rb +16 -0
  21. data/lib/redmine_crm/acts_as_viewed/rcrm_acts_as_viewed.rb +274 -0
  22. data/lib/redmine_crm/{rcrm_acts_as_votable.rb → acts_as_votable/rcrm_acts_as_votable.rb} +15 -14
  23. data/lib/redmine_crm/acts_as_votable/rcrm_acts_as_voter.rb +20 -0
  24. data/lib/redmine_crm/{votable.rb → acts_as_votable/votable.rb} +54 -65
  25. data/lib/redmine_crm/{vote.rb → acts_as_votable/vote.rb} +6 -8
  26. data/lib/redmine_crm/{voter.rb → acts_as_votable/voter.rb} +29 -34
  27. data/lib/redmine_crm/assets_manager.rb +43 -0
  28. data/lib/redmine_crm/colors_helper.rb +192 -0
  29. data/lib/redmine_crm/compatibility/application_controller_patch.rb +33 -0
  30. data/lib/redmine_crm/currency/formatting.rb +5 -8
  31. data/lib/redmine_crm/currency/heuristics.rb +1 -1
  32. data/lib/redmine_crm/currency/loader.rb +5 -6
  33. data/lib/redmine_crm/currency.rb +28 -17
  34. data/lib/redmine_crm/engine.rb +4 -0
  35. data/lib/redmine_crm/helpers/external_assets_helper.rb +19 -0
  36. data/lib/redmine_crm/helpers/form_tag_helper.rb +76 -0
  37. data/lib/redmine_crm/helpers/tags_helper.rb +1 -3
  38. data/lib/redmine_crm/helpers/vote_helper.rb +29 -32
  39. data/lib/redmine_crm/hooks/views_layouts_hook.rb +11 -0
  40. data/lib/redmine_crm/liquid/drops/issues_drop.rb +191 -0
  41. data/lib/redmine_crm/liquid/drops/news_drop.rb +54 -0
  42. data/lib/redmine_crm/liquid/drops/projects_drop.rb +86 -0
  43. data/lib/redmine_crm/liquid/drops/time_entries_drop.rb +65 -0
  44. data/lib/redmine_crm/liquid/drops/users_drop.rb +68 -0
  45. data/lib/redmine_crm/liquid/filters/arrays.rb +187 -0
  46. data/lib/redmine_crm/liquid/filters/base.rb +217 -0
  47. data/lib/redmine_crm/liquid/filters/colors.rb +31 -0
  48. data/lib/redmine_crm/money_helper.rb +17 -18
  49. data/lib/redmine_crm/settings/money.rb +46 -0
  50. data/lib/redmine_crm/settings.rb +53 -0
  51. data/lib/redmine_crm/version.rb +1 -1
  52. data/lib/redmine_crm.rb +60 -21
  53. data/redmine_crm.gemspec +12 -6
  54. data/test/acts_as_draftable/draft_test.rb +29 -0
  55. data/test/acts_as_draftable/rcrm_acts_as_draftable_test.rb +178 -0
  56. data/test/{acts_as_taggable_test.rb → acts_as_taggable/rcrm_acts_as_taggable_test.rb} +117 -156
  57. data/test/acts_as_taggable/tag_list_test.rb +34 -0
  58. data/test/acts_as_taggable/tag_test.rb +72 -0
  59. data/test/acts_as_taggable/tagging_test.rb +15 -0
  60. data/test/{viewed_test.rb → acts_as_viewed/rcrm_acts_as_viewed_test.rb} +17 -15
  61. data/test/acts_as_votable/rcrm_acts_as_votable_test.rb +19 -0
  62. data/test/acts_as_votable/rcrm_acts_as_voter_test.rb +14 -0
  63. data/test/{votable_model_test.rb → acts_as_votable/votable_test.rb} +34 -5
  64. data/test/{voter_model_test.rb → acts_as_votable/voter_test.rb} +8 -8
  65. data/test/currency_test.rb +10 -10
  66. data/test/database.yml +14 -14
  67. data/test/fixtures/issues.yml +13 -1
  68. data/test/fixtures/news.yml +8 -0
  69. data/test/fixtures/projects.yml +10 -0
  70. data/test/fixtures/users.yml +6 -2
  71. data/test/liquid/drops/issues_drop_test.rb +34 -0
  72. data/test/liquid/drops/news_drop_test.rb +38 -0
  73. data/test/liquid/drops/projects_drop_test.rb +44 -0
  74. data/test/liquid/drops/uses_drop_test.rb +36 -0
  75. data/test/liquid/filters/arrays_filter_test.rb +31 -0
  76. data/test/liquid/filters/base_filter_test.rb +63 -0
  77. data/test/liquid/filters/colors_filter_test.rb +33 -0
  78. data/test/liquid/liquid_helper.rb +34 -0
  79. data/test/models/issue.rb +14 -0
  80. data/test/models/news.rb +3 -0
  81. data/test/models/project.rb +8 -0
  82. data/test/{fixtures → models}/user.rb +5 -1
  83. data/test/{fixtures → models}/vote_classes.rb +0 -21
  84. data/test/money_helper_test.rb +5 -5
  85. data/test/schema.rb +33 -10
  86. data/test/test_helper.rb +20 -72
  87. data/vendor/assets/images/money.png +0 -0
  88. data/vendor/assets/images/vcard.png +0 -0
  89. data/vendor/assets/javascripts/Chart.bundle.min.js +16 -0
  90. data/vendor/assets/javascripts/select2.js +2 -0
  91. data/vendor/assets/javascripts/select2_helpers.js +192 -0
  92. data/vendor/assets/stylesheets/money.css +3 -0
  93. data/vendor/assets/stylesheets/select2.css +424 -0
  94. metadata +190 -40
  95. data/lib/redmine_crm/rcrm_acts_as_viewed.rb +0 -287
  96. data/lib/redmine_crm/rcrm_acts_as_voter.rb +0 -27
  97. data/lib/redmine_crm/tag.rb +0 -81
  98. data/lib/redmine_crm/tag_list.rb +0 -112
  99. data/lib/redmine_crm/tagging.rb +0 -20
  100. data/test/fixtures/issue.rb +0 -14
  101. data/test/tag_test.rb +0 -64
  102. data/test/tagging_test.rb +0 -14
  103. data/test/votable_test.rb +0 -17
@@ -0,0 +1,76 @@
1
+ module RedmineCrm
2
+ module FormTagHelper
3
+ # Allows include select2 into your views.
4
+ #
5
+ # ==== Examples
6
+ # select2_tag 'city_id', '<option value="1">Lisbon</option>...'
7
+ # select2_tag 'city_id', options_for_select(...)
8
+ # select2_tag 'tag_list', nil, :multiple => true, :data => [{ id: 0, text: 'deal' }, ...], :tags => true, :include_hidden => false %>
9
+ # select2_tag 'tag_list', options_for_select(...), :multiple => true, :style => 'width: 100%;', :url => '/tags', :placeholder => '+ add tag', :tags => true %>
10
+ #
11
+ # You may use select_tag options and additional options.
12
+ #
13
+ # ==== Additional options
14
+ # * <tt>:url</tt> Allows searches for remote data using the ajax.
15
+ # * <tt>:data</tt> Load dropdown options from a local array if +url+ option not set.
16
+ # * <tt>:placeholder</tt> Supports displaying a placeholder value.
17
+ # * <tt>:include_hidden</tt> Adds hidden field after select when +multiple+ option true. Default value true.
18
+ # * <tt>:allow_clear</tt> Provides support for clearable selections. Default value false.
19
+ # * <tt>:min_input_length</tt> Minimum number of characters required to start a search. Default value 0.
20
+ # * <tt>:format_state</tt> Defines template of search results in the drop-down.
21
+ # * <tt>:tags</tt> Used to enable tagging feature.
22
+ #
23
+ # <b>Note:</b> The HTML specification says when +multiple+ parameter passed to select and all options got deselected
24
+ # web browsers do not send any value to server.
25
+ #
26
+ # In case if you don't want the helper to generate this hidden field you can specify
27
+ # <tt>include_hidden: false</tt> option.
28
+ #
29
+ # <b>Note:</b> Select2 assets must be available on a page.
30
+ # To include select2 assets to a page, you need to use the helper select2_assets.
31
+ # For example:
32
+ # <% content_for :header_tags do %>
33
+ # <%= select2_assets %>
34
+ # <% end %>
35
+ #
36
+ # Also aliased as: select2
37
+ #
38
+ # select2 'city_id', options_for_select(...)
39
+ #
40
+ def select2_tag(name, option_tags = nil, options = {})
41
+ s = select_tag(name, option_tags, options)
42
+
43
+ if options[:multiple] && options.fetch(:include_hidden, true)
44
+ s << hidden_field_tag("#{name}[]", '')
45
+ end
46
+
47
+ s + javascript_tag("select2Tag('#{sanitize_to_id(name)}', #{options.to_json});")
48
+ end
49
+
50
+ alias select2 select2_tag
51
+
52
+ # Transforms select filters of +type+ fields into select2
53
+ #
54
+ # ==== Examples
55
+ # transform_to_select2 'tags', url: auto_complete_tags_url
56
+ # transform_to_select2 'people', format_state: 'formatStateWithAvatar', min_input_length: 1, url: '/managers'
57
+ #
58
+ # ==== Options
59
+ # * <tt>:url</tt> Defines URL to search remote data using the ajax.
60
+ # * <tt>:format_state</tt> Defines template of search results in the drop-down.
61
+ # * <tt>:min_input_length</tt> Minimum number of characters required to start a search. Default value 0.
62
+ # * <tt>:width</tt> Sets the width of the control. Default value '60%'.
63
+ # * <tt>:multiple</tt> Supports multi-value select box. If set to false the selection will not allow multiple choices. Default value true.
64
+ #
65
+ # <b>Note:</b> Select2 assets must be available on a page.
66
+ # To include select2 assets to a page, you need to use the helper select2_assets.
67
+ # For example:
68
+ # <% content_for :header_tags do %>
69
+ # <%= select2_assets %>
70
+ # <% end %>
71
+ #
72
+ def transform_to_select2(type, options = {})
73
+ javascript_tag("setSelect2Filter('#{type}', #{options.to_json});") unless type.empty?
74
+ end
75
+ end
76
+ 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,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RedmineCrm
4
+ module Hooks
5
+ class ViewsLayoutsHook < Redmine::Hook::ViewListener
6
+ def view_layouts_base_html_head(_context = {})
7
+ stylesheet_link_tag(:money, plugin: 'redmine_crm')
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,191 @@
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 visible
20
+ @visible ||= @all.select(&:visible?)
21
+ end
22
+
23
+ def each(&block)
24
+ all.each(&block)
25
+ end
26
+
27
+ def size
28
+ @issues.size
29
+ end
30
+ end
31
+
32
+ class IssueDrop < ::Liquid::Drop
33
+ include ActionView::Helpers::UrlHelper
34
+
35
+ delegate :id,
36
+ :subject,
37
+ :description,
38
+ :visible?,
39
+ :open?,
40
+ :start_date,
41
+ :due_date,
42
+ :overdue?,
43
+ :done_ratio,
44
+ :estimated_hours,
45
+ :spent_hours,
46
+ :total_spent_hours,
47
+ :total_estimated_hours,
48
+ :is_private?,
49
+ :closed_on,
50
+ :updated_on,
51
+ :created_on,
52
+ :to => :@issue
53
+
54
+ def initialize(issue)
55
+ @issue = issue
56
+ end
57
+
58
+ def link
59
+ link_to @issue.subject, self.url
60
+ end
61
+
62
+ def url
63
+ Rails.application.routes.url_helpers.issue_path(@issue)
64
+ end
65
+
66
+ def author
67
+ @user ||= UserDrop.new(@issue.author)
68
+ end
69
+
70
+ def assignee
71
+ @assignee ||= UserDrop.new(@issue.assigned_to)
72
+ end
73
+
74
+ def tracker
75
+ @tracker ||= @issue.tracker && @issue.tracker.name
76
+ end
77
+
78
+ def status
79
+ @status ||= @issue.status && @issue.status.name
80
+ end
81
+
82
+ def priority
83
+ @priority ||= @issue.priority && @issue.priority.name
84
+ end
85
+
86
+ def category
87
+ @category ||= @issue.category && @issue.category.name
88
+ end
89
+
90
+ def version
91
+ @version ||= @issue.fixed_version && @issue.fixed_version.name
92
+ end
93
+
94
+ def time_entries
95
+ @time_entries ||= TimeEntriesDrop.new @issue.time_entries
96
+ end
97
+
98
+ def parent
99
+ @parent ||= IssueDrop.new @issue.parent if @issue.parent
100
+ end
101
+
102
+ def project
103
+ @project ||= ProjectDrop.new @issue.project if @issue.project
104
+ end
105
+
106
+ def subtasks
107
+ @subtasks ||= IssuesDrop.new @issue.children
108
+ end
109
+
110
+ def notes
111
+ @notes ||= @issue.journals.where("#{Journal.table_name}.notes IS NOT ?", nil).order(:created_on).map(&:notes)
112
+ end
113
+
114
+ def journals
115
+ @journals ||= JournalsDrop.new @issue.journals.where("#{Journal.table_name}.notes IS NOT ?", nil)
116
+ end
117
+
118
+ def tags
119
+ @issue.respond_to?(:tag_list) && @issue.tag_list
120
+ end
121
+
122
+ def story_points
123
+ @issue.respond_to?(:story_points) && @issue.story_points
124
+ end
125
+
126
+ def color
127
+ @issue.respond_to?(:color) && @issue.color
128
+ end
129
+
130
+ def day_in_state
131
+ @issue.respond_to?(:day_in_state) && @issue.day_in_state
132
+ end
133
+
134
+ def checklists
135
+ @issue.respond_to?(:checklists) && @issue.checklists.map{|item| {"id_done" => item.is_done, "subject" => item.subject}}
136
+ end
137
+
138
+ def custom_field_values
139
+ @issue.custom_field_values
140
+ end
141
+
142
+ end
143
+
144
+ class JournalsDrop < ::Liquid::Drop
145
+ def initialize(journals)
146
+ @journals = journals
147
+ end
148
+
149
+ def all
150
+ @all ||= @journals.map do |journal|
151
+ JournalDrop.new journal
152
+ end
153
+ end
154
+
155
+ def visible
156
+ @visible ||= @all.select(&:visible?)
157
+ end
158
+
159
+ def each(&block)
160
+ all.each(&block)
161
+ end
162
+
163
+ def size
164
+ @journals.size
165
+ end
166
+ end
167
+
168
+ class JournalDrop < ::Liquid::Drop
169
+ delegate :id,
170
+ :notes,
171
+ :created_on,
172
+ :private_notes,
173
+ :to => :@journal,
174
+ allow_nil: true
175
+
176
+ def initialize(journal)
177
+ @journal = journal
178
+ end
179
+
180
+ def user
181
+ @user ||= UserDrop.new(@journal.user)
182
+ end
183
+
184
+ def issue
185
+ @issue ||= IssueDrop.new @journal.issue if @journal.issue
186
+ end
187
+
188
+ end
189
+
190
+ end
191
+ 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
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,65 @@
1
+ module RedmineCrm
2
+ module Liquid
3
+ class TimeEntriesDrop < ::Liquid::Drop
4
+ def initialize(time_entries)
5
+ @time_entries = time_entries
6
+ end
7
+
8
+ def all
9
+ @all ||= @time_entries.map do |time_entry|
10
+ TimeEntryDrop.new time_entry
11
+ end
12
+ end
13
+
14
+ def visible
15
+ @visible ||= @all.select(&:visible?)
16
+ end
17
+
18
+ def each(&block)
19
+ all.each(&block)
20
+ end
21
+
22
+ def size
23
+ @time_entries.size
24
+ end
25
+ end
26
+
27
+ class TimeEntryDrop < ::Liquid::Drop
28
+ include ActionView::Helpers::UrlHelper
29
+
30
+ delegate :id,
31
+ :hours,
32
+ :comments,
33
+ :spent_on,
34
+ :tyear,
35
+ :tmonth,
36
+ :tweek,
37
+ :visible?,
38
+ :updated_on,
39
+ :created_on,
40
+ :to => :@time_entry,
41
+ allow_nil: true
42
+
43
+ def initialize(time_entry)
44
+ @time_entry = time_entry
45
+ end
46
+
47
+ def user
48
+ @user ||= UserDrop.new(@time_entry.user)
49
+ end
50
+
51
+ def issue
52
+ @issue ||= IssueDrop.new(@time_entry.issue)
53
+ end
54
+
55
+ def activity
56
+ @activity ||= @time_entry.activity && @time_entry.activity.name
57
+ end
58
+
59
+ def custom_field_values
60
+ @time_entry.custom_field_values
61
+ end
62
+
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,68 @@
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, allow_nil: true
39
+
40
+ def initialize(user)
41
+ @user = user
42
+ end
43
+
44
+ def avatar
45
+ ApplicationController.helpers.avatar(@user)
46
+ end
47
+
48
+ def permissions
49
+ roles = @user.memberships.collect { |m| m.roles }.flatten.uniq
50
+ roles << (@user.logged? ? Role.non_member : Role.anonymous)
51
+ roles.map(&:permissions).flatten.uniq.map(&:to_s)
52
+ end
53
+
54
+ def groups
55
+ @user.groups.map(&:name)
56
+ end
57
+
58
+ def projects
59
+ ProjectsDrop.new @user.memberships.map(&:project).flatten.select(&:visible?).uniq
60
+ end
61
+
62
+ def custom_field_values
63
+ @user.custom_field_values
64
+ end
65
+
66
+ end
67
+ end
68
+ end