From 5bd097bcfe75b7d00c720de7fffbe440da3d6f4d Mon Sep 17 00:00:00 2001 From: miteruzo Date: Sun, 12 Jul 2026 01:47:34 +0900 Subject: [PATCH] #399 --- backend/app/models/post.rb | 11 +---------- .../post_import_google_sheets_fetcher.rb | 3 ++- backend/app/services/post_import_previewer.rb | 4 +--- backend/app/services/post_import_runner.rb | 15 ++++++++++++++- .../app/services/post_import_source_parser.rb | 17 ++++++++++++++++- backend/app/services/post_url_normaliser.rb | 13 +++++++++++++ 6 files changed, 47 insertions(+), 16 deletions(-) create mode 100644 backend/app/services/post_url_normaliser.rb diff --git a/backend/app/models/post.rb b/backend/app/models/post.rb index cdfbaef..30e9e22 100644 --- a/backend/app/models/post.rb +++ b/backend/app/models/post.rb @@ -173,15 +173,6 @@ class Post < ApplicationRecord def normalise_url return if url.blank? - self.url = url.strip - - u = URI.parse(url) - return unless u in URI::HTTP - - u.host = u.host.downcase if u.host - u.path = u.path.sub(/\/\Z/, '') if u.path.present? - self.url = u.to_s - rescue URI::InvalidURIError - ; + self.url = PostUrlNormaliser.normalise(url) || url.strip end end diff --git a/backend/app/services/post_import_google_sheets_fetcher.rb b/backend/app/services/post_import_google_sheets_fetcher.rb index 85ab331..23f564f 100644 --- a/backend/app/services/post_import_google_sheets_fetcher.rb +++ b/backend/app/services/post_import_google_sheets_fetcher.rb @@ -24,7 +24,8 @@ class PostImportGoogleSheetsFetcher raise ArgumentError, 'スプレッドシートを CSV として取得できませんでした.' unless csv?(response) response.body - rescue Preview::UrlSafety::UnsafeUrl, Preview::HttpFetcher::FetchFailed => e + rescue Preview::UrlSafety::UnsafeUrl, Preview::HttpFetcher::FetchFailed, + Preview::HttpFetcher::ResponseTooLarge => e Rails.logger.info("post_import_google_sheets_fetch_failure #{ { error: e.class.name, message: e.message }.to_json }") raise ArgumentError, 'スプレッドシートを取得できませんでした.ウェブ公開 URL を確認するか、ファイル保存又はコピー貼付けを使用してください.' end diff --git a/backend/app/services/post_import_previewer.rb b/backend/app/services/post_import_previewer.rb index 6ab88c2..0cd77ea 100644 --- a/backend/app/services/post_import_previewer.rb +++ b/backend/app/services/post_import_previewer.rb @@ -78,9 +78,7 @@ class PostImportPreviewer end def normalised_url value - post = Post.new(url: value) - post.valid? - post.url if post.errors[:url].empty? + PostUrlNormaliser.normalise(value) end private diff --git a/backend/app/services/post_import_runner.rb b/backend/app/services/post_import_runner.rb index 5434269..b2de331 100644 --- a/backend/app/services/post_import_runner.rb +++ b/backend/app/services/post_import_runner.rb @@ -9,8 +9,9 @@ class PostImportRunner def run raise ArgumentError, "取込件数は #{ MAX_ROWS } 件までです." if @rows.length > MAX_ROWS + raise ArgumentError, '取込データが大きすぎます.' if @rows.sum { |row| row.to_json.bytesize } > PostImportSourceParser::MAX_BYTES - results = @rows.map { |row| run_row(row.to_h.deep_transform_keys { _1.to_s.underscore }) } + results = @rows.map { |row| run_row(normalise_row(row)) } { created: results.count { _1[:status] == 'created' }, skipped: results.count { _1[:status] == 'skipped' }, failed: results.count { _1[:status] == 'failed' }, rows: results } end @@ -63,6 +64,10 @@ class PostImportRunner end def validate_row_structure! row + raise ArgumentError unless row['source_row'].is_a?(Integer) && row['source_row'].positive? + raise ArgumentError unless row['url'].is_a?(String) + raise ArgumentError unless row['attributes'].is_a?(Hash) + raise ArgumentError unless row['attributes'].values.all? { _1.is_a?(String) || _1.is_a?(Numeric) || _1 == true || _1 == false || _1.nil? } provenance = row['provenance'] raise ArgumentError unless provenance.is_a?(Hash) allowed = ATTRIBUTE_KEYS + ['url'] @@ -73,4 +78,12 @@ class PostImportRunner raise ArgumentError if metadata_url.to_s.bytesize > PostImportSourceParser::MAX_CELL_BYTES raise ArgumentError if row.to_json.bytesize > PostImportSourceParser::MAX_BYTES end + + def normalise_row row + unless row.is_a?(Hash) || row.is_a?(ActionController::Parameters) + raise ArgumentError, '取込行の形式が不正です.' + end + + row.to_h.deep_transform_keys { _1.to_s.underscore } + end end diff --git a/backend/app/services/post_import_source_parser.rb b/backend/app/services/post_import_source_parser.rb index 7cad66b..5fff5f1 100644 --- a/backend/app/services/post_import_source_parser.rb +++ b/backend/app/services/post_import_source_parser.rb @@ -39,7 +39,22 @@ class PostImportSourceParser def parse_json value = JSON.parse(@source, max_nesting: 20) - @json_path.split('.').reject(&:blank?).each { |part| value = value.is_a?(Array) ? value[Integer(part)] : value.fetch(part) } + @json_path.split('.').reject(&:blank?).each do |part| + value = + case value + when Array + index = Integer(part, exception: false) + raise ArgumentError if index.nil? || index.negative? || index >= value.length + + value[index] + when Hash + raise ArgumentError unless value.key?(part) || value.key?(part.to_sym) + + value.key?(part) ? value[part] : value[part.to_sym] + else + raise ArgumentError + end + end raise ArgumentError, 'JSON の投稿候補は配列にしてください.' unless value.is_a?(Array) ensure_limits!(value) diff --git a/backend/app/services/post_url_normaliser.rb b/backend/app/services/post_url_normaliser.rb new file mode 100644 index 0000000..09aa5be --- /dev/null +++ b/backend/app/services/post_url_normaliser.rb @@ -0,0 +1,13 @@ +class PostUrlNormaliser + def self.normalise raw_url + value = raw_url.to_s.strip + uri = URI.parse(value) + return nil unless uri.is_a?(URI::HTTP) && uri.host.present? + + uri.host = uri.host.downcase + uri.path = uri.path.sub(/\/\z/, '') if uri.path.present? + uri.to_s + rescue URI::InvalidURIError + nil + end +end