forked from e621ng/e621ng
sync
This commit is contained in:
parent
23656e3fa9
commit
5610731b35
2
Gemfile
2
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"
|
||||
|
5
Rakefile
5
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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 << %{<a href="#" data-src="#{post.file_url}" data-width="#{post.image_width}" data-height="#{post.image_height}">Original</a>} if post.has_medium? || post.has_large?
|
||||
links << %{<a href="#" data-src="#{post.medium_file_url}" data-width="#{post.medium_image_width}" data-height="#{post.medium_image_height}">Medium</a>} if post.has_medium?
|
||||
links << %{<a href="#" data-src="#{post.large_file_url}" data-width="#{post.large_image_width}" data-height="#{post.large_image_height}">Large</a>} if post.has_large?
|
||||
|
||||
if links.any?
|
||||
html = %{<li id="resize-link"><a href="#">Resize</a></li><ul id="resize-links">} + links.map {|x| %{<li>#{x}</li>}}.join("") + %{</ul>}
|
||||
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 << %{<menu type="context" data-user-default="<%= current_user.default_image_size %>">}
|
||||
html << %{<li>#{file_size} #{current_dimensions}</li>}
|
||||
html << %{<ul>}
|
||||
html << %{<li id="original">#{file_size} #{original_dimensions}</li>}
|
||||
html << %{<li id="medium">#{file_size} #{medium_dimensions}</li>} if medium_dimensions
|
||||
html << %{<li id="large">#{file_size} #{large_dimensions}</li>} if large_dimensions
|
||||
html << %{</ul>}
|
||||
html << %{</menu>}
|
||||
html.html_safe
|
||||
end
|
||||
end
|
||||
|
@ -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
|
||||
|
@ -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?
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -1,5 +1,5 @@
|
||||
class NoteVersion < ActiveRecord::Base
|
||||
def updater_name
|
||||
User.find_name(updater_id)
|
||||
User.id_to_name(updater_id)
|
||||
end
|
||||
end
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 %>
|
||||
|
@ -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") %>
|
||||
|
@ -6,7 +6,10 @@
|
||||
<li>Approver: <%= link_to(post.approver.name, user_path(post.approver_id)) %></li>
|
||||
<% end %>
|
||||
<li>
|
||||
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 %>
|
||||
</li>
|
||||
<li><%= link_to "Tag History", post_versions_path(:post_id => post) %></li>
|
||||
<li><%= link_to "Note History", note_versions_path(:post_id => post) %></li>
|
||||
|
@ -1,7 +1,5 @@
|
||||
<ul>
|
||||
<% if !post.is_deleted? && post.is_image? && post.image_width && post.image_width > 700 %>
|
||||
<li><%= link_to "Resize", "#" %></li>
|
||||
<% end %>
|
||||
<%= resize_image_links(post, @current_user) %>
|
||||
<li><%= link_to "Favorite", "#" %></li>
|
||||
<li><%= link_to "Unfavorite", "#" %></li>
|
||||
<li><%= link_to "Translate", "#" %></li>
|
||||
|
@ -1,33 +1,15 @@
|
||||
require File.expand_path('../boot', __FILE__)
|
||||
|
||||
require 'rails/all'
|
||||
|
||||
# Auto-require default libraries and those for the current Rails environment.
|
||||
Bundler.require :default, Rails.env
|
||||
Bundler.require(:default, Rails.env) if defined?(Bundler)
|
||||
|
||||
module Danbooru
|
||||
class Application < Rails::Application
|
||||
# Add additional load paths for your own custom dirs
|
||||
config.load_paths += %W( #{config.root}/presenters #{config.root}/logical )
|
||||
|
||||
# Only load the plugins named here, in the order given (default is alphabetical).
|
||||
# :all can be used as a placeholder for all plugins not explicitly named
|
||||
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]
|
||||
|
||||
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
||||
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')]
|
||||
# config.i18n.default_locale = :de
|
||||
|
||||
# Configure generators values. Many other options are available, be sure to check the documentation.
|
||||
# config.generators do |g|
|
||||
# g.orm :active_record
|
||||
# g.template_engine :erb
|
||||
# g.test_framework :test_unit, :fixture => true
|
||||
# end
|
||||
|
||||
config.autoload_paths += %W(#{config.root}/app/presenters #{config.root}/app/logical)
|
||||
config.plugins = [:all]
|
||||
config.time_zone = 'Eastern Time (US & Canada)'
|
||||
config.encoding = "utf-8"
|
||||
config.active_record.schema_format = :sql
|
||||
|
||||
# Configure sensitive parameters which will be filtered from the log file.
|
||||
config.filter_parameters << :password
|
||||
# config.active_record.observers = :cacher, :garbage_collector, :forum_observer
|
||||
end
|
||||
end
|
||||
|
@ -1,17 +1,13 @@
|
||||
# Use Bundler (preferred)
|
||||
require 'rubygems'
|
||||
|
||||
# Set up gems listed in the Gemfile.
|
||||
gemfile = File.expand_path('../../Gemfile', __FILE__)
|
||||
begin
|
||||
require File.expand_path('../../.bundle/environment', __FILE__)
|
||||
rescue LoadError
|
||||
require 'rubygems'
|
||||
ENV['BUNDLE_GEMFILE'] = gemfile
|
||||
require 'bundler'
|
||||
Bundler.setup
|
||||
|
||||
# To use 2.x style vendor/rails and RubyGems
|
||||
#
|
||||
# vendor_rails = File.expand_path('../../vendor/rails', __FILE__)
|
||||
# if File.exist?(vendor_rails)
|
||||
# Dir["#{vendor_rails}/*/lib"].each { |path| $:.unshift(path) }
|
||||
# end
|
||||
#
|
||||
# require 'rubygems'
|
||||
end
|
||||
rescue Bundler::GemNotFound => e
|
||||
STDERR.puts e.message
|
||||
STDERR.puts "Try running `bundle install`."
|
||||
exit!
|
||||
end if File.exist?(gemfile)
|
||||
|
@ -16,4 +16,7 @@ Danbooru::Application.configure do
|
||||
|
||||
# Don't care if the mailer can't send
|
||||
config.action_mailer.raise_delivery_errors = false
|
||||
|
||||
# Print deprecation notices to the Rails logger
|
||||
config.active_support.deprecation = :log
|
||||
end
|
||||
|
@ -1,4 +1,4 @@
|
||||
Danboorus::Application.configure do
|
||||
Danbooru::Application.configure do
|
||||
# Settings specified here will take precedence over those in config/environment.rb
|
||||
|
||||
# The production environment is meant for finished, "live" apps.
|
||||
@ -9,6 +9,15 @@ Danboorus::Application.configure do
|
||||
config.consider_all_requests_local = false
|
||||
config.action_controller.perform_caching = true
|
||||
|
||||
# Specifies the header that your server uses for sending files
|
||||
config.action_dispatch.x_sendfile_header = "X-Sendfile"
|
||||
|
||||
# For nginx:
|
||||
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
|
||||
|
||||
# If you have no front-end server that supports something like X-Sendfile,
|
||||
# just comment this out and Rails will serve the files
|
||||
|
||||
# See everything in the log (default is :info)
|
||||
# config.log_level = :debug
|
||||
|
||||
@ -30,4 +39,11 @@ Danboorus::Application.configure do
|
||||
|
||||
# Enable threaded mode
|
||||
# config.threadsafe!
|
||||
|
||||
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
|
||||
# the I18n.default_locale when a translation can not be found)
|
||||
config.i18n.fallbacks = true
|
||||
|
||||
# Send deprecation notices to registered listeners
|
||||
config.active_support.deprecation = :notify
|
||||
end
|
||||
|
@ -14,6 +14,9 @@ Danbooru::Application.configure do
|
||||
config.consider_all_requests_local = true
|
||||
config.action_controller.perform_caching = false
|
||||
|
||||
# Raise exceptions instead of rendering exception templates
|
||||
config.action_dispatch.show_exceptions = false
|
||||
|
||||
# Disable request forgery protection in test environment
|
||||
config.action_controller.allow_forgery_protection = false
|
||||
|
||||
@ -26,4 +29,7 @@ Danbooru::Application.configure do
|
||||
# This is necessary if your schema can't be completely dumped by the schema dumper,
|
||||
# like if you have constraints or database-specific column types
|
||||
# config.active_record.schema_format = :sql
|
||||
|
||||
# Print deprecation notices to the stderr
|
||||
config.active_support.deprecation = :stderr
|
||||
end
|
||||
|
@ -1,7 +0,0 @@
|
||||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
# Your secret key for verifying the integrity of signed cookies.
|
||||
# If you change this key, all old signed cookies will become invalid!
|
||||
# Make sure the secret is at least 30 characters and all random,
|
||||
# no regular words or you'll be exposed to dictionary attacks.
|
||||
ActionController::Base.cookie_verifier_secret = '214c98302eef905ab8bce4a19562e322097c526f28e718160a3c0d617ddc8edab6ae7e22cb5eec8930e215bfb936a7086d6f5b146c0092a9af1884613ce0a260'
|
@ -1,31 +1,37 @@
|
||||
module Danbooru
|
||||
module Extensions
|
||||
module ActiveRecord
|
||||
%w(execute select_value select_values select_all).each do |method_name|
|
||||
define_method("#{method_name}_sql") do |sql, *params|
|
||||
connection.__send__(method_name, self.class.sanitize_sql_array([sql, *params]))
|
||||
end
|
||||
|
||||
self.class.__send__(:define_method, "#{method_name}_sql") do |sql, *params|
|
||||
connection.__send__(method_name, sanitize_sql_array([sql, *params]))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module String
|
||||
def to_escaped_for_sql_like
|
||||
return self.gsub(/\\/, '\0\0').gsub(/%/, '\\%').gsub(/_/, '\\_').gsub(/\*/, '%')
|
||||
end
|
||||
|
||||
def to_escaped_js
|
||||
return self.gsub(/\\/, '\0\0').gsub(/['"]/) {|m| "\\#{m}"}.gsub(/\r\n|\r|\n/, '\\n')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class ActiveRecord::Base
|
||||
class << self
|
||||
public :sanitize_sql_array
|
||||
end
|
||||
|
||||
%w(execute select_value select_values select_all).each do |method_name|
|
||||
define_method("#{method_name}_sql") do |sql, *params|
|
||||
connection.__send__(method_name, self.class.sanitize_sql_array([sql, *params]))
|
||||
end
|
||||
|
||||
self.class.__send__(:define_method, "#{method_name}_sql") do |sql, *params|
|
||||
connection.__send__(method_name, sanitize_sql_array([sql, *params]))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class NilClass
|
||||
def id
|
||||
raise NoMethodError
|
||||
end
|
||||
include Danbooru::Extensions::ActiveRecord
|
||||
end
|
||||
|
||||
class String
|
||||
def to_escaped_for_sql_like
|
||||
return self.gsub(/\\/, '\0\0').gsub(/%/, '\\%').gsub(/_/, '\\_').gsub(/\*/, '%')
|
||||
end
|
||||
|
||||
def to_escaped_js
|
||||
return self.gsub(/\\/, '\0\0').gsub(/['"]/) {|m| "\\#{m}"}.gsub(/\r\n|\r|\n/, '\\n')
|
||||
end
|
||||
include Danbooru::Extensions::String
|
||||
end
|
||||
|
@ -1,3 +1,10 @@
|
||||
ActiveSupport::Inflector.inflections do |inflect|
|
||||
inflect.uncountable %w( user_feedback )
|
||||
end
|
||||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
# Add new inflection rules using the following format
|
||||
# (all these examples are active by default):
|
||||
# ActiveSupport::Inflector.inflections do |inflect|
|
||||
# inflect.plural /^(ox)$/i, '\1en'
|
||||
# inflect.singular /^(ox)en/i, '\1'
|
||||
# inflect.irregular 'person', 'people'
|
||||
# inflect.uncountable %w( fish sheep )
|
||||
# end
|
||||
|
@ -1,15 +1,8 @@
|
||||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
# Your secret key for verifying cookie session data integrity.
|
||||
# If you change this key, all old sessions will become invalid!
|
||||
# Make sure the secret is at least 30 characters and all random,
|
||||
# no regular words or you'll be exposed to dictionary attacks.
|
||||
ActionController::Base.session = {
|
||||
:key => '_danbooru_session',
|
||||
:secret => '3102c705148af8124298f9e89d45da3d26e47cc4d9a67cb1c8d9c42c008ee253786346efda50331bb14811f1f445c1c9ed2d51597ad2017328de0dd263048d1a'
|
||||
}
|
||||
Danbooru::Application.config.session_store :cookie_store, :key => '_config_session'
|
||||
|
||||
# Use the database for sessions instead of the cookie-based default,
|
||||
# which shouldn't be used to store highly confidential information
|
||||
# (create the session table with "rake db:sessions:create")
|
||||
# ActionController::Base.session_store = :active_record_store
|
||||
# Config::Application.config.session_store :active_record_store
|
||||
|
@ -1,4 +1,4 @@
|
||||
Danbooru::Application.routes.draw do |map|
|
||||
Danbooru::Application.routes.draw do
|
||||
namespace :admin do
|
||||
resources :users
|
||||
end
|
||||
|
@ -13,7 +13,6 @@ class CreatePosts < ActiveRecord::Migration
|
||||
t.column :is_rating_locked, :boolean, :null => false, :default => false
|
||||
t.column :is_pending, :boolean, :null => false, :default => false
|
||||
t.column :is_flagged, :boolean, :null => false, :default => false
|
||||
t.column :is_deleted, :boolean, :null => false, :default => false
|
||||
|
||||
# Uploader
|
||||
t.column :uploader_string, :string, :null => false
|
||||
@ -47,6 +46,10 @@ class CreatePosts < ActiveRecord::Migration
|
||||
t.column :file_size, :integer, :null => false
|
||||
t.column :image_width, :integer, :null => false
|
||||
t.column :image_height, :integer, :null => false
|
||||
|
||||
# Parent
|
||||
t.column :parent_id, :integer
|
||||
t.column :has_children, :boolean, :null => false, :default => false
|
||||
end
|
||||
|
||||
add_index :posts, :md5, :unique => true
|
||||
@ -58,6 +61,7 @@ class CreatePosts < ActiveRecord::Migration
|
||||
add_index :posts, :image_height
|
||||
add_index :posts, :source
|
||||
add_index :posts, :view_count
|
||||
add_index :posts, :parent_id
|
||||
|
||||
execute "CREATE INDEX index_posts_on_mpixels ON posts (((image_width * image_height)::numeric / 1000000.0))"
|
||||
|
||||
|
@ -8,6 +8,7 @@ class CreateFavorites < ActiveRecord::Migration
|
||||
|
||||
add_index "favorites_#{number}", :post_id
|
||||
add_index "favorites_#{number}", :user_id
|
||||
add_index "favorites_#{number}", [:post_id, :user_id], :unique => true
|
||||
end
|
||||
end
|
||||
|
||||
|
90
lib/cache.rb
90
lib/cache.rb
@ -1,90 +0,0 @@
|
||||
module Cache
|
||||
def incr(key, expiry = 0)
|
||||
val = Cache.get(key, expiry)
|
||||
Cache.put(key, val.to_i + 1)
|
||||
ActiveRecord::Base.logger.debug('MemCache Incr %s' % [key])
|
||||
end
|
||||
|
||||
def get_multi(keys, prefix, expiry = 0)
|
||||
key_to_sanitized_key_hash = keys.inject({}) do |hash, x|
|
||||
hash[x] = "#{prefix}:#{Cache.sanitize(x)}"
|
||||
hash
|
||||
end
|
||||
start_time = Time.now
|
||||
sanitized_key_to_value_hash = MEMCACHE.get_multi(key_to_sanitized_key_hash.values)
|
||||
elapsed = Time.now - start_time
|
||||
returning({}) do |result_hash|
|
||||
key_to_sanitized_key_hash.each do |key, sanitized_key|
|
||||
if sanitized_key_to_value_hash.has_key?(sanitized_key)
|
||||
result_hash[key] = sanitized_key_to_value_hash[sanitized_key]
|
||||
else
|
||||
result_hash[key] = yield(key)
|
||||
Cache.put(sanitized_key, result_hash[key], expiry)
|
||||
end
|
||||
end
|
||||
|
||||
ActiveRecord::Base.logger.debug('MemCache Multi-Get (%0.6f) %s' % [elapsed, keys.join(",")])
|
||||
end
|
||||
end
|
||||
|
||||
def get(key, expiry = 0)
|
||||
begin
|
||||
start_time = Time.now
|
||||
value = MEMCACHE.get key
|
||||
elapsed = Time.now - start_time
|
||||
ActiveRecord::Base.logger.debug('MemCache Get (%0.6f) %s' % [elapsed, key])
|
||||
if value.nil? and block_given? then
|
||||
value = yield
|
||||
MEMCACHE.set key, value, expiry
|
||||
end
|
||||
value
|
||||
rescue MemCache::MemCacheError => err
|
||||
ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
|
||||
if block_given? then
|
||||
value = yield
|
||||
put key, value, expiry
|
||||
end
|
||||
value
|
||||
end
|
||||
end
|
||||
|
||||
def put(key, value, expiry = 0)
|
||||
key.gsub!(/\s/, "_")
|
||||
key = key[0, 200]
|
||||
|
||||
begin
|
||||
start_time = Time.now
|
||||
MEMCACHE.set key, value, expiry
|
||||
elapsed = Time.now - start_time
|
||||
ActiveRecord::Base.logger.debug('MemCache Set (%0.6f) %s' % [elapsed, key])
|
||||
value
|
||||
rescue MemCache::MemCacheError => err
|
||||
ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def delete(key, delay = nil)
|
||||
begin
|
||||
start_time = Time.now
|
||||
MEMCACHE.delete key, delay
|
||||
elapsed = Time.now - start_time
|
||||
ActiveRecord::Base.logger.debug('MemCache Delete (%0.6f) %s' % [elapsed, key])
|
||||
nil
|
||||
rescue MemCache::MemCacheError => err
|
||||
ActiveRecord::Base.logger.debug "MemCache Error: #{err.message}"
|
||||
nil
|
||||
end
|
||||
end
|
||||
|
||||
def sanitize(key)
|
||||
key.gsub(/\W/) {|x| "%#{x.ord}"}.slice(0, 240)
|
||||
end
|
||||
|
||||
module_function :get
|
||||
module_function :get_multi
|
||||
module_function :incr
|
||||
module_function :put
|
||||
module_function :delete
|
||||
module_function :sanitize
|
||||
end
|
@ -4,67 +4,84 @@ SHELL = /bin/sh
|
||||
#### Start of system configuration section. ####
|
||||
|
||||
srcdir = .
|
||||
topdir = /opt/local/lib/ruby/1.8/i686-darwin10
|
||||
hdrdir = $(topdir)
|
||||
VPATH = $(srcdir):$(topdir):$(hdrdir)
|
||||
topdir = /Users/ayi/.rvm/rubies/ruby-1.9.2-preview1/include/ruby-1.9.1
|
||||
hdrdir = /Users/ayi/.rvm/rubies/ruby-1.9.2-preview1/include/ruby-1.9.1
|
||||
arch_hdrdir = /Users/ayi/.rvm/rubies/ruby-1.9.2-preview1/include/ruby-1.9.1/$(arch)
|
||||
VPATH = $(srcdir):$(arch_hdrdir)/ruby:$(hdrdir)/ruby
|
||||
prefix = $(DESTDIR)/Users/ayi/.rvm/rubies/ruby-1.9.2-preview1
|
||||
rubylibprefix = $(libdir)/$(RUBY_BASE_NAME)
|
||||
exec_prefix = $(prefix)
|
||||
prefix = $(DESTDIR)/opt/local
|
||||
sharedstatedir = $(prefix)/com
|
||||
mandir = $(DESTDIR)/opt/local/share/man
|
||||
psdir = $(docdir)
|
||||
oldincludedir = $(DESTDIR)/usr/include
|
||||
vendorhdrdir = $(rubyhdrdir)/vendor_ruby
|
||||
sitehdrdir = $(rubyhdrdir)/site_ruby
|
||||
rubyhdrdir = $(includedir)/$(RUBY_BASE_NAME)-$(ruby_version)
|
||||
vendordir = $(rubylibprefix)/vendor_ruby
|
||||
sitedir = $(rubylibprefix)/site_ruby
|
||||
ridir = $(datarootdir)/$(RI_BASE_NAME)
|
||||
mandir = $(datarootdir)/man
|
||||
localedir = $(datarootdir)/locale
|
||||
bindir = $(exec_prefix)/bin
|
||||
libexecdir = $(exec_prefix)/libexec
|
||||
sitedir = $(libdir)/ruby/site_ruby
|
||||
htmldir = $(docdir)
|
||||
vendorarchdir = $(vendorlibdir)/$(sitearch)
|
||||
includedir = $(prefix)/include
|
||||
infodir = $(datarootdir)/info
|
||||
vendorlibdir = $(vendordir)/$(ruby_version)
|
||||
sysconfdir = $(prefix)/etc
|
||||
libdir = $(exec_prefix)/lib
|
||||
sbindir = $(exec_prefix)/sbin
|
||||
rubylibdir = $(libdir)/ruby/$(ruby_version)
|
||||
docdir = $(datarootdir)/doc/$(PACKAGE)
|
||||
dvidir = $(docdir)
|
||||
vendordir = $(DESTDIR)/opt/local/lib/ruby/vendor_ruby
|
||||
datarootdir = $(prefix)/share
|
||||
psdir = $(docdir)
|
||||
pdfdir = $(docdir)
|
||||
archdir = $(rubylibdir)/$(arch)
|
||||
sitearchdir = $(sitelibdir)/$(sitearch)
|
||||
datadir = $(datarootdir)
|
||||
dvidir = $(docdir)
|
||||
htmldir = $(docdir)
|
||||
infodir = $(datarootdir)/info
|
||||
docdir = $(datarootdir)/doc/$(PACKAGE)
|
||||
oldincludedir = $(DESTDIR)/usr/include
|
||||
includedir = $(prefix)/include
|
||||
localstatedir = $(prefix)/var
|
||||
sharedstatedir = $(prefix)/com
|
||||
sysconfdir = $(prefix)/etc
|
||||
datadir = $(datarootdir)
|
||||
datarootdir = $(prefix)/share
|
||||
libexecdir = $(exec_prefix)/libexec
|
||||
sbindir = $(exec_prefix)/sbin
|
||||
bindir = $(exec_prefix)/bin
|
||||
rubylibdir = $(rubylibprefix)/$(ruby_version)
|
||||
archdir = $(rubylibdir)/$(arch)
|
||||
sitelibdir = $(sitedir)/$(ruby_version)
|
||||
sitearchdir = $(sitelibdir)/$(sitearch)
|
||||
vendorlibdir = $(vendordir)/$(ruby_version)
|
||||
vendorarchdir = $(vendorlibdir)/$(sitearch)
|
||||
|
||||
CC = g++
|
||||
LIBRUBY = $(LIBRUBY_SO)
|
||||
CXX = g++
|
||||
LIBRUBY = $(LIBRUBY_A)
|
||||
LIBRUBY_A = lib$(RUBY_SO_NAME)-static.a
|
||||
LIBRUBYARG_SHARED = -l$(RUBY_SO_NAME)
|
||||
LIBRUBYARG_STATIC = -l$(RUBY_SO_NAME)-static
|
||||
OUTFLAG = -o
|
||||
COUTFLAG = -o
|
||||
|
||||
RUBY_EXTCONF_H =
|
||||
CFLAGS = -fno-common -O2 -fno-exceptions -Wall -arch x86_64
|
||||
INCFLAGS = -I. -I. -I/opt/local/lib/ruby/1.8/i686-darwin10 -I.
|
||||
cflags = $(optflags) $(debugflags) $(warnflags)
|
||||
optflags = -O3
|
||||
debugflags = -g
|
||||
warnflags = -Wall -Wno-unused-parameter -Wno-parentheses -Wno-missing-field-initializers -Wshorten-64-to-32 -Wpointer-arith -Wwrite-strings
|
||||
CFLAGS = -fno-common -O2 -fno-exceptions -Wall
|
||||
INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir)
|
||||
DEFS =
|
||||
CPPFLAGS = -DHAVE_GD_H -DHAVE_GDIMAGECREATEFROMGIF -DHAVE_GDIMAGEJPEG -DHAVE_JPEG_SET_QUALITY -DHAVE_PNG_SET_EXPAND_GRAY_1_2_4_TO_8 -I/opt/local/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE -I/opt/local/include
|
||||
CXXFLAGS = $(CFLAGS)
|
||||
ldflags = -L. -L/opt/local/lib
|
||||
CPPFLAGS = -DHAVE_GD_H -DHAVE_GDIMAGECREATEFROMGIF -DHAVE_GDIMAGEJPEG -DHAVE_JPEG_SET_QUALITY -DHAVE_PNG_SET_EXPAND_GRAY_1_2_4_TO_8 -I/opt/local/include -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE $(DEFS) $(cppflags)
|
||||
CXXFLAGS = $(CFLAGS) $(cxxflags)
|
||||
ldflags = -L.
|
||||
dldflags =
|
||||
archflag = -arch x86_64
|
||||
archflag =
|
||||
DLDFLAGS = $(ldflags) $(dldflags) $(archflag)
|
||||
LDSHARED = $(CC) -dynamic -bundle -undefined suppress -flat_namespace
|
||||
LDSHAREDXX = $(CXX) -dynamic -bundle -undefined suppress -flat_namespace
|
||||
AR = ar
|
||||
EXEEXT =
|
||||
|
||||
RUBY_BASE_NAME = ruby
|
||||
RUBY_INSTALL_NAME = ruby
|
||||
RUBY_SO_NAME = ruby
|
||||
arch = i686-darwin10
|
||||
sitearch = i686-darwin10
|
||||
ruby_version = 1.8
|
||||
ruby = /opt/local/bin/ruby
|
||||
arch = i386-darwin10.4.0
|
||||
sitearch = $(arch)
|
||||
ruby_version = 1.9.1
|
||||
ruby = /Users/ayi/.rvm/rubies/ruby-1.9.2-preview1/bin/ruby
|
||||
RUBY = $(ruby)
|
||||
RM = rm -f
|
||||
RM_RF = $(RUBY) -run -e rm -- -rf
|
||||
RMDIRS = $(RUBY) -run -e rmdir -- -p
|
||||
MAKEDIRS = mkdir -p
|
||||
INSTALL = /usr/bin/install -c
|
||||
INSTALL_PROG = $(INSTALL) -m 0755
|
||||
@ -75,18 +92,19 @@ COPY = cp
|
||||
|
||||
preload =
|
||||
|
||||
libpath = . $(libdir)
|
||||
LIBPATH = -L. -L$(libdir)
|
||||
libpath = . $(libdir) /opt/local/lib
|
||||
LIBPATH = -L. -L$(libdir) -L/opt/local/lib
|
||||
DEFFILE =
|
||||
|
||||
CLEANFILES = mkmf.log
|
||||
DISTCLEANFILES =
|
||||
DISTCLEANDIRS =
|
||||
|
||||
extout =
|
||||
extout_prefix =
|
||||
target_prefix =
|
||||
LOCAL_LIBS =
|
||||
LIBS = $(LIBRUBYARG_SHARED) -lpng -ljpeg -lgd -lpthread -ldl -lobjc
|
||||
LIBS = -lpng -ljpeg -lgd -lpthread -ldl -lobjc
|
||||
SRCS = danbooru_image_resizer.cpp GIFReader.cpp JPEGReader.cpp PNGReader.cpp Resize.cpp RowBuffer.cpp
|
||||
OBJS = danbooru_image_resizer.o GIFReader.o JPEGReader.o PNGReader.o Resize.o RowBuffer.o
|
||||
TARGET = danbooru_image_resizer
|
||||
@ -98,27 +116,38 @@ BINDIR = $(bindir)
|
||||
RUBYCOMMONDIR = $(sitedir)$(target_prefix)
|
||||
RUBYLIBDIR = $(sitelibdir)$(target_prefix)
|
||||
RUBYARCHDIR = $(sitearchdir)$(target_prefix)
|
||||
HDRDIR = $(rubyhdrdir)/ruby$(target_prefix)
|
||||
ARCHHDRDIR = $(rubyhdrdir)/$(arch)/ruby$(target_prefix)
|
||||
|
||||
TARGET_SO = $(DLLIB)
|
||||
CLEANLIBS = $(TARGET).bundle $(TARGET).il? $(TARGET).tds $(TARGET).map
|
||||
CLEANOBJS = *.o *.a *.s[ol] *.pdb *.exp *.bak
|
||||
CLEANLIBS = $(TARGET).bundle
|
||||
CLEANOBJS = *.o *.bak
|
||||
|
||||
all: $(DLLIB)
|
||||
static: $(STATIC_LIB)
|
||||
all: $(DLLIB)
|
||||
static: $(STATIC_LIB)
|
||||
.PHONY: all install static install-so install-rb
|
||||
.PHONY: clean clean-so clean-rb
|
||||
|
||||
clean:
|
||||
clean-rb-default::
|
||||
clean-rb::
|
||||
clean-so::
|
||||
clean: clean-so clean-rb-default clean-rb
|
||||
@-$(RM) $(CLEANLIBS) $(CLEANOBJS) $(CLEANFILES)
|
||||
|
||||
distclean: clean
|
||||
distclean-rb-default::
|
||||
distclean-rb::
|
||||
distclean-so::
|
||||
distclean: clean distclean-so distclean-rb-default distclean-rb
|
||||
@-$(RM) Makefile $(RUBY_EXTCONF_H) conftest.* mkmf.log
|
||||
@-$(RM) core ruby$(EXEEXT) *~ $(DISTCLEANFILES)
|
||||
@-$(RMDIRS) $(DISTCLEANDIRS)
|
||||
|
||||
realclean: distclean
|
||||
realclean: distclean
|
||||
install: install-so install-rb
|
||||
|
||||
install-so: $(RUBYARCHDIR)
|
||||
install-so: $(RUBYARCHDIR)/$(DLLIB)
|
||||
$(RUBYARCHDIR)/$(DLLIB): $(DLLIB)
|
||||
$(RUBYARCHDIR)/$(DLLIB): $(RUBYARCHDIR) $(DLLIB)
|
||||
$(INSTALL_PROG) $(DLLIB) $(RUBYARCHDIR)
|
||||
install-rb: pre-install-rb install-rb-default
|
||||
install-rb-default: pre-install-rb-default
|
||||
@ -134,24 +163,24 @@ site-install-rb: install-rb
|
||||
.SUFFIXES: .c .m .cc .cxx .cpp .C .o
|
||||
|
||||
.cc.o:
|
||||
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
||||
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
||||
|
||||
.cxx.o:
|
||||
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
||||
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
||||
|
||||
.cpp.o:
|
||||
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
||||
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
||||
|
||||
.C.o:
|
||||
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $<
|
||||
$(CXX) $(INCFLAGS) $(CPPFLAGS) $(CXXFLAGS) $(COUTFLAG)$@ -c $<
|
||||
|
||||
.c.o:
|
||||
$(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) -c $<
|
||||
$(CC) $(INCFLAGS) $(CPPFLAGS) $(CFLAGS) $(COUTFLAG)$@ -c $<
|
||||
|
||||
$(DLLIB): $(OBJS) Makefile
|
||||
@-$(RM) $@
|
||||
$(LDSHARED) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
|
||||
@-$(RM) $(@)
|
||||
$(LDSHAREDXX) -o $@ $(OBJS) $(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)
|
||||
|
||||
|
||||
|
||||
$(OBJS): ruby.h defines.h
|
||||
$(OBJS): $(hdrdir)/ruby.h $(hdrdir)/ruby/defines.h $(arch_hdrdir)/ruby/config.h
|
||||
|
144
lib/dtext.rb
144
lib/dtext.rb
@ -1,144 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require 'cgi'
|
||||
|
||||
module DText
|
||||
def parse_inline(str, options = {})
|
||||
str = str.gsub(/&/, "&")
|
||||
str.gsub!(/</, "<")
|
||||
str.gsub!(/>/, ">")
|
||||
str.gsub!(/\[\[.+?\]\]/m) do |tag|
|
||||
tag = tag[2..-3]
|
||||
if tag =~ /^(.+?)\|(.+)$/
|
||||
tag = $1
|
||||
name = $2
|
||||
'<a href="/wiki/show?title=' + CGI.escape(CGI.unescapeHTML(tag.tr(" ", "_").downcase)) + '">' + name + '</a>'
|
||||
else
|
||||
'<a href="/wiki/show?title=' + CGI.escape(CGI.unescapeHTML(tag.tr(" ", "_").downcase)) + '">' + tag + '</a>'
|
||||
end
|
||||
end
|
||||
str.gsub!(/\{\{.+?\}\}/m) do |tag|
|
||||
tag = tag[2..-3]
|
||||
'<a href="/post/index?tags=' + CGI.escape(CGI.unescapeHTML(tag)) + '">' + tag + '</a>'
|
||||
end
|
||||
str.gsub!(/[Pp]ost #(\d+)/, '<a href="/post/show/\1">post #\1</a>')
|
||||
str.gsub!(/[Ff]orum #(\d+)/, '<a href="/forum/show/\1">forum #\1</a>')
|
||||
str.gsub!(/[Cc]omment #(\d+)/, '<a href="/comment/show/\1">comment #\1</a>')
|
||||
str.gsub!(/[Pp]ool #(\d+)/, '<a href="/pool/show/\1">pool #\1</a>')
|
||||
str.gsub!(/\n/m, "<br>")
|
||||
str.gsub!(/\[b\](.+?)\[\/b\]/, '<strong>\1</strong>')
|
||||
str.gsub!(/\[i\](.+?)\[\/i\]/, '<em>\1</em>')
|
||||
str.gsub!(/\[spoilers?\](.+?)\[\/spoilers?\]/m, '<span class="spoiler">\1</span>')
|
||||
str.gsub!(/("[^"]+":(http:\/\/|\/)\S+|http:\/\/\S+)/m) do |link|
|
||||
if link =~ /^"([^"]+)":(.+)$/
|
||||
text = $1
|
||||
link = $2
|
||||
else
|
||||
text = link
|
||||
end
|
||||
|
||||
if link =~ /([;,.!?\)\]<>])$/
|
||||
link.chop!
|
||||
ch = $1
|
||||
else
|
||||
ch = ""
|
||||
end
|
||||
|
||||
link.gsub!(/"/, '"')
|
||||
'<a href="' + link + '">' + text + '</a>' + ch
|
||||
end
|
||||
str
|
||||
end
|
||||
|
||||
def parse_list(str, options = {})
|
||||
html = ""
|
||||
layout = []
|
||||
nest = 0
|
||||
|
||||
str.split(/\n/).each do |line|
|
||||
if line =~ /^\s*(\*+) (.+)/
|
||||
nest = $1.size
|
||||
content = parse_inline($2)
|
||||
else
|
||||
content = parse_inline(line)
|
||||
end
|
||||
|
||||
if nest > layout.size
|
||||
html += "<ul>"
|
||||
layout << "ul"
|
||||
end
|
||||
|
||||
while nest < layout.size
|
||||
elist = layout.pop
|
||||
if elist
|
||||
html += "</#{elist}>"
|
||||
end
|
||||
end
|
||||
|
||||
html += "<li>#{content}</li>"
|
||||
end
|
||||
|
||||
while layout.any?
|
||||
elist = layout.pop
|
||||
html += "</#{elist}>"
|
||||
end
|
||||
|
||||
html
|
||||
end
|
||||
|
||||
def parse(str, options = {})
|
||||
return "" if str.blank?
|
||||
|
||||
# Make sure quote tags are surrounded by newlines
|
||||
|
||||
unless options[:inline]
|
||||
str.gsub!(/\s*\[quote\]\s*/m, "\n\n[quote]\n\n")
|
||||
str.gsub!(/\s*\[\/quote\]\s*/m, "\n\n[/quote]\n\n")
|
||||
end
|
||||
|
||||
str.gsub!(/(?:\r?\n){3,}/, "\n\n")
|
||||
str.strip!
|
||||
blocks = str.split(/(?:\r?\n){2}/)
|
||||
|
||||
html = blocks.map do |block|
|
||||
case block
|
||||
when /^(h[1-6])\.\s*(.+)$/
|
||||
tag = $1
|
||||
content = $2
|
||||
|
||||
if options[:inline]
|
||||
"<h6>" + parse_inline(content, options) + "</h6>"
|
||||
else
|
||||
"<#{tag}>" + parse_inline(content, options) + "</#{tag}>"
|
||||
end
|
||||
|
||||
when /^\s*\*+ /
|
||||
parse_list(block, options)
|
||||
|
||||
when "[quote]"
|
||||
if options[:inline]
|
||||
""
|
||||
else
|
||||
'<blockquote>'
|
||||
end
|
||||
|
||||
when "[/quote]"
|
||||
if options[:inline]
|
||||
""
|
||||
else
|
||||
'</blockquote>'
|
||||
end
|
||||
|
||||
else
|
||||
'<p>' + parse_inline(block) + "</p>"
|
||||
end
|
||||
end
|
||||
|
||||
html.join("")
|
||||
end
|
||||
|
||||
module_function :parse_inline
|
||||
module_function :parse_list
|
||||
module_function :parse
|
||||
end
|
||||
|
@ -1,79 +0,0 @@
|
||||
// Cookie.setup();
|
||||
|
||||
$(document).ready(function() {
|
||||
// $("#hide-upgrade-account-link").click(function() {
|
||||
// $("#upgrade-account").hide();
|
||||
// Cookie.put('hide-upgrade-account', '1', 7);
|
||||
// });
|
||||
|
||||
// Comment listing
|
||||
$(".comment-section form").hide();
|
||||
$(".comment-section input.expand-comment-response").click(function() {
|
||||
var post_id = $(this).closest(".comment-section").attr("data-post-id");
|
||||
$(".comment-section[data-post-id=" + post_id + "] form").show();
|
||||
$(this).hide();
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
var Danbooru = {};
|
||||
|
||||
// ContextMenu
|
||||
|
||||
Danbooru.ContextMenu = {};
|
||||
|
||||
Danbooru.ContextMenu.add_icon = function() {
|
||||
$("menu[type=context] > li").append('<img src="/images/arrow2_s.png">');
|
||||
}
|
||||
|
||||
Danbooru.ContextMenu.toggle_icon = function(li) {
|
||||
if (li == null) {
|
||||
$("menu[type=context] > li > img").attr("src", "/images/arrow2_s.png");
|
||||
} else {
|
||||
$(li).find("img").attr("src", function() {
|
||||
if (this.src.match(/_n/)) {
|
||||
return "/images/arrow2_s.png";
|
||||
} else {
|
||||
return "/images/arrow2_n.png";
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Danbooru.ContextMenu.setup = function() {
|
||||
$("menu[type=context] li").hover(
|
||||
function() {$(this).css({"background-color": "#F6F6F6"})},
|
||||
function() {$(this).css({"background-color": "#EEE"})}
|
||||
);
|
||||
|
||||
this.add_icon();
|
||||
|
||||
$("menu[type=context] > li").click(function(e) {
|
||||
$(this).parent().find("ul").toggle();
|
||||
e.stopPropagation();
|
||||
Danbooru.ContextMenu.toggle_icon(this);
|
||||
});
|
||||
|
||||
$(document).click(function() {
|
||||
$("menu[type=context] > ul").hide();
|
||||
Danbooru.ContextMenu.toggle_icon();
|
||||
});
|
||||
|
||||
$("menu[type=context] > ul > li").click(function(element) {
|
||||
$(this).closest("ul").toggle();
|
||||
var text = $(this).text()
|
||||
var menu = $(this).closest("menu");
|
||||
menu.children("li").text(text);
|
||||
if (menu.attr("data-update-field-id")) {
|
||||
$("#" + menu.attr("data-update-field-id")).val(text);
|
||||
Danbooru.ContextMenu.add_icon();
|
||||
}
|
||||
if (menu.attr("data-submit-on-change") == "true") {
|
||||
menu.closest("form").submit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
Danbooru.ContextMenu.setup();
|
||||
});
|
@ -1,129 +0,0 @@
|
||||
// from http://github.com/rails/jquery-ujs/raw/master/src/rails.js
|
||||
|
||||
jQuery(function ($) {
|
||||
var csrf_token = $('meta[name=csrf-token]').attr('content'),
|
||||
csrf_param = $('meta[name=csrf-param]').attr('content');
|
||||
|
||||
$.fn.extend({
|
||||
/**
|
||||
* Triggers a custom event on an element and returns the event result
|
||||
* this is used to get around not being able to ensure callbacks are placed
|
||||
* at the end of the chain.
|
||||
*
|
||||
* TODO: deprecate with jQuery 1.4.2 release, in favor of subscribing to our
|
||||
* own events and placing ourselves at the end of the chain.
|
||||
*/
|
||||
triggerAndReturn: function (name, data) {
|
||||
var event = new $.Event(name);
|
||||
this.trigger(event, data);
|
||||
|
||||
return event.result !== false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles execution of remote calls firing overridable events along the way
|
||||
*/
|
||||
callRemote: function () {
|
||||
var el = this,
|
||||
data = el.is('form') ? el.serializeArray() : [],
|
||||
method = el.attr('method') || el.attr('data-method') || 'GET',
|
||||
url = el.attr('action') || el.attr('href');
|
||||
|
||||
if (url === undefined) {
|
||||
throw "No URL specified for remote call (action or href must be present).";
|
||||
} else {
|
||||
if (el.triggerAndReturn('ajax:before')) {
|
||||
$.ajax({
|
||||
url: url,
|
||||
data: data,
|
||||
dataType: 'script',
|
||||
type: method.toUpperCase(),
|
||||
beforeSend: function (xhr) {
|
||||
el.trigger('ajax:loading', xhr);
|
||||
},
|
||||
success: function (data, status, xhr) {
|
||||
el.trigger('ajax:success', [data, status, xhr]);
|
||||
},
|
||||
complete: function (xhr) {
|
||||
el.trigger('ajax:complete', xhr);
|
||||
},
|
||||
error: function (xhr, status, error) {
|
||||
el.trigger('ajax:failure', [xhr, status, error]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
el.trigger('ajax:after');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* confirmation handler
|
||||
*/
|
||||
$('a[data-confirm],input[data-confirm]').live('click', function () {
|
||||
var el = $(this);
|
||||
if (el.triggerAndReturn('confirm')) {
|
||||
if (!confirm(el.attr('data-confirm'))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* remote handlers
|
||||
*/
|
||||
$('form[data-remote]').live('submit', function (e) {
|
||||
$(this).callRemote();
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
$('a[data-remote],input[data-remote]').live('click', function (e) {
|
||||
$(this).callRemote();
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
$('a[data-method]:not([data-remote])').live('click', function (e){
|
||||
var link = $(this),
|
||||
href = link.attr('href'),
|
||||
method = link.attr('data-method'),
|
||||
form = $('<form method="post" action="'+href+'">'),
|
||||
metadata_input = '<input name="_method" value="'+method+'" type="hidden" />';
|
||||
|
||||
if (csrf_param != null && csrf_token != null) {
|
||||
metadata_input += '<input name="'+csrf_param+'" value="'+csrf_token+'" type="hidden" />';
|
||||
}
|
||||
|
||||
form.hide()
|
||||
.append(metadata_input)
|
||||
.appendTo('body');
|
||||
|
||||
e.preventDefault();
|
||||
form.submit();
|
||||
});
|
||||
|
||||
/**
|
||||
* disable-with handlers
|
||||
*/
|
||||
var disable_with_input_selector = 'input[data-disable-with]';
|
||||
var disable_with_form_selector = 'form[data-remote]:has(' + disable_with_input_selector + ')';
|
||||
|
||||
$(disable_with_form_selector).live('ajax:before', function () {
|
||||
$(this).find(disable_with_input_selector).each(function () {
|
||||
var input = $(this);
|
||||
input.data('enable-with', input.val())
|
||||
.attr('value', input.attr('data-disable-with'))
|
||||
.attr('disabled', 'disabled');
|
||||
});
|
||||
});
|
||||
|
||||
$(disable_with_form_selector).live('ajax:after', function () {
|
||||
$(this).find(disable_with_input_selector).each(function () {
|
||||
var input = $(this);
|
||||
input.removeAttr('disabled')
|
||||
.val(input.data('enable-with'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -227,10 +227,14 @@ aside.sidebar > section > h1 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
aside.sidebar > section > ul > li {
|
||||
aside.sidebar > section > ul li {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
aside.sidebar > section > ul ul li {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
|
||||
/*** Comments ***/
|
||||
div.comment-response {
|
||||
|
0
script/compile_javascripts
Normal file → Executable file
0
script/compile_javascripts
Normal file → Executable file
10
script/rails
10
script/rails
@ -1,10 +1,6 @@
|
||||
#!/usr/bin/env ruby1.9
|
||||
#!/usr/bin/env ruby
|
||||
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
||||
|
||||
ENV_PATH = File.expand_path('../../config/environment', __FILE__)
|
||||
BOOT_PATH = File.expand_path('../../config/boot', __FILE__)
|
||||
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
||||
ROOT_PATH = File.expand_path('../..', __FILE__)
|
||||
|
||||
require BOOT_PATH
|
||||
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
||||
require File.expand_path('../../config/boot', __FILE__)
|
||||
require 'rails/commands'
|
||||
|
@ -2,8 +2,6 @@ Factory.define(:post) do |f|
|
||||
f.md5 {|x| Time.now.to_f.to_s}
|
||||
f.uploader {|x| x.association(:user)}
|
||||
f.uploader_ip_addr "127.0.0.1"
|
||||
f.updater_id {|x| x.uploader_id}
|
||||
f.updater_ip_addr "127.0.0.1"
|
||||
f.tag_string "tag1 tag2"
|
||||
f.tag_count 2
|
||||
f.tag_count_general 2
|
||||
|
@ -1,9 +1,10 @@
|
||||
ENV["RAILS_ENV"] = "test"
|
||||
|
||||
require 'factory_girl'
|
||||
require 'shoulda'
|
||||
require 'mocha'
|
||||
require 'faker'
|
||||
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
|
||||
require File.expand_path('../../config/environment', __FILE__)
|
||||
require 'rails/test_help'
|
||||
|
||||
Dir[File.expand_path(File.dirname(__FILE__) + "/factories/*.rb")].each {|file| require file}
|
||||
|
@ -1,6 +1,142 @@
|
||||
require File.dirname(__FILE__) + '/../test_helper'
|
||||
require_relative '../test_helper'
|
||||
|
||||
class PostTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
user = Factory.create(:user)
|
||||
CurrentUser.user = user
|
||||
CurrentUser.ip_addr = "127.0.0.1"
|
||||
end
|
||||
|
||||
teardown do
|
||||
CurrentUser.user = nil
|
||||
CurrentUser.ip_addr = nil
|
||||
end
|
||||
|
||||
context "Removal:" do
|
||||
context "Removing a post" do
|
||||
should "duplicate the post in the archive table and remove it from the base table" do
|
||||
post = Factory.create(:post)
|
||||
|
||||
assert_difference("RemovedPost.count", 1) do
|
||||
assert_difference("Post.count", -1) do
|
||||
post.remove!
|
||||
end
|
||||
end
|
||||
|
||||
removed_post = RemovedPost.last
|
||||
assert_equal(post.tag_string, removed_post.tag_string)
|
||||
end
|
||||
|
||||
should "decrement the tag counts" do
|
||||
post = Factory.create(:post, :tag_string => "aaa")
|
||||
assert_equal(1, Tag.find_by_name("aaa").post_count)
|
||||
post.remove!
|
||||
assert_equal(0, Tag.find_by_name("aaa").post_count)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "Parenting:" do
|
||||
context "Assignining a parent to a post" do
|
||||
should "update the has_children flag on the parent" do
|
||||
p1 = Factory.create(:post)
|
||||
assert(!p1.has_children?, "Parent should not have any children")
|
||||
c1 = Factory.create(:post, :parent_id => p1.id)
|
||||
p1.reload
|
||||
assert(p1.has_children?, "Parent not updated after child was added")
|
||||
end
|
||||
|
||||
should "update the has_children flag on the old parent" do
|
||||
p1 = Factory.create(:post)
|
||||
p2 = Factory.create(:post)
|
||||
c1 = Factory.create(:post, :parent_id => p1.id)
|
||||
c1.parent_id = p2.id
|
||||
c1.save
|
||||
p1.reload
|
||||
p2.reload
|
||||
assert(!p1.has_children?, "Old parent should not have a child")
|
||||
assert(p2.has_children?, "New parent should have a child")
|
||||
end
|
||||
|
||||
should "validate that the parent exists" do
|
||||
post = Factory.build(:post, :parent_id => 1_000_000)
|
||||
post.save
|
||||
assert(post.errors[:parent].any?, "Parent should be invalid")
|
||||
end
|
||||
|
||||
should "fail if the parent has a parent" do
|
||||
p1 = Factory.create(:post)
|
||||
c1 = Factory.create(:post, :parent_id => p1.id)
|
||||
c2 = Factory.build(:post, :parent_id => c1.id)
|
||||
c2.save
|
||||
assert(c2.errors[:parent].any?, "Parent should be invalid")
|
||||
end
|
||||
end
|
||||
|
||||
context "Destroying a post with a parent" do
|
||||
should "reassign favorites to the parent" do
|
||||
p1 = Factory.create(:post)
|
||||
c1 = Factory.create(:post, :parent_id => p1.id)
|
||||
user = Factory.create(:user)
|
||||
c1.add_favorite(user)
|
||||
c1.remove!
|
||||
p1.reload
|
||||
assert(!Favorite.exists?(:post_id => c1.id, :user_id => user.id))
|
||||
assert(Favorite.exists?(:post_id => p1.id, :user_id => user.id))
|
||||
end
|
||||
|
||||
should "update the parent's has_children flag" do
|
||||
p1 = Factory.create(:post)
|
||||
c1 = Factory.create(:post, :parent_id => p1.id)
|
||||
c1.remove!
|
||||
p1.reload
|
||||
assert(!p1.has_children?, "Parent should not have children")
|
||||
end
|
||||
end
|
||||
|
||||
context "Destroying a post with" do
|
||||
context "one child" do
|
||||
should "remove the parent of that child" do
|
||||
p1 = Factory.create(:post)
|
||||
c1 = Factory.create(:post, :parent_id => p1.id)
|
||||
p1.remove!
|
||||
c1.reload
|
||||
assert_nil(c1.parent)
|
||||
end
|
||||
end
|
||||
|
||||
context "two or more children" do
|
||||
should "reparent all children to the first child" do
|
||||
p1 = Factory.create(:post)
|
||||
c1 = Factory.create(:post, :parent_id => p1.id)
|
||||
c2 = Factory.create(:post, :parent_id => p1.id)
|
||||
c3 = Factory.create(:post, :parent_id => p1.id)
|
||||
p1.remove!
|
||||
c1.reload
|
||||
c2.reload
|
||||
c3.reload
|
||||
assert_nil(c1.parent)
|
||||
assert_equal(c1.id, c2.parent_id)
|
||||
assert_equal(c1.id, c3.parent_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "Undestroying a post with a parent" do
|
||||
should "not preserve the parent's has_children flag" do
|
||||
p1 = Factory.create(:post)
|
||||
c1 = Factory.create(:post, :parent_id => p1.id)
|
||||
c1.remove!
|
||||
c1 = RemovedPost.last
|
||||
c1.unremove!
|
||||
c1 = Post.last
|
||||
p1.reload
|
||||
assert_nil(p1.parent_id)
|
||||
assert(!p1.has_children?, "Parent should not have children")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "During moderation a post" do
|
||||
setup do
|
||||
@post = Factory.create(:post)
|
||||
@ -8,29 +144,29 @@ class PostTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
should "be unapproved once and only once" do
|
||||
@post.unapprove!("bad", @user, "127.0.0.1")
|
||||
@post.unapprove!("bad", @user.id, "127.0.0.1")
|
||||
assert(@post.is_flagged?, "Post should be flagged.")
|
||||
assert_not_nil(@post.unapproval, "Post should have an unapproval record.")
|
||||
assert_equal("bad", @post.unapproval.reason)
|
||||
|
||||
assert_raise(Unapproval::Error) {@post.unapprove!("bad", @user, "127.0.0.1")}
|
||||
assert_raise(Unapproval::Error) {@post.unapprove!("bad", @user.id, "127.0.0.1")}
|
||||
end
|
||||
|
||||
should "not unapprove if no reason is given" do
|
||||
assert_raise(Unapproval::Error) {@post.unapprove!("", @user, "127.0.0.1")}
|
||||
assert_raise(Unapproval::Error) {@post.unapprove!("", @user.id, "127.0.0.1")}
|
||||
end
|
||||
|
||||
should "be deleted" do
|
||||
@post.delete!
|
||||
should "be destroyed" do
|
||||
@post.destroy(1, "127.0.0.1")
|
||||
assert(@post.is_deleted?, "Post should be deleted.")
|
||||
end
|
||||
|
||||
should "be approved" do
|
||||
@post.approve!
|
||||
@post.approve!(1, "127.0.0.1")
|
||||
assert(!@post.is_pending?, "Post should not be pending.")
|
||||
|
||||
@deleted_post = Factory.create(:post, :is_deleted => true)
|
||||
@deleted_post.approve!
|
||||
@deleted_post.approve!(1, "127.0.0.1")
|
||||
assert(!@post.is_deleted?, "Post should not be deleted.")
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user