Remove saved searches

This commit is contained in:
Kira 2019-10-21 02:52:06 -07:00
parent 66ab994b25
commit 160b0cb22e
39 changed files with 5 additions and 870 deletions

View File

@ -1,60 +0,0 @@
class SavedSearchesController < ApplicationController
before_action :check_availability
respond_to :html, :xml, :json, :js
def index
@saved_searches = saved_searches.order("id")
if params[:label]
@saved_searches = saved_searches.labeled(params[:label])
end
respond_with(@saved_searches) do |format|
format.xml do
render :xml => @saved_searches.to_xml(:root => "saved-searches")
end
end
end
def labels
@labels = SavedSearch.search_labels(CurrentUser.id, params[:search])
respond_with(@labels)
end
def create
@saved_search = saved_searches.create(saved_search_params)
respond_with(@saved_search)
end
def destroy
@saved_search = saved_searches.find(params[:id])
@saved_search.destroy
respond_with(@saved_search)
end
def edit
@saved_search = saved_searches.find(params[:id])
end
def update
@saved_search = saved_searches.find(params[:id])
@saved_search.update(saved_search_params)
respond_with(@saved_search, :location => saved_searches_path)
end
private
def saved_searches
CurrentUser.user.saved_searches
end
def check_availability
if !SavedSearch.enabled?
raise NotImplementedError.new("Saved searches are not available.")
end
end
def saved_search_params
params.fetch(:saved_search, {}).permit(%i[query label_string])
end
end

View File

@ -1,5 +1,4 @@
import Utility from './utility'
import SavedSearch from './saved_searches'
let Autocomplete = {};
@ -152,9 +151,6 @@ Autocomplete.initialize_tag_autocomplete = function() {
case "ordpool":
Autocomplete.pool_source(term, resp, metatag);
break;
case "search":
Autocomplete.saved_search_source(term, resp);
break;
default:
Autocomplete.normal_source(term, resp);
break;
@ -482,17 +478,6 @@ Autocomplete.pool_source = function(term, resp, metatag) {
});
}
Autocomplete.saved_search_source = function(term, resp) {
return SavedSearch.labels(term).then(function(labels) {
resp(labels.map(function(label) {
return {
label: label.replace(/_/g, " "),
value: "search:" + label,
};
}));
});
}
$(document).ready(function() {
Autocomplete.initialize_all();
});

View File

