additional_tags 1.0.6 → 3.0.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +26 -7
- data/app/controllers/additional_tags_controller.rb +9 -9
- data/app/controllers/issue_tags_controller.rb +6 -1
- data/app/helpers/additional_tags_helper.rb +41 -32
- data/app/helpers/additional_tags_issues_helper.rb +13 -5
- data/app/helpers/additional_tags_wiki_helper.rb +6 -5
- data/app/models/additional_tag.rb +98 -0
- data/app/views/additional_tags/_tag_list.html.slim +10 -4
- data/app/views/additional_tags/merge.html.slim +0 -1
- data/app/views/additional_tags/settings/_general.html.slim +7 -1
- data/app/views/additional_tags/settings/_manage_tags.html.slim +8 -1
- data/app/views/context_menus/_issues_tags.html.slim +7 -1
- data/app/views/dashboards/blocks/_issue_tags.html.slim +3 -1
- data/app/views/issue_tags/_edit_modal.html.slim +7 -7
- data/app/views/issues/_tags.html.slim +6 -1
- data/app/views/issues/_tags_bulk_edit.html.slim +2 -1
- data/app/views/wiki/_tags_form.html.slim +4 -0
- data/app/views/wiki/_tags_show.html.slim +1 -1
- data/assets/javascripts/tags.js +3 -3
- data/assets/stylesheets/tags.css +41 -16
- data/config/locales/bg.yml +17 -11
- data/config/locales/cs.yml +18 -12
- data/config/locales/de.yml +18 -12
- data/config/locales/en.yml +18 -12
- data/config/locales/es.yml +18 -12
- data/config/locales/fr.yml +18 -12
- data/config/locales/it.yml +18 -12
- data/config/locales/ja.yml +17 -11
- data/config/locales/ko.yml +17 -11
- data/config/locales/pl.yml +18 -12
- data/config/locales/pt-BR.yml +17 -11
- data/config/locales/ru.yml +33 -27
- data/config/settings.yml +5 -5
- data/lib/additional_tags/hooks/view_hook.rb +17 -5
- data/lib/additional_tags/patches/issue_patch.rb +54 -9
- data/lib/additional_tags/patches/issue_query_patch.rb +18 -0
- data/lib/additional_tags/patches/queries_helper_patch.rb +13 -3
- data/lib/additional_tags/patches/query_patch.rb +23 -2
- data/lib/additional_tags/patches/wiki_page_patch.rb +6 -1
- data/lib/additional_tags/plugin_version.rb +1 -1
- data/lib/additional_tags/tags.rb +35 -13
- data/lib/additional_tags.rb +5 -0
- metadata +5 -44
- data/.eslintrc.yml +0 -17
- data/.github/workflows/codeql-analysis.yml +0 -70
- data/.github/workflows/linters.yml +0 -43
- data/.github/workflows/tests.yml +0 -134
- data/.gitignore +0 -11
- data/.rubocop.yml +0 -133
- data/.slim-lint.yml +0 -27
- data/.stylelintrc.json +0 -163
- data/Rakefile +0 -13
- data/additional_tags.gemspec +0 -32
- data/doc/images/additional-tags-framework.png +0 -0
- data/doc/images/additional-tags.gif +0 -0
data/config/locales/pl.yml
CHANGED
@@ -1,38 +1,44 @@
|
|
1
1
|
pl:
|
2
|
+
activerecord:
|
3
|
+
errors:
|
4
|
+
messages:
|
5
|
+
invalid_mutually_exclusive_tags: "używa wzajemnie wykluczających się tagów"
|
6
|
+
field_issue_tags: "Znaczniki emisji"
|
2
7
|
field_tag_list: Tags
|
3
8
|
field_tags: Tags
|
4
|
-
field_issue_tags: Issue tags
|
5
9
|
label_active_issue_tags: "Aktywacja znaczników emisji"
|
6
10
|
label_active_wiki_tags: "Aktywacja tagów wiki"
|
7
11
|
label_add_tags: "Dodaj znaczniki"
|
12
|
+
label_amount_entities_with_tags: "Kwota %{name} z Tags"
|
13
|
+
label_amount_tags: "Kwota Tags"
|
8
14
|
label_edit_tags: "Edycja tagów"
|
9
15
|
label_manage_tags: "Zarządzaj tagami"
|
10
16
|
label_merge_selected_tags: "Łączenie wybranych tagów"
|
11
17
|
label_open_issues_only: "Wyświetlaj tylko sprawy otwarte"
|
12
18
|
label_show_with_count: "Wyświetlanie ilości na etykiecie"
|
19
|
+
label_tag_color_theme: "Kolorowy motyw %{value}"
|
20
|
+
label_tags_colors: Kolor
|
21
|
+
label_tags_sidebar: "Wyświetlać znaczniki na pasku bocznym jako"
|
22
|
+
label_tags_sort_by: "Sortuj znaczniki według"
|
23
|
+
label_tags_suggestion_order: "Zamówienie ofertowe"
|
13
24
|
label_tags_tag: "Tag"
|
14
|
-
|
15
|
-
|
25
|
+
label_tags_without_color: "Bez koloru"
|
26
|
+
label_use_colors: "Użyj kolorów"
|
27
|
+
label_wiki_index_for_tag: "Strony Wiki z tagiem"
|
28
|
+
label_with_chart: "Z wykresem"
|
29
|
+
label_with_table_of_values: "Z tabelą wartości"
|
16
30
|
notice_failed_to_add_tags: "Nie dodano znaczników"
|
17
31
|
notice_tags_added: "Tagi dodane"
|
18
32
|
permission_add_wiki_tags: "Dodaj znaczniki wiki"
|
19
33
|
permission_create_issue_tags: "Dodaj znaczniki wydania"
|
20
34
|
permission_edit_issue_tags: "Edycja znaczników wydania"
|
21
35
|
permission_view_issue_tags: "Wyświetlanie znaczników emisji"
|
22
|
-
tags_order_by_last_created: "Ostatnio stworzony"
|
23
36
|
tags_order_by_count: "Najczęściej używany"
|
37
|
+
tags_order_by_last_created: "Ostatnio stworzony"
|
24
38
|
tags_order_by_name: "Nazwa"
|
25
39
|
tags_sidebar_cloud: "Cloud"
|
26
40
|
tags_sidebar_list: "Lista"
|
27
41
|
tags_sidebar_none: "Brak"
|
28
42
|
tags_sidebar_simple_cloud: "Simple cloud"
|
29
|
-
label_tags_sidebar: "Wyświetlać znaczniki na pasku bocznym jako"
|
30
43
|
tags_sort_by_count: "Hrabia"
|
31
44
|
tags_sort_by_name: "Nazwa"
|
32
|
-
label_tags_sort_by: "Sortuj znaczniki według"
|
33
|
-
label_tags_suggestion_order: "Zamówienie ofertowe"
|
34
|
-
label_with_table_of_values: "Z tabelą wartości"
|
35
|
-
label_with_chart: "Z wykresem"
|
36
|
-
label_amount_tags: "Kwota Tags"
|
37
|
-
label_amount_entities_with_tags: "Kwota %{name} z Tags"
|
38
|
-
label_quantity: "Ilość"
|
data/config/locales/pt-BR.yml
CHANGED
@@ -1,38 +1,44 @@
|
|
1
1
|
pt-BR:
|
2
|
+
activerecord:
|
3
|
+
errors:
|
4
|
+
messages:
|
5
|
+
invalid_mutually_exclusive_tags: "utiliza etiquetas mutuamente exclusivas"
|
6
|
+
field_issue_tags: Issue tags
|
2
7
|
field_tag_list: Tags
|
3
8
|
field_tags: Tags
|
4
|
-
field_issue_tags: Issue tags
|
5
9
|
label_active_issue_tags: "Ativar as etiquetas de emissão"
|
6
10
|
label_active_wiki_tags: "Ativar as etiquetas wiki"
|
7
11
|
label_add_tags: "Adicionar etiquetas"
|
12
|
+
label_amount_entities_with_tags: "Quantidade %{name} com etiquetas"
|
13
|
+
label_amount_tags: "Valor Etiquetas"
|
8
14
|
label_edit_tags: "Editar etiquetas"
|
9
15
|
label_manage_tags: "Gerenciar etiquetas"
|
10
16
|
label_merge_selected_tags: "Fundir tags selecionadas"
|
11
17
|
label_open_issues_only: "Exibir apenas questões em aberto"
|
12
18
|
label_show_with_count: "Mostrar quantidade na etiqueta"
|
19
|
+
label_tag_color_theme: "Tema da cor %{value}"
|
20
|
+
label_tags_colors: "Cor"
|
21
|
+
label_tags_sidebar: "Mostrar etiquetas na barra lateral como"
|
22
|
+
label_tags_sort_by: "Ordenar tags por"
|
23
|
+
label_tags_suggestion_order: "Pedido de sugestão"
|
13
24
|
label_tags_tag: "Tag"
|
25
|
+
label_tags_without_color: "Sem cor"
|
14
26
|
label_use_colors: "Usar cores"
|
15
|
-
|
27
|
+
label_wiki_index_for_tag: "Páginas Wiki com tag"
|
28
|
+
label_with_chart: "Com gráfico"
|
29
|
+
label_with_table_of_values: "Com tabela de valores"
|
16
30
|
notice_failed_to_add_tags: "Falha em adicionar tags"
|
17
31
|
notice_tags_added: "Tags adicionadas"
|
18
32
|
permission_add_wiki_tags: "Adicionar etiquetas wiki"
|
19
33
|
permission_create_issue_tags: "Adicionar etiquetas de edição"
|
20
34
|
permission_edit_issue_tags: "Editar etiquetas de edição"
|
21
35
|
permission_view_issue_tags: "Exibir etiquetas de edição"
|
22
|
-
tags_order_by_last_created: "Última criação"
|
23
36
|
tags_order_by_count: "Mais utilizados"
|
37
|
+
tags_order_by_last_created: "Última criação"
|
24
38
|
tags_order_by_name: "Nome"
|
25
39
|
tags_sidebar_cloud: "Cloud"
|
26
40
|
tags_sidebar_list: "Lista"
|
27
41
|
tags_sidebar_none: "Nenhum"
|
28
42
|
tags_sidebar_simple_cloud: "Simple cloud"
|
29
|
-
label_tags_sidebar: "Mostrar etiquetas na barra lateral como"
|
30
43
|
tags_sort_by_count: "Conde"
|
31
44
|
tags_sort_by_name: "Nome"
|
32
|
-
label_tags_sort_by: "Ordenar tags por"
|
33
|
-
label_tags_suggestion_order: "Pedido de sugestão"
|
34
|
-
label_with_table_of_values: "Com tabela de valores"
|
35
|
-
label_with_chart: "Com gráfico"
|
36
|
-
label_amount_tags: "Valor Etiquetas"
|
37
|
-
label_amount_entities_with_tags: "Quantidade %{name} com etiquetas"
|
38
|
-
label_quantity: "Quantidade"
|
data/config/locales/ru.yml
CHANGED
@@ -1,38 +1,44 @@
|
|
1
1
|
ru:
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
2
|
+
activerecord:
|
3
|
+
errors:
|
4
|
+
messages:
|
5
|
+
invalid_mutually_exclusive_tags: "использует взаимоисключающие метки"
|
6
|
+
field_issue_tags: "Метки задач"
|
7
|
+
field_tag_list: "Метки"
|
8
|
+
field_tags: "Метки"
|
9
|
+
label_active_issue_tags: "Активировать метки задач"
|
10
|
+
label_active_wiki_tags: "Активировать метки вики"
|
11
|
+
label_add_tags: "Добавьте метки"
|
12
|
+
label_amount_entities_with_tags: "Сумма %{name} с метками"
|
13
|
+
label_amount_tags: "Метки Сумма"
|
14
|
+
label_edit_tags: "Редактировать метки"
|
15
|
+
label_manage_tags: "Управление метками"
|
16
|
+
label_merge_selected_tags: "Объединить выбранные метки"
|
11
17
|
label_open_issues_only: "Отображать только открытые задачи"
|
12
|
-
label_show_with_count: "Отображать количество на
|
13
|
-
|
18
|
+
label_show_with_count: "Отображать количество на метке"
|
19
|
+
label_tag_color_theme: "Цветовая тема %{value}"
|
20
|
+
label_tags_colors: "Цвет"
|
21
|
+
label_tags_sidebar: "Способ отображения меток на боковой панели"
|
22
|
+
label_tags_sort_by: "Сортировать метки по"
|
23
|
+
label_tags_suggestion_order: "Порядок предложения при вводе"
|
24
|
+
label_tags_tag: "Метка"
|
25
|
+
label_tags_without_color: "Без цвета"
|
14
26
|
label_use_colors: "Использовать цвета"
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
27
|
+
label_wiki_index_for_tag: "Вики-страницы с меткой"
|
28
|
+
label_with_chart: "С графиком"
|
29
|
+
label_with_table_of_values: "С таблицей значений"
|
30
|
+
notice_failed_to_add_tags: "Не удалось добавить метки"
|
31
|
+
notice_tags_added: "Метки добавлены"
|
32
|
+
permission_add_wiki_tags: "Добавление меток вики"
|
33
|
+
permission_create_issue_tags: "Добавление меток задач"
|
34
|
+
permission_edit_issue_tags: "Редактирование меток задач"
|
35
|
+
permission_view_issue_tags: "Просмотр меток задач"
|
23
36
|
tags_order_by_count: "Наиболее часто используемые"
|
37
|
+
tags_order_by_last_created: "Недавно созданные"
|
24
38
|
tags_order_by_name: "Имя"
|
25
39
|
tags_sidebar_cloud: "Облако"
|
26
40
|
tags_sidebar_list: "Список"
|
27
41
|
tags_sidebar_none: "Нет"
|
28
42
|
tags_sidebar_simple_cloud: "Простое облако"
|
29
|
-
label_tags_sidebar: "Способ отображения тегов на боковой панели"
|
30
43
|
tags_sort_by_count: "Количеству"
|
31
44
|
tags_sort_by_name: "Имени"
|
32
|
-
label_tags_sort_by: "Сортировать теги по"
|
33
|
-
label_tags_suggestion_order: "Порядок предложения при вводе"
|
34
|
-
label_with_table_of_values: "С таблицей значений"
|
35
|
-
label_with_chart: "С графиком"
|
36
|
-
label_amount_tags: "Теги Сумма"
|
37
|
-
label_amount_entities_with_tags: "Сумма %{name} с тегами"
|
38
|
-
label_quantity: "Количество"
|
data/config/settings.yml
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
active_issue_tags: 0
|
2
|
-
active_wiki_tags: 0
|
3
|
-
open_issues_only: 0
|
4
|
-
show_with_count: 0
|
1
|
+
active_issue_tags: '0'
|
2
|
+
active_wiki_tags: '0'
|
3
|
+
open_issues_only: '0'
|
4
|
+
show_with_count: '0'
|
5
|
+
tags_color_theme: '1'
|
5
6
|
tags_sidebar: 'none'
|
6
7
|
tags_sort_by: 'name'
|
7
8
|
tags_sort_order: 'asc'
|
8
9
|
tags_suggestion_order: 'name'
|
9
|
-
use_colors: 1
|
@@ -63,16 +63,28 @@ module AdditionalTags
|
|
63
63
|
def issues_bulk_tags_fix(issue, params)
|
64
64
|
return unless params && params[:issue]
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
|
66
|
+
common_tags = if params[:common_tags].present?
|
67
|
+
params[:common_tags].split(ActsAsTaggableOn.delimiter).map(&:strip)
|
68
|
+
else
|
69
|
+
[]
|
70
|
+
end
|
71
|
+
|
72
|
+
current_tags = ActsAsTaggableOn::TagList.new issue.tags.to_a
|
73
|
+
new_tags = Array(params[:issue][:tag_list]).compact_blank
|
74
|
+
|
75
|
+
tags_to_add = new_tags - common_tags
|
76
|
+
tags_to_remove = common_tags - new_tags
|
77
|
+
|
78
|
+
current_tags.add tags_to_add
|
79
|
+
current_tags.remove tags_to_remove
|
80
|
+
|
81
|
+
issue.tag_list = current_tags
|
69
82
|
end
|
70
83
|
|
71
84
|
def tags_journal(issue, params)
|
72
85
|
return unless params && params[:issue] && params[:issue][:tag_list]
|
73
86
|
|
74
|
-
issue.tags_to_journal
|
75
|
-
issue.tag_list.to_s
|
87
|
+
issue.tags_to_journal issue.tag_list_was&.to_s, issue.tag_list.to_s
|
76
88
|
end
|
77
89
|
end
|
78
90
|
end
|
@@ -13,6 +13,8 @@ module AdditionalTags
|
|
13
13
|
before_save :prepare_save_tag_change
|
14
14
|
before_save :sort_tag_list
|
15
15
|
|
16
|
+
validate :validate_tags, if: proc { AdditionalTags.setting?(:active_issue_tags) }
|
17
|
+
|
16
18
|
after_commit :add_remove_unused_tags_job, on: %i[update destroy],
|
17
19
|
if: proc { AdditionalTags.setting?(:active_issue_tags) }
|
18
20
|
|
@@ -29,21 +31,58 @@ module AdditionalTags
|
|
29
31
|
tags.all? { |tag| allowed_tags.include? tag }
|
30
32
|
end
|
31
33
|
|
32
|
-
def group_by_status_with_tags(project = nil)
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
def group_by_status_with_tags(project = nil, user = User.current)
|
35
|
+
scope = if project && Setting.display_subprojects_issues?
|
36
|
+
visible(user).where(AdditionalTags::Tags.subproject_sql(project))
|
37
|
+
else
|
38
|
+
visible user, project: project
|
39
|
+
end
|
40
|
+
|
41
|
+
scope.joins(:status)
|
42
|
+
.joins(:tags)
|
43
|
+
.group(:is_closed, 'tag_id')
|
44
|
+
.count
|
37
45
|
end
|
38
46
|
|
39
47
|
def available_tags(**options)
|
40
|
-
options[:permission]
|
48
|
+
options[:permission] ||= :view_issue_tags
|
41
49
|
tags = AdditionalTags::Tags.available_tags self, **options
|
42
50
|
return tags unless options[:open_issues_only]
|
43
51
|
|
44
52
|
tags.joins("JOIN #{IssueStatus.table_name} ON #{IssueStatus.table_name}.id = #{table_name}.status_id")
|
45
53
|
.where(issue_statuses: { is_closed: false })
|
46
54
|
end
|
55
|
+
|
56
|
+
def common_tag_list_from_issues(ids)
|
57
|
+
common_tags = ActsAsTaggableOn::Tag.joins(:taggings)
|
58
|
+
.select(
|
59
|
+
"#{ActiveRecord::Base.connection.quote_table_name ActsAsTaggableOn.tags_table}.id",
|
60
|
+
"#{ActiveRecord::Base.connection.quote_table_name ActsAsTaggableOn.tags_table}.name"
|
61
|
+
)
|
62
|
+
.where(taggings: { taggable_type: 'Issue', taggable_id: ids })
|
63
|
+
.group(
|
64
|
+
"#{ActiveRecord::Base.connection.quote_table_name ActsAsTaggableOn.tags_table}.id",
|
65
|
+
"#{ActiveRecord::Base.connection.quote_table_name ActsAsTaggableOn.tags_table}.name"
|
66
|
+
)
|
67
|
+
.having('count(*) = ?', ids.count).to_a
|
68
|
+
|
69
|
+
ActsAsTaggableOn::TagList.new common_tags
|
70
|
+
end
|
71
|
+
|
72
|
+
def load_visible_tags(issues, user = User.current)
|
73
|
+
return if issues.blank?
|
74
|
+
|
75
|
+
available_projects = Project.where(AdditionalTags::Tags.visible_condition(user)).ids
|
76
|
+
|
77
|
+
issues.each do |issue|
|
78
|
+
tags = if available_projects.include? issue.project_id
|
79
|
+
issue.tags
|
80
|
+
else
|
81
|
+
[]
|
82
|
+
end
|
83
|
+
issue.instance_variable_set :@visible_tags, tags
|
84
|
+
end
|
85
|
+
end
|
47
86
|
end
|
48
87
|
|
49
88
|
module InstanceMethods
|
@@ -62,8 +101,6 @@ module AdditionalTags
|
|
62
101
|
tags = attrs.delete :tag_list
|
63
102
|
tags = Array(tags).reject(&:empty?)
|
64
103
|
|
65
|
-
Additionals.debug "tags: #{tags.inspect} - project: #{project&.id} - access: #{user.allowed_to? :create_issue_tags, project}"
|
66
|
-
|
67
104
|
if user.allowed_to?(:create_issue_tags, project) ||
|
68
105
|
user.allowed_to?(:edit_issue_tags, project) && Issue.allowed_tags?(tags)
|
69
106
|
attrs[:tag_list] = tags # required fix for journal details
|
@@ -76,7 +113,8 @@ module AdditionalTags
|
|
76
113
|
|
77
114
|
copy_from_without_tags arg, **options
|
78
115
|
issue = arg.is_a?(Issue) ? arg : Issue.visible.find(arg)
|
79
|
-
self.
|
116
|
+
self.tags = issue.tags # required for bulk copy
|
117
|
+
self.tag_list = tags.map(&:name) # required for copy
|
80
118
|
self
|
81
119
|
end
|
82
120
|
|
@@ -88,6 +126,13 @@ module AdditionalTags
|
|
88
126
|
|
89
127
|
self.tag_list = AdditionalTags::Tags.sort_tags tags
|
90
128
|
end
|
129
|
+
|
130
|
+
def validate_tags
|
131
|
+
return if !User.current.allowed_to?(:create_issue_tags, project) &&
|
132
|
+
!(User.current.allowed_to?(:edit_issue_tags, project) && Issue.allowed_tags?(tags))
|
133
|
+
|
134
|
+
errors.add :tag_list, :invalid_mutually_exclusive_tags unless AdditionalTag.valid_mutually_exclusive_tag tag_list
|
135
|
+
end
|
91
136
|
end
|
92
137
|
end
|
93
138
|
end
|
@@ -15,6 +15,9 @@ module AdditionalTags
|
|
15
15
|
|
16
16
|
alias_method :available_columns_without_tags, :available_columns
|
17
17
|
alias_method :available_columns, :available_columns_with_tags
|
18
|
+
|
19
|
+
alias_method :issues_without_tags, :issues
|
20
|
+
alias_method :issues, :issues_with_tags
|
18
21
|
end
|
19
22
|
|
20
23
|
module InstanceOverwriteMethods
|
@@ -29,9 +32,24 @@ module AdditionalTags
|
|
29
32
|
|
30
33
|
self
|
31
34
|
end
|
35
|
+
|
36
|
+
def sql_for_tags_field(field, _operator, values)
|
37
|
+
build_sql_for_tags_field_with_permission klass: queried_class,
|
38
|
+
operator: operator_for(field),
|
39
|
+
values: values,
|
40
|
+
permission: :view_issue_tags
|
41
|
+
end
|
32
42
|
end
|
33
43
|
|
34
44
|
module InstanceMethods
|
45
|
+
def issues_with_tags(**options)
|
46
|
+
issues = issues_without_tags(**options)
|
47
|
+
return issues unless has_column? :tags
|
48
|
+
|
49
|
+
Issue.load_visible_tags issues
|
50
|
+
issues
|
51
|
+
end
|
52
|
+
|
35
53
|
def initialize_available_filters_with_tags
|
36
54
|
initialize_available_filters_without_tags
|
37
55
|
|
@@ -15,9 +15,19 @@ module AdditionalTags
|
|
15
15
|
module InstanceMethods
|
16
16
|
def column_content_with_tags(column, item)
|
17
17
|
if column.name == :issue_tags || item.is_a?(Issue) && column.name == :tags
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
tags = if item.instance_variable_defined? :@visible_tags
|
19
|
+
item.instance_variable_get :@visible_tags
|
20
|
+
elsif Setting.display_subprojects_issues?
|
21
|
+
# permission check required (expensive)
|
22
|
+
return unless User.current.allowed_to? :view_issue_tags, item.project
|
23
|
+
|
24
|
+
column.value item
|
25
|
+
else
|
26
|
+
# no permission check required
|
27
|
+
column.value item
|
28
|
+
end
|
29
|
+
|
30
|
+
additional_tag_links tags, tag_controller: 'issues'
|
21
31
|
else
|
22
32
|
column_content_without_tags column, item
|
23
33
|
end
|
@@ -11,7 +11,9 @@ module AdditionalTags
|
|
11
11
|
|
12
12
|
module InstanceMethods
|
13
13
|
def sql_for_tags_field(field, _operator, values)
|
14
|
-
build_sql_for_tags_field klass: queried_class,
|
14
|
+
build_sql_for_tags_field klass: queried_class,
|
15
|
+
operator: operator_for(field),
|
16
|
+
values: values
|
15
17
|
end
|
16
18
|
|
17
19
|
def initialize_tags_filter(position: nil)
|
@@ -60,6 +62,25 @@ module AdditionalTags
|
|
60
62
|
end
|
61
63
|
end
|
62
64
|
|
65
|
+
# NOTE: should be used, if tags required permission check
|
66
|
+
def build_sql_for_tags_field_with_permission(klass:, operator:, values:, permission:)
|
67
|
+
compare = ['=', '*'].include?(operator) ? 'in' : 'not_in'
|
68
|
+
case operator
|
69
|
+
when '=', '!'
|
70
|
+
ids_list = klass.tagged_with(values, any: true).ids
|
71
|
+
# special case: filter with deleted tag
|
72
|
+
return AdditionalsQuery::NO_RESULT_CONDITION if ids_list.blank? && values.present? && operator == '='
|
73
|
+
else
|
74
|
+
allowed_projects = Project.where(Project.allowed_to_condition(User.current, permission))
|
75
|
+
.select(:id)
|
76
|
+
ids_list = klass.tagged_with(klass.available_tags(skip_pre_condition: true), any: true)
|
77
|
+
.where(project_id: allowed_projects).ids
|
78
|
+
end
|
79
|
+
|
80
|
+
"(#{klass.arel_table[:id].send(compare, ids_list).to_sql})"
|
81
|
+
end
|
82
|
+
|
83
|
+
# NOTE: should be used, if tags do not require permission check
|
63
84
|
def build_sql_for_tags_field(klass:, operator:, values:)
|
64
85
|
compare = ['=', '*'].include?(operator) ? 'IN' : 'NOT IN'
|
65
86
|
case operator
|
@@ -69,7 +90,7 @@ module AdditionalTags
|
|
69
90
|
"(#{klass.table_name}.id #{compare} (#{ids_list.join ','}))"
|
70
91
|
elsif values.present? && operator == '='
|
71
92
|
# special case: filter with deleted tag
|
72
|
-
|
93
|
+
AdditionalsQuery::NO_RESULT_CONDITION
|
73
94
|
end
|
74
95
|
else
|
75
96
|
entries = ActsAsTaggableOn::Tagging.where taggable_type: klass.name
|
@@ -13,6 +13,7 @@ module AdditionalTags
|
|
13
13
|
alias_method :safe_attributes_without_tags=, :safe_attributes=
|
14
14
|
alias_method :safe_attributes=, :safe_attributes_with_tags=
|
15
15
|
|
16
|
+
validate :validate_tags
|
16
17
|
before_save :sort_tag_list
|
17
18
|
end
|
18
19
|
|
@@ -24,7 +25,7 @@ module AdditionalTags
|
|
24
25
|
|
25
26
|
def available_tags(**options)
|
26
27
|
options[:project_join] = project_joins
|
27
|
-
options[:permission]
|
28
|
+
options[:permission] ||= :view_wiki_pages
|
28
29
|
AdditionalTags::Tags.available_tags self, **options
|
29
30
|
end
|
30
31
|
|
@@ -106,6 +107,10 @@ module AdditionalTags
|
|
106
107
|
|
107
108
|
self.tag_list = AdditionalTags::Tags.sort_tags tag_list
|
108
109
|
end
|
110
|
+
|
111
|
+
def validate_tags
|
112
|
+
errors.add :tag_list, :invalid_mutually_exclusive_tags unless AdditionalTag.valid_mutually_exclusive_tag tag_list
|
113
|
+
end
|
109
114
|
end
|
110
115
|
end
|
111
116
|
end
|
data/lib/additional_tags/tags.rb
CHANGED
@@ -3,13 +3,27 @@
|
|
3
3
|
module AdditionalTags
|
4
4
|
class Tags
|
5
5
|
class << self
|
6
|
+
def visible_condition(user, **options)
|
7
|
+
permission = options[:permission] || :view_issue_tags
|
8
|
+
skip_pre_condition = options[:skip_pre_condition] || true
|
9
|
+
|
10
|
+
tag_access permission, user, skip_pre_condition: skip_pre_condition
|
11
|
+
end
|
12
|
+
|
6
13
|
def available_tags(klass, **options)
|
7
14
|
user = options[:user].presence || User.current
|
8
15
|
|
9
16
|
scope = ActsAsTaggableOn::Tag.where({})
|
10
|
-
|
17
|
+
if options[:project]
|
18
|
+
scope = if Setting.display_subprojects_issues?
|
19
|
+
scope.where subproject_sql(options[:project])
|
20
|
+
else
|
21
|
+
scope.where projects: { id: options[:project] }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
11
25
|
if options[:permission]
|
12
|
-
scope = scope.where tag_access(options[:permission], user)
|
26
|
+
scope = scope.where tag_access(options[:permission], user, skip_pre_condition: options[:skip_pre_condition])
|
13
27
|
elsif options[:visible_condition]
|
14
28
|
scope = scope.where klass.visible_condition(user)
|
15
29
|
end
|
@@ -18,14 +32,7 @@ module AdditionalTags
|
|
18
32
|
scope = scope.where "#{TAGGING_TABLE_NAME}.taggable_id!=?", options[:exclude_id] if options[:exclude_id]
|
19
33
|
scope = scope.where options[:where_field] => options[:where_value] if options[:where_field].present? && options[:where_value]
|
20
34
|
|
21
|
-
|
22
|
-
"#{TAG_TABLE_NAME}.name",
|
23
|
-
"#{TAG_TABLE_NAME}.taggings_count",
|
24
|
-
"COUNT(DISTINCT #{TAGGING_TABLE_NAME}.taggable_id) AS count"]
|
25
|
-
|
26
|
-
columns << "MIN(#{TAGGING_TABLE_NAME}.created_at) AS last_created" if options[:sort_by] == 'last_created'
|
27
|
-
|
28
|
-
scope.select(columns.to_list)
|
35
|
+
scope.select(table_columns(options[:sort_by]))
|
29
36
|
.joins(tag_for_joins(klass, **options.slice(:project_join, :project, :without_projects)))
|
30
37
|
.group("#{TAG_TABLE_NAME}.id, #{TAG_TABLE_NAME}.name, #{TAG_TABLE_NAME}.taggings_count").having('COUNT(*) > 0')
|
31
38
|
.order(build_order_sql(options[:sort_by], options[:order]))
|
@@ -125,8 +132,23 @@ module AdditionalTags
|
|
125
132
|
counts
|
126
133
|
end
|
127
134
|
|
135
|
+
def subproject_sql(project)
|
136
|
+
"#{Project.table_name}.lft >= #{project.lft} " \
|
137
|
+
"AND #{Project.table_name}.rgt <= #{project.rgt}"
|
138
|
+
end
|
139
|
+
|
128
140
|
private
|
129
141
|
|
142
|
+
def table_columns(sort_by)
|
143
|
+
columns = ["#{TAG_TABLE_NAME}.id",
|
144
|
+
"#{TAG_TABLE_NAME}.name",
|
145
|
+
"#{TAG_TABLE_NAME}.taggings_count",
|
146
|
+
"COUNT(DISTINCT #{TAGGING_TABLE_NAME}.taggable_id) AS count"]
|
147
|
+
|
148
|
+
columns << "MIN(#{TAGGING_TABLE_NAME}.created_at) AS last_created" if sort_by == 'last_created'
|
149
|
+
columns.to_list
|
150
|
+
end
|
151
|
+
|
130
152
|
def status_for_tag_value(scope:, tag_id:, group_id: nil, group_id_is_bool: false)
|
131
153
|
value = if group_id_is_bool || group_id
|
132
154
|
if group_id_is_bool
|
@@ -176,17 +198,17 @@ module AdditionalTags
|
|
176
198
|
joins
|
177
199
|
end
|
178
200
|
|
179
|
-
def tag_access(permission, user)
|
201
|
+
def tag_access(permission, user, skip_pre_condition: false)
|
180
202
|
projects_allowed = if permission.nil?
|
181
203
|
Project.visible.ids
|
182
204
|
else
|
183
|
-
Project.where(Project.allowed_to_condition(user, permission)).ids
|
205
|
+
Project.where(Project.allowed_to_condition(user, permission, skip_pre_condition: skip_pre_condition)).ids
|
184
206
|
end
|
185
207
|
|
186
208
|
if projects_allowed.present?
|
187
209
|
"#{Project.table_name}.id IN (#{projects_allowed.join ','})" unless projects_allowed.empty?
|
188
210
|
else
|
189
|
-
|
211
|
+
AdditionalsQuery::NO_RESULT_CONDITION
|
190
212
|
end
|
191
213
|
end
|
192
214
|
end
|
data/lib/additional_tags.rb
CHANGED
@@ -14,6 +14,11 @@ module AdditionalTags
|
|
14
14
|
setting(:tags_sidebar).present? && setting(:tags_sidebar) != 'none'
|
15
15
|
end
|
16
16
|
|
17
|
+
# color is used by default (if setting is missing, too)
|
18
|
+
def use_colors?
|
19
|
+
setting(:tags_color_theme).to_s != '0'
|
20
|
+
end
|
21
|
+
|
17
22
|
private
|
18
23
|
|
19
24
|
def setup
|