diff --git a/Gemfile b/Gemfile
index 86300e1e9..7786f5468 100644
--- a/Gemfile
+++ b/Gemfile
@@ -8,7 +8,7 @@ group :test do
gem "faker"
end
-gem "rails", "3.0.0.beta3"
+gem "rails", "3.0.0.rc"
gem "pg"
gem "memcache-client", :require => "memcache"
gem "imagesize", :require => "image_size"
diff --git a/Rakefile b/Rakefile
index 9cb204643..f18d325ad 100644
--- a/Rakefile
+++ b/Rakefile
@@ -2,9 +2,6 @@
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__)
-
require 'rake'
-require 'rake/testtask'
-require 'rake/rdoctask'
-Rails::Application.load_tasks
+Danbooru::Application.load_tasks
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index dcd6faa0d..77e4d2449 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -1,6 +1,7 @@
class ApplicationController < ActionController::Base
protect_from_forgery
before_filter :set_current_user
+ after_filter :reset_current_user
before_filter :initialize_cookies
layout "default"
@@ -27,24 +28,29 @@ protected
def set_current_user
if session[:user_id]
- @current_user = User.find_by_id(session[:user_id])
+ CurrentUser.user = User.find_by_id(session[:user_id])
+ CurrentUser.ip_addr = request.remote_ip
end
- if @current_user
- if @current_user.is_banned? && @current_user.ban && @current_user.ban.expires_at < Time.now
- @current_user.update_attribute(:is_banned, false)
- Ban.destroy_all("user_id = #{@current_user.id}")
+ if CurrentUser.user
+ if CurrentUser.user.is_banned? && CurrentUser.user.ban && CurrentUser.user.ban.expires_at < Time.now
+ CurrentUser.user.unban!
end
else
- @current_user = AnonymousUser.new
+ CurrentUser.user = AnonymousUser.new
end
- Time.zone = @current_user.time_zone
+ Time.zone = CurrentUser.user.time_zone
+ end
+
+ def reset_current_user
+ CurrentUser.user = nil
+ CurrentUser.ip_addr = nil
end
%w(member banned privileged contributor janitor moderator admin).each do |level|
define_method("#{level}_only") do
- if @current_user.__send__("is_#{level}?")
+ if CurrentUser.user.__send__("is_#{level}?")
true
else
access_denied()
@@ -53,10 +59,10 @@ protected
end
def initialize_cookies
- if @current_user.is_anonymous?
+ if CurrentUser.user.is_anonymous?
cookies["blacklisted_tags"] = ""
else
- cookies["blacklisted_tags"] = @current_user.blacklisted_tags
+ cookies["blacklisted_tags"] = CurrentUser.user.blacklisted_tags
end
end
end
diff --git a/app/controllers/artists_controller.rb b/app/controllers/artists_controller.rb
index 2b83ec653..d13fe52c9 100644
--- a/app/controllers/artists_controller.rb
+++ b/app/controllers/artists_controller.rb
@@ -1,11 +1,16 @@
class ArtistsController < ApplicationController
def new
+ @artist = Artist.new_with_defaults(params)
end
def edit
+ @artist = Artist.find(params[:id])
end
def index
+ order = params[:order] == "date" ? "updated_at DESC" : "name"
+ limit = params[:limit] || 50
+ @artists = Artist.paginate(Artist.build_relation())
end
def show
diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb
index 4171b4be3..672437795 100644
--- a/app/controllers/comments_controller.rb
+++ b/app/controllers/comments_controller.rb
@@ -2,6 +2,7 @@ class CommentsController < ApplicationController
respond_to :html, :xml, :json
def index
+ @posts = Post.paginate :order => "last_commented_at DESC", :per_page => 8
end
def update
diff --git a/app/controllers/favorites_controller.rb b/app/controllers/favorites_controller.rb
index f36237cf8..5b5cff9c5 100644
--- a/app/controllers/favorites_controller.rb
+++ b/app/controllers/favorites_controller.rb
@@ -1,7 +1,15 @@
class FavoritesController < ApplicationController
def create
+ @favorite = Favorite.create(
+ :user_id => @current_user.id,
+ :post_id => params[:favorite][:post_id]
+ )
end
def destroy
+ Favorite.destroy(
+ :user_id => @current_user.id,
+ :post_id => params[:favorite][:post_id]
+ )
end
end
diff --git a/app/helpers/posts_helper.rb b/app/helpers/posts_helper.rb
index db1e2f370..83bc4d372 100644
--- a/app/helpers/posts_helper.rb
+++ b/app/helpers/posts_helper.rb
@@ -1,27 +1,16 @@
module PostsHelper
- def image_dimensions(post, current_user)
- if post.is_image?
- "(#{post.image_width_for(current_user)}x#{post.image_height_for(current_user)})"
+ def resize_image_links(post, user)
+ links = []
+
+ links << %{Original} if post.has_medium? || post.has_large?
+ links << %{Medium} if post.has_medium?
+ links << %{Large} if post.has_large?
+
+ if links.any?
+ html = %{
Resize} + links.map {|x| %{- #{x}
}}.join("") + %{
}
+ html.html_safe
else
""
end
end
-
- def image_dimension_menu(post, current_user)
- html = ""
- file_size = number_to_human_size(post.file_size)
- original_dimensions = post.is_image? ? "(#{post.image_width}x#{post.image_height})" : nil
- large_dimensions = post.has_large? ? "(#{post.large_image_width}x#{post.large_image_height})" : nil
- medium_dimensions = post.has_medium? ? "(#{post.medium_image_width}x#{post.medium_image_height})" : nil
- current_dimensions = "(#{post.image_width_for(current_user)}x#{post.image_height_for(current_user)})"
- html << %{}
- html << %{- #{file_size} #{original_dimensions}
}
- html << %{- #{file_size} #{medium_dimensions}
} if medium_dimensions
- html << %{- #{file_size} #{large_dimensions}
} if large_dimensions
- html << %{
}
- html << %{}
- html.html_safe
- end
end
diff --git a/app/logical/favorite.rb b/app/logical/favorite.rb
index 1fe2dab49..2ce80c134 100644
--- a/app/logical/favorite.rb
+++ b/app/logical/favorite.rb
@@ -1,23 +1,60 @@
class Favorite
- def self.table_name_for(user)
- "favorites_#{user.id % 10}"
+ attr_accessor :attributes, :errors
+
+ def self.table_name_for(user_id)
+ "favorites_#{user_id.to_i % 10}"
end
- def self.create(user, post)
- ActiveRecord::Base.connection.execute("INSERT INTO #{table_name_for(user)} (user_id, post_id) VALUES (#{user.id}, #{post.id})")
+ def self.create(attributes)
+ user_id = attributes[:user_id]
+ post_id = attributes[:post_id]
+ execute_sql("INSERT INTO #{table_name_for(user_id)} (user_id, post_id) VALUES (?, ?)", user_id, post_id)
+ rescue ActiveRecord::RecordNotUnique
+ # ignore
end
- def self.destroy(user, post)
- ActiveRecord::Base.connection.execute("DELETE FROM #{table_name_for(user)} WHERE user_id = #{user.id} AND post_id = #{post.id}")
+ def self.destroy(conditions)
+ if conditions[:user_id] && conditions[:post_id]
+ destroy_for_post_and_user(conditions[:post_id], conditions[:user_id])
+ elsif conditions[:user_id]
+ destroy_for_user(conditions[:user_id])
+ elsif conditions[:post_id]
+ destroy_for_post(conditions[:post_id])
+ end
+ end
+
+ def self.exists?(conditions)
+ if conditions[:user_id] && conditions[:post_id]
+ select_value_sql("SELECT 1 FROM #{table_name_for(conditions[:user_id])} WHERE user_id = ? AND post_id = ?", conditions[:user_id], conditions[:post_id])
+ elsif conditions[:user_id]
+ select_value_sql("SELECT 1 FROM #{table_name_for(conditions[:user_id])} WHERE user_id = ?", conditions[:user_id])
+ elsif conditions[:post_id]
+ select_value_sql("SELECT 1 FROM #{table_name_for(conditions[:user_id])} WHERE post_id = ?", conditions[:post_id])
+ else
+ false
+ end
+ end
+
+private
+ def self.destroy_for_post_and_user(post_id, user_id)
+ execute_sql("DELETE FROM #{table_name_for(user_id)} WHERE post_id = #{post_id} AND user_id = #{user_id}")
end
- def self.destroy_all_for_post(post)
+ def self.destroy_for_post(post)
0.upto(9) do |i|
- ActiveRecord::Base.connection.execute("DELETE FROM favorites_#{i} WHERE post_id = #{post.id}")
+ execute_sql("DELETE FROM favorites_#{i} WHERE post_id = #{post.id}")
end
end
- def self.destroy_all_for_user(user)
- ActiveRecord::Base.connection.execute("DELETE FROM #{table_name_for(user)} WHERE user_id = #{user.id}")
+ def self.destroy_for_user(user)
+ execute_sql("DELETE FROM #{table_name_for(user)} WHERE user_id = #{user.id}")
+ end
+
+ def self.select_value_sql(sql, *params)
+ ActiveRecord::Base.select_value_sql(sql, *params)
+ end
+
+ def self.execute_sql(sql, *params)
+ ActiveRecord::Base.execute_sql(sql, *params)
end
end
diff --git a/app/models/artist.rb b/app/models/artist.rb
index 5d5332ed2..bac0afa27 100644
--- a/app/models/artist.rb
+++ b/app/models/artist.rb
@@ -3,7 +3,7 @@ class Artist < ActiveRecord::Base
before_create :initialize_creator
before_save :normalize_name
after_save :create_version
- after_save :commit_url_string
+ after_save :save_url_string
validates_uniqueness_of :name
validates_presence_of :updater_id, :updater_ip_addr
belongs_to :updater, :class_name => "User"
@@ -36,7 +36,7 @@ class Artist < ActiveRecord::Base
m.extend(ClassMethods)
end
- def commit_url_string
+ def save_url_string
if @url_string
artist_urls.clear
@@ -82,7 +82,7 @@ class Artist < ActiveRecord::Base
module UpdaterMethods
def updater_name
- User.find_name(updater_id).tr("_", " ")
+ User.id_to_name(updater_id).tr("_", " ")
end
end
@@ -150,12 +150,35 @@ class Artist < ActiveRecord::Base
end
end
+ module FactoryMethods
+ def new_with_defaults(params)
+ returning(Artist.new) do |artist|
+ if params[:name]
+ artist.name = params[:name]
+ post = Post.find_by_tags("source:http* #{artist.name}").first
+ unless post.nil? || post.source.blank?
+ artist.url_string = post.source
+ end
+ end
+
+ if params[:other_names]
+ artist.other_names = params[:other_names]
+ end
+
+ if params[:urls]
+ artist.url_string = params[:urls]
+ end
+ end
+ end
+ end
+
include UrlMethods
include NameMethods
include GroupMethods
include UpdaterMethods
extend SearchMethods
include VersionMethods
+ extend FactoryMethods
def initialize_creator
if creator.nil?
diff --git a/app/models/artist_version.rb b/app/models/artist_version.rb
index 756bb2cde..d4c71129a 100644
--- a/app/models/artist_version.rb
+++ b/app/models/artist_version.rb
@@ -3,6 +3,6 @@ class ArtistVersion < ActiveRecord::Base
belongs_to :artist
def updater_name
- User.find_name(updater_id).tr("_", " ")
+ User.id_to_name(updater_id).tr("_", " ")
end
end
diff --git a/app/models/comment.rb b/app/models/comment.rb
index e31f5f9dd..5c81126f9 100644
--- a/app/models/comment.rb
+++ b/app/models/comment.rb
@@ -13,7 +13,7 @@ class Comment < ActiveRecord::Base
scope :hidden, lambda {|user| where("score < ?", user.comment_threshold)}
def creator_name
- User.find_name(creator_id)
+ User.id_to_name(creator_id)
end
def validate_creator_is_not_limited
diff --git a/app/models/dmail.rb b/app/models/dmail.rb
index 376c9a3fd..1ce321df3 100644
--- a/app/models/dmail.rb
+++ b/app/models/dmail.rb
@@ -18,11 +18,11 @@ class Dmail < ActiveRecord::Base
module AddressMethods
def to_name
- User.find_pretty_name(to_id)
+ User.id_to_pretty_name(to_id)
end
def from_name
- User.find_pretty_name(from_id)
+ User.id_to_pretty_name(from_id)
end
def to_name=(name)
diff --git a/app/models/job.rb b/app/models/job.rb
index c4e9e5843..57f322371 100644
--- a/app/models/job.rb
+++ b/app/models/job.rb
@@ -120,7 +120,7 @@ class Job < ActiveRecord::Base
when "mass_tag_edit"
start = data["start_tags"]
result = data["result_tags"]
- user = User.find_name(data["updater_id"])
+ user = User.id_to_name(data["updater_id"])
"start:#{start} result:#{result} user:#{user}"
when "approve_tag_alias"
diff --git a/app/models/note.rb b/app/models/note.rb
index 113fd6f30..02014d2f3 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -37,7 +37,7 @@ class Note < ActiveRecord::Base
end
def creator_name
- User.find_name(creator_id)
+ User.id_to_name(creator_id)
end
def update_post
diff --git a/app/models/note_version.rb b/app/models/note_version.rb
index 14d88626a..d9ca9a646 100644
--- a/app/models/note_version.rb
+++ b/app/models/note_version.rb
@@ -1,5 +1,5 @@
class NoteVersion < ActiveRecord::Base
def updater_name
- User.find_name(updater_id)
+ User.id_to_name(updater_id)
end
end
diff --git a/app/models/pool.rb b/app/models/pool.rb
index 62c1bec60..156b1001e 100644
--- a/app/models/pool.rb
+++ b/app/models/pool.rb
@@ -6,9 +6,14 @@ class Pool < ActiveRecord::Base
belongs_to :creator, :class_name => "User"
belongs_to :updater, :class_name => "User"
has_many :versions, :class_name => "PoolVersion", :dependent => :destroy
+ before_save :normalize_name
after_save :create_version
attr_accessible :name, :description, :post_ids, :is_public, :is_active
+ def self.name_to_id(name)
+ select_value_sql("SELECT id FROM pools WHERE name = ?", name.downcase)
+ end
+
def self.create_anonymous(creator, creator_ip_addr)
Pool.new do |pool|
pool.name = "TEMP:#{Time.now.to_f}.#{rand(1_000_000)}"
@@ -21,6 +26,10 @@ class Pool < ActiveRecord::Base
end
end
+ def normalize_name
+ self.name = name.downcase
+ end
+
def revert_to!(version)
self.post_ids = version.post_ids
save
diff --git a/app/models/post.rb b/app/models/post.rb
index 5cc253bd6..670cebda2 100644
--- a/app/models/post.rb
+++ b/app/models/post.rb
@@ -1,9 +1,8 @@
class Post < ActiveRecord::Base
- attr_accessor :updater_id, :updater_ip_addr, :old_tag_string, :should_create_pool
+ attr_accessor :old_tag_string, :old_parent_id
after_destroy :delete_files
- after_destroy :delete_favorites
- after_destroy :update_tag_post_counts
after_save :create_version
+ after_save :update_parent_on_save
before_save :merge_old_tags
before_save :normalize_tags
before_save :create_tags
@@ -11,6 +10,7 @@ class Post < ActiveRecord::Base
before_save :set_tag_counts
belongs_to :updater, :class_name => "User"
belongs_to :approver, :class_name => "User"
+ belongs_to :parent, :class_name => "Post"
has_one :unapproval, :dependent => :destroy
has_one :upload, :dependent => :destroy
has_one :moderation_detail, :class_name => "PostModerationDetail", :dependent => :destroy
@@ -18,9 +18,11 @@ class Post < ActiveRecord::Base
has_many :votes, :class_name => "PostVote", :dependent => :destroy
has_many :notes, :dependent => :destroy
has_many :comments
- validates_presence_of :updater_id, :updater_ip_addr
+ has_many :children, :class_name => "Post", :foreign_key => "parent_id", :order => "posts.id"
validates_uniqueness_of :md5
- attr_accessible :source, :rating, :tag_string, :old_tag_string, :updater_id, :updater_ip_addr, :last_noted_at
+ validates_presence_of :parent, :if => lambda {|rec| !rec.parent_id.nil?}
+ validate :validate_parent_does_not_have_a_parent
+ attr_accessible :source, :rating, :tag_string, :old_tag_string, :last_noted_at
module FileMethods
def delete_files
@@ -179,13 +181,13 @@ class Post < ActiveRecord::Base
end
end
- module ModerationMethods
- def unapprove!(reason, current_user, current_ip_addr)
+ module ApprovalMethods
+ def unapprove!(reason)
raise Unapproval::Error.new("You can't unapprove a post more than once") if is_flagged?
unapproval = create_unapproval(
- :unapprover_id => current_user.id,
- :unapprover_ip_addr => current_ip_addr,
+ :unapprover_id => CurrentUser.user.id,
+ :unapprover_ip_addr => CurrentUser.ip_addr,
:reason => reason
)
@@ -193,15 +195,13 @@ class Post < ActiveRecord::Base
raise Unapproval::Error.new(unapproval.errors.full_messages.join("; "))
end
- update_attribute(:is_flagged, true)
+ toggle!(:is_flagged)
end
-
- def delete!
- update_attribute(:is_deleted, true)
- end
-
+
def approve!
- update_attributes(:is_deleted => false, :is_pending => false)
+ update_attributes(
+ :is_pending => false
+ )
end
end
@@ -226,19 +226,17 @@ class Post < ActiveRecord::Base
:source => source,
:rating => rating,
:tag_string => tag_string,
- :updater_id => updater_id,
- :updater_ip_addr => updater_ip_addr
+ :updater_id => CurrentUser.user.id,
+ :updater_ip_addr => CurrentUser.ip_addr
)
raise PostVersion::Error.new(version.errors.full_messages.join("; ")) if version.errors.any?
end
- def revert_to!(version, reverter_id, reverter_ip_addr)
+ def revert_to!(version)
self.source = version.source
self.rating = version.rating
self.tag_string = version.tag_string
- self.updater_id = reverter_id
- self.updater_ip_addr = reverter_ip_addr
save!
end
end
@@ -256,6 +254,14 @@ class Post < ActiveRecord::Base
set_tag_string(tag_array.map {|x| Tag.find_or_create_by_name(x).name}.join(" "))
end
+ def increment_tag_post_counts
+ execute_sql("UPDATE tags SET post_count = post_count + 1 WHERE name IN (?)", tag_array) if tag_array.any?
+ end
+
+ def decrement_tag_post_counts
+ execute_sql("UPDATE tags SET post_count = post_count - 1 WHERE name IN (?)", tag_array) if tag_array.any?
+ end
+
def update_tag_post_counts
decrement_tags = tag_array_was - tag_array
increment_tags = tag_array - tag_array_was
@@ -333,19 +339,44 @@ class Post < ActiveRecord::Base
module FavoriteMethods
def delete_favorites
- Favorite.destroy_all_for_post(self)
+ Favorite.destroy_for_post(self)
end
def add_favorite(user)
- self.fav_string += " fav:#{user.name}"
+ if user.is_a?(ActiveRecord::Base)
+ user_id = user.id
+ else
+ user_id = user
+ end
+
+ return false if fav_string =~ /fav:#{user_id}/
+ self.fav_string += " fav:#{user_id}"
self.fav_string.strip!
- Favorite.create(user, self)
+
+ # in order to avoid rerunning the callbacks, just update through raw sql
+ execute_sql("UPDATE posts SET fav_string = ? WHERE id = ?", fav_string, id)
+
+ Favorite.create(:user_id => user_id, :post_id => id)
end
def remove_favorite(user)
- self.fav_string.gsub!(/(?:\A| )fav:#{user.name}(?:\Z| )/, " ")
+ if user.is_a?(ActiveRecord::Base)
+ user_id = user.id
+ else
+ user_id = user
+ end
+
+ self.fav_string.gsub!(/(?:\A| )fav:#{user_id}(?:\Z| )/, " ")
self.fav_string.strip!
- Favorite.destroy(user, self)
+
+ # in order to avoid rerunning the callbacks, just update through raw sql
+ execute_sql("UPDATE posts SET fav_string = ? WHERE id = ?", fav_string, id)
+
+ Favorite.destroy(:user_id => user_id, :post_id => id)
+ end
+
+ def favorited_user_ids
+ fav_string.scan(/\d+/)
end
end
@@ -435,7 +466,11 @@ class Post < ActiveRecord::Base
q = Tag.parse_query(q)
end
- relation = where()
+ if q[:status] == "deleted"
+ relation = RemovedPost.where()
+ else
+ relation = where()
+ end
relation = add_range_relation(q[:post_id], "posts.id", relation)
relation = add_range_relation(q[:mpixels], "posts.width * posts.height / 1000000.0", relation)
@@ -458,14 +493,10 @@ class Post < ActiveRecord::Base
relation = relation.where(["posts.md5 IN (?)", q[:md5]])
end
- if q[:status] == "deleted"
- relation = relation.where("posts.is_deleted = TRUE")
- elsif q[:status] == "pending"
+ if q[:status] == "pending"
relation = relation.where("posts.is_pending = TRUE")
elsif q[:status] == "flagged"
relation = relation.where("posts.is_flagged = TRUE")
- else
- relation = relation.where("posts.is_deleted = FALSE")
end
if q[:source].is_a?(String)
@@ -477,7 +508,7 @@ class Post < ActiveRecord::Base
end
relation = add_tag_string_search_relation(q[:tags], relation)
-
+
if q[:rating] == "q"
relation = relation.where("posts.rating = 'q'")
elsif q[:rating] == "s"
@@ -553,31 +584,31 @@ class Post < ActiveRecord::Base
end
def uploader_id
- uploader.id
- end
-
- def uploader_name
uploader_string[9..-1]
end
+ def uploader_name
+ User.id_to_name(uploader_id)
+ end
+
def uploader
- User.find_by_name(uploader_name)
+ User.find(uploader_id)
end
def uploader=(user)
- self.uploader_string = "uploader:#{user.name}"
+ self.uploader_string = "uploader:#{user.id}"
end
end
module PoolMethods
def add_pool(pool)
- self.pool_string += " pool:#{pool.name}"
+ self.pool_string += " pool:#{pool.id}"
self.pool_string.strip!
pool.add_post!(self)
end
def remove_pool(pool)
- self.pool_string.gsub!(/(?:\A| )pool:#{pool.name}(?:\Z| )/, " ")
+ self.pool_string.gsub!(/(?:\A| )pool:#{pool.id}(?:\Z| )/, " ")
self.pool_string.strip!
pool.remove_post!(self)
end
@@ -631,9 +662,106 @@ class Post < ActiveRecord::Base
end
end
+ module ParentMethods
+ # A parent has many children. A child belongs to a parent.
+ # A parent cannot have a parent.
+ #
+ # After deleting a child:
+ # - Move favorites to parent.
+ # - Does the parent have any active children?
+ # - Yes: Done.
+ # - No: Update parent's has_children flag to false.
+ #
+ # After deleting a parent:
+ # - Move favorites to the first child.
+ # - Reparent all active children to the first active child.
+
+ module ClassMethods
+ def update_has_children_flag_for(post_id)
+ has_children = Post.exists?(["parent_id = ?", post_id])
+ execute_sql("UPDATE posts SET has_children = ? WHERE id = ?", has_children, post_id)
+ end
+
+ def recalculate_has_children_for_all_posts
+ transaction do
+ execute_sql("UPDATE posts SET has_children = false WHERE has_children = true")
+ execute_sql("UPDATE posts SET has_children = true WHERE id IN (SELECT p.parent_id FROM posts p WHERE p.parent_id IS NOT NULL)")
+ end
+ end
+ end
+
+ def self.included(m)
+ m.extend(ClassMethods)
+ end
+
+ def validate_parent_does_not_have_a_parent
+ return if parent.nil?
+ if !parent.parent.nil?
+ errors.add(:parent, "can not have a parent")
+ end
+ end
+
+ def update_parent_on_destroy
+ Post.update_has_children_flag_for(parent_id)
+ Post.update_has_children_flag_for(parent_id_was) if parent_id_was && parent_id != parent_id_was
+ end
+
+ def update_children_on_destroy
+ if children.size == 0
+ # do nothing
+ elsif children.size == 1
+ children.first.update_attribute(:parent_id, nil)
+ else
+ cached_children = children
+ cached_children[1..-1].each do |child|
+ child.update_attribute(:parent_id, cached_children[0].id)
+ end
+ cached_children[0].update_attribute(:parent_id, nil)
+ end
+ end
+
+ def update_parent_on_save
+ if parent_id == parent_id_was
+ # do nothing
+ elsif !parent_id_was.nil?
+ Post.update_has_children_flag_for(parent_id)
+ Post.update_has_children_flag_for(parent_id_was)
+ else
+ Post.update_has_children_flag_for(parent_id)
+ end
+ end
+
+ def give_favorites_to_parent
+ return if parent.nil?
+
+ favorited_user_ids.each do |user_id|
+ parent.add_favorite(user_id)
+ remove_favorite(user_id)
+ end
+ end
+
+ def delete_favorites
+ Favorite.destroy_for_post(self)
+ end
+ end
+
+ module RemovalMethods
+ def remove!
+ Post.transaction do
+ execute_sql("INSERT INTO removed_posts (#{Post.column_names.join(', ')}) SELECT #{Post.column_names.join(', ')} FROM posts WHERE posts.id = #{id}")
+ give_favorites_to_parent
+ update_children_on_destroy
+ delete_favorites
+ decrement_tag_post_counts
+ execute_sql("DELETE FROM posts WHERE id = #{id}")
+ update_parent_on_destroy
+ end
+ end
+ end
+
include FileMethods
include ImageMethods
- include ModerationMethods
+ include ApprovalMethods
include PresenterMethods
include VersionMethods
include TagMethods
@@ -644,6 +772,8 @@ class Post < ActiveRecord::Base
include VoteMethods
extend CountMethods
include CacheMethods
+ include ParentMethods
+ include RemovalMethods
def reload(options = nil)
super
diff --git a/app/models/tag.rb b/app/models/tag.rb
index 62c32c0c1..f2d43f200 100644
--- a/app/models/tag.rb
+++ b/app/models/tag.rb
@@ -217,22 +217,22 @@ class Tag < ActiveRecord::Base
if token =~ /\A(-uploader|uploader|-pool|pool|-fav|fav|sub|md5|-rating|rating|width|height|mpixels|score|filesize|source|id|date|order|status|tagcount|gentags|arttags|chartags|copytags):(.+)\Z/
case $1
when "-uploader"
- q[:tags][:exclude] << token[1..-1]
+ q[:tags][:exclude] << "uploader:#{User.name_to_id(token[1..-1])}"
when "uploader"
- q[:tags][:related] << token
+ q[:tags][:related] << "uploader:#{User.name_to_id(token)}"
when "-pool"
- q[:tags][:exclude] << token[1..-1]
+ q[:tags][:exclude] << "pool:#{Pool.name_to_id(token[1..-1])}"
when "pool"
- q[:tags][:related] << token
+ q[:tags][:related] << "pool:#{Pool.name_to_id(token)}"
when "-fav"
- q[:tags][:exclude] << token[1..-1]
+ q[:tags][:exclude] << "fav:#{User.name_to_id(token[1..-1])}"
when "fav"
- q[:tags][:related] << token
+ q[:tags][:related] << "fav:#{User.name_to_id(token)}"
when "sub"
q[:subscriptions] << $2
diff --git a/app/models/user.rb b/app/models/user.rb
index 8e0a40ba0..d994d01f3 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -20,6 +20,7 @@ class User < ActiveRecord::Base
before_create :promote_to_admin_if_first_user
before_create :normalize_level
has_many :feedback, :class_name => "UserFeedback", :dependent => :destroy
+ has_one :ban
belongs_to :inviter, :class_name => "User"
scope :named, lambda {|name| where(["lower(name) = ?", name])}
@@ -30,12 +31,23 @@ class User < ActiveRecord::Base
return false
end
end
+
+ def unban!
+ update_attribute(:is_banned, false)
+ ban.destroy
+ end
end
module NameMethods
module ClassMethods
- def find_name(user_id)
- Cache.get("un:#{user_id}") do
+ def name_to_id(name)
+ Cache.get("uni:#{Cache.sanitize(name)}") do
+ select_value_sql("SELECT id FROM users WHERE name = ?", name.downcase)
+ end
+ end
+
+ def id_to_name(user_id)
+ Cache.get("uin:#{user_id}") do
select_value_sql("SELECT name FROM users WHERE id = ?", user_id) || Danbooru.config.default_guest_name
end
end
@@ -44,8 +56,8 @@ class User < ActiveRecord::Base
where(["lower(name) = ?", name.downcase]).first
end
- def find_pretty_name(user_id)
- find_name.tr("_", " ")
+ def id_to_pretty_name(user_id)
+ id_to_name.tr("_", " ")
end
end
@@ -58,7 +70,7 @@ class User < ActiveRecord::Base
end
def update_cache
- Cache.put("un:#{id}", name)
+ Cache.put("uin:#{id}", name)
end
end
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
index 8e3cde121..b14b34592 100644
--- a/app/models/wiki_page.rb
+++ b/app/models/wiki_page.rb
@@ -45,7 +45,7 @@ class WikiPage < ActiveRecord::Base
end
def creator_name
- User.find_name(user_id).tr("_", " ")
+ User.id_to_name(user_id).tr("_", " ")
end
def pretty_title
diff --git a/app/models/wiki_page_version.rb b/app/models/wiki_page_version.rb
index 43bea5863..199ea5464 100644
--- a/app/models/wiki_page_version.rb
+++ b/app/models/wiki_page_version.rb
@@ -3,7 +3,7 @@ class WikiPageVersion < ActiveRecord::Base
belongs_to :updater
def updater_name
- User.find_name(updater_id)
+ User.id_to_name(updater_id)
end
def pretty_title
diff --git a/app/views/layouts/default.html.erb b/app/views/layouts/default.html.erb
index 948c84da0..252069d4e 100644
--- a/app/views/layouts/default.html.erb
+++ b/app/views/layouts/default.html.erb
@@ -10,7 +10,8 @@
<% end %>
<%= auto_discovery_link_tag :atom, posts_path(:format => "atom", :tags => params[:tags]) %>
<%= stylesheet_link_tag "default" %>
- <%= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" %>
+ <%#= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" %>
+ <%= javascript_include_tag "jquery.min.js" %>
<%= javascript_include_tag "rails" %>
<%= javascript_include_tag "application" %>
<%= Danbooru.config.custom_html_header_content %>
diff --git a/app/views/posts/partials/show/_image.html.erb b/app/views/posts/partials/show/_image.html.erb
index 0aaaa4a94..d98c3f2b6 100644
--- a/app/views/posts/partials/show/_image.html.erb
+++ b/app/views/posts/partials/show/_image.html.erb
@@ -1,2 +1,2 @@
<%= render :partial => "posts/partials/show/notes", :locals => {:post => post, :notes => post.notes.active} %>
-<%= image_tag(post.file_url_for(@current_user), :alt => post.tag_string, :width => post.image_width_for(@current_user), :height => post.image_height_for(@current_user), "data-original-width" => post.image_width, "data-original-height" => post.image_height) %>
+<%= image_tag(post.file_url_for(@current_user), :alt => post.tag_string, :width => post.image_width_for(@current_user), :height => post.image_height_for(@current_user), :id => "image") %>
diff --git a/app/views/posts/partials/show/_information.html.erb b/app/views/posts/partials/show/_information.html.erb
index 09f0d6c76..d7e77ef31 100644
--- a/app/views/posts/partials/show/_information.html.erb
+++ b/app/views/posts/partials/show/_information.html.erb
@@ -6,7 +6,10 @@
Approver: <%= link_to(post.approver.name, user_path(post.approver_id)) %>
<% end %>
- Size: <%= image_dimension_menu(post, @current_user) %>
+ Size: <%= number_to_human_size(post.file_size) %>
+ <% if post.is_image? %>
+ (<%= post.image_width %>x<%= post.image_height %>)
+ <% end %>
<%= link_to "Tag History", post_versions_path(:post_id => post) %>
<%= link_to "Note History", note_versions_path(:post_id => post) %>
diff --git a/app/views/posts/partials/show/_options.html.erb b/app/views/posts/partials/show/_options.html.erb
index f4dcdbeb7..8c15457b5 100644
--- a/app/views/posts/partials/show/_options.html.erb
+++ b/app/views/posts/partials/show/_options.html.erb
@@ -1,7 +1,5 @@