diff --git a/app/controllers/favorite_groups_controller.rb b/app/controllers/favorite_groups_controller.rb index 2df12890f..9ffd97cf2 100644 --- a/app/controllers/favorite_groups_controller.rb +++ b/app/controllers/favorite_groups_controller.rb @@ -8,9 +8,12 @@ class FavoriteGroupsController < ApplicationController end def show + limit = params[:limit].presence || CurrentUser.user.per_page + @current_item = @favorite_group = FavoriteGroup.find(params[:id]) check_read_privilege(@favorite_group) - @post_set = PostSets::FavoriteGroup.new(@favorite_group, params[:page]) + @posts = @favorite_group.posts.paginate(params[:page], limit: limit, count: @favorite_group.post_count) + respond_with(@favorite_group) end @@ -52,7 +55,7 @@ class FavoriteGroupsController < ApplicationController @favorite_group = FavoriteGroup.find(params[:id]) check_write_privilege(@favorite_group) @post = Post.find(params[:post_id]) - @favorite_group.add!(@post.id) + @favorite_group.add!(@post) end private @@ -66,6 +69,6 @@ class FavoriteGroupsController < ApplicationController end def favgroup_params - params.fetch(:favorite_group, {}).permit(%i[name post_ids is_public], post_id_array: []) + params.fetch(:favorite_group, {}).permit(%i[name post_ids post_ids_string is_public], post_ids: []) end end diff --git a/app/javascript/src/javascripts/posts.js.erb b/app/javascript/src/javascripts/posts.js.erb index bbce80f17..58ce1fb80 100644 --- a/app/javascript/src/javascripts/posts.js.erb +++ b/app/javascript/src/javascripts/posts.js.erb @@ -193,7 +193,7 @@ Post.nav_prev = function(e) { } else if ($(".paginator a[rel~=prev]").length) { location.href = $("a[rel~=prev]").attr("href"); } else { - href = $("#pool-nav li.pool-selected-true a[rel~=prev], #favgroup-nav a.active[rel~=prev]").attr("href"); + href = $("#pool-nav li[data-selected=true] a[rel=prev], #favgroup-nav li[data-selected=true] a[rel=prev]").attr("href"); if (href) { location.href = href; } @@ -211,7 +211,7 @@ Post.nav_next = function(e) { } else if ($(".paginator a[rel~=next]").length) { location.href = $(".paginator a[rel~=next]").attr("href"); } else { - href = $("#pool-nav li.pool-selected-true a[rel~=next], #favgroup-nav a.active[rel~=next]").attr("href"); + href = $("#pool-nav li[data-selected=true] a[rel=next], #favgroup-nav li[data-selected=true] a[rel=next]").attr("href"); if (href) { location.href = href; } diff --git a/app/javascript/src/styles/specific/posts.scss b/app/javascript/src/styles/specific/posts.scss index bf6336b71..fdbb5ac33 100644 --- a/app/javascript/src/styles/specific/posts.scss +++ b/app/javascript/src/styles/specific/posts.scss @@ -316,10 +316,6 @@ div#c-posts { } div#a-show { - .active, .pool-selected-true { - font-weight: bold; - } - #post-info-source { word-break: break-all; } @@ -377,6 +373,10 @@ div#c-posts { text-align: center; padding: 0 5.5em; + &[data-selected="true"] { + font-weight: bold; + } + .prev { position: absolute; left: 2em; diff --git a/app/logical/post_query_builder.rb b/app/logical/post_query_builder.rb index 83c2c07d5..c2b5fdc7f 100644 --- a/app/logical/post_query_builder.rb +++ b/app/logical/post_query_builder.rb @@ -450,24 +450,12 @@ class PostQueryBuilder relation = relation.joins("JOIN (#{pool_posts.to_sql}) pool_posts ON pool_posts.post_id = posts.id").order("pool_posts.pool_index ASC") end - if q[:favgroups_neg].present? - q[:favgroups_neg].each do |favgroup_rec| - favgroup_id = favgroup_rec.to_i - favgroup = FavoriteGroup.where("favorite_groups.id = ?", favgroup_id).first - if favgroup - relation = relation.where.not("posts.id": favgroup.post_id_array) - end - end + q[:favgroups_neg].to_a.each do |favgroup| + relation = relation.where.not("posts.id": favgroup.post_ids) end - if q[:favgroups].present? - q[:favgroups].each do |favgroup_rec| - favgroup_id = favgroup_rec.to_i - favgroup = FavoriteGroup.where("favorite_groups.id = ?", favgroup_id).first - if favgroup - relation = relation.where("posts.id": favgroup.post_id_array) - end - end + q[:favgroups].to_a.each do |favgroup| + relation = relation.where("posts.id": favgroup.post_ids) end if q[:upvote].present? diff --git a/app/logical/post_sets/favorite_group.rb b/app/logical/post_sets/favorite_group.rb deleted file mode 100644 index ea571ef70..000000000 --- a/app/logical/post_sets/favorite_group.rb +++ /dev/null @@ -1,7 +0,0 @@ -module PostSets - class FavoriteGroup < PostSets::Pool - def presenter - @presenter ||= PostSetPresenters::FavoriteGroup.new(self) - end - end -end diff --git a/app/logical/post_sets/pool.rb b/app/logical/post_sets/pool.rb deleted file mode 100644 index 981412229..000000000 --- a/app/logical/post_sets/pool.rb +++ /dev/null @@ -1,60 +0,0 @@ -module PostSets - class Pool < PostSets::Base - module ActiveRecordExtension - attr_accessor :total_pages, :current_page - end - - attr_reader :pool, :page - - def initialize(pool, page = 1) - @pool = pool - @page = page - end - - def offset - (current_page - 1) * limit - end - - def limit - CurrentUser.user.per_page - end - - def tag_array - ["pool:#{pool.id}"] - end - - def posts - @posts ||= begin - x = pool.posts(:offset => offset, :limit => limit) - x.extend(ActiveRecordExtension) - x.total_pages = total_pages - x.current_page = current_page - x - end - end - - def tag_string - tag_array.join("") - end - - def humanized_tag_string - "pool:#{pool.pretty_name}" - end - - def presenter - @presenter ||= PostSetPresenters::Pool.new(self) - end - - def total_pages - (pool.post_count.to_f / limit).ceil - end - - def size - posts.size - end - - def current_page - [page.to_i, 1].max - end - end -end diff --git a/app/models/favorite_group.rb b/app/models/favorite_group.rb index a13003253..cb16bee9a 100644 --- a/app/models/favorite_group.rb +++ b/app/models/favorite_group.rb @@ -1,15 +1,13 @@ -require 'ostruct' - class FavoriteGroup < ApplicationRecord validates_uniqueness_of :name, :case_sensitive => false, :scope => :creator_id validates_format_of :name, :with => /\A[^,]+\Z/, :message => "cannot have commas" belongs_to_creator - before_validation :normalize_post_ids before_validation :normalize_name before_validation :strip_name validate :creator_can_create_favorite_groups, :on => :create validate :validate_number_of_posts - before_save :update_post_count + + array_attribute :post_ids, parse: /\d+/, cast: :to_i module SearchMethods def for_creator(user_id) @@ -17,8 +15,7 @@ class FavoriteGroup < ApplicationRecord end def for_post(post_id) - regexp = "(^#{post_id}$|^#{post_id} | #{post_id}$| #{post_id} )" - where("favorite_groups.post_ids ~ ?", regexp) + where_array_includes_any(:post_ids, [post_id]) end def named(name) @@ -47,7 +44,7 @@ class FavoriteGroup < ApplicationRecord def search(params) q = super - q = q.search_attributes(params, :name, :is_public, :post_count) + q = q.search_attributes(params, :name, :is_public, :post_ids) if params[:creator_id].present? user = User.find(params[:creator_id]) @@ -91,15 +88,11 @@ class FavoriteGroup < ApplicationRecord end def validate_number_of_posts - if post_id_array.size > 10_000 - self.errors.add(:base, "Favorite groups can have up to 10,000 posts each") + if post_count > 10_000 + errors[:base] << "Favorite groups can have up to 10,000 posts each" end end - def normalize_post_ids - self.post_ids = post_ids.scan(/\d+/).uniq.join(" ") - end - def self.normalize_name(name) name.gsub(/[[:space:]]+/, "_") end @@ -126,94 +119,49 @@ class FavoriteGroup < ApplicationRecord name.tr("_", " ") end - def posts(options = {}) - offset = options[:offset] || 0 - limit = options[:limit] || Danbooru.config.posts_per_page - slice = post_id_array.slice(offset, limit) - if slice&.any? - slice.map do |id| - Post.find(id) - rescue ActiveRecord::RecordNotFound - # swallow - end.compact - else - [] - end + def posts + favgroup_posts = FavoriteGroup.where(id: id).joins("CROSS JOIN unnest(favorite_groups.post_ids) WITH ORDINALITY AS row(post_id, favgroup_index)").select(:post_id, :favgroup_index) + posts = Post.joins("JOIN (#{favgroup_posts.to_sql}) favgroup_posts ON favgroup_posts.post_id = posts.id").order("favgroup_posts.favgroup_index ASC") end - def post_id_array - @post_id_array ||= post_ids.scan(/\d+/).map(&:to_i) - end - - def post_id_array=(array) - self.post_ids = array.join(" ") - clear_post_id_array - end - - def post_id_array_was - @post_id_array_was ||= post_ids_was.scan(/\d+/).map(&:to_i) - end - - def clear_post_id_array - @post_id_array = nil - @post_id_array_was = nil - end - - def update_post_count - normalize_post_ids - clear_post_id_array - self.post_count = post_id_array.size - end - - def add!(post_id) + def add!(post) with_lock do - post_id = post_id.id if post_id.is_a?(Post) - return if contains?(post_id) - - clear_post_id_array - update(post_ids: add_number_to_string(post_id, post_ids)) + return if contains?(post.id) + update!(post_ids: post_ids + [post.id]) end end - def remove!(post_id) + def remove!(post) with_lock do - post_id = post_id.id if post_id.is_a?(Post) - return unless contains?(post_id) - - clear_post_id_array - update(post_ids: remove_number_from_string(post_id, post_ids)) + return unless contains?(post.id) + update!(post_ids: post_ids - [post.id]) end end - def add_number_to_string(number, string) - "#{string} #{number}" + def post_count + post_ids.size end - def remove_number_from_string(number, string) - string.gsub(/(?:\A| )#{number}(?:\Z| )/, " ") + def first_post?(post_id) + post_id == post_ids.first end - def neighbors(post) - @neighbor_posts ||= begin - post_ids =~ /\A#{post.id} (\d+)|(\d+) #{post.id} (\d+)|(\d+) #{post.id}\Z/ - - if $2 && $3 - OpenStruct.new(:previous => $2.to_i, :next => $3.to_i) - elsif $1 - OpenStruct.new(:next => $1.to_i) - elsif $4 - OpenStruct.new(:previous => $4.to_i) - else - OpenStruct.new - end - end + def last_post?(post_id) + post_id == post_ids.last end - def reload(options = {}) - super - @neighbor_posts = nil - clear_post_id_array - self + def previous_post_id(post_id) + return nil if first_post?(post_id) || !contains?(post_id) + + n = post_ids.index(post_id) - 1 + post_ids[n] + end + + def next_post_id(post_id) + return nil if last_post?(post_id) || !contains?(post_id) + + n = post_ids.index(post_id) + 1 + post_ids[n] end def last_page @@ -221,7 +169,7 @@ class FavoriteGroup < ApplicationRecord end def contains?(post_id) - post_ids =~ /(?:\A| )#{post_id}(?:\Z| )/ + post_ids.include?(post_id) end def editable_by?(user) diff --git a/app/models/pool.rb b/app/models/pool.rb index 652490d2d..e1873542d 100644 --- a/app/models/pool.rb +++ b/app/models/pool.rb @@ -34,15 +34,6 @@ class Pool < ApplicationRecord where("pools.category = ?", "collection") end - def series_first - order(Arel.sql("(case pools.category when 'series' then 0 else 1 end), pools.name")) - end - - def selected_first(current_pool_id) - return all if current_pool_id.blank? - reorder(Arel.sql("(case pools.id when #{current_pool_id.to_i} then 0 else 1 end), pools.name")) - end - def name_matches(name) name = normalize_name_for_search(name) name = "*#{name}*" unless name =~ /\*/ diff --git a/app/models/post.rb b/app/models/post.rb index f7c736ae6..0704236b4 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -822,19 +822,19 @@ class Post < ApplicationRecord when /^-favgroup:(\d+)$/i favgroup = FavoriteGroup.where("id = ?", $1.to_i).for_creator(CurrentUser.user.id).first - favgroup&.remove!(id) + favgroup&.remove!(self) when /^-favgroup:(.+)$/i favgroup = FavoriteGroup.named($1).for_creator(CurrentUser.user.id).first - favgroup&.remove!(id) + favgroup&.remove!(self) when /^favgroup:(\d+)$/i favgroup = FavoriteGroup.where("id = ?", $1.to_i).for_creator(CurrentUser.user.id).first - favgroup&.add!(id) + favgroup&.add!(self) when /^favgroup:(.+)$/i favgroup = FavoriteGroup.named($1).for_creator(CurrentUser.user.id).first - favgroup&.add!(id) + favgroup&.add!(self) end end @@ -962,21 +962,8 @@ class Post < ApplicationRecord ordered_users end - def favorite_groups(active_id = nil) - @favorite_groups ||= begin - groups = [] - - if active_id.present? - active_group = FavoriteGroup.where(:id => active_id.to_i).first - groups << active_group if active_group&.contains?(self.id) - end - - groups += CurrentUser.user.favorite_groups.select do |favgroup| - favgroup.contains?(self.id) - end - - groups.uniq - end + def favorite_groups + FavoriteGroup.for_post(id) end def remove_from_favorites @@ -988,7 +975,7 @@ class Post < ApplicationRecord def remove_from_fav_groups FavoriteGroup.for_post(id).find_each do |favgroup| - favgroup.remove!(id) + favgroup.remove!(self) end end end @@ -1008,7 +995,7 @@ class Post < ApplicationRecord module PoolMethods def pools - Pool.where("pools.post_ids && array[?]", id).series_first + Pool.where("pools.post_ids && array[?]", id) end def has_active_pools? @@ -1804,7 +1791,6 @@ class Post < ApplicationRecord super reset_tag_array_cache @pools = nil - @favorite_groups = nil @tag_categories = nil @typed_tags = nil self diff --git a/app/models/tag.rb b/app/models/tag.rb index 55466ce01..4c47daad2 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -602,7 +602,7 @@ class Tag < ApplicationRecord end q[:favgroups_neg] ||= [] - q[:favgroups_neg] << favgroup_id + q[:favgroups_neg] << favgroup when "favgroup" favgroup_id = FavoriteGroup.name_to_id(g2) @@ -613,7 +613,7 @@ class Tag < ApplicationRecord end q[:favgroups] ||= [] - q[:favgroups] << favgroup_id + q[:favgroups] << favgroup when "-fav" favuser = User.find_by_name(g2) diff --git a/app/presenters/post_presenter.rb b/app/presenters/post_presenter.rb index 430b2c33a..3980dc809 100644 --- a/app/presenters/post_presenter.rb +++ b/app/presenters/post_presenter.rb @@ -173,7 +173,7 @@ class PostPresenter < Presenter end def has_nav_links?(template) - has_sequential_navigation?(template.params) || @post.pools.undeleted.any? || @post.favorite_groups(active_id = template.params[:favgroup_id]).any? + has_sequential_navigation?(template.params) || @post.pools.undeleted.any? || CurrentUser.favorite_groups.for_post(@post.id).any? end def has_sequential_navigation?(params) diff --git a/app/presenters/post_set_presenters/favorite_group.rb b/app/presenters/post_set_presenters/favorite_group.rb deleted file mode 100644 index b2056f272..000000000 --- a/app/presenters/post_set_presenters/favorite_group.rb +++ /dev/null @@ -1,17 +0,0 @@ -module PostSetPresenters - class FavoriteGroup < PostSetPresenters::Pool - def post_previews_html(template) - html = "" - - if posts.empty? - return template.render("post_sets/blank") - end - - posts.each do |post| - html << PostPresenter.preview(post, :favgroup_id => post_set.pool.id, :show_deleted => true) - end - - html.html_safe - end - end -end diff --git a/app/presenters/post_set_presenters/pool.rb b/app/presenters/post_set_presenters/pool.rb deleted file mode 100644 index 1b0e312de..000000000 --- a/app/presenters/post_set_presenters/pool.rb +++ /dev/null @@ -1,24 +0,0 @@ -module PostSetPresenters - class Pool < Base - attr_reader :post_set - delegate :posts, :to => :post_set - - def initialize(post_set) - @post_set = post_set - end - - def post_previews_html(template) - html = "" - - if posts.empty? - return template.render("post_sets/blank") - end - - posts.each do |post| - html << PostPresenter.preview(post, :pool_id => post_set.pool.id) - end - - html.html_safe - end - end -end diff --git a/app/views/favorite_group_orders/edit.html.erb b/app/views/favorite_group_orders/edit.html.erb index d3a3099a2..460af7004 100644 --- a/app/views/favorite_group_orders/edit.html.erb +++ b/app/views/favorite_group_orders/edit.html.erb @@ -6,8 +6,8 @@ <%= render "posts/partials/common/inline_blacklist" %>