Files
danbooru/app/models/artist_url.rb
evazion 5837b614d4 artists: fix exception on show page when artist has invalid URLs.
Fix an exception on the artist show page when the artist entry contained invalid URLs such
as `http://ttp://album.yahoo.co.jp/photos/my/8027988`. Caused by `ArtistUrl#domain`
returning nil for certain invalid URLs, which caused `Artist#sorted_urls` to blow up.

ref: https://danbooru.donmai.us/forum_posts/206488
2022-02-25 02:06:57 -06:00

157 lines
4.5 KiB
Ruby

# frozen_string_literal: true
class ArtistURL < ApplicationRecord
normalize :url, :normalize_url
validates :url, presence: true, uniqueness: { scope: :artist_id }
validate :validate_url_format
belongs_to :artist, :touch => true
scope :url_matches, ->(url) { url_attribute_matches(:url, url) }
scope :normalized_url_matches, ->(url) { url_attribute_matches(:normalized_url, url) }
scope :active, -> { where(is_active: true) }
def self.parse_prefix(url)
prefix, url = url.match(/\A(-)?(.*)/)[1, 2]
is_active = prefix.nil?
[is_active, url]
end
def self.normalize_normalized_url(url)
if url.nil?
nil
else
url = url.sub(%r{^https://}, "http://")
url = url.sub(%r{^http://blog-imgs-\d+\.fc2}, "http://blog.fc2")
url = url.sub(%r{^http://blog-imgs-\d+-\w+\.fc2}, "http://blog.fc2")
url = url.sub(%r{^http://blog\d*\.fc2\.com/(?:\w/){,3}(\w+)}, "http://\\1.blog.fc2.com")
url = url.sub(%r{^http://pictures.hentai-foundry.com//}, "http://pictures.hentai-foundry.com/")
# the strategy won't always work for twitter because it looks for a status
url = url.downcase if url =~ %r{^https?://(?:mobile\.)?twitter\.com}i
url = Sources::Strategies.find(url).normalize_for_artist_finder
# XXX the Pixiv strategy should implement normalize_for_artist_finder and return the correct url directly.
url = url.sub(%r{\Ahttps?://www\.pixiv\.net/(?:en/)?users/(\d+)\z}i, 'https://www.pixiv.net/member.php?id=\1')
url = url.gsub(%r{/+\Z}, "")
url = url.gsub(%r{^https://}, "http://")
url + "/"
end
end
def self.search(params = {})
q = search_attributes(params, :id, :created_at, :updated_at, :url, :normalized_url, :is_active, :artist)
q = q.url_matches(params[:url_matches])
q = q.normalized_url_matches(params[:normalized_url_matches])
case params[:order]
when /\A(id|artist_id|url|normalized_url|is_active|created_at|updated_at)(?:_(asc|desc))?\z/i
dir = $2 || :desc
q = q.order($1 => dir).order(id: :desc)
else
q = q.apply_default_order(params)
end
q
end
def self.url_attribute_matches(attr, url)
if url.blank?
all
elsif url =~ %r{\A/(.*)/\z}
where_regex(attr, $1)
elsif url.include?("*")
where_ilike(attr, url)
else
where(attr => normalize_normalized_url(url))
end
end
def domain
Danbooru::URL.parse(normalized_url)&.domain.to_s
end
def site_name
source = Sources::Strategies.find(normalized_url)
source.site_name
end
# A secondary URL is an artist URL that we don't normally want to display,
# usually because it's redundant with the primary profile URL.
def secondary_url?
case url
when %r{pixiv\.net/stacc}i
true
when %r{pixiv\.net/fanbox}i
true
when %r{twitter\.com/intent}i
true
when %r{lohas\.nicoseiga\.jp}i
true
when %r{(?:www|com|dic)\.nicovideo\.jp}i
true
when %r{pawoo\.net/web/accounts}i
true
when %r{www\.artstation\.com}i
true
when %r{blogimg\.jp}i, %r{image\.blog\.livedoor\.jp}i
true
else
false
end
end
# The sort order of sites in artist URL lists.
def priority
sites = %w[
Pixiv Twitter
ArtStation baraag.net BCY Deviant\ Art Hentai\ Foundry Foundation Nico\ Seiga Nijie pawoo.net Pixiv\ Fanbox Pixiv\ Sketch Plurk Tinami Tumblr
Ask.fm Booth.pm Facebook Fantia FC2 Gumroad Instagram Ko-fi Livedoor Lofter Mihuashi Mixi.jp Patreon Piapro.jp Picarto Privatter Sakura.ne.jp Stickam Skeb Twitch Weibo Youtube
Amazon Circle.ms DLSite Doujinshi.org Erogamescape Mangaupdates Melonbooks Toranoana Wikipedia
]
sites.index(site_name) || 1000
end
def self.normalize_url(url)
Danbooru::URL.parse(url)&.to_normalized_s.presence || url
end
def url=(url)
super(url)
self.normalized_url = self.class.normalize_normalized_url(self.url)
end
def to_s
if is_active?
url
else
"-#{url}"
end
end
def validate_scheme(uri)
errors.add(:url, "'#{uri}' must begin with http:// or https:// ") unless uri.scheme.in?(%w[http https])
end
def validate_hostname(uri)
errors.add(:url, "'#{uri}' has a hostname '#{uri.host}' that does not contain a dot") unless uri.host&.include?(".")
end
def validate_url_format
uri = Addressable::URI.parse(url)
validate_scheme(uri)
validate_hostname(uri)
rescue Addressable::URI::InvalidURIError => e
errors.add(:url, "'#{uri}' is malformed: #{e}")
end
def self.available_includes
[:artist]
end
end