diff --git a/app/logical/post_query_builder.rb b/app/logical/post_query_builder.rb
index d7d7c5da9..da7b5148a 100644
--- a/app/logical/post_query_builder.rb
+++ b/app/logical/post_query_builder.rb
@@ -101,6 +101,21 @@ class PostQueryBuilder
relation
end
+ def add_saved_search_relation(saved_searches, relation)
+ saved_searches.each do |saved_search|
+ if saved_search == "all"
+ post_ids = SavedSearch.post_ids(CurrentUser.id)
+ else
+ post_ids = SavedSearch.post_ids(CurrentUser.id, saved_search)
+ end
+
+ post_ids = [0] if post_ids.empty?
+ relation = relation.where(["posts.id IN (?)", post_ids])
+ end
+
+ relation
+ end
+
def build(relation = nil)
unless query_string.is_a?(Hash)
q = Tag.parse_query(query_string)
@@ -208,6 +223,11 @@ class PostQueryBuilder
has_constraints!
end
+ if q[:saved_searches]
+ relation = add_saved_search_relation(q[:saved_searches], relation)
+ has_constraints!
+ end
+
if q[:uploader_id_neg]
relation = relation.where("posts.uploader_id not in (?)", q[:uploader_id_neg])
end
diff --git a/app/models/saved_search.rb b/app/models/saved_search.rb
index 39412c80a..4b0f9af32 100644
--- a/app/models/saved_search.rb
+++ b/app/models/saved_search.rb
@@ -3,11 +3,13 @@ class SavedSearch < ActiveRecord::Base
extend ActiveSupport::Concern
module ClassMethods
- def refresh_listbooru(user_id, name)
+ def refresh_listbooru(user_id)
return unless Danbooru.config.listbooru_auth_key
+ user = User.find(user_id)
+ return unless user.is_gold?
+
params = {
:user_id => user_id,
- :name => name,
:key => Danbooru.config.listbooru_auth_key
}
uri = URI.parse("#{Danbooru.config.listbooru_server}/users")
@@ -87,7 +89,27 @@ class SavedSearch < ActiveRecord::Base
Tag.scan_query(tag_query).join(" ")
end
+ def self.post_ids(user_id, name = nil)
+ params = {
+ "key" => Danbooru.config.listbooru_auth_key,
+ "user_id" => user_id,
+ "name" => name
+ }
+ uri = URI.parse("#{Danbooru.config.listbooru_server}/users")
+ uri.query = URI.encode_www_form(params)
+
+ Net::HTTP.start(uri.host, uri.port) do |http|
+ resp = http.request_get(uri.request_uri)
+ if resp.is_a?(Net::HTTPSuccess)
+ resp.body.scan(/\d+/).map(&:to_i)
+ else
+ raise "HTTP error code: #{resp.code} #{resp.message}"
+ end
+ end
+ end
+
def normalize
+ self.category = category.strip.gsub(/\s+/, "_").downcase if category
self.tag_query = SavedSearch.normalize(tag_query)
end
@@ -108,23 +130,4 @@ class SavedSearch < ActiveRecord::Base
user.update_attribute(:has_saved_searches, false)
end
end
-
- def post_ids
- params = {
- "key" => Danbooru.config.listbooru_auth_key,
- "user_id" => user_id,
- "name" => category
- }
- uri = URI.parse("#{Danbooru.config.listbooru_server}/users")
- uri.query = URI.encode_www_form(params)
-
- Net::HTTP.start(uri.host, uri.port) do |http|
- resp = http.request_get(uri.request_uri)
- if resp.is_a?(Net::HTTPSuccess)
- resp.body.scan(/\d+/)
- else
- raise "HTTP error code: #{resp.code} #{resp.message}"
- end
- end
- end
end
diff --git a/app/models/tag.rb b/app/models/tag.rb
index f08a3c421..ff946eae0 100644
--- a/app/models/tag.rb
+++ b/app/models/tag.rb
@@ -1,5 +1,5 @@
class Tag < ActiveRecord::Base
- METATAGS = "-user|user|-approver|approver|commenter|comm|noter|noteupdater|artcomm|-pool|pool|ordpool|-favgroup|favgroup|-fav|fav|ordfav|sub|md5|-rating|rating|-locked|locked|width|height|mpixels|ratio|score|favcount|filesize|source|-source|id|-id|date|age|order|limit|-status|status|tagcount|gentags|arttags|chartags|copytags|parent|-parent|child|pixiv_id|pixiv"
+ METATAGS = "-user|user|-approver|approver|commenter|comm|noter|noteupdater|artcomm|-pool|pool|ordpool|-favgroup|favgroup|-fav|fav|ordfav|sub|md5|-rating|rating|-locked|locked|width|height|mpixels|ratio|score|favcount|filesize|source|-source|id|-id|date|age|order|limit|-status|status|tagcount|gentags|arttags|chartags|copytags|parent|-parent|child|pixiv_id|pixiv|search"
SUBQUERY_METATAGS = "commenter|comm|noter|noteupdater|artcomm"
attr_accessible :category, :as => [:moderator, :janitor, :gold, :member, :anonymous, :default, :builder, :admin]
attr_accessible :is_locked, :as => [:moderator, :admin]
@@ -493,6 +493,10 @@ class Tag < ActiveRecord::Base
q[:subscriptions] ||= []
q[:subscriptions] << $2
+ when "search"
+ q[:saved_searches] ||= []
+ q[:saved_searches] << $2
+
when "md5"
q[:md5] = $2.downcase.split(/,/)
diff --git a/app/models/user.rb b/app/models/user.rb
index 9e61f6dac..9883eda43 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -460,10 +460,8 @@ class User < ActiveRecord::Base
def max_saved_searches
if is_platinum?
1_000
- elsif is_gold?
- 200
else
- 100
+ 250
end
end
diff --git a/app/views/saved_searches/_secondary_links.html.erb b/app/views/saved_searches/_secondary_links.html.erb
new file mode 100644
index 000000000..8a6c57c64
--- /dev/null
+++ b/app/views/saved_searches/_secondary_links.html.erb
@@ -0,0 +1,6 @@
+<% content_for(:secondary_links) do %>
+
+<% end %>
diff --git a/app/views/saved_searches/edit.html.erb b/app/views/saved_searches/edit.html.erb
index f59a03b9a..989a3861a 100644
--- a/app/views/saved_searches/edit.html.erb
+++ b/app/views/saved_searches/edit.html.erb
@@ -12,7 +12,7 @@
-<%= render "users/secondary_links" %>
+<%= render "secondary_links" %>
<% content_for(:page_title) do %>
Edit Saved Search - <%= Danbooru.config.app_name %>
diff --git a/app/views/saved_searches/index.html.erb b/app/views/saved_searches/index.html.erb
index 48b04ae70..db452e677 100644
--- a/app/views/saved_searches/index.html.erb
+++ b/app/views/saved_searches/index.html.erb
@@ -3,7 +3,13 @@
Saved Searches
<% @categories.each do |category, saved_searches| %>
- <%= category.present? ? category : "Uncategorized" %>
+
+ <% if category.present? %>
+ <%= link_to category.tr("_", " "), posts_path(:tags => "search:#{category}") %>
+ <% else %>
+ Uncategorized
+ <% end %>
+
@@ -17,7 +23,8 @@
| <%= link_to saved_search.tag_query, posts_path(:tags => saved_search.tag_query) %> |
- <%= link_to "delete", saved_search_path(saved_search), :method => :delete, :remote => true %>
+ <%= link_to "edit", edit_saved_search_path(saved_search) %>
+ | <%= link_to "delete", saved_search_path(saved_search), :method => :delete, :remote => true %>
|
<% end %>
@@ -27,7 +34,7 @@
-<%= render "users/secondary_links" %>
+<%= render "secondary_links" %>
<% content_for(:page_title) do %>
Saved Searches - <%= Danbooru.config.app_name %>
diff --git a/config/danbooru_default_config.rb b/config/danbooru_default_config.rb
index 202d7248b..70863f8fc 100644
--- a/config/danbooru_default_config.rb
+++ b/config/danbooru_default_config.rb
@@ -4,7 +4,7 @@ module Danbooru
class Configuration
# The version of this Danbooru.
def version
- "2.96.0"
+ "2.97.0"
end
# The name of this Danbooru.
diff --git a/script/fixes/039_fix_saved_search_categories.rb b/script/fixes/039_fix_saved_search_categories.rb
new file mode 100644
index 000000000..b6bb38412
--- /dev/null
+++ b/script/fixes/039_fix_saved_search_categories.rb
@@ -0,0 +1,15 @@
+#!/usr/bin/env ruby
+
+require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'config', 'environment'))
+
+ActiveRecord::Base.connection.execute("set statement_timeout = 0")
+
+CurrentUser.user = User.admins.first
+CurrentUser.ip_addr = "127.0.0.1"
+
+SavedSearch.where("category is not null and category <> ''").find_each do |ss|
+ print ss.category + " -> "
+ ss.normalize
+ puts ss.category
+ ss.save
+end
diff --git a/test/factories/saved_search.rb b/test/factories/saved_search.rb
new file mode 100644
index 000000000..7940ca213
--- /dev/null
+++ b/test/factories/saved_search.rb
@@ -0,0 +1,5 @@
+FactoryGirl.define do
+ factory(:saved_search) do
+ tag_query "aaa"
+ end
+end
diff --git a/test/fixtures/vcr_cassettes/unit/saved_searches/get-named.yml b/test/fixtures/vcr_cassettes/unit/saved_searches/get-named.yml
new file mode 100644
index 000000000..04986f09b
--- /dev/null
+++ b/test/fixtures/vcr_cassettes/unit/saved_searches/get-named.yml
@@ -0,0 +1,42 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: http://localhost:3001/users?key=blahblahblah&name=blah&user_id=1
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: 'OK '
+ headers:
+ Content-Type:
+ - text/html;charset=utf-8
+ Content-Length:
+ - '7'
+ X-Xss-Protection:
+ - 1; mode=block
+ X-Content-Type-Options:
+ - nosniff
+ X-Frame-Options:
+ - SAMEORIGIN
+ Server:
+ - WEBrick/1.3.1 (Ruby/2.1.3/2014-09-19)
+ Date:
+ - Tue, 24 Nov 2015 20:43:18 GMT
+ Connection:
+ - Keep-Alive
+ body:
+ encoding: UTF-8
+ string: '["1","2","3","4"]'
+ http_version:
+ recorded_at: Tue, 24 Nov 2015 20:43:18 GMT
+recorded_with: VCR 2.9.3
diff --git a/test/fixtures/vcr_cassettes/unit/saved_searches/get-unnamed.yml b/test/fixtures/vcr_cassettes/unit/saved_searches/get-unnamed.yml
new file mode 100644
index 000000000..f9e661c10
--- /dev/null
+++ b/test/fixtures/vcr_cassettes/unit/saved_searches/get-unnamed.yml
@@ -0,0 +1,42 @@
+---
+http_interactions:
+- request:
+ method: get
+ uri: http://localhost:3001/users?key=blahblahblah&name&user_id=1
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept-Encoding:
+ - gzip;q=1.0,deflate;q=0.6,identity;q=0.3
+ Accept:
+ - "*/*"
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: 'OK '
+ headers:
+ Content-Type:
+ - text/html;charset=utf-8
+ Content-Length:
+ - '7'
+ X-Xss-Protection:
+ - 1; mode=block
+ X-Content-Type-Options:
+ - nosniff
+ X-Frame-Options:
+ - SAMEORIGIN
+ Server:
+ - WEBrick/1.3.1 (Ruby/2.1.3/2014-09-19)
+ Date:
+ - Tue, 24 Nov 2015 20:43:18 GMT
+ Connection:
+ - Keep-Alive
+ body:
+ encoding: UTF-8
+ string: '["1","2","3","4"]'
+ http_version:
+ recorded_at: Tue, 24 Nov 2015 20:43:18 GMT
+recorded_with: VCR 2.9.3
diff --git a/test/unit/post_test.rb b/test/unit/post_test.rb
index 86eb369cc..280e21de0 100644
--- a/test/unit/post_test.rb
+++ b/test/unit/post_test.rb
@@ -1371,6 +1371,24 @@ class PostTest < ActiveSupport::TestCase
assert_equal(1, relation.count)
end
+ should "return posts for a metatag" do
+ SavedSearch.stubs(:update_listbooru_on_create)
+ post1 = FactoryGirl.create(:post, :tag_string => "aaa")
+ sub = FactoryGirl.create(:saved_search, :tag_query => "aaa", :name => "zzz", :user_id => CurrentUser.id)
+ SavedSearch.expects(:post_ids).returns([post1.id])
+ relation = Post.tag_match("search:#{CurrentUser.name}")
+ assert_equal(1, relation.count)
+ end
+
+ should "return posts for a named metatag" do
+ SavedSearch.stubs(:update_listbooru_on_create)
+ post1 = FactoryGirl.create(:post, :tag_string => "aaa")
+ sub = FactoryGirl.create(:saved_search, :tag_query => "aaa", :name => "zzz", :user_id => CurrentUser.id)
+ SavedSearch.expects(:post_ids).returns([post1.id])
+ relation = Post.tag_match("search:#{CurrentUser.name}:zzz")
+ assert_equal(1, relation.count)
+ end
+
should "return posts for a particular rating" do
post1 = FactoryGirl.create(:post, :rating => "s")
post2 = FactoryGirl.create(:post, :rating => "q")
diff --git a/test/unit/saved_search_test.rb b/test/unit/saved_search_test.rb
index 64f3642f3..c850a9bf9 100644
--- a/test/unit/saved_search_test.rb
+++ b/test/unit/saved_search_test.rb
@@ -1,6 +1,31 @@
require 'test_helper'
class SavedSearchTest < ActiveSupport::TestCase
+ context "Fetching the post ids for a search" do
+ setup do
+ Danbooru.config.stubs(:listbooru_auth_key).returns("blahblahblah")
+ Danbooru.config.stubs(:listbooru_server).returns("http://localhost:3001")
+ end
+
+ context "with a name" do
+ should "return a list of ids" do
+ VCR.use_cassette("unit/saved_searches/get-named", :record => :once) do
+ post_ids = SavedSearch.post_ids(1, "blah")
+ assert_equal([1,2,3,4], post_ids)
+ end
+ end
+ end
+
+ context "without a name" do
+ should "return a list of ids" do
+ VCR.use_cassette("unit/saved_searches/get-unnamed", :record => :once) do
+ post_ids = SavedSearch.post_ids(1)
+ assert_equal([1,2,3,4], post_ids)
+ end
+ end
+ end
+ end
+
context "Creating a saved search" do
setup do
@user = FactoryGirl.create(:user)