このコミットが含まれているのは:
2026-07-18 12:15:32 +09:00
コミット 040cc3f25d
4個のファイルの変更27行の追加26行の削除
+6 -8
ファイルの表示
@@ -18,14 +18,12 @@ class PreviewController < ApplicationController
def thumbnail def thumbnail
return render_bad_request('URL は必須です.') if params[:url].blank? return render_bad_request('URL は必須です.') if params[:url].blank?
image = MiniMagick::Image.read(Preview::ThumbnailFetcher.fetch(params[:url])) attachment =
image.auto_orient Post.resized_thumbnail_attachment(
image.resize '180x180>' StringIO.new(Preview::ThumbnailFetcher.fetch(params[:url])))
image.format 'png' send_data attachment[:io].read,
width, height = image.dimensions type: attachment[:content_type],
raise Preview::ThumbnailFetcher::GenerationFailed, 'サムネール画像の変換に失敗しました.' if width > 180 || height > 180 disposition: 'inline'
send_data image.to_blob, type: 'image/png', disposition: 'inline'
rescue Preview::UrlSafety::UnsafeUrl => e rescue Preview::UrlSafety::UnsafeUrl => e
render_bad_request(e.message) render_bad_request(e.message)
rescue Preview::HttpFetcher::FetchTimeout => e rescue Preview::HttpFetcher::FetchTimeout => e
-2
ファイルの表示
@@ -17,8 +17,6 @@ class Post < ApplicationRecord
MAX_SVG_DIMENSION = 4_096 MAX_SVG_DIMENSION = 4_096
MAX_SVG_PIXELS = 16_777_216 MAX_SVG_PIXELS = 16_777_216
THUMBNAIL_PROCESS_TIMEOUT = 5.seconds THUMBNAIL_PROCESS_TIMEOUT = 5.seconds
RASTER_THUMBNAIL_FORMATS = ['jpeg', 'png', 'gif', 'webp'].freeze
def self.resized_thumbnail_attachment(upload, content_type: nil) def self.resized_thumbnail_attachment(upload, content_type: nil)
upload.rewind upload.rewind
bytes = upload.read bytes = upload.read
+1 -11
ファイルの表示
@@ -4,10 +4,6 @@ module Preview
RASTER_IMAGE_CONTENT_TYPES = [ RASTER_IMAGE_CONTENT_TYPES = [
'image/jpeg', 'image/png', 'image/gif', 'image/webp' 'image/jpeg', 'image/png', 'image/gif', 'image/webp'
].freeze ].freeze
REMOTE_IMAGE_CONTENT_TYPES = [
*RASTER_IMAGE_CONTENT_TYPES,
'image/svg+xml'
].freeze
HTML_MAX_BYTES = 1.megabyte HTML_MAX_BYTES = 1.megabyte
NICONICO_XML_MAX_BYTES = 256.kilobytes NICONICO_XML_MAX_BYTES = 256.kilobytes
@@ -100,13 +96,7 @@ module Preview
nil nil
end end
def self.allowed_remote_image_content_type?(content_type)
mime_type = content_type.to_s.split(';', 2).first.downcase.strip
REMOTE_IMAGE_CONTENT_TYPES.include?(mime_type)
end
private_class_method :fetch_image_or_nil, :fetch_image!, private_class_method :fetch_image_or_nil, :fetch_image!,
:niconico_thumbnail_url, :niconico_thumbnail_url
:allowed_remote_image_content_type?
end end
end end
+20 -5
ファイルの表示
@@ -110,6 +110,7 @@ const isRepairRow = (row: PostImportRow): boolean =>
&& hasErrorMessages (row.validationErrors))) && hasErrorMessages (row.validationErrors)))
const DUPLICATE_URL_MESSAGE = 'URL が重複しています.' const DUPLICATE_URL_MESSAGE = 'URL が重複しています.'
const BULK_PROCESSING_FAILED_MESSAGE = '登録中にエラーが発生しました.'
const rowMetadataPending = (row: PostImportRow): boolean => const rowMetadataPending = (row: PostImportRow): boolean =>
row.status === 'pending' row.status === 'pending'
@@ -314,14 +315,28 @@ const indexedBulkResults = (
} }
if (result?.status === 'skipped') if (result?.status === 'skipped')
{ {
return { const existingPostId =
sourceRow: row.sourceRow,
status: 'skipped',
existingPostId:
result.existingPostId result.existingPostId
?? result.existingPost?.id ?? result.existingPost?.id
?? row.existingPostId ?? row.existingPostId
?? row.sourceRow, if (existingPostId == null)
{
return {
sourceRow: row.sourceRow,
status: 'failed',
fieldWarnings: result.fieldWarnings,
baseWarnings: result.baseWarnings,
errors: {
...(errors ?? { }),
base: [...new Set ([...(errors?.base ?? []),
BULK_PROCESSING_FAILED_MESSAGE])],
},
recoverable: false }
}
return {
sourceRow: row.sourceRow,
status: 'skipped',
existingPostId,
existingPost: result.existingPost, existingPost: result.existingPost,
fieldWarnings: result.fieldWarnings, fieldWarnings: result.fieldWarnings,
baseWarnings: result.baseWarnings, baseWarnings: result.baseWarnings,