@ -2,7 +2,6 @@ import Utility from './utility'
import Hammer from 'hammerjs'
import LS from './local_storage'
import Note from './notes'
import SavedSearch from './saved_searches'
import { SendQueue } from './send_queue'
let Post = {};
@ -14,7 +13,6 @@ Post.initialize_all = function() {
if ($("#c-posts").length) {
this.initialize_shortcuts();
this.initialize_saved_searches();
}
if ($("#c-posts").length && $("#a-index").length) {
@ -43,10 +41,6 @@ Post.initialize_all = function() {
var $fields_multiple = $('[data-autocomplete="tag-edit"]');
$fields_multiple.on("keypress.danbooru", Post.update_tag_count);
$fields_multiple.on("click", Post.update_tag_count);
$(window).on('danbooru:initialize_saved_seraches', () => {
Post.initialize_saved_searches();
});
}
Post.initialize_voting = function() {
@ -675,53 +669,6 @@ Post.approve = function(post_id) {
});
}
Post.initialize_saved_searches = function() {
$("#new_saved_search #saved_search_label_string").autocomplete({
search: function() {
$(this).data("ui-autocomplete").menu.bindings = $();
},
source: function(req, resp) {
SavedSearch.labels(req.term).then(function(labels) {
resp(labels.map(function(label) {
return {
label: label.replace(/_/g, " "),
value: label
};
}));
});
}
});
$("#save-search-dialog").dialog({
width: 500,
modal: true,
autoOpen: false,
buttons: {
"Submit": function() {
$("#save-search-dialog form").submit();
$(this).dialog("close");
},
"Cancel": function() {
$(this).dialog("close");
}
}
});
$("#save-search").on("click.danbooru", function(e) {
$("#save-search-dialog #saved_search_query").val($("#tags").val());
$.post(
"/saved_searches.js",
{
"saved_search": {
"query": $("#tags").val()
}
}
);
e.preventDefault();
});
}
Post.update_tag_count = function(event) {
let string = "0 tags";
let count = 0;

View File

@ -1,18 +0,0 @@
let SavedSearch = {};
SavedSearch.initialize_all = function() {
if ($("#c-saved-searches").length) {
$("#c-saved-searches table").stupidtable();
}
}
SavedSearch.labels = function(term) {
return $.getJSON("/saved_searches/labels", {
"search[label]": term + "*",
"limit": 10
});
}
$(SavedSearch.initialize_all);
export default SavedSearch

View File

@ -1,7 +0,0 @@
class SavedSearchJob < ApplicationJob
queue_as :default
def perform(*args)
SavedSearch.populate(args[0])
end
end

View File

@ -15,7 +15,6 @@ class TagBatchJob < ApplicationJob
CurrentUser.without_safe_mode do
CurrentUser.scoped(updater, @updater_ip_addr) do
migrate_posts(normalized_antecedent, normalized_consequent)
migrate_saved_searches(normalized_antecedent, normalized_consequent)
migrate_blacklists(normalized_antecedent, normalized_consequent)
end
end
@ -35,19 +34,6 @@ class TagBatchJob < ApplicationJob
end
end
def migrate_saved_searches(normalized_antecedent, normalized_consequent)
if SavedSearch.enabled?
tags = Tag.scan_tags(normalized_antecedent.join(" "), strip_metatags: true)
# https://www.postgresql.org/docs/current/static/functions-array.html
saved_searches = SavedSearch.where("string_to_array(query, ' ') @> ARRAY[?]", tags)
saved_searches.find_each do |ss|
ss.query = (ss.query.split - tags + normalized_consequent).uniq.join(" ")
ss.save
end
end
end
# this can't handle negated tags or other special cases
def migrate_blacklists(normalized_antecedent, normalized_consequent)
query = normalized_antecedent

View File

@ -6,7 +6,6 @@ class UserDeletionJob < ApplicationJob
remove_favorites(user)
remove_saved_searches(user)
rename(user)
end
@ -18,10 +17,6 @@ class UserDeletionJob < ApplicationJob
end
end
def remove_saved_searches(user)
SavedSearch.where(user_id: user.id).destroy_all
end
def rename(user)
name = "user_#{user.id}"
n = 0

View File

@ -61,21 +61,6 @@ class ElasticPostQueryBuilder
}})
end
def saved_search_relation(saved_searches, should)
if SavedSearch.enabled?
saved_searches.map do |saved_search|
if saved_search == "all"
post_ids = SavedSearch.post_ids_for(CurrentUser.id)
else
post_ids = SavedSearch.post_ids_for(CurrentUser.id, label: saved_search)
end
post_ids = [] if post_ids.empty?
should.push({terms: {id: post_ids}})
end
end
end
def table_for_metatag(metatag)
if metatag.in?(Tag::COUNT_METATAGS)
metatag[/(?<table>[a-z]+)_count\z/i, :table]
@ -278,11 +263,6 @@ class ElasticPostQueryBuilder
must_not.concat(q[:fav_ids_neg].map {|x| {term: {faves: x}}})
end
if q[:saved_searches]
# TODO
# saved_search_relation(q[:saved_searches], should)
end
if q[:uploader_id_neg]
must_not.concat(q[:uploader_id_neg].map {|x| {term: {uploader: x.to_i}}})
end

View File

@ -68,23 +68,6 @@ class PostQueryBuilder
relation
end
def add_saved_search_relation(saved_searches, relation)
if SavedSearch.enabled?
saved_searches.each do |saved_search|
if saved_search == "all"
post_ids = SavedSearch.post_ids_for(CurrentUser.id)
else
post_ids = SavedSearch.post_ids_for(CurrentUser.id, label: saved_search)
end
post_ids = [0] if post_ids.empty?
relation = relation.where("posts.id": post_ids)
end
end
relation
end
def table_for_metatag(metatag)
if metatag.in?(Tag::COUNT_METATAGS)
metatag[/(?<table>[a-z]+)_count\z/i, :table]
@ -225,10 +208,6 @@ class PostQueryBuilder
relation = relation.where("posts.pool_string != ''")
end
if q[:saved_searches]
relation = add_saved_search_relation(q[:saved_searches], relation)
end
if q[:uploader_id_neg]
relation = relation.where.not("posts.uploader_id": q[:uploader_id_neg])
end

View File

