This tag has been aliased to "
+ html << link_to(antecedent_alias.consequent_name, show_or_new_wiki_pages_path(:title => antecedent_alias.consequent_name))
+ html << ".
"
+ end
+
+ if consequent_aliases.any?
+ html << "
The following tags are aliased to this tag: "
+ html << raw(consequent_aliases.map {|x| link_to(x.antecedent_name, show_or_new_wiki_pages_path(:title => x.antecedent_name))}.join(", "))
+ html << ".
"
+ end
+
+ if antecedent_implications.any?
+ html << "
This tag implicates "
+ html << raw(antecedent_implications.map {|x| link_to(x.consequent_name, show_or_new_wiki_pages_path(:title => x.consequent_name))}.join(", "))
+ html << ".
"
+ end
+
+ if consequent_implications.any?
+ html << "
The following tags implicate this tag: "
+ html << raw(consequent_implications.map {|x| link_to(x.antecedent_name, show_or_new_wiki_pages_path(:title => x.antecedent_name))}.join(", "))
+ html << ".
"
+ end
+
+ html.html_safe
+ end
+
+ def wiki_page_post_previews(wiki_page)
+ html = '
'
+
+ if Post.fast_count(wiki_page.title) > 0
+ html << "
Posts
"
+ html << wiki_page.post_set.presenter.post_previews_html(self)
+ end
+
+ html << "
"
+
+ html.html_safe
+ end
end
diff --git a/app/logical/alias_and_implication_importer.rb b/app/logical/alias_and_implication_importer.rb
index 5ee2887d8..21ce73a85 100644
--- a/app/logical/alias_and_implication_importer.rb
+++ b/app/logical/alias_and_implication_importer.rb
@@ -1,9 +1,10 @@
class AliasAndImplicationImporter
- attr_accessor :text, :commands, :forum_id
+ attr_accessor :text, :commands, :forum_id, :rename_aliased_pages
- def initialize(text, forum_id)
+ def initialize(text, forum_id, rename_aliased_pages = "0")
@forum_id = forum_id
@text = text
+ @rename_aliased_pages = rename_aliased_pages
end
def process!
@@ -11,6 +12,10 @@ class AliasAndImplicationImporter
parse(tokens)
end
+ def rename_aliased_pages?
+ @rename_aliased_pages == "1"
+ end
+
private
def tokenize(text)
@@ -40,6 +45,7 @@ private
case token[0]
when :create_alias
tag_alias = TagAlias.create(:forum_topic_id => forum_id, :status => "pending", :antecedent_name => token[1], :consequent_name => token[2])
+ tag_alias.rename_wiki_and_artist if rename_aliased_pages?
tag_alias.delay(:queue => "default").process!
when :create_implication
diff --git a/app/logical/moderator/dashboard/report.rb b/app/logical/moderator/dashboard/report.rb
index 3694988f9..c3600e8ac 100644
--- a/app/logical/moderator/dashboard/report.rb
+++ b/app/logical/moderator/dashboard/report.rb
@@ -5,7 +5,7 @@ module Moderator
def initialize(min_date, max_level)
@min_date = min_date.present? ? min_date.to_date : 1.week.ago
- @max_level = max_level.present? ? User::Levels::MEMBER : max_level.to_i
+ @max_level = max_level.present? ? max_level.to_i : User::Levels::MEMBER
end
def artists
diff --git a/app/logical/post_query_builder.rb b/app/logical/post_query_builder.rb
index cb2ec7a0a..9eaf29a6a 100644
--- a/app/logical/post_query_builder.rb
+++ b/app/logical/post_query_builder.rb
@@ -170,6 +170,20 @@ class PostQueryBuilder
end
end
+ if q[:source_neg]
+ if q[:source_neg] == "none%"
+ relation = relation.where("(posts.source != '' AND posts.source IS NOT NULL)")
+ elsif q[:source_neg] == "http%"
+ relation = relation.where("(posts.source not like ?)", "http%")
+ elsif q[:source_neg] =~ /^%\.?pixiv(?:\.net(?:\/img)?)?(?:%\/|(?=%$))(.+)$/
+ relation = relation.where("SourcePattern(posts.source) NOT LIKE ? ESCAPE E'\\\\'", "pixiv/" + $1)
+ has_constraints!
+ else
+ relation = relation.where("SourcePattern(posts.source) NOT LIKE SourcePattern(?) ESCAPE E'\\\\'", q[:source_neg])
+ has_constraints!
+ end
+ end
+
if q[:subscriptions]
relation = add_tag_subscription_relation(q[:subscriptions], relation)
has_constraints!
diff --git a/app/logical/post_sets/favorite.rb b/app/logical/post_sets/favorite.rb
index b0d051260..f5bae6a00 100644
--- a/app/logical/post_sets/favorite.rb
+++ b/app/logical/post_sets/favorite.rb
@@ -6,6 +6,10 @@ module PostSets
@params = params
@user = ::User.find(user_id)
@favorites = ::Favorite.for_user(user.id).paginate(page, :limit => limit).order("favorites.id desc")
+
+ if CurrentUser.user.hide_deleted_posts?
+ @favorites = @favorites.where("is_deleted = false")
+ end
end
def limit
diff --git a/app/logical/post_sets/post_relationship.rb b/app/logical/post_sets/post_relationship.rb
new file mode 100644
index 000000000..2cd085590
--- /dev/null
+++ b/app/logical/post_sets/post_relationship.rb
@@ -0,0 +1,24 @@
+module PostSets
+ class PostRelationship < PostSets::Post
+ attr_reader :parent, :children
+
+ def initialize(parent_id, options = {})
+ @parent = ::Post.where("id = ?", parent_id)
+ @children = ::Post.where("parent_id = ?", parent_id).order("id ASC")
+ if options[:include_deleted]
+ super("parent:#{parent_id} status:any")
+ else
+ @children = @children.where("is_deleted = ?", false)
+ super("parent:#{parent_id}")
+ end
+ end
+
+ def posts
+ @parent + @children
+ end
+
+ def presenter
+ ::PostSetPresenters::Post.new(self)
+ end
+ end
+end
diff --git a/app/logical/post_sets/wiki_page.rb b/app/logical/post_sets/wiki_page.rb
index 2c83d5c2c..22625fa43 100644
--- a/app/logical/post_sets/wiki_page.rb
+++ b/app/logical/post_sets/wiki_page.rb
@@ -2,7 +2,7 @@ module PostSets
class SearchError < Exception
end
- class WikiPage < Post
+ class WikiPage < PostSets::Post
def presenter
@presenter ||= ::PostSetPresenters::WikiPage.new(self)
end
diff --git a/app/logical/session_loader.rb b/app/logical/session_loader.rb
index af3836c9b..c8d321ee8 100644
--- a/app/logical/session_loader.rb
+++ b/app/logical/session_loader.rb
@@ -74,7 +74,7 @@ private
end
def ban_expired?
- CurrentUser.user.is_banned? && CurrentUser.user.ban && CurrentUser.user.ban.expired?
+ CurrentUser.user.is_banned? && CurrentUser.user.recent_ban && CurrentUser.user.recent_ban.expired?
end
def cookie_password_hash_valid?
diff --git a/app/logical/upload_error_checker.rb b/app/logical/upload_error_checker.rb
index 9ee480560..f9c32afb1 100644
--- a/app/logical/upload_error_checker.rb
+++ b/app/logical/upload_error_checker.rb
@@ -4,7 +4,7 @@ require 'mail'
class UploadErrorChecker
def check!
- uploads = Upload.where("status like 'error%' and created_at >= ?", 1.hour.ago).all
+ uploads = Upload.where("status like 'error%' and status not like 'error: RuntimeError - duplicate%' and created_at >= ?", 1.hour.ago).all
if uploads.size > 5
mail = Mail.new do
from "webmaster@danbooru.donmai.us"
diff --git a/app/models/artist.rb b/app/models/artist.rb
index 155a2ef90..45b09435e 100644
--- a/app/models/artist.rb
+++ b/app/models/artist.rb
@@ -28,7 +28,7 @@ class Artist < ActiveRecord::Base
u = u.to_escaped_for_sql_like.gsub(/\*/, '%') + '%'
artists += Artist.joins(:urls).where(["artists.is_active = TRUE AND artist_urls.normalized_url LIKE ? ESCAPE E'\\\\'", u]).limit(10).order("artists.name").all
url = File.dirname(url) + "/"
- break if url =~ /pixiv\.net\/$/
+ break if url =~ /pixiv\.net\/(?:img\/)?$/
end
artists.uniq_by {|x| x.name}.slice(0, 20)
diff --git a/app/models/favorite.rb b/app/models/favorite.rb
index d3c84890e..4bcb0bd4f 100644
--- a/app/models/favorite.rb
+++ b/app/models/favorite.rb
@@ -12,24 +12,24 @@ class Favorite < ActiveRecord::Base
end
def self.add(post, user)
- return if Favorite.for_user(user.id).exists?(:user_id => user.id, :post_id => post.id)
+ return if Favorite.for_user(user.id).where(:user_id => user.id, :post_id => post.id).exists?
Favorite.create(:user_id => user.id, :post_id => post.id)
- Post.update_all("fav_count = fav_count + 1", "id = #{post.id}")
- Post.update_all("score = score + 1", "id = #{post.id}") if user.is_gold?
+ Post.update_all("fav_count = fav_count + 1", {:id => post.id})
+ Post.update_all("score = score + 1", {:id => post.id}) if user.is_gold?
post.append_user_to_fav_string(user.id)
- user.add_favorite!(post)
- user.increment!(:favorite_count)
- post.add_favorite!(user)
+ User.update_all("favorite_count = favorite_count + 1", {:id => user.id})
+ user.favorite_count += 1
+ post.fav_count += 1
end
def self.remove(post, user)
- return unless Favorite.for_user(user.id).exists?(:user_id => user.id, :post_id => post.id)
+ return unless Favorite.for_user(user.id).where(:user_id => user.id, :post_id => post.id).exists?
Favorite.destroy_all(:user_id => user.id, :post_id => post.id)
- Post.update_all("fav_count = fav_count - 1", "id = #{post.id}")
- Post.update_all("score = score - 1", "id = #{post.id}") if user.is_gold?
+ Post.update_all("fav_count = fav_count - 1", {:id => post.id})
+ Post.update_all("score = score - 1", {:id => post.id}) if user.is_gold?
post.delete_user_from_fav_string(user.id)
- user.remove_favorite!(post)
- user.decrement!(:favorite_count)
- post.remove_favorite!(user)
+ User.update_all("favorite_count = favorite_count - 1", {:id => user.id})
+ user.favorite_count -= 1
+ post.fav_count -= 1
end
end
diff --git a/app/models/forum_post.rb b/app/models/forum_post.rb
index 5d2b5822d..c8755205c 100644
--- a/app/models/forum_post.rb
+++ b/app/models/forum_post.rb
@@ -7,7 +7,8 @@ class ForumPost < ActiveRecord::Base
before_validation :initialize_creator, :on => :create
before_validation :initialize_updater
before_validation :initialize_is_deleted, :on => :create
- after_create :update_topic_updated_at
+ after_create :update_topic_updated_at_on_create
+ after_destroy :update_topic_updated_at_on_destroy
validates_presence_of :body, :creator_id
validate :validate_topic_is_unlocked
before_destroy :validate_topic_is_unlocked
@@ -87,7 +88,7 @@ class ForumPost < ActiveRecord::Base
creator_id == user.id || user.is_janitor?
end
- def update_topic_updated_at
+ def update_topic_updated_at_on_create
if topic
topic.updater_id = CurrentUser.id
topic.response_count = topic.response_count + 1
@@ -95,6 +96,13 @@ class ForumPost < ActiveRecord::Base
end
end
+ def update_topic_updated_at_on_destroy
+ max = ForumPost.where(:topic_id => topic.id).maximum(:updated_at)
+ if max
+ topic.update_column(:updated_at, max)
+ end
+ end
+
def initialize_creator
self.creator_id = CurrentUser.id
end
diff --git a/app/models/news_update.rb b/app/models/news_update.rb
index 5fa37bbc0..29755564b 100644
--- a/app/models/news_update.rb
+++ b/app/models/news_update.rb
@@ -1,6 +1,6 @@
class NewsUpdate < ActiveRecord::Base
belongs_to :creator, :class_name => "User"
- belongs_to :udpater, :class_name => "User"
+ belongs_to :updater, :class_name => "User"
scope :recent, order("created_at desc").limit(5)
before_validation :initialize_creator, :on => :create
before_validation :initialize_updater
diff --git a/app/models/note.rb b/app/models/note.rb
index d7a75cea6..80c0a1ec4 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -7,6 +7,8 @@ class Note < ActiveRecord::Base
before_validation :initialize_updater
before_validation :blank_body
validates_presence_of :post_id, :creator_id, :updater_id, :x, :y, :width, :height
+ validate :post_must_exist
+ validate :note_within_image, :message => "must be inside the image"
has_many :versions, :class_name => "NoteVersion", :order => "note_versions.id ASC"
after_save :update_post
after_save :create_version
@@ -95,6 +97,13 @@ class Note < ActiveRecord::Base
self.updater_ip_addr = CurrentUser.ip_addr
end
+ def post_must_exist
+ if !Post.exists?(post_id)
+ errors.add :post, "must exist"
+ return false
+ end
+ end
+
def post_must_not_be_note_locked
if is_locked?
errors.add :post, "is note locked"
@@ -102,6 +111,14 @@ class Note < ActiveRecord::Base
end
end
+ def note_within_image
+ return false unless post.present?
+ if x < 0 || y < 0 || (x > post.image_width) || (y > post.image_height) || width < 0 || height < 0 || (x + width > post.image_width) || (y + height > post.image_height)
+ self.errors.add(:note, "must be inside the image")
+ return false
+ end
+ end
+
def is_locked?
Post.exists?(["id = ? AND is_note_locked = ?", post_id, true])
end
diff --git a/app/models/pool.rb b/app/models/pool.rb
index 7365d272a..42574de2f 100644
--- a/app/models/pool.rb
+++ b/app/models/pool.rb
@@ -11,6 +11,7 @@ class Pool < ActiveRecord::Base
before_validation :initialize_is_active, :on => :create
before_validation :initialize_creator, :on => :create
after_save :create_version
+ after_create :synchronize!
before_destroy :create_mod_action_for_destroy
attr_accessible :name, :description, :post_ids, :post_id_array, :post_count, :is_active, :as => [:member, :gold, :platinum, :contributor, :janitor, :moderator, :admin, :default]
attr_accessible :is_deleted, :as => [:janitor, :moderator, :admin]
@@ -25,9 +26,9 @@ class Pool < ActiveRecord::Base
params = {} if params.blank?
if params[:name_matches].present?
- params[:name_matches] = params[:name_matches].tr(" ", "_")
- params[:name_matches] = "*#{params[:name_matches]}*" unless params[:name_matches] =~ /\*/
- q = q.where("name ilike ? escape E'\\\\'", params[:name_matches].to_escaped_for_sql_like)
+ name_matches = params[:name_matches].tr(" ", "_")
+ name_matches = "*#{name_matches}*" unless name_matches =~ /\*/
+ q = q.where("name ilike ? escape E'\\\\'", name_matches.to_escaped_for_sql_like)
end
if params[:description_matches].present?
diff --git a/app/models/post.rb b/app/models/post.rb
index 377d562e8..1ef54ddf6 100644
--- a/app/models/post.rb
+++ b/app/models/post.rb
@@ -3,7 +3,7 @@ class Post < ActiveRecord::Base
class DisapprovalError < Exception ; end
class SearchError < Exception ; end
- attr_accessor :old_tag_string, :old_parent_id, :has_constraints
+ attr_accessor :old_tag_string, :old_parent_id, :has_constraints, :disable_versioning
after_destroy :delete_files
after_destroy :delete_remote_files
after_save :create_version
@@ -31,6 +31,7 @@ class Post < ActiveRecord::Base
has_many :disapprovals, :class_name => "PostDisapproval", :dependent => :destroy
validates_uniqueness_of :md5
validates_presence_of :parent, :if => lambda {|rec| !rec.parent_id.nil?}
+ validate :post_is_not_its_own_parent
attr_accessible :source, :rating, :tag_string, :old_tag_string, :last_noted_at, :parent_id, :as => [:member, :builder, :gold, :platinum, :contributor, :janitor, :moderator, :admin, :default]
attr_accessible :is_rating_locked, :is_note_locked, :as => [:builder, :contributor, :janitor, :moderator, :admin]
attr_accessible :is_status_locked, :as => [:admin]
@@ -313,20 +314,24 @@ class Post < ActiveRecord::Base
end
def increment_tag_post_counts
- Post.execute_sql("UPDATE tags SET post_count = post_count + 1 WHERE name IN (?)", tag_array) if tag_array.any?
+ Tag.update_all("post_count = post_count + 1", {:name => tag_array}) if tag_array.any?
end
def decrement_tag_post_counts
- Post.execute_sql("UPDATE tags SET post_count = post_count - 1 WHERE name IN (?)", tag_array) if tag_array.any?
+ Tag.update_all("post_count = post_count - 1", {:name => 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
- Post.execute_sql("UPDATE tags SET post_count = post_count - 1 WHERE name IN (?)", decrement_tags) if decrement_tags.any?
- Post.execute_sql("UPDATE tags SET post_count = post_count + 1 WHERE name IN (?)", increment_tags) if increment_tags.any?
- Post.expire_cache_for_all(decrement_tags) if decrement_tags.any?
- Post.expire_cache_for_all(increment_tags) if increment_tags.any?
+ if increment_tags.any?
+ Tag.update_all("post_count = post_count + 1", {:name => increment_tags})
+ Post.expire_cache_for_all(increment_tags)
+ end
+ if decrement_tags.any?
+ Tag.update_all("post_count = post_count - 1", {:name => decrement_tags})
+ Post.expire_cache_for_all(decrement_tags)
+ end
Post.expire_cache_for_all([""]) if new_record? || id <= 100_000
end
@@ -337,7 +342,7 @@ class Post < ActiveRecord::Base
self.tag_count_copyright = 0
self.tag_count_character = 0
- categories = Tag.categories_for(tag_array)
+ categories = Tag.categories_for(tag_array, :disable_caching => true)
categories.each_value do |category|
self.tag_count += 1
@@ -622,11 +627,9 @@ class Post < ActiveRecord::Base
def vote!(score)
if can_be_voted_by?(CurrentUser.user)
if score == "up"
- increment!(:score)
- increment!(:up_score)
+ Post.update_all("score = score + 1, up_score = up_score + 1", {:id => id})
elsif score == "down"
- decrement!(:score)
- decrement!(:down_score)
+ Post.update_all("score = score - 1, down_score = down_score - 1", {:id => id})
end
votes.create(:score => score)
@@ -798,6 +801,13 @@ class Post < ActiveRecord::Base
update_column(:score, 0)
end
+
+ def post_is_not_its_own_parent
+ if parent_id.present? && id == parent_id
+ errors[:base] << "Post cannot have itself as a parent"
+ false
+ end
+ end
end
module DeletionMethods
@@ -860,6 +870,8 @@ class Post < ActiveRecord::Base
module VersionMethods
def create_version
+ return if disable_versioning
+
if created_at == updated_at
CurrentUser.increment!(:post_update_count)
versions.create(
diff --git a/app/models/post_flag.rb b/app/models/post_flag.rb
index e125d0bb2..800d8c988 100644
--- a/app/models/post_flag.rb
+++ b/app/models/post_flag.rb
@@ -68,9 +68,6 @@ class PostFlag < ActiveRecord::Base
if post.is_deleted?
errors[:post] << "is deleted"
false
- elsif post.is_pending?
- errors[:post] << "is pending"
- false
else
true
end
diff --git a/app/models/tag.rb b/app/models/tag.rb
index 347f4a35a..e692922ca 100644
--- a/app/models/tag.rb
+++ b/app/models/tag.rb
@@ -1,5 +1,5 @@
class Tag < ActiveRecord::Base
- METATAGS = "-user|user|-approver|approver|commenter|comm|noter|-pool|pool|-fav|fav|sub|md5|-rating|rating|-locked|locked|width|height|mpixels|score|favcount|filesize|source|id|-id|date|age|order|-status|status|tagcount|gentags|arttags|chartags|copytags|parent|-parent|pixiv_id|pixiv"
+ METATAGS = "-user|user|-approver|approver|commenter|comm|noter|-pool|pool|-fav|fav|sub|md5|-rating|rating|-locked|locked|width|height|mpixels|score|favcount|filesize|source|-source|id|-id|date|age|order|-status|status|tagcount|gentags|arttags|chartags|copytags|parent|-parent|pixiv_id|pixiv"
attr_accessible :category
has_one :wiki_page, :foreign_key => "name", :primary_key => "title"
@@ -66,20 +66,21 @@ class Tag < ActiveRecord::Base
select_value_sql("SELECT category FROM tags WHERE name = ?", tag_name).to_i
end
- def category_for(tag_name)
- Cache.get("tc:#{Cache.sanitize(tag_name)}") do
+ def category_for(tag_name, options = {})
+ if options[:disable_caching]
select_category_for(tag_name)
+ else
+ Cache.get("tc:#{Cache.sanitize(tag_name)}") do
+ select_category_for(tag_name)
+ end
end
end
- def categories_for(tag_names)
+ def categories_for(tag_names, options = {})
Array(tag_names).inject({}) do |hash, tag_name|
- hash[tag_name] = category_for(tag_name)
+ hash[tag_name] = category_for(tag_name, options)
hash
end
- # Cache.get_multi(tag_names, "tc") do |name|
- # select_category_for(name)
- # end
end
end
@@ -104,11 +105,7 @@ class Tag < ActiveRecord::Base
Post.raw_tag_match(name).find_each do |post|
post.reload
post.set_tag_counts
- post.update_column(:tag_count, post.tag_count)
- post.update_column(:tag_count_general, post.tag_count_general)
- post.update_column(:tag_count_artist, post.tag_count_artist)
- post.update_column(:tag_count_copyright, post.tag_count_copyright)
- post.update_column(:tag_count_character, post.tag_count_character)
+ Post.update_all({:tag_count => post.tag_count, :tag_count_general => post.tag_count_general, :tag_count_artist => post.tag_count_artist, :tag_count_copyright => post.tag_count_copyright, :tag_count_character => post.tag_count_character}, {:id => post.id})
end
end
end
@@ -253,7 +250,7 @@ class Tag < ActiveRecord::Base
return [:gt, parse_cast($1, type)]
when /,/
- return [:in, range.split(/,/)]
+ return [:in, range.split(/,/).map {|x| parse_cast(x, type)}]
else
return [:eq, parse_cast(range, type)]
@@ -402,6 +399,9 @@ class Tag < ActiveRecord::Base
when "source"
q[:source] = ($2.to_escaped_for_sql_like + "%").gsub(/%+/, '%')
+ when "-source"
+ q[:source_neg] = ($2.to_escaped_for_sql_like + "%").gsub(/%+/, '%')
+
when "date"
q[:date] = parse_helper($2, :date)
@@ -547,14 +547,20 @@ class Tag < ActiveRecord::Base
elsif params[:order] == "date"
q = q.reorder("id desc")
+ elsif params[:order] == "count"
+ q = q.reorder("post_count desc")
+
elsif params[:sort] == "date"
q = q.reorder("id desc")
elsif params[:sort] == "name"
q = q.reorder("name")
- else
+ elsif params[:sort] == "count"
q = q.reorder("post_count desc")
+
+ else
+ q = q.reorder("id desc")
end
q
diff --git a/app/models/tag_alias.rb b/app/models/tag_alias.rb
index 9870a85d8..40b7695a6 100644
--- a/app/models/tag_alias.rb
+++ b/app/models/tag_alias.rb
@@ -130,6 +130,7 @@ class TagAlias < ActiveRecord::Base
escaped_antecedent_name = Regexp.escape(antecedent_name)
fixed_tags = post.tag_string.sub(/(?:\A| )#{escaped_antecedent_name}(?:\Z| )/, " #{consequent_name} ").strip
CurrentUser.scoped(creator, creator_ip_addr) do
+ post.disable_versioning = true
post.update_attributes(
:tag_string => fixed_tags
)
@@ -139,4 +140,27 @@ class TagAlias < ActiveRecord::Base
antecedent_tag.fix_post_count if antecedent_tag
consequent_tag.fix_post_count if consequent_tag
end
+
+ def rename_wiki_and_artist
+ antecedent_wiki = WikiPage.titled(antecedent_name).first
+ if antecedent_wiki.present? && WikiPage.titled(consequent_name).blank?
+ CurrentUser.scoped(creator, creator_ip_addr) do
+ antecedent_wiki.update_attributes(
+ :title => consequent_name,
+ :body => "[i]This page was automatically renamed from [[#{antecedent_name}]] by a tag alias.[/i]\n\n#{antecedent_wiki.body}"
+ )
+ end
+ end
+
+ if antecedent_tag.category == Tag.categories.artist
+ antecedent_artist = Artist.name_matches(antecedent_name).first
+ if antecedent_artist.present? && Artist.name_matches(consequent_name).blank?
+ CurrentUser.scoped(creator, creator_ip_addr) do
+ antecedent_artist.update_attributes(
+ :name => consequent_name
+ )
+ end
+ end
+ end
+ end
end
diff --git a/app/models/tag_implication.rb b/app/models/tag_implication.rb
index f47e47084..b0a9ccaac 100644
--- a/app/models/tag_implication.rb
+++ b/app/models/tag_implication.rb
@@ -1,6 +1,8 @@
class TagImplication < ActiveRecord::Base
before_save :update_descendant_names
after_save :update_descendant_names_for_parent
+ after_destroy :update_descendant_names_for_parent
+ after_destroy :update_posts_for_destroy
belongs_to :creator, :class_name => "User"
before_validation :initialize_creator, :on => :create
before_validation :normalize_names
@@ -90,13 +92,41 @@ class TagImplication < ActiveRecord::Base
q = q.where("antecedent_name = ?", params[:antecedent_name])
end
+ if params[:consequent_name].present?
+ q = q.where("consequent_name = ?", params[:consequent_name])
+ end
+
q
end
end
+ module DeletionMethods
+ extend ActiveSupport::Concern
+
+ module ClassMethods
+ def update_posts_for_destroy(creator_id, creator_ip_addr, tag_name)
+ Post.tag_match("#{tag_name} status:any").find_each do |post|
+ escaped_tag_name = Regexp.escape(tag_name)
+ fixed_tags = post.tag_string.sub(/(?:\A| )#{escaped_tag_name}(?:\Z| )/, " ").strip
+ CurrentUser.scoped(User.find(creator_id), creator_ip_addr) do
+ post.disable_versioning = true
+ post.update_attributes(
+ :tag_string => fixed_tags
+ )
+ end
+ end
+ end
+ end
+
+ def update_posts_for_destroy
+ TagImplication.delay(:queue => "default").update_posts_for_destroy(CurrentUser.user.id, CurrentUser.ip_addr, consequent_name)
+ end
+ end
+
include DescendantMethods
include ParentMethods
extend SearchMethods
+ include DeletionMethods
def initialize_creator
self.creator_id = CurrentUser.user.id
@@ -105,7 +135,7 @@ class TagImplication < ActiveRecord::Base
def process!
update_column(:status, "processing")
- update_posts
+ update_posts_for_create
update_column(:status, "active")
update_descendant_names_for_parent
rescue Exception => e
@@ -120,11 +150,12 @@ class TagImplication < ActiveRecord::Base
end
end
- def update_posts
+ def update_posts_for_create
Post.tag_match("#{antecedent_name} status:any").find_each do |post|
escaped_antecedent_name = Regexp.escape(antecedent_name)
fixed_tags = post.tag_string.sub(/(?:\A| )#{escaped_antecedent_name}(?:\Z| )/, " #{antecedent_name} #{descendant_names} ").strip
CurrentUser.scoped(creator, creator_ip_addr) do
+ post.disable_versioning = true
post.update_attributes(
:tag_string => fixed_tags
)
diff --git a/app/models/tag_subscription.rb b/app/models/tag_subscription.rb
index cc049ca56..dcc3c297e 100644
--- a/app/models/tag_subscription.rb
+++ b/app/models/tag_subscription.rb
@@ -6,7 +6,7 @@ class TagSubscription < ActiveRecord::Base
before_save :limit_tag_count
attr_accessible :name, :tag_query, :post_ids, :is_public, :is_visible_on_profile
validates_presence_of :name, :tag_query, :creator_id
- validates_format_of :tag_query, :with => /^(?:\S+\s*){1,20}$/m, :message => "can have up to 20 tags"
+ validates_format_of :tag_query, :with => /\A(?:\S*\s*){1,20}\Z/, :message => "can have up to 20 tags"
validate :creator_can_create_subscriptions, :on => :create
def normalize_name
@@ -124,7 +124,13 @@ class TagSubscription < ActiveRecord::Base
end
def self.find_posts(user_id, name = nil, limit = Danbooru.config.tag_subscription_post_limit)
- Post.where(["id in (?)", find_post_ids(user_id, name, limit)]).order("id DESC").limit(limit)
+ arel = Post.where(["id in (?)", find_post_ids(user_id, name, limit)])
+
+ if CurrentUser.user.hide_deleted_posts?
+ arel = arel.where("is_deleted = false")
+ end
+
+ arel.order("id DESC").limit(limit)
end
def self.process_all
diff --git a/app/models/user.rb b/app/models/user.rb
index d5eed17a8..5f07a402d 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -40,7 +40,8 @@ class User < ActiveRecord::Base
before_create :promote_to_admin_if_first_user
has_many :feedback, :class_name => "UserFeedback", :dependent => :destroy
has_many :posts, :foreign_key => "uploader_id"
- has_one :ban
+ has_many :bans, :order => "bans.id desc"
+ has_one :recent_ban, :class_name => "Ban", :order => "bans.id desc"
has_many :subscriptions, :class_name => "TagSubscription", :foreign_key => "creator_id", :order => "name"
has_many :note_versions, :foreign_key => "updater_id"
has_many :dmails, :foreign_key => "owner_id", :order => "dmails.id desc"
@@ -351,7 +352,7 @@ class User < ActiveRecord::Base
def create_mod_action
if level_changed?
- ModAction.create(:description => "#{name} level changed #{level_string(level_was)} -> #{level_string} by #{CurrentUser.name}")
+ ModAction.create(:description => %{"#{name}":/users/#{id} level changed #{level_string(level_was)} -> #{level_string}})
end
end
@@ -510,13 +511,15 @@ class User < ActiveRecord::Base
module ApiMethods
def hidden_attributes
- super + [:password_hash, :bcrypt_password_hash, :email, :email_verification_key, :time_zone, :created_at, :updated_at, :receive_email_notifications, :last_logged_in_at, :last_forum_read_at, :has_mail, :default_image_size, :comment_threshold, :always_resize_images, :favorite_tags, :blacklisted_tags, :base_upload_limit, :recent_tags, :enable_privacy_mode, :enable_post_navigation, :new_post_navigation_layout, :enable_sequential_post_navigation, :hide_deleted_posts, :per_page, :style_usernames]
+ super + [:password_hash, :bcrypt_password_hash, :email, :email_verification_key, :time_zone, :updated_at, :receive_email_notifications, :last_logged_in_at, :last_forum_read_at, :has_mail, :default_image_size, :comment_threshold, :always_resize_images, :favorite_tags, :blacklisted_tags, :recent_tags, :enable_privacy_mode, :enable_post_navigation, :new_post_navigation_layout, :enable_sequential_post_navigation, :hide_deleted_posts, :per_page, :style_usernames]
end
def serializable_hash(options = {})
options ||= {}
options[:except] ||= []
options[:except] += hidden_attributes
+ options[:methods] ||= []
+ options[:methods] += [:wiki_page_version_count, :artist_version_count, :pool_version_count, :forum_post_count, :comment_count]
super(options)
end
@@ -525,6 +528,8 @@ class User < ActiveRecord::Base
options ||= {}
options[:except] ||= []
options[:except] += hidden_attributes
+ options[:methods] ||= []
+ options[:methods] += [:wiki_page_version_count, :artist_version_count, :pool_version_count, :forum_post_count, :comment_count]
super(options, &block)
end
@@ -538,6 +543,28 @@ class User < ActiveRecord::Base
end
end
+ module CountMethods
+ def wiki_page_version_count
+ WikiPageVersion.for_user(id).count
+ end
+
+ def artist_version_count
+ ArtistVersion.for_user(id).count
+ end
+
+ def pool_version_count
+ PoolVersion.for_user(id).count
+ end
+
+ def forum_post_count
+ ForumPost.for_user(id).count
+ end
+
+ def comment_count
+ Comment.for_creator(id).count
+ end
+ end
+
module SearchMethods
def named(name)
where("lower(name) = ?", name)
@@ -657,6 +684,7 @@ class User < ActiveRecord::Base
include LimitMethods
include InvitationMethods
include ApiMethods
+ include CountMethods
extend SearchMethods
include DeletionMethods
diff --git a/app/models/user_feedback.rb b/app/models/user_feedback.rb
index 796d34a01..4ce908d07 100644
--- a/app/models/user_feedback.rb
+++ b/app/models/user_feedback.rb
@@ -5,6 +5,7 @@ class UserFeedback < ActiveRecord::Base
before_validation :initialize_creator, :on => :create
attr_accessible :body, :user_id, :category, :user_name
validates_presence_of :user, :creator, :body, :category
+ validates_inclusion_of :category, :in => %w(positive negative neutral)
validate :creator_is_gold
validate :user_is_not_creator
after_create :create_dmail
@@ -46,6 +47,10 @@ class UserFeedback < ActiveRecord::Base
q = q.where("creator_id = (select _.id from users _ where lower(_.name) = ?)", params[:creator_name].mb_chars.downcase)
end
+ if params[:category].present?
+ q = q.where("category = ?", params[:category])
+ end
+
q
end
end
diff --git a/app/presenters/post_presenter.rb b/app/presenters/post_presenter.rb
index 5c2a704c3..9bdac970f 100644
--- a/app/presenters/post_presenter.rb
+++ b/app/presenters/post_presenter.rb
@@ -166,7 +166,7 @@ class PostPresenter < Presenter
end
else
first = true
- @post.pools.active.each do |pool|
+ @post.pools.each do |pool|
if first && template.params[:tags].blank?
html += pool_link_html(template, pool, :include_rel => true)
first = false
@@ -181,7 +181,7 @@ class PostPresenter < Presenter
end
def pool_link_html(template, pool, options = {})
- pool_html = ['