FEATURE: in:pinned and in:unpinned search filters

FEATURE: in:pinned and in:unpinned search filters

diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml
index 6dd216e..2f1a11b 100644
--- a/config/locales/server.en.yml
+++ b/config/locales/server.en.yml
@@ -2722,7 +2722,7 @@ en:
         <tr><td><code>status:open</code></td><td><code>status:closed</code></td><td><code>status:archived</code></td><td><code>status:noreplies</code></td><td><code>status:single_user</code></td></tr>
         <tr><td><code>category:foo</code></td><td><code>user:foo</code></td><td><code>group:foo</code></td><td><code>badge:foo</code></td><td></td></tr>
         <tr><td><code>in:likes</code></td><td><code>in:posted</code></td><td><code>in:watching</code></td><td><code>in:tracking</code></td><td><code>in:private</code></td></tr>
-        <tr><td><code>in:bookmarks</code></td><td><code>in:first</code></td><td colspan=3></td></tr>
+        <tr><td><code>in:bookmarks</code></td><td><code>in:first</code></td><td><code>in:pinned</code></td><td><code>in:unpinned</code></td><td></td></tr>
         <tr><td><code>posts_count:num</code></td><td><code>before:days or date</code></td><td><code>after:days or date</code></td> <td colspan=2></td></tr>
         </table>
       </p>
diff --git a/lib/search.rb b/lib/search.rb
index fb8b989..5bfd9d4 100644
--- a/lib/search.rb
+++ b/lib/search.rb
@@ -219,6 +219,18 @@ class Search
     posts.where("posts.post_number = 1")
   end
 
+  advanced_filter(/in:pinned/) do |posts|
+    posts.where("topics.pinned_at IS NOT NULL")
+  end
+
+  advanced_filter(/in:unpinned/) do |posts|
+    if @guardian.user
+      posts.where("topics.pinned_at IS NOT NULL AND topics.id IN (
+                  SELECT topic_id FROM topic_users WHERE user_id = ? AND cleared_pinned_at IS NOT NULL
+                 )", @guardian.user.id)
+    end
+  end
+
   advanced_filter(/badge:(.*)/) do |posts,match|
     badge_id = Badge.where('name ilike ? OR id = ?', match, match.to_i).pluck(:id).first
     if badge_id
diff --git a/spec/components/search_spec.rb b/spec/components/search_spec.rb
index 42a4f18..7a0e580 100644
--- a/spec/components/search_spec.rb
+++ b/spec/components/search_spec.rb
@@ -408,6 +408,24 @@ describe Search do
 
   describe 'Advanced search' do
 
+    it 'supports pinned and unpinned' do
+      topic = Fabricate(:topic)
+      Fabricate(:post, raw: 'hi this is a test 123 123', topic: topic)
+      _post = Fabricate(:post, raw: 'boom boom shake the room', topic: topic)
+
+      topic.update_pinned(true)
+
+      user = Fabricate(:user)
+      guardian = Guardian.new(user)
+
+      expect(Search.execute('boom in:pinned').posts.length).to eq(1)
+      expect(Search.execute('boom in:unpinned', guardian: guardian).posts.length).to eq(0)
+
+      topic.clear_pin_for(user)
+
+      expect(Search.execute('boom in:unpinned', guardian: guardian).posts.length).to eq(1)
+    end
+
     it 'supports before and after in:first user:' do
 
       time = Time.zone.parse('2001-05-20 2:55')

GitHub sha: 77242e46

?

1 Like

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

https://meta.discourse.org/t/search-for-topics-that-are-not-pinned-returns-unexpected-results/150855/1