additional_tags 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/brakeman.yml +2 -1
  3. data/.github/workflows/linters.yml +2 -1
  4. data/.gitignore +1 -0
  5. data/.rubocop.yml +37 -4
  6. data/.slim-lint.yml +3 -2
  7. data/Rakefile +2 -0
  8. data/additional_tags.gemspec +5 -3
  9. data/app/controllers/additional_tags_controller.rb +4 -1
  10. data/app/controllers/issue_tags_controller.rb +6 -4
  11. data/app/helpers/additional_tags_helper.rb +39 -41
  12. data/app/helpers/additional_tags_issues_helper.rb +3 -1
  13. data/app/helpers/additional_tags_wiki_helper.rb +6 -4
  14. data/app/jobs/additional_tags_job.rb +2 -0
  15. data/app/jobs/additional_tags_remove_unused_tag_job.rb +2 -0
  16. data/app/models/migrate_tag.rb +2 -0
  17. data/app/models/migrate_tagging.rb +2 -0
  18. data/app/models/query_tags_column.rb +7 -0
  19. data/app/views/additional_tags/_tag_list.html.slim +1 -1
  20. data/app/views/additional_tags/merge.html.slim +4 -3
  21. data/app/views/additional_tags/settings/_manage_tags.html.slim +1 -1
  22. data/app/views/issue_tags/_edit_modal.html.slim +2 -2
  23. data/app/views/issues/_tags_form.html.slim +1 -1
  24. data/config/routes.rb +2 -0
  25. data/db/migrate/20201116145429_acts_as_taggable_migration.rb +3 -1
  26. data/db/migrate/20201123093214_migrate_existing_tags.rb +4 -2
  27. data/init.rb +2 -0
  28. data/lib/additional_tags.rb +5 -15
  29. data/lib/additional_tags/hooks.rb +2 -0
  30. data/lib/additional_tags/patches/agile_boards_controller_patch.rb +2 -0
  31. data/lib/additional_tags/patches/agile_query_patch.rb +11 -9
  32. data/lib/additional_tags/patches/agile_versions_controller_patch.rb +2 -0
  33. data/lib/additional_tags/patches/agile_versions_query_patch.rb +3 -1
  34. data/lib/additional_tags/patches/auto_completes_controller_patch.rb +3 -1
  35. data/lib/additional_tags/patches/calendars_controller_patch.rb +2 -0
  36. data/lib/additional_tags/patches/dashboard_async_blocks_controller_patch.rb +2 -0
  37. data/lib/additional_tags/patches/dashboards_controller_patch.rb +2 -0
  38. data/lib/additional_tags/patches/gantts_controller_patch.rb +2 -0
  39. data/lib/additional_tags/patches/imports_controller_patch.rb +2 -0
  40. data/lib/additional_tags/patches/issue_patch.rb +8 -6
  41. data/lib/additional_tags/patches/issue_query_patch.rb +17 -14
  42. data/lib/additional_tags/patches/issues_controller_patch.rb +2 -0
  43. data/lib/additional_tags/patches/journal_patch.rb +2 -0
  44. data/lib/additional_tags/patches/my_controller_patch.rb +2 -0
  45. data/lib/additional_tags/patches/queries_helper_patch.rb +3 -15
  46. data/lib/additional_tags/patches/query_patch.rb +76 -0
  47. data/lib/additional_tags/patches/reports_controller_patch.rb +2 -0
  48. data/lib/additional_tags/patches/settings_controller_patch.rb +2 -0
  49. data/lib/additional_tags/patches/time_entry_patch.rb +2 -0
  50. data/lib/additional_tags/patches/time_entry_query_patch.rb +5 -15
  51. data/lib/additional_tags/patches/time_report_patch.rb +2 -0
  52. data/lib/additional_tags/patches/timelog_controller_patch.rb +2 -0
  53. data/lib/additional_tags/patches/wiki_controller_patch.rb +2 -0
  54. data/lib/additional_tags/patches/wiki_page_patch.rb +4 -2
  55. data/lib/additional_tags/tags.rb +28 -17
  56. data/lib/additional_tags/version.rb +3 -1
  57. metadata +4 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f6573f962ff7b251ce5afae13e2659985887d486d320fcb99f4c99892fa8a52
4
- data.tar.gz: a258bcf71c8c53b40a5b7bcec92e9b6ff8a7dde6070fe5cfdc3eac0adb3d2ccb
3
+ metadata.gz: '094d1e57c687d9c643b002e5e6134a457d47791a2b086c3c159d690242228488'
4
+ data.tar.gz: dbfd7b4cb744aef1df5d132615bc1d8816ac85ccb7b837b04376d2b1eb9a76d6
5
5
  SHA512:
6
- metadata.gz: 46e6f62fae40af6b03d6b09a2b237f4049ab4d54ce30289e1fa7a74b9ee7f57df586feb3cf695f4268a86478365fee580db550e9b044c84281fcb464e2fde321
7
- data.tar.gz: 8b1c9a8b5873b2b993f27d80186e9c7e0a024e201aba3c0125f47331c6fda50d673cbb1f572c17b2aef1b613b687f6a66c86c17d9b325f8c20e9c2bd8e6bf103
6
+ metadata.gz: f95b50b1d98bb7f22c8a2d3bfc5d767ba85a6df06b5e259d9fe2a03ce2980f6577e948f6120f0fb831d3dee5155f88ebdab215534a3264fc24adb31749610122
7
+ data.tar.gz: 417da0e654d1d966592242c95dd12899638758023b0822499c92e2079d03c28f0b9788046ee161f6ce721df325a0cdd91f1bd6dfe621cb88f910d7b9c12dcd3e
@@ -16,7 +16,8 @@ jobs:
16
16
 
17
17
  - name: Setup Gemfile
18
18
  run: |
19
- cp test/support/gemfile.rb Gemfile
19
+ touch .enable_dev
20
+ sed -i "3isource 'https://rubygems.org'" Gemfile
20
21
 
21
22
  - name: Setup Ruby
22
23
  uses: ruby/setup-ruby@v1
@@ -16,7 +16,8 @@ jobs:
16
16
 
17
17
  - name: Setup Gemfile
18
18
  run: |
19
- cp test/support/gemfile.rb Gemfile
19
+ touch .enable_dev
20
+ sed -i "3isource 'https://rubygems.org'" Gemfile
20
21
 
