From f02f72fac11d0414a9e08792dd61635a911f224c Mon Sep 17 00:00:00 2001 From: r888888888 Date: Tue, 3 Jun 2014 15:54:22 -0700 Subject: [PATCH] implement saved searches, move user boolean settings to bitprefs --- app/assets/javascripts/posts.js | 7 + .../stylesheets/specific/posts.css.scss | 4 + app/controllers/saved_searches_controller.rb | 33 +++ app/logical/anonymous_user.rb | 12 + app/models/saved_search.rb | 31 +++ app/models/user.rb | 49 ++++ .../partials/common/_secondary_links.html.erb | 3 + .../posts/partials/index/_posts.html.erb | 10 +- app/views/saved_searches/_interface.html.erb | 9 + app/views/saved_searches/create.js.erb | 6 + app/views/saved_searches/destroy.js.erb | 3 + app/views/saved_searches/edit.html.erb | 19 ++ app/views/saved_searches/index.html.erb | 34 +++ app/views/users/edit.html.erb | 21 +- config/locales/en.yml | 5 +- config/routes.rb | 1 + ...748_add_last_comment_bumped_at_to_posts.rb | 4 +- .../20140603225334_create_saved_searches.rb | 16 ++ .../20140604002414_add_bit_prefs_to_users.rb | 63 +++++ db/seeds.rb | 3 + db/structure.sql | 255 +++++++++++------- script/testing/reset_db.sh | 1 - .../saved_searches_controller_test.rb | 7 + test/factories/user.rb | 1 + test/fixtures/saved_searches.yml | 11 + test/helpers/saved_searches_helper_test.rb | 4 + test/unit/saved_search_test.rb | 40 +++ 27 files changed, 547 insertions(+), 105 deletions(-) create mode 100644 app/controllers/saved_searches_controller.rb create mode 100644 app/models/saved_search.rb create mode 100644 app/views/saved_searches/_interface.html.erb create mode 100644 app/views/saved_searches/create.js.erb create mode 100644 app/views/saved_searches/destroy.js.erb create mode 100644 app/views/saved_searches/edit.html.erb create mode 100644 app/views/saved_searches/index.html.erb create mode 100644 db/migrate/20140603225334_create_saved_searches.rb create mode 100644 db/migrate/20140604002414_add_bit_prefs_to_users.rb create mode 100644 test/controllers/saved_searches_controller_test.rb create mode 100644 test/fixtures/saved_searches.yml create mode 100644 test/helpers/saved_searches_helper_test.rb create mode 100644 test/unit/saved_search_test.rb diff --git a/app/assets/javascripts/posts.js b/app/assets/javascripts/posts.js index 4a3262c06..8ebd8e601 100644 --- a/app/assets/javascripts/posts.js +++ b/app/assets/javascripts/posts.js @@ -497,6 +497,13 @@ } }); } + + Danbooru.Post.save_search = function() { + $.post( + "/saved_searches.js", + {"saved_search[tag_query]": $("#tags").val()} + ); + } })(); $(document).ready(function() { diff --git a/app/assets/stylesheets/specific/posts.css.scss b/app/assets/stylesheets/specific/posts.css.scss index c67bc4414..f679b0599 100644 --- a/app/assets/stylesheets/specific/posts.css.scss +++ b/app/assets/stylesheets/specific/posts.css.scss @@ -18,6 +18,10 @@ article.post-preview { overflow: hidden; } +#saved-searches-nav { + margin-top: 1em; +} + a.blacklisted-active { font-weight: bold; } diff --git a/app/controllers/saved_searches_controller.rb b/app/controllers/saved_searches_controller.rb new file mode 100644 index 000000000..743fe7783 --- /dev/null +++ b/app/controllers/saved_searches_controller.rb @@ -0,0 +1,33 @@ +class SavedSearchesController < ApplicationController + respond_to :html, :js + + def index + @saved_searches = saved_searches.order("name") + end + + def create + @saved_search = saved_searches.create(:tag_query => params[:tags]) + end + + def destroy + @saved_search = saved_searches.find(params[:id]) + @saved_search.destroy + end + + def edit + @saved_search = saved_searches.find(params[:id]) + end + + def update + @saved_search = saved_searches.find(params[:id]) + @saved_search.update_attributes(params[:saved_search]) + flash[:notice] = "Saved search updated" + respond_with(@saved_search, :location => saved_searches_path) + end + +private + + def saved_searches + CurrentUser.user.saved_searches + end +end diff --git a/app/logical/anonymous_user.rb b/app/logical/anonymous_user.rb index 2b424f2f5..6e3fa00e3 100644 --- a/app/logical/anonymous_user.rb +++ b/app/logical/anonymous_user.rb @@ -209,6 +209,18 @@ class AnonymousUser false end + def saved_searches + [] + end + + def has_saved_searches? + false + end + + def show_saved_searches? + false + end + %w(member banned gold builder platinum contributor janitor moderator admin).each do |name| define_method("is_#{name}?") do false diff --git a/app/models/saved_search.rb b/app/models/saved_search.rb new file mode 100644 index 000000000..eafa15e1e --- /dev/null +++ b/app/models/saved_search.rb @@ -0,0 +1,31 @@ +class SavedSearch < ActiveRecord::Base + belongs_to :user + validates :tag_query, :presence => true + validate :validate_count + attr_accessible :tag_query, :category + before_create :update_user_on_create + after_destroy :update_user_on_destroy + validates_uniqueness_of :tag_query, :scope => :user_id + + def self.tagged(tags) + where(:tag_query => tags).first + end + + 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_attribute(:has_saved_searches, true) + end + end + + def update_user_on_destroy + if user.saved_searches.count == 0 + user.update_attribute(:has_saved_searches, false) + end + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 3f91a6fce..0d271ccbc 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -16,6 +16,22 @@ class User < ActiveRecord::Base ADMIN = 50 end + BOOLEAN_ATTRIBUTES = { + :is_banned => 0x0001, + :has_mail => 0x0002, + :receive_email_notifications => 0x0004, + :always_resize_images => 0x0008, + :enable_post_navigation => 0x0010, + :new_post_navigation_layout => 0x0020, + :enable_privacy_mode => 0x0040, + :enable_sequential_post_navigation => 0x0080, + :hide_deleted_posts => 0x0100, + :style_usernames => 0x0200, + :enable_auto_complete => 0x0400, + :show_deleted_children => 0x0800, + :has_saved_searches => 0x1000 + } + attr_accessor :password, :old_password attr_accessible :enable_privacy_mode, :enable_post_navigation, :new_post_navigation_layout, :password, :old_password, :password_confirmation, :password_hash, :email, :last_logged_in_at, :last_forum_read_at, :has_mail, :receive_email_notifications, :comment_threshold, :always_resize_images, :favorite_tags, :blacklisted_tags, :name, :ip_addr, :time_zone, :default_image_size, :enable_sequential_post_navigation, :per_page, :hide_deleted_posts, :style_usernames, :enable_auto_complete, :custom_style, :show_deleted_children, :as => [:moderator, :janitor, :contributor, :gold, :member, :anonymous, :default, :builder, :admin] attr_accessible :level, :as => :admin @@ -45,6 +61,7 @@ class User < ActiveRecord::Base has_many :subscriptions, lambda {order("tag_subscriptions.name")}, :class_name => "TagSubscription", :foreign_key => "creator_id" has_many :note_versions, :foreign_key => "updater_id" has_many :dmails, lambda {order("dmails.id desc")}, :foreign_key => "owner_id" + has_many :saved_searches belongs_to :inviter, :class_name => "User" after_update :create_mod_action @@ -417,6 +434,20 @@ class User < ActiveRecord::Base end module LimitMethods + def max_saved_searches + if is_platinum? + 1_000 + elsif is_gold? + 200 + else + 100 + end + end + + def show_saved_searches? + id < 1_000 + end + def can_upload? if is_contributor? true @@ -703,6 +734,24 @@ class User < ActiveRecord::Base include CountMethods extend SearchMethods + BOOLEAN_ATTRIBUTES.each do |boolean_attribute, bit_flag| + define_method(boolean_attribute) do + bit_prefs & bit_flag > 0 + end + + define_method("#{boolean_attribute}?") do + bit_prefs & bit_flag > 0 + end + + define_method("#{boolean_attribute}=") do |val| + if val.to_s =~ /t|1|y/ + self.bit_prefs = bit_prefs | bit_flag + else + self.bit_prefs = bit_prefs - bit_flag + end + end + end + def initialize_default_image_size self.default_image_size = "large" end diff --git a/app/views/posts/partials/common/_secondary_links.html.erb b/app/views/posts/partials/common/_secondary_links.html.erb index a997d4126..b4c41409f 100644 --- a/app/views/posts/partials/common/_secondary_links.html.erb +++ b/app/views/posts/partials/common/_secondary_links.html.erb @@ -6,6 +6,9 @@
  • <%= link_to "Hot", posts_path(:tags => "order:rank") %>
  • <% unless CurrentUser.is_anonymous? %>
  • <%= link_to "Favorites", favorites_path %>
  • + <% if CurrentUser.user.has_saved_searches? %> +
  • <%= link_to "Saved searches", saved_searches_path %>
  • + <% end %>
  • <%= link_to "Subscriptions", posts_path(:tags => "sub:#{CurrentUser.name}") %>
  • <% end %>
  • <%= link_to "Changes", post_versions_path %>
  • diff --git a/app/views/posts/partials/index/_posts.html.erb b/app/views/posts/partials/index/_posts.html.erb index 8c7b88295..016c1bb6b 100644 --- a/app/views/posts/partials/index/_posts.html.erb +++ b/app/views/posts/partials/index/_posts.html.erb @@ -1,5 +1,13 @@
    - <%= post_set.presenter.post_previews_html(self) %> +
    + <%= post_set.presenter.post_previews_html(self) %> +
    + + <% if params[:tags] %> +
    + <%= render "saved_searches/interface", :saved_searches => CurrentUser.user.saved_searches %> +
    + <% end %> <%= numbered_paginator(post_set.posts) %>
    diff --git a/app/views/saved_searches/_interface.html.erb b/app/views/saved_searches/_interface.html.erb new file mode 100644 index 000000000..eeb3e9650 --- /dev/null +++ b/app/views/saved_searches/_interface.html.erb @@ -0,0 +1,9 @@ +<% if CurrentUser.user.show_saved_searches? %> + + <% if CurrentUser.user.has_saved_searches? && saved_searches.tagged(params[:tags]) %> + <%= button_to "Remove this saved search", saved_search_path(saved_searches.tagged(params[:tags]), :tags => params[:tags]), :remote => true, :method => :delete %> + <% elsif CurrentUser.user.is_member? %> + <%= button_to "Save this search", saved_searches_path(:tags => params[:tags]), :remote => true, :method => :post %> + <% end %> + +<% end %> \ No newline at end of file diff --git a/app/views/saved_searches/create.js.erb b/app/views/saved_searches/create.js.erb new file mode 100644 index 000000000..21a4f9fb7 --- /dev/null +++ b/app/views/saved_searches/create.js.erb @@ -0,0 +1,6 @@ +<% if @saved_search.errors.any? %> + Danbooru.error("<%= j @saved_search.errors.full_messages.join(', ') %>"); +<% else %> + Danbooru.notice("Search '<%= j @saved_search.tag_query %>' was saved"); + $("#saved-searches-nav").html("<%= j render('saved_searches/interface', :saved_searches => CurrentUser.user.saved_searches) %>"); +<% end %> diff --git a/app/views/saved_searches/destroy.js.erb b/app/views/saved_searches/destroy.js.erb new file mode 100644 index 000000000..f7181b01e --- /dev/null +++ b/app/views/saved_searches/destroy.js.erb @@ -0,0 +1,3 @@ +Danbooru.notice("Search '<%= j @saved_search.tag_query %>' was deleted"); +$("#saved-searches-nav").html("<%= j render('saved_searches/interface', :saved_searches => CurrentUser.user.saved_searches) %>"); +$("#saved-search-<%= @saved_search.id %>").remove(); diff --git a/app/views/saved_searches/edit.html.erb b/app/views/saved_searches/edit.html.erb new file mode 100644 index 000000000..f59a03b9a --- /dev/null +++ b/app/views/saved_searches/edit.html.erb @@ -0,0 +1,19 @@ +
    +
    +

    Edit Saved Search

    + + <%= error_messages_for :saved_search %> + + <%= simple_form_for(@saved_search) do |f| %> + <%= f.input :tag_query %> + <%= f.input :category %> + <%= f.button :submit %> + <% end %> +
    +
    + +<%= render "users/secondary_links" %> + +<% content_for(:page_title) do %> + Edit Saved Search - <%= Danbooru.config.app_name %> +<% end %> diff --git a/app/views/saved_searches/index.html.erb b/app/views/saved_searches/index.html.erb new file mode 100644 index 000000000..caf77fa70 --- /dev/null +++ b/app/views/saved_searches/index.html.erb @@ -0,0 +1,34 @@ +
    +
    +

    Saved Searches

    + + + + + + + + + + + + <% @saved_searches.each do |saved_search| %> + + + + + + <% end %> + +
    TagsCategory
    <%= link_to saved_search.tag_query, posts_path(:tags => saved_search.tag_query) %><%= saved_search.category %> + <%= link_to "edit", edit_saved_search_path(saved_search) %> | + <%= link_to "delete", saved_search_path(saved_search), :method => :delete, :remote => true %> +
    +
    +
    + +<%= render "users/secondary_links" %> + +<% content_for(:page_title) do %> + Saved Searches - <%= Danbooru.config.app_name %> +<% end %> diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb index 3aada85e2..62acc2b9f 100644 --- a/app/views/users/edit.html.erb +++ b/app/views/users/edit.html.erb @@ -30,8 +30,11 @@ <%= f.input :time_zone, :include_blank => false %> - <%= f.input :receive_email_notifications, :as => :select, :include_blank => false %> + + <%= f.input :receive_email_notifications, :as => :select, :include_blank => false, :collection => [["Yes", "true"], ["No", "false"]] %> + <%= f.input :comment_threshold, :hint => "Comments below this score will be hidden by default" %> + <%= f.input :default_image_size, :hint => "Show original image or show resized #{Danbooru.config.large_image_width} pixel version", :label => "Default image width", :collection => [["850px", "large"], ["original", "original"]], :include_blank => false %> <% if CurrentUser.user.is_gold? %> @@ -43,23 +46,33 @@
    <%= f.input :style_usernames, :as => :select, :label => "Colored usernames", :hint => "Color each user's name depending on their level", :include_blank => false, :collection => [["Yes", "true"], ["No", "false"]] %> - <%= f.input :always_resize_images, :as => :select, :include_blank => false, :label => "Fit images to window", :hint => "Use JavaScript to resize images to fit window" %> - <%= f.input :enable_post_navigation, :as => :select, :include_blank => false, :label => "Enable keyboard shortcuts" %> - <%= f.input :enable_sequential_post_navigation, :as => :select, :label => "Enable slideshow mode", :hint => "Show prev/next links when viewing a post", :include_blank => false %> + + <%= f.input :always_resize_images, :as => :select, :include_blank => false, :label => "Fit images to window", :hint => "Use JavaScript to resize images to fit window", :collection => [["Yes", "true"], ["No", "false"]] %> + + <%= f.input :enable_post_navigation, :as => :select, :include_blank => false, :label => "Enable keyboard shortcuts", :collection => [["Yes", "true"], ["No", "false"]] %> + + <%= f.input :enable_sequential_post_navigation, :as => :select, :label => "Enable slideshow mode", :hint => "Show prev/next links when viewing a post", :include_blank => false, :collection => [["Yes", "true"], ["No", "false"]] %> + <%= f.input :new_post_navigation_layout, :as => :select, :label => "Navigation bar position", :include_blank => false, :collection => [["Below", "true"], ["Above", "false"]], :hint => "When browsing pools or slideshows, place navigation links above or below the image" %> + <%= f.input :hide_deleted_posts, :as => :select, :label => "Deleted post filter", :hint => "Remove deleted posts from search results", :include_blank => false, :collection => [["Yes", "true"], ["No", "false"]] %> + <%= f.input :show_deleted_children, :as => :select, :label => "Show deleted children", :hint => "Indicate that a post has children even if the children are deleted", :include_blank => false, :collection => [["Yes", "true"], ["No", "false"]] %> + <%= f.input :enable_auto_complete, :as => :select, :collection => [["Yes", "true"], ["No", "false"]], :include_blank => false %> +
    A list of tags that you use often. They will appear when using the list of Related Tags.
    + <%= f.input :custom_style, :label => "Custom CSS style".html_safe, :hint => "Style to apply to the whole site.", :input_html => {:size => "40x5"} %>
    <%= f.input :password, :hint => "Leave blank if you don't want to change your password", :label => "New password", :input_html => {:autocomplete => "off"} %> + <%= f.input :old_password, :as => :password, :input_html => {:autocomplete => "off"} %>
    diff --git a/config/locales/en.yml b/config/locales/en.yml index 3ea810665..3ba3c2f17 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -34,4 +34,7 @@ en: uploader_id: "You" user_feedback: creator: "You" - creator_id: "You" \ No newline at end of file + creator_id: "You" + saved_search: + user: "You" + user_id: "You" \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 7e1e4f34d..128631d25 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -198,6 +198,7 @@ Rails.application.routes.draw do resources :artist_commentary_versions, :only => [:index] resource :related_tag, :only => [:show] get "reports/user_promotions" => "reports#user_promotions" + resources :saved_searches resource :session do collection do get :sign_out diff --git a/db/migrate/20131225002748_add_last_comment_bumped_at_to_posts.rb b/db/migrate/20131225002748_add_last_comment_bumped_at_to_posts.rb index 2f76a4678..6b3da0768 100644 --- a/db/migrate/20131225002748_add_last_comment_bumped_at_to_posts.rb +++ b/db/migrate/20131225002748_add_last_comment_bumped_at_to_posts.rb @@ -3,7 +3,7 @@ class AddLastCommentBumpedAtToPosts < ActiveRecord::Migration execute "SET statement_timeout = 0" rename_column :posts, :last_commented_at, :last_comment_bumped_at - rename_index :posts, "index_posts_on_last_commented_at", "index_posts_on_last_comment_bumped_at" + # rename_index :posts, :index_posts_on_last_commented_at, :index_posts_on_last_comment_bumped_at add_column :posts, :last_commented_at, :datetime add_column :comments, :do_not_bump_post, :boolean, :null => false, :default => false @@ -15,7 +15,7 @@ class AddLastCommentBumpedAtToPosts < ActiveRecord::Migration remove_column :posts, :last_commented_at rename_column :posts, :last_comment_bumped_at, :last_commented_at - rename_index :posts, "index_posts_on_last_comment_bumped_at", "index_posts_on_last_commented_at" + # rename_index :posts, "index_posts_on_last_comment_bumped_at", "index_posts_on_last_commented_at" remove_column :comments, :do_not_bump_posts end diff --git a/db/migrate/20140603225334_create_saved_searches.rb b/db/migrate/20140603225334_create_saved_searches.rb new file mode 100644 index 000000000..ca6162a22 --- /dev/null +++ b/db/migrate/20140603225334_create_saved_searches.rb @@ -0,0 +1,16 @@ +class CreateSavedSearches < ActiveRecord::Migration + def change + create_table :saved_searches do |t| + t.integer :user_id + t.text :tag_query + t.text :name + t.string :category + + t.timestamps + end + + add_index :saved_searches, :user_id + add_index :saved_searches, :tag_query + add_index :saved_searches, :category + end +end diff --git a/db/migrate/20140604002414_add_bit_prefs_to_users.rb b/db/migrate/20140604002414_add_bit_prefs_to_users.rb new file mode 100644 index 000000000..fa421803a --- /dev/null +++ b/db/migrate/20140604002414_add_bit_prefs_to_users.rb @@ -0,0 +1,63 @@ +class AddBitPrefsToUsers < ActiveRecord::Migration + def up + execute "set statement_timeout = 0" + add_column :users, :bit_prefs, "bigint", :null => false, :default => 0 + execute "update users set bit_prefs = bit_prefs | 1 where is_banned = true" + execute "update users set bit_prefs = bit_prefs | 2 where has_mail = true" + execute "update users set bit_prefs = bit_prefs | 4 where receive_email_notifications = true" + execute "update users set bit_prefs = bit_prefs | 8 where always_resize_images = true" + execute "update users set bit_prefs = bit_prefs | 16 where enable_post_navigation = true" + execute "update users set bit_prefs = bit_prefs | 32 where new_post_navigation_layout = true" + execute "update users set bit_prefs = bit_prefs | 64 where enable_privacy_mode = true" + execute "update users set bit_prefs = bit_prefs | 128 where enable_sequential_post_navigation = true" + execute "update users set bit_prefs = bit_prefs | 256 where hide_deleted_posts = true" + execute "update users set bit_prefs = bit_prefs | 512 where style_usernames = true" + execute "update users set bit_prefs = bit_prefs | 1024 where enable_auto_complete = true" + execute "update users set bit_prefs = bit_prefs | 2048 where show_deleted_children = true" + + remove_column :users, :is_banned + remove_column :users, :has_mail + remove_column :users, :receive_email_notifications + remove_column :users, :always_resize_images + remove_column :users, :enable_post_navigation + remove_column :users, :new_post_navigation_layout + remove_column :users, :enable_privacy_mode + remove_column :users, :enable_sequential_post_navigation + remove_column :users, :hide_deleted_posts + remove_column :users, :style_usernames + remove_column :users, :enable_auto_complete + remove_column :users, :show_deleted_children + end + + def down + execute "set statement_timeout = 0" + + add_column :users, :is_banned, :boolean + add_column :users, :has_mail, :boolean + add_column :users, :receive_email_notifications, :boolean + add_column :users, :always_resize_images, :boolean + add_column :users, :enable_post_navigation, :boolean + add_column :users, :new_post_navigation_layout, :boolean + add_column :users, :enable_privacy_mode, :boolean + add_column :users, :enable_sequential_post_navigation, :boolean + add_column :users, :hide_deleted_posts, :boolean + add_column :users, :style_usernames, :boolean + add_column :users, :enable_auto_complete, :boolean + add_column :users, :show_deleted_children, :boolean + + execute "update users set is_banned = true where bit_prefs & 1 > 0" + execute "update users set has_mail = true where bit_prefs & 2 > 0" + execute "update users set receive_email_notifications = true where bit_prefs & 4 > 0" + execute "update users set always_resize_images = true where bit_prefs & 8 > 0" + execute "update users set enable_post_navigation = true where bit_prefs & 16 > 0" + execute "update users set new_post_navigation_layout = true where bit_prefs & 32 > 0" + execute "update users set enable_privacy_mode = true where bit_prefs & 64 > 0" + execute "update users set enable_sequential_post_navigation = true where bit_prefs & 128 > 0" + execute "update users set hide_deleted_posts = true where bit_prefs & 256 > 0" + execute "update users set style_usernames = true where bit_prefs & 512 > 0" + execute "update users set enable_auto_complete = true where bit_prefs & 1024 > 0" + execute "update users set show_deleted_children = true where bit_prefs & 2048 > 0" + + remove_column :users, :bit_prefs, :integer, :null => false, :default => 0 + end +end diff --git a/db/seeds.rb b/db/seeds.rb index ae48aede0..a148960e4 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -80,6 +80,9 @@ if Post.count == 0 Upload.all.each do |upload| upload.process! end + if Post.count == 0 + raise "Uploads failed conversion" + end else puts "Skipping posts" end diff --git a/db/structure.sql b/db/structure.sql index e06e6276d..2b788641c 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -422,8 +422,8 @@ CREATE TABLE advertisement_hits ( id integer NOT NULL, advertisement_id integer NOT NULL, ip_addr inet NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -460,8 +460,8 @@ CREATE TABLE advertisements ( height integer NOT NULL, file_name character varying(255) NOT NULL, is_work_safe boolean DEFAULT false NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -491,8 +491,8 @@ ALTER SEQUENCE advertisements_id_seq OWNED BY advertisements.id; CREATE TABLE amazon_backups ( id integer NOT NULL, last_id integer, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -526,8 +526,8 @@ CREATE TABLE artist_commentaries ( original_description text, translated_title text, translated_description text, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -563,8 +563,8 @@ CREATE TABLE artist_commentary_versions ( original_description text, translated_title text, translated_description text, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -596,8 +596,8 @@ CREATE TABLE artist_urls ( artist_id integer NOT NULL, url text NOT NULL, normalized_url text NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -635,8 +635,8 @@ CREATE TABLE artist_versions ( group_name character varying(255), url_string text, is_banned boolean DEFAULT false NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -672,8 +672,8 @@ CREATE TABLE artists ( other_names text, other_names_index tsvector, group_name character varying(255), - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -706,8 +706,8 @@ CREATE TABLE bans ( reason text NOT NULL, banner_id integer NOT NULL, expires_at timestamp without time zone NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -773,8 +773,8 @@ CREATE TABLE comment_votes ( comment_id integer NOT NULL, user_id integer NOT NULL, score integer NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -809,8 +809,8 @@ CREATE TABLE comments ( ip_addr inet NOT NULL, body_index tsvector NOT NULL, score integer DEFAULT 0 NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone, updater_id integer, updater_ip_addr inet, do_not_bump_post boolean DEFAULT false NOT NULL @@ -850,8 +850,8 @@ CREATE TABLE delayed_jobs ( locked_at timestamp without time zone, failed_at timestamp without time zone, locked_by character varying(255), - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone, queue character varying(255) ); @@ -889,8 +889,8 @@ CREATE TABLE dmails ( message_index tsvector NOT NULL, is_read boolean DEFAULT false NOT NULL, is_deleted boolean DEFAULT false NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone, creator_ip_addr inet DEFAULT '127.0.0.1'::inet NOT NULL ); @@ -1956,8 +1956,8 @@ CREATE TABLE forum_posts ( body text NOT NULL, text_index tsvector NOT NULL, is_deleted boolean DEFAULT false NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -1994,8 +1994,8 @@ CREATE TABLE forum_topics ( is_locked boolean DEFAULT false NOT NULL, is_deleted boolean DEFAULT false NOT NULL, text_index tsvector NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone, category_id integer DEFAULT 0 NOT NULL ); @@ -2028,8 +2028,8 @@ CREATE TABLE ip_bans ( creator_id integer NOT NULL, ip_addr inet NOT NULL, reason text NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -2061,8 +2061,8 @@ CREATE TABLE janitor_trials ( creator_id integer NOT NULL, user_id integer NOT NULL, original_level integer NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -2093,8 +2093,8 @@ CREATE TABLE key_values ( id integer NOT NULL, key character varying(255) NOT NULL, value text, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -2125,8 +2125,8 @@ CREATE TABLE mod_actions ( id integer NOT NULL, creator_id integer NOT NULL, description text NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -2158,8 +2158,8 @@ CREATE TABLE news_updates ( message text NOT NULL, creator_id integer NOT NULL, updater_id integer NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -2198,8 +2198,8 @@ CREATE TABLE note_versions ( height integer NOT NULL, is_active boolean DEFAULT true NOT NULL, body text NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone, version integer DEFAULT 0 NOT NULL ); @@ -2238,8 +2238,8 @@ CREATE TABLE notes ( is_active boolean DEFAULT true NOT NULL, body text NOT NULL, body_index tsvector NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone, version integer DEFAULT 0 NOT NULL ); @@ -2273,8 +2273,8 @@ CREATE TABLE pool_versions ( post_ids text DEFAULT ''::text NOT NULL, updater_id integer NOT NULL, updater_ip_addr inet NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone, name character varying(255) ); @@ -2311,8 +2311,8 @@ CREATE TABLE pools ( post_ids text DEFAULT ''::text NOT NULL, post_count integer DEFAULT 0 NOT NULL, is_deleted boolean DEFAULT false NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone, category character varying(255) DEFAULT 'series'::character varying NOT NULL ); @@ -2346,8 +2346,8 @@ CREATE TABLE post_appeals ( creator_id integer NOT NULL, creator_ip_addr integer NOT NULL, reason text, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -2378,8 +2378,8 @@ CREATE TABLE post_disapprovals ( id integer NOT NULL, user_id integer NOT NULL, post_id integer NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -2413,8 +2413,8 @@ CREATE TABLE post_flags ( creator_ip_addr inet NOT NULL, reason text, is_resolved boolean DEFAULT false NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -2443,8 +2443,8 @@ ALTER SEQUENCE post_flags_id_seq OWNED BY post_flags.id; CREATE TABLE post_versions ( id integer NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone, post_id integer NOT NULL, tags text DEFAULT ''::text NOT NULL, rating character(1), @@ -2483,8 +2483,8 @@ CREATE TABLE post_votes ( post_id integer NOT NULL, user_id integer NOT NULL, score integer NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -2513,8 +2513,8 @@ ALTER SEQUENCE post_votes_id_seq OWNED BY post_votes.id; CREATE TABLE posts ( id integer NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone, up_score integer DEFAULT 0 NOT NULL, down_score integer DEFAULT 0 NOT NULL, score integer DEFAULT 0 NOT NULL, @@ -2574,6 +2574,40 @@ CREATE SEQUENCE posts_id_seq ALTER SEQUENCE posts_id_seq OWNED BY posts.id; +-- +-- Name: saved_searches; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE saved_searches ( + id integer NOT NULL, + user_id integer, + tag_query text, + name text, + category character varying(255), + created_at timestamp without time zone, + updated_at timestamp without time zone +); + + +-- +-- Name: saved_searches_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE saved_searches_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: saved_searches_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE saved_searches_id_seq OWNED BY saved_searches.id; + + -- -- Name: schema_migrations; Type: TABLE; Schema: public; Owner: -; Tablespace: -- @@ -2595,8 +2629,8 @@ CREATE TABLE tag_aliases ( creator_ip_addr inet NOT NULL, forum_topic_id integer, status text DEFAULT 'pending'::text NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -2632,8 +2666,8 @@ CREATE TABLE tag_implications ( creator_ip_addr inet NOT NULL, forum_topic_id integer, status text DEFAULT 'pending'::text NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -2669,8 +2703,8 @@ CREATE TABLE tag_subscriptions ( is_public boolean DEFAULT true NOT NULL, last_accessed_at timestamp without time zone, is_opted_in boolean DEFAULT false NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -2704,8 +2738,8 @@ CREATE TABLE tags ( category integer DEFAULT 0 NOT NULL, related_tags text, related_tags_updated_at timestamp without time zone, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone, is_locked boolean DEFAULT false NOT NULL ); @@ -2738,8 +2772,8 @@ CREATE TABLE transaction_log_items ( category character varying(255), user_id integer, data text, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -2779,8 +2813,8 @@ CREATE TABLE uploads ( backtrace text, post_id integer, md5_confirmation character varying(255), - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone, server text, parent_id integer ); @@ -2815,8 +2849,8 @@ CREATE TABLE user_feedback ( creator_id integer NOT NULL, category character varying(255) NOT NULL, body text NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -2852,8 +2886,8 @@ CREATE TABLE user_name_change_requests ( desired_name character varying(255), change_reason text, rejection_reason text, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -2884,8 +2918,8 @@ CREATE TABLE user_password_reset_nonces ( id integer NOT NULL, key character varying(255) NOT NULL, email character varying(255) NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL + created_at timestamp without time zone, + updated_at timestamp without time zone ); @@ -2914,42 +2948,31 @@ ALTER SEQUENCE user_password_reset_nonces_id_seq OWNED BY user_password_reset_no CREATE TABLE users ( id integer NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone, name character varying(255) NOT NULL, password_hash character varying(255) NOT NULL, email character varying(255), email_verification_key character varying(255), inviter_id integer, - is_banned boolean DEFAULT false NOT NULL, level integer DEFAULT 0 NOT NULL, base_upload_limit integer DEFAULT 10 NOT NULL, last_logged_in_at timestamp without time zone, last_forum_read_at timestamp without time zone, - has_mail boolean DEFAULT false NOT NULL, recent_tags text, post_upload_count integer DEFAULT 0 NOT NULL, post_update_count integer DEFAULT 0 NOT NULL, note_update_count integer DEFAULT 0 NOT NULL, favorite_count integer DEFAULT 0 NOT NULL, - receive_email_notifications boolean DEFAULT false NOT NULL, comment_threshold integer DEFAULT (-1) NOT NULL, - always_resize_images boolean DEFAULT false NOT NULL, default_image_size character varying(255) DEFAULT 'large'::character varying NOT NULL, favorite_tags text, blacklisted_tags text, time_zone character varying(255) DEFAULT 'Eastern Time (US & Canada)'::character varying NOT NULL, bcrypt_password_hash text, - enable_post_navigation boolean DEFAULT true NOT NULL, - new_post_navigation_layout boolean DEFAULT true NOT NULL, - enable_privacy_mode boolean DEFAULT false NOT NULL, - enable_sequential_post_navigation boolean DEFAULT true NOT NULL, per_page integer DEFAULT 20 NOT NULL, - hide_deleted_posts boolean DEFAULT false NOT NULL, - style_usernames boolean DEFAULT false NOT NULL, - enable_auto_complete boolean DEFAULT true NOT NULL, custom_style text, - show_deleted_children boolean DEFAULT false NOT NULL + bit_prefs bigint DEFAULT 0 NOT NULL ); @@ -2984,8 +3007,8 @@ CREATE TABLE wiki_page_versions ( title character varying(255) NOT NULL, body text NOT NULL, is_locked boolean NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone, other_names text ); @@ -3020,8 +3043,8 @@ CREATE TABLE wiki_pages ( body text NOT NULL, body_index tsvector NOT NULL, is_locked boolean DEFAULT false NOT NULL, - created_at timestamp without time zone NOT NULL, - updated_at timestamp without time zone NOT NULL, + created_at timestamp without time zone, + updated_at timestamp without time zone, updater_id integer, other_names text, other_names_index tsvector @@ -3971,6 +3994,13 @@ ALTER TABLE ONLY post_votes ALTER COLUMN id SET DEFAULT nextval('post_votes_id_s ALTER TABLE ONLY posts ALTER COLUMN id SET DEFAULT nextval('posts_id_seq'::regclass); +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY saved_searches ALTER COLUMN id SET DEFAULT nextval('saved_searches_id_seq'::regclass); + + -- -- Name: id; Type: DEFAULT; Schema: public; Owner: - -- @@ -4311,6 +4341,14 @@ ALTER TABLE ONLY posts ADD CONSTRAINT posts_pkey PRIMARY KEY (id); +-- +-- Name: saved_searches_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY saved_searches + ADD CONSTRAINT saved_searches_pkey PRIMARY KEY (id); + + -- -- Name: tag_aliases_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- @@ -6381,6 +6419,27 @@ CREATE INDEX index_posts_on_uploader_id ON posts USING btree (uploader_id); CREATE INDEX index_posts_on_uploader_ip_addr ON posts USING btree (uploader_ip_addr); +-- +-- Name: index_saved_searches_on_category; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_saved_searches_on_category ON saved_searches USING btree (category); + + +-- +-- Name: index_saved_searches_on_tag_query; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_saved_searches_on_tag_query ON saved_searches USING btree (tag_query); + + +-- +-- Name: index_saved_searches_on_user_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE INDEX index_saved_searches_on_user_id ON saved_searches USING btree (user_id); + + -- -- Name: index_tag_aliases_on_antecedent_name; Type: INDEX; Schema: public; Owner: -; Tablespace: -- @@ -6800,5 +6859,9 @@ INSERT INTO schema_migrations (version) VALUES ('20140428015134'); INSERT INTO schema_migrations (version) VALUES ('20140505000956'); +INSERT INTO schema_migrations (version) VALUES ('20140603225334'); + +INSERT INTO schema_migrations (version) VALUES ('20140604002414'); + INSERT INTO schema_migrations (version) VALUES ('20140613004559'); diff --git a/script/testing/reset_db.sh b/script/testing/reset_db.sh index 16e10e5a3..f9d659cf7 100755 --- a/script/testing/reset_db.sh +++ b/script/testing/reset_db.sh @@ -1,7 +1,6 @@ #!/usr/bin/env bash bundle exec rake db:drop db:create -psql -c 'create language plpgsql;' danbooru2 bundle exec rake db:migrate bundle exec rake db:seed diff --git a/test/controllers/saved_searches_controller_test.rb b/test/controllers/saved_searches_controller_test.rb new file mode 100644 index 000000000..58f1f29aa --- /dev/null +++ b/test/controllers/saved_searches_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class SavedSearchesControllerTest < ActionController::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/factories/user.rb b/test/factories/user.rb index 2119c2cf7..12b37cfc7 100644 --- a/test/factories/user.rb +++ b/test/factories/user.rb @@ -9,6 +9,7 @@ FactoryGirl.define do level 20 last_logged_in_at {Time.now} favorite_count 0 + bit_prefs 0 factory(:banned_user) do is_banned true diff --git a/test/fixtures/saved_searches.yml b/test/fixtures/saved_searches.yml new file mode 100644 index 000000000..3623f19a7 --- /dev/null +++ b/test/fixtures/saved_searches.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + user_id: 1 + tag_query: MyText + name: MyText + +two: + user_id: 1 + tag_query: MyText + name: MyText diff --git a/test/helpers/saved_searches_helper_test.rb b/test/helpers/saved_searches_helper_test.rb new file mode 100644 index 000000000..873c00763 --- /dev/null +++ b/test/helpers/saved_searches_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class SavedSearchesHelperTest < ActionView::TestCase +end diff --git a/test/unit/saved_search_test.rb b/test/unit/saved_search_test.rb new file mode 100644 index 000000000..cbf0ff109 --- /dev/null +++ b/test/unit/saved_search_test.rb @@ -0,0 +1,40 @@ +require 'test_helper' + +class SavedSearchTest < ActiveSupport::TestCase + context "Creating a saved search" do + setup do + @user = FactoryGirl.create(:user) + @saved_search = @user.saved_searches.create(:tag_query => "xxx") + end + + should "update the bitpref on the user" do + @user.reload + assert(@user.has_saved_searchs?, "should have saved_searches bitpref set") + end + end + + context "Destroying a saved search" do + setup do + @user = FactoryGirl.create(:user) + @saved_search = @user.saved_searches.create(:tag_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 = FactoryGirl.create(:user) + User.any_instance.stubs(:max_saved_searches).returns(0) + @saved_search = @user.saved_searches.create(:tag_query => "xxx") + end + + should "not be able to create another saved search" do + assert_equal(["User can only have up to 0 saved searches"], @saved_search.errors.full_messages) + end + end +end