diff --git a/app/components/layout/tag_list_component.html.erb b/app/components/layout/tag_list_component.html.erb index 06e350a86..bc27c3944 100644 --- a/app/components/layout/tag_list_component.html.erb +++ b/app/components/layout/tag_list_component.html.erb @@ -3,27 +3,11 @@

Štítky

<% @tags.each do |tag| %> - <%= link_to message_threads_path(q: "label:(#{tag.name})"), class:"flex justify-start items-start px-4 py-2 gap-2 overflow-hidden" do %> + <%= link_to message_threads_path(q: "label:(#{tag.name})"), class: "flex justify-start items-start px-4 py-2 gap-2 overflow-hidden" do %>

<%= tag.name %>

<% end %> <% end %> - <% if Current.user.admin? %> - <%= link_to message_threads_path(no_visible_tags: "1"), class: "group relative" do %> -
- - - -

Bez GO štítku -

-
- - <% end %> - <% end %> diff --git a/app/controllers/message_threads_controller.rb b/app/controllers/message_threads_controller.rb index 7ce31d98a..f55f1bad1 100644 --- a/app/controllers/message_threads_controller.rb +++ b/app/controllers/message_threads_controller.rb @@ -37,7 +37,6 @@ def load_threads scope: message_thread_policy_scope.includes(:tags, :box), search_permissions: search_permissions, query: search_params[:q], - no_visible_tags: search_params[:no_visible_tags] == "1" && Current.user.admin?, cursor: cursor ) @@ -82,9 +81,9 @@ def message_thread_policy_scope end def search_permissions - result = { tenant_id: Current.tenant } - result[:box_id] = Current.box if Current.box - result[:tag_ids] = policy_scope(Tag).pluck(:id) unless Current.user.admin? + result = { tenant: Current.tenant } + result[:box] = Current.box if Current.box + result[:tag_ids] = policy_scope(Tag).pluck(:id) result end @@ -93,6 +92,6 @@ def message_thread_params end def search_params - params.permit(:q, :no_visible_tags, :format, cursor: MessageThreadCollection::CURSOR_PARAMS) + params.permit(:q, :format, cursor: MessageThreadCollection::CURSOR_PARAMS) end end diff --git a/app/models/message_thread_collection.rb b/app/models/message_thread_collection.rb index bb6eca7e0..327cc85f3 100644 --- a/app/models/message_thread_collection.rb +++ b/app/models/message_thread_collection.rb @@ -21,12 +21,11 @@ def self.serialize_cursor(cursor) cursor end - def self.all(scope: nil, search_permissions:, query: nil, no_visible_tags: false, cursor:) + def self.all(scope: nil, search_permissions:, query: nil, cursor:) parsed_query = Searchable::MessageThreadQuery.parse(query.to_s) filter = Searchable::MessageThreadQuery.labels_to_ids( parsed_query, - tenant_id: search_permissions.fetch(:tenant_id), - no_visible_tags: no_visible_tags + tenant: search_permissions.fetch(:tenant) ) ids, next_cursor, highlights = Searchable::MessageThread.search_ids( diff --git a/app/models/searchable/message_thread.rb b/app/models/searchable/message_thread.rb index 5f9bc596b..b4022ea1e 100644 --- a/app/models/searchable/message_thread.rb +++ b/app/models/searchable/message_thread.rb @@ -29,8 +29,8 @@ def self.fulltext_search(query) def self.search_ids(query_filter, search_permissions:, cursor:, per_page:, direction: ) scope = self - scope = scope.where(tenant_id: search_permissions.fetch(:tenant_id)) - scope = scope.where(box_id: search_permissions.fetch(:box_id)) if search_permissions[:box_id] + scope = scope.where(tenant_id: search_permissions.fetch(:tenant)) + scope = scope.where(box_id: search_permissions.fetch(:box)) if search_permissions[:box] if search_permissions.key?(:tag_ids) if search_permissions[:tag_ids].any? diff --git a/app/models/searchable/message_thread_query.rb b/app/models/searchable/message_thread_query.rb index e9259328c..d27b991b2 100644 --- a/app/models/searchable/message_thread_query.rb +++ b/app/models/searchable/message_thread_query.rb @@ -1,50 +1,45 @@ -class Searchable::MessageThreadQuery - def self.remove_label_from_text(text, match) - text.gsub("#{match[0]}:(#{match[1]})", '') - end +# frozen_string_literal: true +class Searchable::MessageThreadQuery def self.parse(query) filter_labels = [] filter_out_labels = [] with_text = query.to_s - query.to_s.scan(/(-?label):\(([^)]+)\)/).each do |match| - raise "unexpected label case" if match.length != 2 + query.to_s.scan(/(-?label):(\(([^)]+)\)|([^ ]+)|\*)/).each do |match| + raise "unexpected label case" if match.length != 4 - if match[0] == "label" - filter_labels << match[1] + label_name = [match[2], match[3]].find(&:presence) - with_text = remove_label_from_text(with_text, match) + if match[0] == "label" + filter_labels << label_name + elsif match[0] == "-label" + filter_out_labels << label_name end - if match[0] == "-label" - filter_out_labels << match[1] - - with_text = remove_label_from_text(with_text, match) - end + with_text = with_text.gsub("#{match[0]}:#{match[1]}", "") end { fulltext: with_text.gsub(/\s+/, ' ').strip, filter_labels: filter_labels, - filter_out_labels: filter_out_labels + filter_out_labels: filter_out_labels, } end - def self.labels_to_ids(parsed_query, tenant_id:, no_visible_tags: false) + def self.labels_to_ids(parsed_query, tenant:) fulltext, filter_labels, filter_out_labels = parsed_query.fetch_values(:fulltext, :filter_labels, :filter_out_labels) - filter_tag_ids = label_names_to_tag_ids(tenant_id, filter_labels) - filter_out_tag_ids = label_names_to_tag_ids(tenant_id, filter_out_labels) - - filter_out_tag_ids.concat(visible_tag_ids(tenant_id)) if no_visible_tags + # TODO maybe with one query + found_all, filter_tag_ids = label_names_to_tag_ids(tenant, filter_labels) + _, filter_out_tag_ids = label_names_to_tag_ids(tenant, filter_out_labels) result = {} if filter_labels.present? - if filter_labels.length == filter_tag_ids.length + if found_all result[:filter_tag_ids] = filter_tag_ids else result[:filter_tag_ids] = :missing_tag @@ -57,11 +52,12 @@ def self.labels_to_ids(parsed_query, tenant_id:, no_visible_tags: false) result end - def self.label_names_to_tag_ids(tenant_id, label_names) - Tag.where(tenant_id: tenant_id, name: label_names).pluck(:id) - end - - def self.visible_tag_ids(tenant_id) - Tag.where(tenant_id: tenant_id, visible: true).pluck(:id) + def self.label_names_to_tag_ids(tenant, label_names) + if label_names.find { |name| name == "*" }.present? + [true, tenant.tags.visible.pluck(:id)] + else + ids = tenant.tags.where(name: label_names).pluck(:id) + [ids.length == label_names.length, ids] + end end end diff --git a/app/models/tag.rb b/app/models/tag.rb index aa324596f..a0d7eabd6 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -22,6 +22,8 @@ class Tag < ApplicationRecord validates :name, presence: true validates :name, uniqueness: { scope: :tenant_id, case_sensitive: false } + scope :visible, -> { where(visible: true) } + after_create_commit ->(tag) { tag.mark_readable_by_groups(tag.tenant.admin_groups) } after_update_commit ->(tag) { EventBus.publish(:tag_renamed, tag) if previous_changes.key?("name") } after_destroy ->(tag) { EventBus.publish(:tag_removed, tag) } diff --git a/test/models/searchable/message_thread_query_test.rb b/test/models/searchable/message_thread_query_test.rb index 663775c52..30eacb0e5 100644 --- a/test/models/searchable/message_thread_query_test.rb +++ b/test/models/searchable/message_thread_query_test.rb @@ -39,4 +39,22 @@ class Searchable::MessageThreadQueryTest < ActiveSupport::TestCase filter_out_labels: ['without this tag'] } end + + test "parser no visible tags" do + query = 'something -label:* else' + assert_equal Searchable::MessageThreadQuery.parse(query), { + fulltext: 'something else', + filter_labels: [], + filter_out_labels: ["*"] + } + end + + test "parser no visible tags with other labels to filter out" do + query = 'something -label:* else -label:two' + assert_equal Searchable::MessageThreadQuery.parse(query), { + fulltext: 'something else', + filter_labels: [], + filter_out_labels: ["*", "two"] + } + end end