class PostCreatePlan def initialize attributes: @attributes = attributes.symbolize_keys end def build! Tag.normalise_tags!(tag_names, with_tagme: false, deny_deprecated: true, with_sections: true) => { tags:, sections: } tags = Tag.expand_parent_tags(tags).reject(&:deprecated?) video_ms = normalise_video_ms(tags) validate_video_sections!(video_ms, sections) parent_post_ids = normalise_parent_post_ids validate_parent_post_ids!(parent_post_ids) { url: @attributes[:url], title: @attributes[:title].to_s, thumbnail_base: @attributes[:thumbnail_base].presence, original_created_from: @attributes[:original_created_from].presence, original_created_before: @attributes[:original_created_before].presence, tags: serialised_tags(tags, sections), duration: @attributes[:duration].to_s, video_ms: video_ms, parent_post_ids: parent_post_ids.join(' '), normalised_tags: tags, tag_sections: sections, normalised_parent_post_ids: parent_post_ids } end private def tag_names = @attributes[:tags].to_s.split def normalise_parent_post_ids Array(@attributes[:parent_post_ids]).flat_map { _1.to_s.split }.map { |token| id = Integer(token, exception: false) raise ArgumentError, "親投稿 Id. が不正です: #{ token }" if id.nil? || id <= 0 id }.uniq.sort end def validate_parent_post_ids! ids missing = ids - Post.where(id: ids).pluck(:id) raise ArgumentError, "存在しない親投稿 Id. があります: #{ missing.join(' ') }" if missing.present? end def serialised_tags tags, sections tags.uniq(&:id).map { |tag| "#{ tag.name }#{ sections[tag.id].to_a.map { Post.section_literal(_1) }.join }" }.sort.join(' ') end def normalise_video_ms tags return nil unless tags.any? { _1.id == Tag.video.id } video_ms = @attributes[:video_ms] if video_ms.present? value = Integer(video_ms, exception: false) raise PostCreator::VideoMsParseError unless value&.positive? return value end duration = @attributes[:duration] return nil if duration.blank? value = Tag.time_to_ms!(duration.to_s, tag_name: '動画時間') raise PostCreator::VideoMsParseError unless value.positive? value rescue Tag::SectionLiteralParseError raise PostCreator::VideoMsParseError end def validate_video_sections! video_ms, sections return unless video_ms sections.each_value do |ranges| ranges.each do |begin_ms, end_ms| post = Post.new if begin_ms >= video_ms post.errors.add :video_ms, 'タグ区間の開始が動画時間以上です.' raise ActiveRecord::RecordInvalid, post end if end_ms && end_ms > video_ms post.errors.add :video_ms, 'タグ区間の終端が動画時間を超えてゐます.' raise ActiveRecord::RecordInvalid, post end end end end end