21
22
  - name: Setup Ruby
22
23
  uses: ruby/setup-ruby@v1
data/.gitignore CHANGED
@@ -6,3 +6,4 @@ Gemfile.lock
6
6
  .project
7
7
  .settings/
8
8
  ._*
9
+ .enable_dev
data/.rubocop.yml CHANGED
@@ -16,6 +16,10 @@ Metrics/AbcSize:
16
16
  Metrics/BlockLength:
17
17
  Enabled: false
18
18
 
19
+ Metrics/ParameterLists:
20
+ Enabled: true
21
+ CountKeywordArgs: false
22
+
19
23
  Metrics/ClassLength:
20
24
  Enabled: false
21
25
 
@@ -34,6 +38,12 @@ Metrics/ModuleLength:
34
38
  Metrics/PerceivedComplexity:
35
39
  Max: 25
36
40
 
41
+ Style/ExpandPathArguments:
42
+ Enabled: true
43
+ Exclude:
44
+ - additional_tags.gemspec
45
+ - test/**/*
46
+
37
47
  Rails/ApplicationJob:
38
48
  Enabled: false
39
49
 
@@ -56,14 +66,37 @@ Style/AutoResourceCleanup:
56
66
  Enabled: true
57
67
 
58
68
  Style/FrozenStringLiteralComment:
59
- Enabled: false
69
+ Enabled: true
70
+ Exclude:
71
+ - '/**/*.rsb'
60
72
 
61
73
  Style/Documentation:
62
74
  Enabled: false
63
75
 
