From 23f1ffb04bf698f18c59f706d8a8e8b79b4c762f Mon Sep 17 00:00:00 2001 From: miteruzo Date: Sun, 12 Jul 2026 02:08:32 +0900 Subject: [PATCH] #399 --- .../app/controllers/post_imports_controller.rb | 11 +++++++++-- backend/app/services/post_import_previewer.rb | 18 +++++++++++++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/backend/app/controllers/post_imports_controller.rb b/backend/app/controllers/post_imports_controller.rb index 582d589..b66aec2 100644 --- a/backend/app/controllers/post_imports_controller.rb +++ b/backend/app/controllers/post_imports_controller.rb @@ -70,8 +70,15 @@ class PostImportsController < ApplicationController end raise ArgumentError, '解析結果が大きすぎます.' if rows.sum { Array(_1['values']).sum(&:bytesize) } > PostImportSourceParser::MAX_BYTES - { columns: columns.map { |column| column.slice('key', 'label') }, - rows: rows.map { |row| { source_row: row['source_row'], values: Array(row['values']) } } } + parsed_rows = rows.map do |row| + source_row = Integer(row['source_row'], exception: false) + raise ArgumentError, '元行番号が不正です.' if source_row.nil? || source_row <= 0 + + { source_row:, values: Array(row['values']) } + end + raise ArgumentError, '元行番号が重複しています.' if parsed_rows.map { _1[:source_row] }.uniq.length != parsed_rows.length + + { columns: columns.map { |column| column.slice('key', 'label') }, rows: parsed_rows } end def validate_rows_params diff --git a/backend/app/services/post_import_previewer.rb b/backend/app/services/post_import_previewer.rb index 3ec1625..bccd974 100644 --- a/backend/app/services/post_import_previewer.rb +++ b/backend/app/services/post_import_previewer.rb @@ -23,6 +23,14 @@ class PostImportPreviewer tag_sources['manual'] = attributes['tags'].to_s if provenance['tags'] == 'manual' url = row[:url].presence || values[@url_column].to_s.strip url_for_metadata = normalised_url(url) || url + existing_post = normalised_url(url).present? && Post.exists?(url: normalised_url(url)) + if existing_post && @existing == 'skip' + next { source_row: row[:source_row], url: normalised_url(url) || url, attributes:, + provenance:, tag_sources:, metadata_url: url_for_metadata, + fetch_warnings: [], validation_warnings: ['既存投稿のためスキップします.'], + warnings: ['既存投稿のためスキップします.'], validation_errors: { }, + status: 'warning', existing: true } + end url_changed = row[:metadata_url].present? && row[:metadata_url] != url_for_metadata clear_automatic_values!(attributes, provenance, tag_sources) if url_changed provenance['url'] ||= row[:url].present? ? 'manual' : 'mapped' @@ -53,7 +61,7 @@ class PostImportPreviewer validation_warnings = [] 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) + if normal_url.present? && existing_post @existing == 'error' ? errors[:url] = ['既存投稿です.'] : validation_warnings << '既存投稿のためスキップします.' end validate_basic_data(attributes, errors) @@ -163,10 +171,10 @@ class PostImportPreviewer original_created_before: attributes['original_created_before'].presence, video_ms: parse_duration(attributes['duration'], errors)) post.valid? - post.errors.each { |error| (errors[error.attribute] ||= []) << error.message } - if errors[:url] - errors[:url].reject! { |message| message.include?('すでに存在') || message.include?('taken') } - errors.delete(:url) if errors[:url].empty? + post.errors.each do |error| + next if error.attribute == :url && error.type == :taken + + (errors[error.attribute] ||= []) << error.message end end