@ -164,10 +164,6 @@ module PostSets
[page.to_i, 1].max
end
def is_saved_search?
tag_string =~ /search:/
end
def presenter
@presenter ||= ::PostSetPresenters::Post.new(self)
end

View File

@ -1,152 +0,0 @@
class SavedSearch < ApplicationRecord
REDIS_EXPIRY = 3600
QUERY_LIMIT = 1000
def self.enabled?
Danbooru.config.redis_url.present?
end
concerning :Redis do
class_methods do
extend Memoist
def redis
::Redis.new(url: Danbooru.config.redis_url)
end
memoize :redis
def post_ids_for(user_id, label: nil)
label = normalize_label(label) if label
queries = queries_for(user_id, label: label)
post_ids = Set.new
queries.each do |query|
redis_key = "search:#{query}"
if redis.exists(redis_key)
sub_ids = redis.smembers(redis_key).map(&:to_i)
post_ids.merge(sub_ids)
redis.expire(redis_key, REDIS_EXPIRY)
else
SavedSearchJob.perform_later(query)
end
end
post_ids.to_a.sort.last(QUERY_LIMIT)
end
end
end
concerning :Labels do
class_methods do
def normalize_label(label)
label.
to_s.
strip.
downcase.
gsub(/[[:space:]]/, "_")
end
def search_labels(user_id, params)
labels = labels_for(user_id)
if params[:label].present?
query = Regexp.escape(params[:label]).gsub("\\*", ".*")
query = ".*#{query}.*" unless query.include?("*")
query = /\A#{query}\z/
labels = labels.grep(query)
end
labels
end
def labels_for(user_id)
SavedSearch.
where(user_id: user_id).
order("label").
pluck(Arel.sql("distinct unnest(labels) as label"))
end
end
def normalize_labels
self.labels = labels.
map {|x| SavedSearch.normalize_label(x)}.
reject {|x| x.blank?}
end
def label_string
labels.join(" ")
end
def label_string=(val)
self.labels = val.to_s.split(/[[:space:]]+/)
end
def labels=(labels)
labels = labels.map { |label| SavedSearch.normalize_label(label) }
super(labels)
end
end
concerning :Search do
class_methods do
def populate(query)
CurrentUser.as_system do
redis_key = "search:#{query}"
return if redis.exists(redis_key)
post_ids = Post.tag_match(query, true).limit(QUERY_LIMIT).records.pluck(:id)
redis.sadd(redis_key, post_ids)
redis.expire(redis_key, REDIS_EXPIRY)
end
rescue Exception
# swallow
end
end
end
concerning :Queries do
class_methods do
def queries_for(user_id, label: nil, options: {})
SavedSearch.
where(user_id: user_id).
labeled(label).
pluck(:query).
map {|x| Tag.normalize_query(x, sort: true)}.
sort.
uniq
end
end
def normalized_query
Tag.normalize_query(query, sort: true)
end
def normalize_query
self.query = Tag.normalize_query(query, sort: false)
end
end
belongs_to :user
validates :query, presence: true
validate :validate_count
before_create :update_user_on_create
after_destroy :update_user_on_destroy
before_validation :normalize_query
before_validation :normalize_labels
scope :labeled, ->(label) { label.present? ? where("labels @> string_to_array(?, '~~~~')", label) : where("true") }
def validate_count
if user.saved_searches.count + 1 > user.max_saved_searches
self.errors[:user] << "can only have up to #{user.max_saved_searches} " + "saved search".pluralize(user.max_saved_searches)
end
end
def update_user_on_create
if !user.has_saved_searches?
user.update(has_saved_searches: true)
end
end
def update_user_on_destroy
if user.saved_searches.count == 0
user.update(has_saved_searches: false)
end
end
end

View File

@ -728,10 +728,6 @@ class Tag < ApplicationRecord
q[:fav_ids] << favuser.id
when "search"
q[:saved_searches] ||= []
q[:saved_searches] << g2
when "md5"
q[:md5] = g2.downcase.split(/,/)[0..99]

View File

