FEATURE: Ability to exclude category from search results. (#7194)

FEATURE: Ability to exclude category from search results. (#7194)

This commit also adds Category#search_priority which sets the ground work to enable prioritizing of posts for certain categories when searching.

diff --git a/app/assets/javascripts/discourse/components/concerns/category_search_priorities.js.es6.erb b/app/assets/javascripts/discourse/components/concerns/category_search_priorities.js.es6.erb
new file mode 100644
index 0000000..643b177
--- /dev/null
+++ b/app/assets/javascripts/discourse/components/concerns/category_search_priorities.js.es6.erb
@@ -0,0 +1 @@
+export const searchPriorities = <%= Searchable::PRIORITIES.to_json %>;
diff --git a/app/assets/javascripts/discourse/components/edit-category-settings.js.es6 b/app/assets/javascripts/discourse/components/edit-category-settings.js.es6
index 712aa67..82af15b 100644
--- a/app/assets/javascripts/discourse/components/edit-category-settings.js.es6
+++ b/app/assets/javascripts/discourse/components/edit-category-settings.js.es6
@@ -1,6 +1,7 @@
 import { setting } from "discourse/lib/computed";
 import { buildCategoryPanel } from "discourse/components/edit-category-panel";
 import computed from "ember-addons/ember-computed-decorators";
+import { searchPriorities } from "discourse/components/concerns/category_search_priorities";
 
 const categorySortCriteria = [];
 export function addCategorySortCriteria(criteria) {
@@ -58,6 +59,20 @@ export default buildCategoryPanel("settings", {
   },
 
   @computed
+  searchPrioritiesOptions() {
+    const options = [];
+
+    for (const [name, value] of Object.entries(searchPriorities)) {
+      options.push({
+        name: I18n.t(`category.search_priority.options.${name}`),
+        value: value
+      });
+    }
+
+    return options.sort((a, b) => a.value <= b.value);
+  },
+
+  @computed
   availableSorts() {
     return [
       "likes",
diff --git a/app/assets/javascripts/discourse/models/category.js.es6 b/app/assets/javascripts/discourse/models/category.js.es6
index 2e6928a..d31fcb7 100644
--- a/app/assets/javascripts/discourse/models/category.js.es6
+++ b/app/assets/javascripts/discourse/models/category.js.es6
@@ -129,7 +129,8 @@ const Category = RestModel.extend({
         minimum_required_tags: this.get("minimum_required_tags"),
         navigate_to_first_post_after_read: this.get(
           "navigate_to_first_post_after_read"
-        )
+        ),
+        search_priority: this.get("search_priority")
       },
       type: id ? "PUT" : "POST"
     });
diff --git a/app/assets/javascripts/discourse/templates/components/edit-category-settings.hbs b/app/assets/javascripts/discourse/templates/components/edit-category-settings.hbs
index f9628a3..1aab620 100644
--- a/app/assets/javascripts/discourse/templates/components/edit-category-settings.hbs
+++ b/app/assets/javascripts/discourse/templates/components/edit-category-settings.hbs
@@ -43,6 +43,17 @@
   </label>
 </section>
 
+<section class="field">
+  <label for="category-search-priority">
+    {{i18n "category.search_priority.label"}}
+  </label>
+
+  {{combo-box valueAttribute="value"
+      id="category-search-priority"
+      content=searchPrioritiesOptions
+      value=category.search_priority}}
+</section>
+
 {{#if isParentCategory}}
   <section class="field show-subcategory-list-field">
     <label>
diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb
index 4e6a6da..53236f4 100644
--- a/app/controllers/categories_controller.rb
+++ b/app/controllers/categories_controller.rb
@@ -293,6 +293,7 @@ class CategoriesController < ApplicationController
                       :default_top_period,
                       :minimum_required_tags,
                       :navigate_to_first_post_after_read,
+                      :search_priority,
                       custom_fields: [params[:custom_fields].try(:keys)],
                       permissions: [*p.try(:keys)],
                       allowed_tags: [],
diff --git a/app/models/category.rb b/app/models/category.rb
index 96c9a09..a1e5771 100644
--- a/app/models/category.rb
+++ b/app/models/category.rb
@@ -44,17 +44,18 @@ class Category < ActiveRecord::Base
   has_and_belongs_to_many :web_hooks
 
   validates :user_id, presence: true
+
   validates :name, if: Proc.new { |c| c.new_record? || c.will_save_change_to_name? },
                    presence: true,
                    uniqueness: { scope: :parent_category_id, case_sensitive: false },
                    length: { in: 1..50 }
+
   validates :num_featured_topics, numericality: { only_integer: true, greater_than: 0 }
-  validate :parent_category_validator
+  validates :search_priority, inclusion: { in: Searchable::PRIORITIES.values }
 
+  validate :parent_category_validator
   validate :email_in_validator
-
   validate :ensure_slug
-
   validate :permissions_compatibility_validator
 
   validates :auto_close_hours, numericality: { greater_than: 0, less_than_or_equal_to: 87600 }, allow_nil: true
diff --git a/app/models/concerns/searchable.rb b/app/models/concerns/searchable.rb
index dd67af0..e655a2e 100644
--- a/app/models/concerns/searchable.rb
+++ b/app/models/concerns/searchable.rb
@@ -1,6 +1,11 @@
 module Searchable
   extend ActiveSupport::Concern
 
+  PRIORITIES = Enum.new(
+    normal: 0,
+    ignore: 1
+  )
+
   included do
     has_one "#{self.name.underscore}_search_data".to_sym, dependent: :destroy
   end
diff --git a/app/serializers/category_serializer.rb b/app/serializers/category_serializer.rb
index 30540b1..1621397 100644
--- a/app/serializers/category_serializer.rb
+++ b/app/serializers/category_serializer.rb
@@ -18,7 +18,8 @@ class CategorySerializer < BasicCategorySerializer
              :custom_fields,
              :allowed_tags,
              :allowed_tag_groups,
-             :topic_featured_link_allowed
+             :topic_featured_link_allowed,
+             :search_priority
 
   def group_permissions
     @group_permissions ||= begin
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 0221f6f..783d6ce 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -2453,6 +2453,11 @@ en:
         muted:
           title: "Muted"
           description: "You will never be notified of anything about new topics in these categories, and they will not appear in latest."
+      search_priority:
+        label: "Search Priority"
+        options:
+          normal: "Normal"
+          ignore: "Ignore"
       sort_options:
         default: "default"
         likes: "Likes"
diff --git a/db/migrate/20190314082018_add_search_priority_to_categories.rb b/db/migrate/20190314082018_add_search_priority_to_categories.rb
new file mode 100644
index 0000000..af2c673
--- /dev/null
+++ b/db/migrate/20190314082018_add_search_priority_to_categories.rb
@@ -0,0 +1,6 @@
+class AddSearchPriorityToCategories < ActiveRecord::Migration[5.2]
+  def change
+    add_column :categories, :search_priority, :integer, default: 0
+    add_index :categories, :search_priority
+  end
+end
diff --git a/lib/search.rb b/lib/search.rb
index 2535b6b..bf3a771 100644
--- a/lib/search.rb
+++ b/lib/search.rb
@@ -243,7 +243,7 @@ class Search
       end
     end
 
-    find_grouped_results unless @results.posts.present?
+    find_grouped_results if @results.posts.blank?
 
     if preloaded_topic_custom_fields.present? && @results.posts.present?
       topics = @results.posts.map(&:topic)
@@ -608,7 +608,6 @@ class Search
   end
 
   def find_grouped_results
-
     if @results.type_filter.present?
       raise Discourse::InvalidAccess.new("invalid type filter") unless Search.facets.include?(@results.type_filter)
       send("#{@results.type_filter}_search")
@@ -727,6 +726,7 @@ class Search
 
   def posts_query(limit, opts = nil)
     opts ||= {}
+
     posts = Post.where(post_type: Topic.visible_post_types(@guardian.user))
       .joins(:post_search_data, :topic)
       .joins("LEFT JOIN categories ON categories.id = topics.category_id")
@@ -768,6 +768,7 @@ class Search
         weights = @in_title ? 'A' : (SiteSetting.tagging_enabled ? 'ABCD' : 'ABD')
         posts = posts.where("post_search_data.search_data @@ #{ts_query(weight_filter: weights)}")
         exact_terms = @term.scan(/"([^"]+)"/).flatten

[... diff too long, it was truncated ...]

GitHub sha: 5e410dc5

This commit has been mentioned on Discourse Meta. There might be relevant details there: