diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb index eb5409bfc..0033546c6 100644 --- a/app/controllers/uploads_controller.rb +++ b/app/controllers/uploads_controller.rb @@ -9,6 +9,11 @@ class UploadsController < ApplicationController end end + def index + @uploads = Upload.where("uploader_id = ?", @current_user.id).includes(:uploader).order("uploads.id desc").limit(10) + respond_with(@uploads) + end + def show @upload = Upload.find(params[:id]) end diff --git a/app/logical/favorite.rb b/app/logical/favorite.rb index 5f992fe66..1fe2dab49 100644 --- a/app/logical/favorite.rb +++ b/app/logical/favorite.rb @@ -12,7 +12,9 @@ class Favorite end def self.destroy_all_for_post(post) - ActiveRecord::Base.connection.execute("DELETE FROM #{table_name_for(user)} WHERE post_id = #{post.id}") + 0.upto(9) do |i| + ActiveRecord::Base.connection.execute("DELETE FROM favorites_#{i} WHERE post_id = #{post.id}") + end end def self.destroy_all_for_user(user) diff --git a/app/logical/post_set.rb b/app/logical/post_set.rb index 5a92bb53f..24dbfba68 100644 --- a/app/logical/post_set.rb +++ b/app/logical/post_set.rb @@ -1,7 +1,7 @@ class PostSet class Error < Exception ; end - attr_accessor :tags, :page, :current_user, :before_id, :errors + attr_accessor :tags, :page, :current_user, :before_id, :errors, :count attr_accessor :wiki_page, :artist, :posts, :suggestions def initialize(tags, page, current_user, before_id = nil) @@ -11,16 +11,24 @@ class PostSet @before_id = before_id @errors = [] load_associations - load_paginator + load_posts validate end + def use_sequential_paginator? + !use_numbered_paginator? + end + + def use_numbered_paginator? + before_id.nil? + end + def has_errors? errors.any? end def offset - x = (page - 1) * 20 + x = (page - 1) * limit if x < 0 x = 0 end @@ -28,7 +36,7 @@ class PostSet end def limit - 20 + Danbooru.config.posts_per_page end def is_single_tag? @@ -42,28 +50,13 @@ class PostSet end end - def load_paginator - if before_id - load_sequential_paginator - else - load_paginated_paginator - end - end - - def load_paginated_paginator + def load_posts + @count = Post.fast_count(tags) @posts = Post.find_by_tags(tags, :before_id => before_id).all(:order => "posts.id desc", :limit => limit, :offset => offset) end - def load_sequential_paginator - count = Post.fast_count(tags) - @posts = WillPaginate::Collection.create(page, limit, count) do |pager| - pager.replace(Post.find_by_sql(tags).all(:order => "posts.id desc", :limit => pager.per_page, :offset => pager.offset)) - end - load_suggestions(count) - end - def load_suggestions(count) - @suggestions = Tag.find_suggestions(tags) if count < 20 && is_single_tag? + @suggestions = Tag.find_suggestions(tags) if count < limit && is_single_tag? end def tag_array diff --git a/app/models/post.rb b/app/models/post.rb index 2f296c7b4..b86d82898 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -2,6 +2,7 @@ class Post < ActiveRecord::Base attr_accessor :updater_id, :updater_ip_addr, :old_tag_string after_destroy :delete_files after_destroy :delete_favorites + after_destroy :update_tag_post_counts after_save :create_version before_save :merge_old_tags before_save :normalize_tags @@ -9,6 +10,7 @@ class Post < ActiveRecord::Base before_save :update_tag_post_counts before_save :set_tag_counts belongs_to :updater, :class_name => "User" + belongs_to :approver, :class_name => "User" has_one :unapproval, :dependent => :destroy has_one :upload, :dependent => :destroy has_one :moderation_detail, :class_name => "PostModerationDetail", :dependent => :destroy @@ -16,6 +18,7 @@ class Post < ActiveRecord::Base has_many :votes, :class_name => "PostVote", :dependent => :destroy has_many :notes, :dependent => :destroy validates_presence_of :updater_id, :updater_ip_addr + validates_uniqueness_of :md5 attr_accessible :source, :rating, :tag_string, :old_tag_string, :updater_id, :updater_ip_addr, :last_noted_at module FileMethods @@ -74,6 +77,10 @@ class Post < ActiveRecord::Base file_url end end + + def is_image? + file_ext =~ /jpg|gif|png/ + end end module ImageMethods @@ -168,6 +175,12 @@ class Post < ActiveRecord::Base increment_tags = tag_array - tag_array_was execute_sql("UPDATE tags SET post_count = post_count - 1 WHERE name IN (?)", decrement_tags) if decrement_tags.any? execute_sql("UPDATE tags SET post_count = post_count + 1 WHERE name IN (?)", increment_tags) if increment_tags.any? + decrement_tags.each do |tag| + expire_cache(tag) + end + increment_tags.each do |tag| + expire_cache(tag) + end end def set_tag_counts @@ -501,15 +514,32 @@ class Post < ActiveRecord::Base module CountMethods def fast_count(tags) - Cache.get("pfc:#{Cache.sanitize(tags)}", 24.hours) do - Post.find_by_tags(tags).count - end + count = Cache.get("pfc:#{Cache.sanitize(tags)}") + return count unless count.nil? + count = Post.find_by_tags(tags).count + expiry = (count < 100) ? 0 : (count * 4).minutes + Cache.put("pfc:#{Cache.sanitize(tags)}", count, expiry) + count end def fast_delete_count(tags) - Cache.get("pfdc:#{Cache.sanitize(tags)}", 24.hours) do - Post.find_by_tags("#{tags} status:deleted").count + count = Cache.get("pfdc:#{Cache.sanitize(tags)}") + return count unless count.nil? + count = Post.find_by_tags("#{tags} status:deleted").count + expiry = (count < 100) ? 0 : (count * 4).minutes + Cache.put("pfc:#{Cache.sanitize(tags)}", count, expiry) + count + end + end + + module CacheMethods + def expire_cache(tag_name) + if Post.fast_count("") < 1000 + Cache.delete("pfc:") + Cache.delete("pfdc:") end + Cache.delete("pfc:#{Cache.sanitize(tag_name)}") + Cache.delete("pfdc:#{Cache.sanitize(tag_name)}") end end @@ -525,9 +555,14 @@ class Post < ActiveRecord::Base extend SearchMethods include VoteMethods extend CountMethods + include CacheMethods def reload(options = nil) super reset_tag_array_cache end + + def presenter + @presenter ||= PostPresenter.new(self) + end end diff --git a/app/models/upload.rb b/app/models/upload.rb index eb41d6951..841d924ce 100644 --- a/app/models/upload.rb +++ b/app/models/upload.rb @@ -18,6 +18,12 @@ class Upload < ActiveRecord::Base raise end end + + # Because uploads are processed serially, there's no race condition here. + def validate_md5_uniqueness + md5_post = Post.find_by_md5(md5) + merge_tags(md5_post) if md5_post + end def validate_file_exists unless File.exists?(file_path) @@ -51,6 +57,7 @@ class Upload < ActiveRecord::Base self.file_ext = content_type_to_file_ext(content_type) validate_file_content_type calculate_hash(file_path) + validate_md5_uniqueness validate_md5_confirmation calculate_file_size(file_path) calculate_dimensions(file_path) if has_dimensions? @@ -85,6 +92,15 @@ class Upload < ActiveRecord::Base end end end + + def merge_tags(post) + post.tag_string += " #{tag_string}" + post.updater_id = uploader_id + post.updater_ip_addr = uploader_ip_addr + post.save + update_attribute(:status, "duplicate: #{post.id}") + raise + end end module FileMethods @@ -274,4 +290,8 @@ class Upload < ActiveRecord::Base include FilePathMethods include CgiFileMethods include StatusMethods + + def presenter + @presenter ||= UploadPresenter.new(self) + end end \ No newline at end of file diff --git a/app/presenters/paginator_presenter.rb b/app/presenters/paginator_presenter.rb index aabd68dc6..48a747f61 100644 --- a/app/presenters/paginator_presenter.rb +++ b/app/presenters/paginator_presenter.rb @@ -1,2 +1,2 @@ -class PaginatorPresenter +class PaginatorPresenter < Presenter end diff --git a/app/presenters/post_presenter.rb b/app/presenters/post_presenter.rb new file mode 100644 index 000000000..c07a7b51c --- /dev/null +++ b/app/presenters/post_presenter.rb @@ -0,0 +1,14 @@ +class PostPresenter < Presenter + def initialize(post) + @post = post + end + + def tag_list_html + end + + def image_html + end + + def note_html + end +end diff --git a/app/presenters/post_set_presenter.rb b/app/presenters/post_set_presenter.rb index 0a2f993c2..33a207eb8 100644 --- a/app/presenters/post_set_presenter.rb +++ b/app/presenters/post_set_presenter.rb @@ -1,3 +1,5 @@ +require 'pp' + class PostSetPresenter < Presenter attr_accessor :post_set @@ -17,7 +19,80 @@ class PostSetPresenter < Presenter "" end - def pagination_html + def pagination_html(template) + if @post_set.use_sequential_paginator? + sequential_pagination_html(template) + else + numbered_pagination_html(template) + end + end + + def sequential_pagination_html(template) + html = "
" + html.html_safe + end + + def numbered_pagination_html(template) + total_pages = (@post_set.count.to_f / @post_set.limit.to_f).ceil + current_page = [1, @post_set.page].max + before_current_page = current_page - 1 + after_current_page = current_page + 1 + html = "" + html.html_safe + end + + def numbered_pagination_item(template, page) + html = "