64
- # required for travis/ci (symbolic links problem)
65
- Style/ExpandPathArguments:
66
- Enabled: false
76
+ Style/OptionHash:
77
+ Enabled: true
78
+ SuspiciousParamNames:
79
+ - options
80
+ - api_options
81
+ - opts
82
+ - args
83
+ - params
84
+ - parameters
85
+ - settings
86
+ Exclude:
87
+ - lib/additional_tags/patches/*.rb
88
+
89
+ Style/ReturnNil:
90
+ Enabled: true
91
+
92
+ Style/UnlessLogicalOperators:
93
+ Enabled: true
94
+
95
+ Style/MethodCallWithArgsParentheses:
96
+ Enabled: true
97
+ AllowParenthesesInMultilineCall: true
98
+ AllowParenthesesInChaining: true
99
+ EnforcedStyle: omit_parentheses
67
100
 
68
101
  Style/HashTransformKeys:
69
102
  Enabled: false
data/.slim-lint.yml CHANGED
@@ -17,10 +17,11 @@ linters:
17
17
  - Layout/MultilineMethodCallIndentation
18
18
  - Layout/MultilineMethodDefinitionBraceLayout
19
19
  - Layout/MultilineOperationIndentation
20
+ - Layout/SpaceBeforeBrackets
20
21
  - Layout/TrailingEmptyLines
21
22
  - Lint/Void
22
23
  - Rails/OutputSafety
24
+ - Style/FrozenStringLiteralComment
23
25
  - Style/IfUnlessModifier
24
- - Style/WhileUntilModifier
25
26
  - Style/Next
26
- - Layout/SpaceBeforeBrackets
27
+ - Style/WhileUntilModifier
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'bundler/gem_tasks'
2
4
  require 'rake/testtask'
3
5
 
@@ -1,5 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  lib = File.expand_path '../lib', __FILE__
2
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ $LOAD_PATH.unshift lib unless $LOAD_PATH.include? lib
3
5
  require 'additional_tags/version'
4
6
 
5
7
  Gem::Specification.new do |spec|
@@ -14,10 +16,10 @@ Gem::Specification.new do |spec|
14
16
  spec.license = 'GPL-2.0'
15
17
 
16
18
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
- f.match(%r{^((test|spec|features)/|Gemfile)})
19
+ f.match %r{^((test|spec|features)/|Gemfile)}
18
20
  end
19
21
  spec.bindir = 'exe'
20
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename f }
21
23
  spec.require_paths = ['lib']
22
24
  spec.required_ruby_version = '>= 2.5'
23
25
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class AdditionalTagsController < ApplicationController
2
4
  before_action :require_admin
3
5
  before_action :find_tag, only: %i[edit update]
@@ -56,7 +58,7 @@ class AdditionalTagsController < ApplicationController
56
58
  end
57
59
 
58
60
  def bulk_find_tags
59
- @tags = ActsAsTaggableOn::Tag.joins("JOIN #{ActiveRecord::Base.connection.quote_table_name ActsAsTaggableOn.taggings_table}" \
61
+ @tags = ActsAsTaggableOn::Tag.joins("LEFT JOIN #{ActiveRecord::Base.connection.quote_table_name ActsAsTaggableOn.taggings_table}" \
60
62
  " ON #{ActiveRecord::Base.connection.quote_table_name ActsAsTaggableOn.taggings_table}.tag_id =" \
61
63
  " #{ActiveRecord::Base.connection.quote_table_name ActsAsTaggableOn.tags_table}.id ")
62
64
  .select("#{ActiveRecord::Base.connection.quote_table_name ActsAsTaggableOn.tags_table}.id," \
@@ -67,6 +69,7 @@ class AdditionalTagsController < ApplicationController
67
69
  .group("#{ActiveRecord::Base.connection.quote_table_name ActsAsTaggableOn.tags_table}.id" \
68
70
  ", #{ActiveRecord::Base.connection.quote_table_name ActsAsTaggableOn.tags_table}.name" \
69
71
  ", #{ActiveRecord::Base.connection.quote_table_name ActsAsTaggableOn.tags_table}.taggings_count")
72
+
70
73
  raise ActiveRecord::RecordNotFound if @tags.empty?
71
74
  end
72
75
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class IssueTagsController < ApplicationController
2
4
  before_action :find_issues, only: %i[edit update]
3
5
 
@@ -25,7 +27,7 @@ class IssueTagsController < ApplicationController
25
27
  tags = params[:issue] && params[:issue][:tag_list] ? params[:issue][:tag_list].reject(&:empty?) : []
26
28
 
27
29
  unless User.current.allowed_to?(:create_issue_tags, @projects.first) || Issue.allowed_tags?(tags)
28
- flash[:error] = t(:notice_failed_to_add_tags)
30
+ flash[:error] = t :notice_failed_to_add_tags
29
31
  return
30
32
  end
31
33
 
@@ -35,13 +37,13 @@ class IssueTagsController < ApplicationController
35
37
  issue.save!
36
38
  end
37
39
  end
38
- flash[:notice] = t(:notice_tags_added)
40
+ flash[:notice] = t :notice_tags_added
39
41
  else
40
- flash[:error] = t(:notice_failed_to_add_tags)
42
+ flash[:error] = t :notice_failed_to_add_tags
41
43
  end
42
44
  rescue StandardError => e
43
45
  Rails.logger.warn "Failed to add tags: #{e.inspect}"
44
- flash[:error] = t(:notice_failed_to_add_tags)
46
+ flash[:error] = t :notice_failed_to_add_tags
45
47
  ensure
46
48
  redirect_to_referer_or { render text: 'Tags updated.', layout: true }
47
49
  end
@@ -1,4 +1,4 @@
1
- require 'digest/md5'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module AdditionalTagsHelper
4
4
  include ActsAsTaggableOn::TagsHelper
@@ -12,13 +12,13 @@ module AdditionalTagsHelper
12
12
 
13
13
  columns = {}
14
14
 
15
- if AdditionalTags.setting?(:active_issue_tags)
15
+ if AdditionalTags.setting? :active_issue_tags
16
16
  columns[:issue] = { label: l(:label_issue_plural),
17
17
  tag_controller: :issues,
18
18
  counts: Issue.available_tags.map { |tag| [tag.id, tag.count] }.to_h }
19
19
  end
20
20
 
21
- if AdditionalTags.setting?(:active_wiki_tags)
21
+ if AdditionalTags.setting? :active_wiki_tags
22
22
  columns[:wiki] = { label: l(:label_wiki),
23
23
  counts: WikiPage.available_tags.map { |tag| [tag.id, tag.count] }.to_h }
24
24
  end
@@ -43,11 +43,11 @@ module AdditionalTagsHelper
43
43
  columns
44
44
  end
45
45
 
46
- def render_tags_list(tags, options = {})
46
+ def render_tags_list(tags, **options)
47
47
  return if tags.blank?
48
48
 
49
- style = options.delete(:style)
50
- tags = tags.all.to_a if tags.respond_to?(:all)
49
+ style = options.delete :style
50
+ tags = tags.all.to_a if tags.respond_to? :all
51
51
 
52
52
  case "#{AdditionalTags.setting :tags_sort_by}:#{AdditionalTags.setting :tags_sort_order}"
53
53
  when 'name:desc'
@@ -71,7 +71,7 @@ module AdditionalTagsHelper
71
71
  raise 'Unknown list style'
72
72
  end
73
73
 
74
- content = ''.html_safe
74
+ content = +''.html_safe
75
75
  if style == :list && AdditionalTags.setting(:tags_sort_by) == 'name'
76
76
  tags.group_by { |tag| tag.name.downcase.first }.each do |letter, grouped_tags|
77
77
  content << content_tag(item_el, letter.upcase, class: 'letter')
@@ -84,26 +84,26 @@ module AdditionalTagsHelper
84
84
  content_tag(list_el, content, class: 'tags-cloud', style: (style == :simple_cloud ? 'text-align: left;' : ''))
85
85
  end
86
86
 
87
- def additional_tag_link(tag_object, options = {})
87
+ def additional_tag_link(tag_object, link: nil, link_wiki_tag: false, show_count: false, use_colors: nil, **options)
88
88
  tag_name = []
89
89
  tag_name << tag_object.name
90
90
 
91
91
  options[:project] = @project if options[:project].blank? && @project.present?
92
92
 
93
- use_colors = AdditionalTags.setting?(:use_colors)
93
+ use_colors ||= AdditionalTags.setting? :use_colors
94
94
  if use_colors
95
95
  tag_bg_color = additional_tag_color tag_object.name
96
96
  tag_fg_color = additional_tag_fg_color tag_bg_color
97
97
  tag_style = "background-color: #{tag_bg_color}; color: #{tag_fg_color}"
98
98
  end
99
99
 
100
- tag_name << tag.span("(#{tag_object.count})", class: 'tag-count') if options[:show_count]
100
+ tag_name << tag.span("(#{tag_object.count})", class: 'tag-count') if show_count
101
101
 
102
- content = if options[:link]
102
+ content = if link
103
103
  link_to safe_join(tag_name),
104
- options[:link],
104
+ link,
105
105
  style: tag_style
106
- elsif options[:link_wiki_tag]
106
+ elsif link_wiki_tag
107
107
  link = if options[:project].present?
108
108
  project_wiki_index_path options[:project], tag: tag_object.name
109
109
  else
@@ -112,7 +112,7 @@ module AdditionalTagsHelper
112
112
  link_to safe_join(tag_name), link, style: tag_style
113
113
  else
114
114
  link_to safe_join(tag_name),
115
- tag_url(tag_object.name, options),
115
+ tag_url(tag_object.name, **options),
116
116
  style: tag_style
117
117
  end
118
118
 
@@ -122,11 +122,11 @@ module AdditionalTagsHelper
122
122
  { class: 'tag-label' }
123
123
  end
124
124
 
125
- tag.span content, style
125
+ tag.span content, **style
126
126
  end
127
127
 
128
128
  def additional_tag_color(tag_name)
129
- "##{Digest::MD5.hexdigest(tag_name)[0..5]}"
129
+ "##{Digest::SHA256.hexdigest(tag_name)[0..5]}"
130
130
  end
131
131
 
132
132
  def additional_tag_fg_color(bg_color)
@@ -140,53 +140,51 @@ module AdditionalTagsHelper
140
140
  end
141
141
 
142
142
  # plain list of tags
143
- def additional_plain_tag_list(tags, sep = ' ')
144
- s = if tags.blank?
145
- ['']
146
- else
147
- tags.map(&:name)
148
- end
143
+ def additional_plain_tag_list(tags, sep: nil)
144
+ sep ||= "#{Query.additional_csv_separator} "
145
+
146
+ s = tags.present? ? tags.map(&:name) : ['']
149
147
  s.join sep
150
148
  end
151
149
 
152
- def additional_tag_sep(use_colors)
153
- if use_colors.nil? || use_colors
154
- ' '
155
- else
156
- ', '
157
- end
150
+ def additional_tag_sep(use_colors: true)
151
+ use_colors ? ' ' : ', '
152
+ end
153
+
154
+ def additional_tags_from_string(str)
155
+ str.to_s.split(',').map(&:strip)
158
156
  end
159
157
 
160
- def additional_tag_links(tag_list, options = {})
158
+ def additional_tag_links(tag_list, **options)
161
159
  return if tag_list.blank?
162
160
 
163
- unsorted = options.delete(:unsorted)
164
- tag_list = AdditionalTags::Tags.sort_tag_list(tag_list) unless unsorted
161
+ unsorted = options.delete :unsorted
162
+ tag_list = AdditionalTags::Tags.sort_tag_list tag_list unless unsorted
165
163
 
166
- safe_join tag_list.map { |tag| additional_tag_link tag, options },
167
- additional_tag_sep(options[:use_colors])
164
+ safe_join tag_list.map { |tag| additional_tag_link tag, **options },
165
+ additional_tag_sep(use_colors: options[:use_colors])
168
166
  end
169
167
 
170
168
  private
171
169
 
172
- def tag_url(tag_name, options = {})
173
- action = options[:tag_action].presence || (controller_name == 'hrm_user_resources' ? 'show' : 'index')
170
+ def tag_url(tag_name, filter: nil, tag_action: nil, tag_controller: nil, project: nil)
171
+ action = tag_action.presence || (controller_name == 'hrm_user_resources' ? 'show' : 'index')
174
172
 
175
173
  fields = [:tags]
176
174
  values = { tags: [tag_name] }
177
175
  operators = { tags: '=' }
178
176
 
179
- if options[:filter].present?
180
- field = options[:filter][:field]
177
+ if filter.present?
178
+ field = filter[:field]
181
179
  fields << field
182
- operators[field] = options[:filter][:operator]
183
- values[field] = options[:filter][:value] if options[:filter].key?(:value)
180
+ operators[field] = filter[:operator]
181
+ values[field] = filter[:value] if filter.key? :value
184
182
  end
185
183
 
186
- { controller: options[:tag_controller].presence || controller_name,
184
+ { controller: tag_controller.presence || controller_name,
187
185
  action: action,
188
186
  set_filter: 1,
189
- project_id: options[:project],
187
+ project_id: project,
190
188
  f: fields,
191
189
  v: values,
192
190
  op: operators }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTagsIssuesHelper
2
4
  # Hacked render_api_custom_values to add plugin values to issue api
3
5
  def render_api_custom_values(custom_values, api)
@@ -9,7 +11,7 @@ module AdditionalTagsIssuesHelper
9
11
 
10
12
  api.array :tags do
11
13
  @issue.tags.each do |tag|
12
- api.tag(id: tag.id, name: tag.name)
14
+ api.tag id: tag.id, name: tag.name
13
15
  end
14
16
  end
15
17
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTagsWikiHelper
2
4
  def sidebar_tags
3
5
  unless @sidebar_tags
4
6
  @sidebar_tags = []
5
- @sidebar_tags = WikiPage.available_tags(project: @project) if AdditionalTags.show_sidebar_tags?
7
+ @sidebar_tags = WikiPage.available_tags project: @project if AdditionalTags.show_sidebar_tags?
6
8
  end
7
9
  @sidebar_tags
8
10
  end
@@ -37,13 +39,13 @@ module AdditionalTagsWikiHelper
37
39
  scope = if wiki
38
40
  wiki.pages
39
41
  else
40
- WikiPage.joins(wiki: :project)
42
+ WikiPage.joins wiki: :project
41
43
  end
42
44
 
43
- scope = scope.visible(User.current, project: project) if scope.respond_to? :visible
45
+ scope = scope.visible User.current, project: project if scope.respond_to? :visible
44
46
 
45
47
  scope = scope.joins(AdditionalTags::Tags.tag_to_joins(WikiPage))
46
- .where("LOWER(#{ActiveRecord::Base.connection.quote_table_name(ActsAsTaggableOn.tags_table)}.name) = LOWER(:p)",
48
+ .where("LOWER(#{ActiveRecord::Base.connection.quote_table_name ActsAsTaggableOn.tags_table}.name) = LOWER(:p)",
47
49
  p: tag.to_s.strip)
48
50
  .with_updated_on
49
51
  .joins(wiki: :project)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class AdditionalTagsJob < AdditionalsJob
2
4
  queue_as :additional_tags
3
5
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class AdditionalTagsRemoveUnusedTagJob < AdditionalTagsJob
2
4
  def perform
3
5
  AdditionalTags::Tags.remove_unused_tags
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class MigrateTag < ActiveRecord::Base
2
4
  self.table_name = 'tags'
3
5
  has_many :migrate_taggings, dependent: :destroy, foreign_key: :tag_id, inverse_of: :migrate_tag
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class MigrateTagging < ActiveRecord::Base
2
4
  self.table_name = 'taggings'
3
5
  belongs_to :migrate_tag, foreign_key: :tag_id, inverse_of: :migrate_taggings
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class QueryTagsColumn < QueryRelationsColumn
4
+ def initialize(name = :tags, **options)
5
+ super name, **options
6
+ end
7
+ end
@@ -2,7 +2,7 @@
2
2
  .tags.attribute
3
3
  - unless defined? hide_label
4
4
  span.label
5
- = l(:field_tag_list)
5
+ = l :field_tag_list
6
6
  ' :
7
7
  - if defined?(editable) && editable
8
8
  #tags-data
@@ -6,9 +6,10 @@ h2
6
6
 
7
7
  = form_tag merge_additional_tags_path(ids: @tags.map(&:id)), class: 'tabular' do
8
8
  = error_messages_for 'tag'
9
- = additional_tag_links @tags, { show_count: true,
10
- use_colors: AdditionalTags.setting?(:use_colors),
11
- link: '#' }
9
+ = additional_tag_links @tags,
10
+ show_count: true,
11
+ use_colors: AdditionalTags.setting?(:use_colors),
12
+ link: '#'
12
13
  .box
13
14
  p
14
15
  label[for="tag_name"]
@@ -15,7 +15,7 @@
15
15
  - tags.each do |tag|
16
16
  tr.hascontextmenu id="#{tag.id}"
17
17
  td.checkbox.hide-when-print
18
- = check_box_tag('ids[]', tag.id, false, id: nil)
18
+ = check_box_tag 'ids[]', tag.id, false, id: nil
19
19
  td = additional_tag_link tag, link: edit_additional_tag_path(tag)
20
20
  - manageable_tag_column_values(tag).each do |column|
21
21
  td = column
@@ -21,10 +21,10 @@ h3.title = l :label_add_tags
21
21
  placeholder: @is_bulk_editing ? t(:label_no_change_option) : '+ add tag',
22
22
  tags: User.current.allowed_to?(:create_issue_tags, @project)
23
23
  p.most_used_tags
24
- = safe_join @most_used_tags.collect { |t| tag.span(t.name, class: 'most_used_tag') }, ', '
24
+ = safe_join @most_used_tags.collect { |t| tag.span t.name, class: 'most_used_tag' }, ', '
25
25
  = javascript_tag "var mostUsedTags = #{@most_used_tags.map(&:name)}"
26
26
 
27
27
  .buttons
28
28
  = submit_tag l(:button_add), name: nil
29
29
  '
30
- = submit_tag l(:button_cancel), name: nil, onclick: 'hideModal(this);', type: 'button'
30
+ = link_to_function l(:button_cancel), 'hideModal(this);'
@@ -1,4 +1,4 @@
1
- - project = defined?(project) ? project : @project
1
+ - project = @project unless defined?(project)
2
2
  - options = { multiple: true,
3
3
  width: '95%',
4
4
  url: issue_tags_auto_completes_path(project_id: project),
data/config/routes.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Rails.application.routes.draw do
2
4
  resources :auto_completes, only: [] do
3
5
  collection do
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class ActsAsTaggableMigration < ActiveRecord::Migration[5.2]
2
4
  def up
3
5
  create_table ActsAsTaggableOn.tags_table do |t|
@@ -30,7 +32,7 @@ class ActsAsTaggableMigration < ActiveRecord::Migration[5.2]
30
32
 
31
33
  return unless ActsAsTaggableOn::Utils.using_mysql?
32
34
 
33
- execute("ALTER TABLE #{ActsAsTaggableOn.tags_table} MODIFY name varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;")
35
+ execute "ALTER TABLE #{ActsAsTaggableOn.tags_table} MODIFY name varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;"
34
36
  end
35
37
 
36
38
  def down
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class MigrateExistingTags < ActiveRecord::Migration[5.2]
2
4
  def up
3
5
  return unless table_exists?(MigrateTag.table_name) && table_exists?(MigrateTagging.table_name)
@@ -11,7 +13,7 @@ class MigrateExistingTags < ActiveRecord::Migration[5.2]
11
13
  old_tag.migrate_taggings.each do |tagging|
12
14
  next if excluded_taggable_types.include? tagging.taggable_type
13
15
 
14
- tag = ActsAsTaggableOn::Tag.create!(name: old_tag.name) if cnt.zero? && tag.nil?
16
+ tag = ActsAsTaggableOn::Tag.create! name: old_tag.name if cnt.zero? && tag.nil?
15
17
  context = tagging.respond_to?('context') && tagging.context.present? ? tagging.context : 'tags'
16
18
 
17
19
  # old data can include dups
@@ -28,7 +30,7 @@ class MigrateExistingTags < ActiveRecord::Migration[5.2]
28
30
  cnt += 1
29
31
  end
30
32
 
31
- ActsAsTaggableOn::Tag.reset_counters(tag.id, :taggings) unless tag.nil?
33
+ ActsAsTaggableOn::Tag.reset_counters tag.id, :taggings unless tag.nil?
32
34
  end
33
35
  end
34
36
  end
data/init.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  Redmine::Plugin.register :additional_tags do
2
4
  name 'Additional Tags'
3
5
  author 'AlphaNodes GmbH'
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'additional_tags/version'
2
4
  require 'additional_tags/tags'
3
5
 
4
6
  module AdditionalTags
5
- TAG_TABLE_NAME = 'additional_tags'.freeze
6
- TAGGING_TABLE_NAME = 'additional_taggings'.freeze
7
+ TAG_TABLE_NAME = 'additional_tags'
8
+ TAGGING_TABLE_NAME = 'additional_taggings'
7
9
 
8
10
  class << self
9
11
  def setup
@@ -22,6 +24,7 @@ module AdditionalTags
22
24
  MyController.include AdditionalTags::Patches::MyControllerPatch
23
25
  Issue.include AdditionalTags::Patches::IssuePatch
24
26
  Journal.include AdditionalTags::Patches::JournalPatch
27
+ Query.include AdditionalTags::Patches::QueryPatch
25
28
  IssuesController.include AdditionalTags::Patches::IssuesControllerPatch
26
29
  ImportsController.include AdditionalTags::Patches::ImportsControllerPatch
27
30
  QueriesHelper.include AdditionalTags::Patches::QueriesHelperPatch
@@ -69,19 +72,6 @@ module AdditionalTags
69
72
  setting(:tags_sidebar).present? && setting(:tags_sidebar) != 'none'
70
73
  end
71
74
 
72
- def sql_for_tags_field(klass, operator, values)
73
- compare = ['=', '*'].include?(operator) ? 'IN' : 'NOT IN'
74
-
75
- case operator
76
- when '=', '!'
77
- ids_list = klass.tagged_with(values, any: true).pluck :id
78
- "(#{klass.table_name}.id #{compare} (#{ids_list.join ','}))" if ids_list.present?
79
- else
80
- entries = ActsAsTaggableOn::Tagging.where taggable_type: klass.name
81
- "(#{klass.table_name}.id #{compare} (#{entries.select(:taggable_id).to_sql}))"
82
- end
83
- end
84
-
85
75
  private
86
76
 
87
77
  def settings
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  class AdditionalTagsHookListener < Redmine::Hook::ViewListener
3
5
  render_on :view_issues_bulk_edit_details_bottom,
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module AgileBoardsControllerPatch
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module AgileQueryPatch
@@ -10,19 +12,19 @@ module AdditionalTags
10
12
  alias_method :initialize_available_filters_without_tags, :initialize_available_filters
11
13
  alias_method :initialize_available_filters, :initialize_available_filters_with_tags
12
14
 
13
- add_available_column QueryColumn.new(:tags)
15
+ add_available_column ::QueryTagsColumn.new
14
16
  end
15
17
 
16
18
  module InstanceMethods
17
19
  def sql_for_tags_field(_field, operator, value)
18
- case operator
19
- when '=', '!'
20
- issues = Issue.tagged_with(value.clone, any: true)
21
- when '!*'
22
- issues = Issue.joins(:tags).uniq
23
- else
24
- issues = Issue.tagged_with(ActsAsTaggableOn::Tag.all.map(&:to_s), any: true)
25
- end
20
+ issues = case operator
21
+ when '=', '!'
22
+ Issue.tagged_with value.clone, any: true
23
+ when '!*'
24
+ Issue.joins(:tags).uniq
25
+ else
26
+ Issue.tagged_with(ActsAsTaggableOn::Tag.all.map(&:to_s), any: true)
27
+ end
26
28
 
27
29
  compare = operator.include?('!') ? 'NOT IN' : 'IN'
28
30
  ids_list = issues.collect(&:id).push(0).join(',')
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module AgileVersionsControllerPatch
@@ -1,10 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module AgileVersionsQueryPatch
4
6
  extend ActiveSupport::Concern
5
7
 
6
8
  included do
7
- add_available_column QueryColumn.new(:tags)
9
+ add_available_column ::QueryTagsColumn.new
8
10
  end
9
11
  end
10
12
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module AutoCompletesControllerPatch
@@ -30,7 +32,7 @@ module AdditionalTags
30
32
  return render_403 unless User.current.admin?
31
33
 
32
34
  @name = params[:q].to_s
33
- sql_for_where = "LOWER(#{ActiveRecord::Base.connection.quote_table_name(ActsAsTaggableOn.tags_table)}.name) LIKE ?"
35
+ sql_for_where = "LOWER(#{ActiveRecord::Base.connection.quote_table_name ActsAsTaggableOn.tags_table}.name) LIKE ?"
34
36
  @tags = ActsAsTaggableOn::Tag.where(sql_for_where, "%#{@name.downcase}%")
35
37
  .order(name: :asc)
36
38
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module CalendarsControllerPatch
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module DashboardAsyncBlocksControllerPatch
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module DashboardsControllerPatch
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module GanttsControllerPatch
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module ImportsControllerPatch
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module IssuePatch
@@ -20,16 +22,16 @@ module AdditionalTags
20
22
  class_methods do
21
23
  def allowed_tags?(tags)
22
24
  allowed_tags = available_tags.map(&:name)
23
- tags.all? { |tag| allowed_tags.include?(tag) }
25
+ tags.all? { |tag| allowed_tags.include? tag }
24
26
  end
25
27
 
26
28
  def by_tags(project, with_subprojects: false)
27
- count_and_group_by(project: project, association: :tags, with_subprojects: with_subprojects)
29
+ count_and_group_by project: project, association: :tags, with_subprojects: with_subprojects
28
30
  end
29
31
 
30
- def available_tags(options = {})
32
+ def available_tags(**options)
31
33
  options[:permission] = :view_issues
32
- tags = AdditionalTags::Tags.available_tags self, options
34
+ tags = AdditionalTags::Tags.available_tags self, **options
33
35
  return tags unless options[:open_issues_only]
34
36
 
35
37
  tags.joins("JOIN #{IssueStatus.table_name} ON #{IssueStatus.table_name}.id = #{table_name}.status_id")
@@ -65,8 +67,8 @@ module AdditionalTags
65
67
  send 'safe_attributes_without_tags=', attrs, user
66
68
  end
67
69
 
68
- def copy_from_with_tags(arg, options = {})
69
- copy_from_without_tags(arg, options)
70
+ def copy_from_with_tags(arg, **options)
71
+ copy_from_without_tags(arg, **options)
70
72
  issue = arg.is_a?(Issue) ? arg : Issue.visible.find(arg)
71
73
  self.tag_list = issue.tag_list
72
74
  self
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module IssueQueryPatch
@@ -5,6 +7,7 @@ module AdditionalTags
5
7
 
6
8
  included do
7
9
  include AdditionalsQuery
10
+ prepend InstanceOverwriteMethods
8
11
  include InstanceMethods
9
12
 
10
13
  alias_method :initialize_available_filters_without_tags, :initialize_available_filters
@@ -12,9 +15,20 @@ module AdditionalTags
12
15
 
13
16
  alias_method :available_columns_without_tags, :available_columns
14
17
  alias_method :available_columns, :available_columns_with_tags
18
+ end
19
+
20
+ module InstanceOverwriteMethods
21
+ def build_from_params(params, defaults = {})
22
+ super
23
+
24
+ return self if params[:tag_id].blank?
15
25
 
16
- alias_method :build_from_params_without_tags, :build_from_params
17
- alias_method :build_from_params, :build_from_params_with_tags
26
+ add_filter 'tags',
27
+ '=',
28
+ [ActsAsTaggableOn::Tag.find_by(id: params[:tag_id]).try(:name)]
29
+
30
+ self
31
+ end
18
32
  end
19
33
 
20
34
  module InstanceMethods
@@ -31,24 +45,13 @@ module AdditionalTags
31
45
  @available_columns = available_columns_without_tags
32
46
 
33
47
  if AdditionalTags.setting?(:active_issue_tags) && User.current.allowed_to?(:view_issue_tags, project, global: true)
34
- @available_columns << QueryColumn.new(:tags)
48
+ @available_columns << ::QueryTagsColumn.new
35
49
  end
36
50
  else
37
51
  available_columns_without_tags
38
52
  end
39
53
  @available_columns
40
54
  end
41
-
42
- def build_from_params_with_tags(params, defaults = {})
43
- build_from_params_without_tags params, defaults
44
- return self if params[:tag_id].blank?
45
-
46
- add_filter 'tags',
47
- '=',
48
- [ActsAsTaggableOn::Tag.find_by(id: params[:tag_id]).try(:name)]
49
-
50
- self
51
- end
52
55
  end
53
56
  end
54
57
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module IssuesControllerPatch
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module JournalPatch
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module MyControllerPatch
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module QueriesHelperPatch
@@ -8,25 +10,11 @@ module AdditionalTags
8
10
 
9
11
  alias_method :column_content_without_tags, :column_content
10
12
  alias_method :column_content, :column_content_with_tags
11
-
12
- alias_method :csv_content_without_tags, :csv_content
13
- alias_method :csv_content, :csv_content_with_tags
14
13
  end
15
14
 
16
15
  module InstanceMethods
17
- def csv_content_with_tags(column, item)
18
- if item.is_a?(Issue) && column.name == :tags ||
19
- item.is_a?(TimeEntry) && column.name == :issue_tags
20
-
21
- additional_plain_tag_list column.value_object(item)
22
- else
23
- csv_content_without_tags column, item
24
- end
25
- end
26
-
27
16
  def column_content_with_tags(column, item)
28
- if item.is_a?(Issue) && column.name == :tags ||
29
- item.is_a?(TimeEntry) && column.name == :issue_tags
17
+ if column.name == :issue_tags || item.is_a?(Issue) && column.name == :tags
30
18
  additional_tag_links column.value(item),
31
19
  tag_controller: 'issues',
32
20
  use_colors: AdditionalTags.setting?(:use_colors)
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AdditionalTags
4
+ module Patches
5
+ module QueryPatch
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ include InstanceMethods
10
+ end
11
+
12
+ module InstanceMethods
13
+ def sql_for_tags_field(field, _operator, values)
14
+ build_sql_for_tags_field klass: queried_class, operator: operator_for(field), values: values
15
+ end
16
+
17
+ def initialize_tags_filter(position: nil)
18
+ add_available_filter 'tags', order: position,
19
+ type: :list_optional,
20
+ values: -> { available_tag_values queried_class }
21
+ end
22
+
23
+ def initialize_issue_tags_filter
24
+ return unless AdditionalTags.setting?(:active_issue_tags) && User.current.allowed_to?(:view_issue_tags, project, global: true)
25
+
26
+ add_available_filter 'issue.tags',
27
+ type: :list_optional,
28
+ name: l('label_attribute_of_issue', name: l(:field_tags)),
29
+ values: -> { available_tag_values Issue }
30
+ end
31
+
32
+ def available_tag_values(klass)
33
+ klass.available_tags(project: project)
34
+ .pluck(:name)
35
+ .map { |name| [name, name] }
36
+ end
37
+
38
+ def build_subquery_for_tags_field(klass:, operator:, values:, joined_table:, joined_field:, target_field: 'issue_id')
39
+ quoted_joined_table = self.class.connection.quote_table_name joined_table
40
+ quoted_joined_field = self.class.connection.quote_column_name joined_field
41
+ quoted_target_field = self.class.connection.quote_column_name target_field
42
+ subsql = ActsAsTaggableOn::Tagging.joins("INNER JOIN #{quoted_joined_table}" \
43
+ " ON additional_taggings.taggable_id = #{quoted_joined_table}.#{quoted_target_field}")
44
+ .where(taggable_type: klass.name)
45
+ .where("#{self.class.connection.quote_table_name queried_table_name}.id ="\
46
+ " #{quoted_joined_table}.#{quoted_joined_field}")
47
+ .select(1)
48
+
49
+ if %w[= !].include? operator
50
+ ids_list = klass.tagged_with(values, any: true).pluck :id
51
+ subsql = subsql.where taggable_id: ids_list
52
+ end
53
+
54
+ if %w[= *].include? operator
55
+ " EXISTS(#{subsql.to_sql})"
56
+ else
57
+ " NOT EXISTS(#{subsql.to_sql})"
58
+ end
59
+ end
60
+
61
+ def build_sql_for_tags_field(klass:, operator:, values:)
62
+ compare = ['=', '*'].include?(operator) ? 'IN' : 'NOT IN'
63
+ case operator
64
+ when '=', '!'
65
+ ids_list = klass.tagged_with(values, any: true).pluck :id
66
+ "(#{klass.table_name}.id #{compare} (#{ids_list.join ','}))" if ids_list.present?
67
+ else
68
+ entries = ActsAsTaggableOn::Tagging.where taggable_type: klass.name
69
+ id_table = klass.table_name
70
+ "(#{id_table}.id #{compare} (#{entries.select(:taggable_id).to_sql}))"
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module ReportsControllerPatch
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module SettingsControllerPatch
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module TimeEntryPatch
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_dependency 'time_entry_query'
2
4
 
3
5
  module AdditionalTags
@@ -18,13 +20,7 @@ module AdditionalTags
18
20
  module InstanceMethods
19
21
  def initialize_available_filters_with_tags
20
22
  initialize_available_filters_without_tags
21
-
22
- return unless AdditionalTags.setting?(:active_issue_tags) && User.current.allowed_to?(:view_issue_tags, project, global: true)
23
-
24
- add_available_filter 'issue.tags',
25
- type: :list_optional,
26
- name: l('label_attribute_of_issue', name: l(:field_tags)),
27
- values: -> { available_issue_tags_values }
23
+ initialize_issue_tags_filter
28
24
  end
29
25
 
30
26
  def available_columns_with_tags
@@ -39,14 +35,8 @@ module AdditionalTags
39
35
  @available_columns
40
36
  end
41
37
 
42
- def sql_for_issue_tags_field(_field, operator, value)
43
- AdditionalTags.sql_for_tags_field Issue, operator, value
44
- end
45
-
46
- def available_issue_tags_values
47
- Issue.available_tags(project: project)
48
- .pluck(:name)
49
- .map { |name| [name, name] }
38
+ def sql_for_issue_tags_field(_field, operator, values)
39
+ build_sql_for_tags_field klass: Issue, operator: operator, values: values
50
40
  end
51
41
  end
52
42
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require_dependency 'query'
2
4
 
3
5
  module AdditionalTags
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module TimelogControllerPatch
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module WikiControllerPatch
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  module Patches
3
5
  module WikiPagePatch
@@ -20,10 +22,10 @@ module AdditionalTags
20
22
  "JOIN #{Project.table_name} ON wikis.project_id = #{Project.table_name}.id"]
21
23
  end
22
24
 
23
- def available_tags(options = {})
25
+ def available_tags(**options)
24
26
  options[:project_join] = project_joins
25
27
  options[:permission] = :view_wiki_pages
26
- AdditionalTags::Tags.available_tags self, options
28
+ AdditionalTags::Tags.available_tags self, **options
27
29
  end
28
30
  end
29
31
 
@@ -1,20 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
4
  class Tags
3
5
  class << self
4
- def available_tags(klass, options = {})
6
+ def available_tags(klass, **options)
5
7
  user = options[:user].presence || User.current
6
8
 
7
9
  scope = ActsAsTaggableOn::Tag.where({})
8
- scope = scope.where("#{Project.table_name}.id = ?", options[:project]) if options[:project]
10
+ scope = scope.where "#{Project.table_name}.id = ?", options[:project] if options[:project]
9
11
  if options[:permission]
10
- scope = scope.where(tag_access(options[:permission], user))
12
+ scope = scope.where tag_access(options[:permission], user)
11
13
  elsif options[:visible_condition]
12
- scope = scope.where(klass.visible_condition(user))
14
+ scope = scope.where klass.visible_condition(user)
13
15
  end
14
- scope = scope.where("LOWER(#{TAG_TABLE_NAME}.name) LIKE ?", "%#{options[:name_like].downcase}%") if options[:name_like]
15
- scope = scope.where("#{TAG_TABLE_NAME}.name=?", options[:name]) if options[:name]
16
- scope = scope.where("#{TAGGING_TABLE_NAME}.taggable_id!=?", options[:exclude_id]) if options[:exclude_id]
17
- scope = scope.where(options[:where_field] => options[:where_value]) if options[:where_field].present? && options[:where_value]
16
+ scope = scope.where "LOWER(#{TAG_TABLE_NAME}.name) LIKE ?", "%#{options[:name_like].downcase}%" if options[:name_like]
17
+ scope = scope.where "#{TAG_TABLE_NAME}.name=?", options[:name] if options[:name]
18
+ scope = scope.where "#{TAGGING_TABLE_NAME}.taggable_id!=?", options[:exclude_id] if options[:exclude_id]
19
+ scope = scope.where options[:where_field] => options[:where_value] if options[:where_field].present? && options[:where_value]
18
20
 
19
21
  columns = ["#{TAG_TABLE_NAME}.id",
20
22
  "#{TAG_TABLE_NAME}.name",
@@ -24,14 +26,14 @@ module AdditionalTags
24
26
  columns << "MIN(#{TAGGING_TABLE_NAME}.created_at) AS last_created" if options[:sort_by] == 'last_created'
25
27
 
26
28
  scope.select(columns.join(', '))
27
- .joins(tag_for_joins(klass, options))
29
+ .joins(tag_for_joins(klass, **options.slice(:project_join, :project, :without_projects)))
28
30
  .group("#{TAG_TABLE_NAME}.id, #{TAG_TABLE_NAME}.name, #{TAG_TABLE_NAME}.taggings_count").having('COUNT(*) > 0')
29
31
  .order(build_order_sql(options[:sort_by], options[:order]))
30
32
  end
31
33
 
32
- def all_type_tags(klass, options = {})
33
- ActsAsTaggableOn::Tag.where({})
34
- .joins(tag_for_joins(klass, options))
34
+ def all_type_tags(klass, without_projects: false)
35
+ ActsAsTaggableOn::Tag.all
36
+ .joins(tag_for_joins(klass, without_projects: without_projects))
35
37
  .distinct
36
38
  .order("#{TAG_TABLE_NAME}.name")
37
39
  end
@@ -61,7 +63,7 @@ module AdditionalTags
61
63
  # remove old (merged) tags
62
64
  tags_to_merge.reject { |t| t.id == tag.id }.each(&:destroy)
63
65
  # remove duplicate taggings
64
- dup_scope = ActsAsTaggableOn::Tagging.where(tag_id: tag.id)
66
+ dup_scope = ActsAsTaggableOn::Tagging.where tag_id: tag.id
65
67
  valid_ids = dup_scope.group(:tag_id, :taggable_id, :taggable_type, :tagger_id, :tagger_type, :context).pluck(Arel.sql('MIN(id)'))
66
68
  dup_scope.where.not(id: valid_ids).destroy_all if valid_ids.any?
67
69
  # recalc count for new tag
@@ -83,6 +85,15 @@ module AdditionalTags
83
85
  end
84
86
  end
85
87
 
88
+ def build_relation_tags(entries)
89
+ return [] if entries.none?
90
+
91
+ tags = entries.map(&:tags)
92
+ tags.flatten!
93
+
94
+ tags.uniq
95
+ end
96
+
86
97
  private
87
98
 
88
99
  def build_order_sql(sort_by, order)
@@ -100,16 +111,16 @@ module AdditionalTags
100
111
  Arel.sql sql
101
112
  end
102
113
 
103
- def tag_for_joins(klass, options = {})
114
+ def tag_for_joins(klass, project_join: nil, project: nil, without_projects: false)
104
115
  table_name = klass.table_name
105
116
 
106
117
  joins = ["JOIN #{TAGGING_TABLE_NAME} ON #{TAGGING_TABLE_NAME}.tag_id = #{TAG_TABLE_NAME}.id"]
107
118
  joins << "JOIN #{table_name} " \
108
119
  "ON #{table_name}.id = #{TAGGING_TABLE_NAME}.taggable_id AND #{TAGGING_TABLE_NAME}.taggable_type = '#{klass}'"
109
120
 
110
- if options[:project_join]
111
- joins << options[:project_join]
112
- elsif options[:project] || !options[:without_projects]
121
+ if project_join
122
+ joins << project_join
123
+ elsif project || !without_projects
113
124
  joins << "JOIN #{Project.table_name} ON #{table_name}.project_id = #{Project.table_name}.id"
114
125
  end
115
126
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTags
2
- VERSION = '1.0.1'.freeze unless defined? VERSION
4
+ VERSION = '1.0.2' unless defined? VERSION
3
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: additional_tags
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - AlphaNodes
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-04-10 00:00:00.000000000 Z
11
+ date: 2021-08-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: acts-as-taggable-on
@@ -80,6 +80,7 @@ files:
80
80
  - app/jobs/additional_tags_remove_unused_tag_job.rb
81
81
  - app/models/migrate_tag.rb
82
82
  - app/models/migrate_tagging.rb
83
+ - app/models/query_tags_column.rb
83
84
  - app/views/additional_tags/_html_head.html.slim
84
85
  - app/views/additional_tags/_tag_list.html.slim
85
86
  - app/views/additional_tags/context_menu.html.slim
@@ -142,6 +143,7 @@ files:
142
143
  - lib/additional_tags/patches/journal_patch.rb
143
144
  - lib/additional_tags/patches/my_controller_patch.rb
144
145
  - lib/additional_tags/patches/queries_helper_patch.rb
146
+ - lib/additional_tags/patches/query_patch.rb
145
147
  - lib/additional_tags/patches/reports_controller_patch.rb
146
148
  - lib/additional_tags/patches/settings_controller_patch.rb
147
149
  - lib/additional_tags/patches/time_entry_patch.rb