@ -27,6 +27,7 @@ class User < ApplicationRecord
# candidates for removal:
# - disable_cropped_thumbnails (enabled by 22)
# - has_saved_searches (removed in removal of saved searches)
BOOLEAN_ATTRIBUTES = %w(
show_avatars
blacklist_avatars
@ -112,7 +113,6 @@ class User < ApplicationRecord
has_one :dmail_filter
has_many :note_versions, :foreign_key => "updater_id"
has_many :dmails, -> {order("dmails.id desc")}, :foreign_key => "owner_id"
has_many :saved_searches
has_many :forum_posts, -> {order("forum_posts.created_at, forum_posts.id")}, :foreign_key => "creator_id"
has_many :user_name_change_requests, -> {visible.order("user_name_change_requests.id desc")}
has_many :post_sets, -> {order(name: :asc)}, foreign_key: :creator_id
@ -495,18 +495,6 @@ class User < ApplicationRecord
create_user_throttle(:ticket, ->{ Danbooru.config.ticket_limit - Ticket.for_creator(id).where("created_at > ?", 1.hour.ago).count },
:general_bypass_throttle?, 3.days)
def max_saved_searches
if is_contributor?
1_000
else
250
end
end
def show_saved_searches?
true
end
def can_remove_from_pools?
older_than 7.days
end

View File

@ -18,8 +18,6 @@ module PostSetPresenters
def related_tags
if post_set.is_pattern_search?
pattern_tags
elsif post_set.is_saved_search?
["search:all"] + SavedSearch.labels_for(CurrentUser.user.id).map {|x| "search:#{x}"}
elsif post_set.is_empty_tag? || post_set.tag_string == "order:rank"
popular_tags
elsif post_set.is_single_tag?
@ -63,12 +61,8 @@ module PostSetPresenters
RelatedTagCalculator.calculate_from_posts_to_array(post_set.posts).map(&:first)
end
def saved_search_labels
SavedSearch.labels_for(CurrentUser.user.id).map {|x| "search:#{x}"}
end
def tag_list_html(**options)
tag_set_presenter.tag_list_html(name_only: post_set.is_saved_search?, **options)
tag_set_presenter.tag_list_html(name_only: false, **options)
end
end
end

View File

@ -39,10 +39,6 @@ class UserPresenter
permissions.join(", ")
end
def posts_for_saved_search_category(category)
Post.tag_match("search:#{category}").limit(10).records
end
def upload_limit(template)
if user.can_upload_free?
return "none"
@ -140,14 +136,6 @@ class UserPresenter
template.link_to("positive:#{positive} neutral:#{neutral} negative:#{negative}", template.user_feedbacks_path(:search => {:user_id => user.id}))
end
def saved_search_labels
if CurrentUser.user.id == user.id
SavedSearch.labels_for(CurrentUser.user.id)
else
[]
end
end
def previous_names(template)
user.user_name_change_requests.map { |req| template.link_to req.original_name, req }.join(" -> ").html_safe
end

View File

@ -15,8 +15,6 @@
<%= @post_set.presenter.tag_list_html(current_query: params[:tags], show_extra_links: CurrentUser.user.is_privileged?) %>
</section>
<%= render "posts/partials/index/options" %>
<%= render "posts/partials/index/related" %>
</aside>
@ -46,18 +44,11 @@
<%= post_search_count_js %>
<div id="saved-searches-nav">
<%= render "saved_searches/interface" %>
</div>
</div>
</div>
<% if params[:tags] =~ /search:/ %>
<%= render "saved_searches/secondary_links" %>
<% else %>
<%= render "posts/partials/common/secondary_links" %>
<% end %>
<%= render "posts/partials/common/secondary_links" %>
<% content_for(:page_title) do %>
<% if @post_set.public_tag_string.present? %>

View File

@ -8,9 +8,6 @@
<% end %>
<% unless CurrentUser.is_anonymous? %>
<%= subnav_link_to "Favorites", favorites_path %>
<% if CurrentUser.has_saved_searches? %>
<%= subnav_link_to "Saved searches", posts_path(:tags => "search:all") %>
<% end %>
<% end %>
<%= subnav_link_to "Changes", post_versions_path %>
<% if CurrentUser.can_approve_posts? %>

View File

@ -1,8 +0,0 @@
<section id="options-box">
<h1>Options</h1>
<ul>
<% if SavedSearch.enabled? && CurrentUser.is_member? %>
<li><%= button_tag(tag.i(class: "fas fa-bookmark") + " Save search", id: "save-search", class: "ui-button ui-widget ui-corner-all sub") %></li>
<% end %>
</ul>
</section>

View File

@ -1,9 +0,0 @@
<% if SavedSearch.enabled? %>
<div id="save-search-dialog" title="Save Search" style="display: none;">
<%= simple_form_for(SavedSearch.new, remote: true) do |f| %>
<%= f.input :query, as: :string, input_html: { value: params[:tags], data: { autocomplete: "tag-query" } } %>
<%= f.input :label_string, label: "Labels", hint: "A list of tags to help categorize this search. Space delimited." %>
<% end %>
</div>
<% end %>

View File

@ -1,6 +0,0 @@
<% content_for(:secondary_links) do %>
<menu>
<%= subnav_link_to "View posts", posts_path(:tags => "search:all") %>
<%= subnav_link_to "Manage saved searches", saved_searches_path %>
</menu>
<% end %>

View File

@ -1,5 +0,0 @@
<% if @saved_search.errors.any? %>
$(window).trigger("danbooru:error", "<%= j @saved_search.errors.full_messages.join(', ') %>");
<% else %>
$(window).trigger("danbooru:notice", "Search '<%= j @saved_search.query %>' was saved");
<% end %>

View File

@ -1,4 +0,0 @@
$(window).trigger("danbooru:notice", "Search '<%= j @saved_search.query %>' was deleted");
$("#saved-searches-nav").html("<%= j render('saved_searches/interface', :saved_searches => CurrentUser.user.saved_searches) %>");
$(window).trigger("danbooru:initialize_saved_searches");
$("#saved-search-<%= @saved_search.id %>").remove();

View File

@ -1,19 +0,0 @@
<div id="c-saved-searches">
<div id="a-edit">
<h1>Edit Saved Search</h1>
<%= error_messages_for :saved_search %>
<%= simple_form_for(@saved_search) do |f| %>
<%= f.input :query, :as => :string %>
<%= f.input :label_string, :label => "Labels", :hint => "A list of tags to help categorize this search. Space delimited." %>
<%= f.button :submit, :value => "Submit" %>
<% end %>
</div>
</div>
<%= render "secondary_links" %>
<% content_for(:page_title) do %>
Edit Saved Search - <%= Danbooru.config.app_name %>
<% end %>

View File

@ -1,43 +0,0 @@
<div id="c-saved-searches">
<div id="a-index">
<h1>
Saved Searches
<% if params[:label] %>
(<%= params[:label] %>)
<% end %>
</h1>
<table class="striped" width="100%">
<thead>
<tr>
<th data-sort="string" width="60%">Query</th>
<th data-sort="string" width="20%">Labels</th>
<th width="20%" class="links"></th>
</tr>
</thead>
<tbody>
<% @saved_searches.each do |ss| %>
<tr id="saved-search-<%= ss.id %>">
<td><%= link_to ss.query, posts_path(:tags => ss.query) %></td>
<td>
<% ss.labels.each do |label| %>
<%= link_to label, posts_path(:tags => "search:#{label}") %>
<% end %>
</td>
<td class="links">
<%= link_to "edit", edit_saved_search_path(ss) %>
| <%= link_to "delete", saved_search_path(ss), :method => :delete, :remote => true %>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
<%= render "secondary_links" %>
<% content_for(:page_title) do %>
Saved Searches - <%= Danbooru.config.app_name %>
<% end %>

View File

@ -23,20 +23,3 @@
</div>
</div>
<% end %>
<% if CurrentUser.user.id == @user.id && @user.has_saved_searches? && @user.is_privileged? %>
<% presenter.saved_search_labels.each do |label| %>
<div class="box user-saved-search" data-label="<%= label %>">
<h2>
Saved Search: <%= link_to label, posts_path(:tags => "search:#{label}") %>
(<%= link_to "manage", saved_searches_path(label: label) %>)
</h2>
<div class="vertical-section">
<% presenter.posts_for_saved_search_category(label).each do |post| %>
<%= PostPresenter.preview(post, :tags => "search:#{label}") %>
<% end %>
</div>
</div>
<% end %>
<% end %>

View File

@ -113,17 +113,6 @@
<% end %>
<% if CurrentUser.id == user.id %>
<% if CurrentUser.has_saved_searches? %>
<tr>
<th>Saved Searches</th>
<td>
<% SavedSearch.labels_for(CurrentUser.user.id).each do |label| %>
<%= link_to label, posts_path(tags: "search:#{label}") %>
<% end %>
</td>
</tr>
<% end %>
<tr>
<th>API Key</th>
<td>

View File

@ -59,5 +59,5 @@ Rails.application.configure do
# Use an evented file watcher to asynchronously detect changes in source code,
# routes, locales, etc. This feature depends on the listen gem.
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
config.hosts << 'e621.lc'
config.hosts << 'e621ng.local'
end

View File

@ -37,6 +37,3 @@ en:
user_feedback:
creator: "You"
creator_id: "You"
saved_search:
user: "You"
user_id: "You"

View File

@ -295,11 +295,6 @@ Rails.application.routes.draw do
get "reports/down_voting_post" => "reports#down_voting_post"
post "reports/down_voting_post_create" => "reports#down_voting_post_create"
resource :recommended_posts, only: [:show]
resources :saved_searches, :except => [:show] do
collection do
get :labels
end
end
resource :session, only: [:new, :create, :destroy] do
get :sign_out, on: :collection
end

View File

@ -1,7 +0,0 @@
FactoryBot.define do
factory(:saved_search) do
query { FFaker::Lorem.words }
labels { [FFaker::Lorem.word] }
user
end
end

View File

@ -1,4 +0,0 @@
FactoryBot.define do
factory(:super_voter) do
end
end

View File

@ -1,63 +0,0 @@
require 'test_helper'
class SavedSearchesControllerTest < ActionDispatch::IntegrationTest
context "The saved searches controller" do
setup do
SavedSearch.stubs(:enabled?).returns(true)
@user = create(:user)
as_user do
@saved_search = create(:saved_search, user: @user)
end
mock_saved_search_service!
end
context "index action" do
should "render" do
get_auth saved_searches_path, @user
assert_response :success
assert_select "#saved-search-#{@saved_search.id}"
end
end
context "create action" do
should "render" do
post_auth saved_searches_path, @user, params: { saved_search: { query: "bkub", label_string: "artist" }}
assert_response :redirect
end
end
context "edit action" do
should "render" do
as_user do
@saved_search = create(:saved_search, user: @user)
end
get_auth edit_saved_search_path(@saved_search), @user, params: { id: @saved_search.id }
assert_response :success
end
end
context "update action" do
should "render" do
as_user do
@saved_search = create(:saved_search, user: @user)
end
params = { id: @saved_search.id, saved_search: { label_string: "foo" } }
put_auth saved_search_path(@saved_search), @user, params: params
assert_redirected_to saved_searches_path
assert_equal(["foo"], @saved_search.reload.labels)
end
end
context "destroy action" do
should "render" do
as_user do
@saved_search = create(:saved_search, user: @user)
end
delete_auth saved_search_path(@saved_search), @user
assert_redirected_to saved_searches_path
end
end
end
end

View File

@ -38,7 +38,6 @@ class UsersControllerTest < ActionDispatch::IntegrationTest
# flesh out profile to get more test coverage of user presenter.
@user = create(:banned_user, can_approve_posts: true, is_super_voter: true)
as_user do
create(:saved_search, user: @user)
create(:post, uploader: @user, tag_string: "fav:#{@user.name}")
end
end

View File

@ -70,7 +70,6 @@ class ActiveSupport::TestCase
include ReportbooruHelper
include DownloadTestHelper
include IqdbTestHelper
include SavedSearchTestHelper
include UploadTestHelper
include TestHelpers

View File

@ -1,5 +0,0 @@
module SavedSearchTestHelper
def mock_saved_search_service!
SavedSearch.stubs(:enabled?).returns(true)
end
end

View File

@ -4,7 +4,6 @@ module Moderator
class TagBatchChangeTest < ActiveSupport::TestCase
def setup
super
mock_saved_search_service!
end
context "a tag batch change" do
@ -37,14 +36,6 @@ module Moderator
assert_equal("bbb", @post.tag_string)
end
should "move saved searches" do
ss = FactoryBot.create(:saved_search, :user => @user, :query => "123 ... 456")
tag_batch_change = TagBatchChange.new("...", "bbb", @user.id, "127.0.0.1")
tag_batch_change.perform
assert_equal("123 456 bbb", ss.reload.normalized_query)
end
should "move blacklists" do
@user.update(blacklisted_tags: "123 456\n789\n")
tag_batch_change = TagBatchChange.new("456", "xxx", @user.id, "127.0.0.1")
@ -53,19 +44,6 @@ module Moderator
assert_equal("123 xxx\n789", @user.blacklisted_tags)
end
should "move only saved searches that match the mass update exactly" do
ss = FactoryBot.create(:saved_search, :user => @user, :query => "123 ... 456")
tag_batch_change = TagBatchChange.new("1", "bbb", @user.id, "127.0.0.1")
tag_batch_change.perform
assert_equal("... 123 456", ss.reload.normalized_query, "expected '123' to remain unchanged")
tag_batch_change = TagBatchChange.new("123 456", "789", @user.id, "127.0.0.1")
tag_batch_change.perform
assert_equal("... 789", ss.reload.normalized_query, "expected '123 456' to be changed to '789'")
end
should "raise an error if there is no predicate" do
tag_batch_change = TagBatchChange.new("", "bbb", @user.id, "127.0.0.1")
assert_raises(TagBatchChange::Error) do

View File

@ -13,7 +13,6 @@ class PostTest < ActiveSupport::TestCase
end
CurrentUser.user = @user
CurrentUser.ip_addr = "127.0.0.1"
mock_saved_search_service!
mock_pool_archive_service!
end
@ -2196,37 +2195,6 @@ class PostTest < ActiveSupport::TestCase
assert_tag_match([post], "pixiv_id:none")
end
context "saved searches" do
setup do
SavedSearch.stubs(:enabled?).returns(true)
@post1 = FactoryBot.create(:post, tag_string: "aaa")
@post2 = FactoryBot.create(:post, tag_string: "bbb")
FactoryBot.create(:saved_search, query: "aaa", labels: ["zzz"], user: CurrentUser.user)
FactoryBot.create(:saved_search, query: "bbb", user: CurrentUser.user)
end
context "labeled" do
should "work" do
SavedSearch.expects(:post_ids_for).with(CurrentUser.id, label: "zzz").returns([@post1.id])
assert_tag_match([@post1], "search:zzz")
end
end
context "missing" do
should "work" do
SavedSearch.expects(:post_ids_for).with(CurrentUser.id, label: "uncategorized").returns([@post2.id])
assert_tag_match([@post2], "search:uncategorized")
end
end
context "all" do
should "work" do
SavedSearch.expects(:post_ids_for).with(CurrentUser.id).returns([@post1.id, @post2.id])
assert_tag_match([@post2, @post1], "search:all")
end
end
end
should "return posts for a rating:<s|q|e> metatag" do
s = FactoryBot.create(:post, :rating => "s")
q = FactoryBot.create(:post, :rating => "q")

View File

@ -1,168 +0,0 @@
require 'test_helper'
class SavedSearchTest < ActiveSupport::TestCase
def setup
super
Sidekiq::Testing::inline!
@user = FactoryBot.create(:user)
CurrentUser.user = @user
CurrentUser.ip_addr = "127.0.0.1"
@mock_redis = MockRedis.new
SavedSearch.stubs(:redis).returns(@mock_redis)
end
def teardown
super
Sidekiq::Testing::fake!
CurrentUser.user = nil
CurrentUser.ip_addr = nil
end
context ".labels_for" do
setup do
FactoryBot.create(:saved_search, user: @user, label_string: "blah", query: "blah")
FactoryBot.create(:saved_search, user: @user, label_string: "zah", query: "blah")
end
should "fetch the labels used by a user" do
assert_equal(%w(blah zah), SavedSearch.labels_for(@user.id))
end
end
context ".queries_for" do
setup do
FactoryBot.create(:tag_alias, antecedent_name: "bbb", consequent_name: "ccc", creator: @user)
FactoryBot.create(:saved_search, user: @user, label_string: "blah", query: "aaa")
FactoryBot.create(:saved_search, user: @user, label_string: "zah", query: "CCC BBB AAA")
FactoryBot.create(:saved_search, user: @user, label_string: "qux", query: " aaa bbb ccc ")
end
should "fetch the queries used by a user for a label" do
assert_equal(%w(aaa), SavedSearch.queries_for(@user.id, label: "blah"))
end
should "fetch the queries used by a user without a label" do
assert_equal(["aaa", "aaa ccc"], SavedSearch.queries_for(@user.id))
end
end
context ".search_labels" do
setup do
FactoryBot.create(:tag_alias, antecedent_name: "bbb", consequent_name: "ccc", creator: @user)
FactoryBot.create(:saved_search, user: @user, label_string: "blah", query: "aaa")
FactoryBot.create(:saved_search, user: @user, label_string: "blahbling", query: "CCC BBB AAA")
FactoryBot.create(:saved_search, user: @user, label_string: "qux", query: " aaa bbb ccc ")
end
should "fetch the queries used by a user for a label" do
assert_equal(%w(blah blahbling), SavedSearch.search_labels(@user.id, label: "blah"))
end
end
context ".post_ids_for" do
context "with a label" do
setup do
SavedSearch.expects(:queries_for).with(1, label: "blah").returns(%w(a b c))
end
context "without a primed cache" do
should "delay processing three times" do
SavedSearch.expects(:populate).times(3)
post_ids = SavedSearch.post_ids_for(1, label: "blah")
assert_equal([], post_ids)
end
end
context "with a primed cached" do
setup do
@mock_redis.sadd("search:a", 1)
@mock_redis.sadd("search:b", 2)
@mock_redis.sadd("search:c", 3)
end
should "fetch the post ids" do
SavedSearch.expects(:delay).never
post_ids = SavedSearch.post_ids_for(1, label: "blah")
assert_equal([1,2,3], post_ids)
end
end
end
context "without a label" do
setup do
SavedSearch.expects(:queries_for).with(1, label: nil).returns(%w(a b c))
end
context "without a primed cache" do
should "delay processing three times" do
SavedSearch.expects(:populate).times(3)
post_ids = SavedSearch.post_ids_for(1)
assert_equal([], post_ids)
end
end
context "with a primed cache" do
setup do
@mock_redis.sadd("search:a", 1)
@mock_redis.sadd("search:b", 2)
@mock_redis.sadd("search:c", 3)
end
should "fetch the post ids" do
SavedSearch.expects(:delay).never
post_ids = SavedSearch.post_ids_for(1)
assert_equal([1,2,3], post_ids)
end
end
end
end
context "Creating a saved search" do
setup do
FactoryBot.create(:tag_alias, antecedent_name: "zzz", consequent_name: "yyy", creator: @user)
@saved_search = @user.saved_searches.create(query: " ZZZ xxx ")
end
should "update the bitpref on the user" do
@user.reload
assert(@user.has_saved_searches?, "should have saved_searches bitpref set")
end
should "normalize the query aside from the order" do
assert_equal("yyy xxx", @saved_search.query)
end
should "normalize the label string" do
@saved_search.label_string = "Foo Bar"
assert_equal(%w[foo bar], @saved_search.labels)
@saved_search.labels = ["Artist 1", "Artist 2"]
assert_equal(%w[artist_1 artist_2], @saved_search.labels)
end
end
context "Destroying a saved search" do
setup do
@saved_search = @user.saved_searches.create(query: "xxx")
@saved_search.destroy
end
should "update the bitpref on the user" do
@user.reload
assert(!@user.has_saved_searches?, "should not have the saved_searches bitpref set")
end
end
context "A user with max saved searches" do
setup do
@user = FactoryBot.create(:privileged_user)
CurrentUser.user = @user
User.any_instance.stubs(:max_saved_searches).returns(0)
@saved_search = @user.saved_searches.create(:query => "xxx")
end
should "not be able to create another saved search" do
assert_equal(["You can only have up to 0 saved searches"], @saved_search.errors.full_messages)
end
end
end

View File

@ -18,7 +18,6 @@ class TagAliasTest < ActiveSupport::TestCase
CurrentUser.user = user
end
CurrentUser.ip_addr = "127.0.0.1"
mock_saved_search_service!
end
teardown do
@ -125,22 +124,6 @@ class TagAliasTest < ActiveSupport::TestCase
assert_equal(["bbb", "bbb"], TagAlias.to_aliased(["aaa", "aaa"]))
end
context "saved searches" do
setup do
SavedSearch.stubs(:enabled?).returns(true)
end
should "move saved searches" do
tag1 = FactoryBot.create(:tag, :name => "...")
tag2 = FactoryBot.create(:tag, :name => "bbb")
ss = FactoryBot.create(:saved_search, :query => "123 ... 456", :user => CurrentUser.user)
ta = FactoryBot.create(:tag_alias, :antecedent_name => "...", :consequent_name => "bbb")
ta.approve!(approver: @admin)
assert_equal(%w(123 456 bbb), ss.reload.query.split.sort)
end
end
should "update any affected posts when saved" do
post1 = FactoryBot.create(:post, :tag_string => "aaa bbb")
post2 = FactoryBot.create(:post, :tag_string => "ccc ddd")