このコミットが含まれているのは:
@@ -0,0 +1,79 @@
|
||||
class PostImportPreviewer
|
||||
FIELDS = %w[title thumbnail_base original_created_from original_created_before duration tags parent_post_ids].freeze
|
||||
|
||||
def initialize parsed:, url_column:, mappings: { }, existing: 'skip'
|
||||
@parsed = parsed
|
||||
@url_column = url_column.to_i
|
||||
@mappings = mappings.to_h.stringify_keys
|
||||
@existing = existing == 'error' ? 'error' : 'skip'
|
||||
end
|
||||
|
||||
def preview
|
||||
urls = { }
|
||||
@parsed[:rows].map do |row|
|
||||
values = row[:values]
|
||||
attributes = FIELDS.to_h { |field| [field, mapped_value(field, values)] }
|
||||
url = values[@url_column].to_s.strip
|
||||
metadata, warnings = fetch_metadata(url)
|
||||
attributes = metadata.merge(attributes) { |_key, automatic, input| input.presence || automatic }
|
||||
post = Post.new(url:)
|
||||
post.valid?
|
||||
normal_url = post.url
|
||||
errors = post.errors.to_hash.transform_values(&:dup)
|
||||
errors[:url] = ['URL が重複しています.'] if normal_url.present? && urls.key?(normal_url)
|
||||
urls[normal_url] = true if normal_url.present?
|
||||
if normal_url.present? && Post.exists?(url: normal_url)
|
||||
@existing == 'error' ? errors[:url] = ['既存投稿です.'] : warnings << '既存投稿のためスキップします.'
|
||||
end
|
||||
validate_preview_tags(attributes['tags'], errors)
|
||||
validate_parents(attributes['parent_post_ids'], errors)
|
||||
{ source_row: row[:source_row], url: normal_url || url, attributes:, warnings:, errors:,
|
||||
status: errors.present? ? 'error' : (warnings.present? ? 'warning' : 'ready'),
|
||||
existing: normal_url.present? && Post.exists?(url: normal_url) }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def mapped_value field, values
|
||||
mapping = @mappings[field]
|
||||
return '' if mapping.blank?
|
||||
return mapping['value'].to_s if mapping['kind'] == 'fixed'
|
||||
|
||||
Array(mapping['columns']).filter_map { |index| values[index.to_i].to_s.presence }.join(field == 'tags' ? ' ' : '')
|
||||
end
|
||||
|
||||
def fetch_metadata url
|
||||
return [{ }, ['URL が空です.']] if url.blank?
|
||||
|
||||
data = PostMetadataFetcher.fetch(url)
|
||||
warnings = []
|
||||
warnings << 'タイトルを取得できませんでした.' if data[:title].blank?
|
||||
warnings << 'サムネールを取得できませんでした.' if data[:thumbnail_base].blank?
|
||||
[data.compact, warnings]
|
||||
rescue Preview::UrlSafety::UnsafeUrl, Preview::HttpFetcher::FetchFailed, Preview::HttpFetcher::ResponseTooLarge => e
|
||||
[{ }, ["メタデータを取得できませんでした: #{ e.message }"]]
|
||||
end
|
||||
|
||||
def validate_preview_tags raw, errors
|
||||
names = raw.to_s.split
|
||||
return if names.empty?
|
||||
if names.any? { _1.downcase.start_with?('nico:') }
|
||||
errors[:tags] = ['ニコニコ・タグは直接指定できません.']
|
||||
return
|
||||
end
|
||||
canonical = names.map { TagName.canonicalise(_1.sub(/\[.*\]\z/, '')).first }
|
||||
if Tag.joins(:tag_name).where(tag_names: { name: canonical }, deprecated_at: nil).count < canonical.uniq.length
|
||||
errors[:tags] = ['存在しないタグ又は廃止済みタグがあります.']
|
||||
end
|
||||
rescue Tag::SectionLiteralParseError
|
||||
errors[:tags] = ['タグ区間の記法が不正です.']
|
||||
end
|
||||
|
||||
def validate_parents raw, errors
|
||||
ids = raw.to_s.split.map { Integer(_1, exception: false) }
|
||||
return if ids.compact.empty? && raw.to_s.blank?
|
||||
errors[:parent_post_ids] = ['親投稿 Id. が不正です.'] and return if ids.any? { _1.nil? || _1 <= 0 }
|
||||
errors[:parent_post_ids] = ['存在しない親投稿 Id. があります.'] if Post.where(id: ids).count != ids.uniq.length
|
||||
end
|
||||
end
|
||||
新しい課題から参照
ユーザをブロックする