Files
danbooru/app/models/artist.rb
2013-10-26 00:13:09 -04:00

378 lines
9.7 KiB
Ruby

class Artist < ActiveRecord::Base
before_create :initialize_creator
before_save :normalize_name
after_save :create_version
after_save :save_url_string
after_save :categorize_tag
validates_uniqueness_of :name
belongs_to :creator, :class_name => "User"
has_many :members, :class_name => "Artist", :foreign_key => "group_name", :primary_key => "name"
has_many :urls, :dependent => :destroy, :class_name => "ArtistUrl"
has_many :versions, :order => "artist_versions.id ASC", :class_name => "ArtistVersion"
has_one :wiki_page, :foreign_key => "title", :primary_key => "name"
has_one :tag_alias, :foreign_key => "antecedent_name", :primary_key => "name"
has_one :tag, :foreign_key => "name", :primary_key => "name"
accepts_nested_attributes_for :wiki_page
attr_accessible :body, :name, :url_string, :other_names, :other_names_comma, :group_name, :wiki_page_attributes, :notes, :as => [:member, :gold, :builder, :platinum, :contributor, :janitor, :moderator, :default, :admin]
attr_accessible :is_active, :as => [:builder, :contributor, :janitor, :moderator, :default, :admin]
attr_accessible :is_banned, :as => :admin
module UrlMethods
extend ActiveSupport::Concern
module ClassMethods
def find_all_by_url(url)
url = ArtistUrl.normalize(url)
artists = []
while artists.empty? && url.size > 10
u = url.sub(/\/+$/, "") + "/"
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\/(?:img\/)?$/
end
artists.uniq_by {|x| x.name}.slice(0, 20)
end
end
def save_url_string
if @url_string
urls.clear
@url_string.scan(/\S+/).each do |url|
urls.create(:url => url)
end
end
end
def url_string=(string)
@url_string = string
end
def url_string
@url_string || urls.map {|x| x.url}.join("\n")
end
end
module NameMethods
extend ActiveSupport::Concern
module ClassMethods
def normalize_name(name)
name.to_s.mb_chars.downcase.strip.gsub(/ /, '_').to_s
end
end
def normalize_name
self.name = Artist.normalize_name(name)
end
def other_names_array
other_names.try(:split, /\s/)
end
def other_names_comma
other_names_array.try(:join, ", ")
end
def other_names_comma=(string)
self.other_names = string.split(/,/).map {|x| Artist.normalize_name(x)}.join(" ")
end
end
module GroupMethods
def member_names
members.map(&:name).join(", ")
end
end
module VersionMethods
def create_version
ArtistVersion.create(
:artist_id => id,
:name => name,
:updater_id => CurrentUser.user.id,
:updater_ip_addr => CurrentUser.ip_addr,
:url_string => url_string,
:is_active => is_active,
:is_banned => is_banned,
:other_names => other_names,
:group_name => group_name
)
end
def revert_to!(version)
self.name = version.name
self.url_string = version.url_string
self.is_active = version.is_active
self.other_names = version.other_names
self.group_name = version.group_name
save
end
end
module FactoryMethods
def new_with_defaults(params)
Artist.new.tap do |artist|
if params[:name]
artist.name = params[:name]
post = CurrentUser.without_safe_mode do
Post.tag_match("source:http #{artist.name}").first
end
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
module NoteMethods
def notes
if wiki_page
wiki_page.body
else
nil
end
end
def notes=(msg)
if name_changed? && name_was.present?
old_wiki_page = WikiPage.titled(name_was).first
end
if wiki_page
if name_changed? && name_was.present?
wiki_page.body = wiki_page.body + "\n\n" + msg
else
wiki_page.body = msg
end
wiki_page.save if wiki_page.body_changed?
elsif old_wiki_page
old_wiki_page.title = name
old_wiki_page.body = msg
old_wiki_page.save if old_wiki_page.body_changed? || old_wiki_page.title_changed?
elsif msg.present?
self.wiki_page = WikiPage.new(:title => name, :body => msg)
end
end
end
module TagMethods
def has_tag_alias?
TagAlias.exists?(["antecedent_name = ?", name])
end
def tag_alias_name
TagAlias.find_by_antecedent_name(name).consequent_name
end
def categorize_tag
if new_record? || name_changed?
Tag.find_or_create_by_name("artist:#{name}")
end
end
end
module BanMethods
def ban!
Post.transaction do
CurrentUser.without_safe_mode do
begin
Post.tag_match(name).each do |post|
begin
post.flag!("Artist requested removal")
rescue PostFlag::Error
# swallow
end
post.delete!(:ban => true)
end
rescue Post::SearchError
# swallow
end
# potential race condition but unlikely
unless TagImplication.where(:antecedent_name => name, :consequent_name => "banned_artist").exists?
tag_implication = TagImplication.create(:antecedent_name => name, :consequent_name => "banned_artist")
tag_implication.delay(:queue => "default").process!
end
update_column(:is_banned, true)
end
end
end
end
module SearchMethods
def active
where("is_active = true")
end
def banned
where("is_banned = true")
end
def url_matches(string)
matches = find_all_by_url(string).map(&:id)
if matches.any?
where("id in (?)", matches)
else
where("false")
end
end
def other_names_match(string)
if string =~ /\*/ && CurrentUser.user.is_builder?
where("other_names ILIKE ? ESCAPE E'\\\\'", string.to_escaped_for_sql_like)
else
where("other_names_index @@ to_tsquery('danbooru', E?)", Artist.normalize_name(string).to_escaped_for_tsquery)
end
end
def group_name_matches(name)
stripped_name = normalize_name(name).to_escaped_for_sql_like
where("group_name LIKE ? ESCAPE E'\\\\'", stripped_name)
end
def name_matches(name)
stripped_name = normalize_name(name).to_escaped_for_sql_like
where("name LIKE ? ESCAPE E'\\\\'", stripped_name)
end
def named(name)
where("name = ?", normalize_name(name))
end
def any_name_matches(name)
stripped_name = normalize_name(name).to_escaped_for_sql_like
if name =~ /\*/ && CurrentUser.user.is_builder?
where("(name LIKE ? ESCAPE E'\\\\' OR other_names LIKE ? ESCAPE E'\\\\')", stripped_name, stripped_name)
else
name_for_tsquery = normalize_name(name).to_escaped_for_tsquery
where("(name LIKE ? ESCAPE E'\\\\' OR other_names_index @@ to_tsquery('danbooru', E?))", stripped_name, name_for_tsquery)
end
end
def search(params)
q = scoped
params = {} if params.blank?
case params[:name]
when /^http/
q = q.url_matches(params[:name])
when /name:(.+)/
q = q.name_matches($1)
when /other:(.+)/
q = q.other_names_match($1)
when /group:(.+)/
q = q.group_name_matches($1)
when /status:banned/
q = q.banned
when /status:active/
q = q.where("is_banned = false and is_deleted = false")
when /./
q = q.any_name_matches(params[:name])
end
params[:order] ||= params.delete(:sort)
if params[:order] == "name"
q = q.reorder("name")
else
q = q.reorder("id desc")
end
if params[:is_active] == "true"
q = q.active
elsif params[:is_active] == "false"
q = q.where("is_active = false")
end
if params[:is_banned] == "true"
q = q.banned
elsif params[:is_banned] == "false"
q = q.where("is_banned = false")
end
if params[:id].present?
q = q.where("id = ?", params[:id])
end
if params[:creator_name].present?
q = q.where("creator_id = (select _.id from users _ where lower(_.name) = ?)", params[:creator_name].tr(" ", "_").mb_chars.downcase)
end
if params[:creator_id].present?
q = q.where("creator_id = ?", params[:creator_id].to_i)
end
q
end
end
module ApiMethods
def hidden_attributes
super + [:other_names_index]
end
def legacy_api_hash
return {
:id => id,
:name => name,
:other_names => other_names,
:group_name => group_name,
:urls => artist_urls.map {|x| x.url},
:is_active => is_active?,
:updater_id => 0
}
end
end
include UrlMethods
include NameMethods
include GroupMethods
include VersionMethods
extend FactoryMethods
include NoteMethods
include TagMethods
include BanMethods
extend SearchMethods
include ApiMethods
def status
if is_banned? && is_active?
"Banned"
elsif is_banned?
"Banned Deleted"
elsif is_active?
"Active"
else
"Deleted"
end
end
def initialize_creator
self.creator_id = CurrentUser.user.id
end
def deletable_by?(user)
user.is_builder?
end
end