asxpio/lib/s3.rb
Sergei Poljanski 61bb1393fe
All checks were successful
Build and Deploy to Production / test (push) Successful in 22s
Build and Deploy to Production / build (push) Successful in 1m3s
Build and Deploy to Production / deploy (push) Successful in 39s
bingo: fix photo rebuild on UTF-8 tagged S3 bodies
aws-sdk returns object bodies from a plain StringIO, so S3.get handed
back a UTF-8 tagged string and Photo.sniff's binary prefix comparison
raised Encoding::CompatibilityError: "Rebuild resized photos" died on
the first photo with a 500. URL imports had the same flaw via a UTF-8
read buffer. Treat image data as binary at the source and in sniff, and
let one failing photo no longer abort the batch (errors are reported in
the admin flash and logged).

Assisted-by: Claude:opus-5
2026-10-10 06:32:06 +04:00

61 lines
1.7 KiB
Ruby

require 'aws-sdk-s3'
module S3
module_function
def client
@client ||= Aws::S3::Client.new(
region: ENV.fetch('S3_REGION', 'us-east-1'),
endpoint: ENV.fetch('S3_ENDPOINT'),
access_key_id: ENV.fetch('S3_ACCESS_KEY'),
secret_access_key: ENV.fetch('S3_SECRET_KEY'),
force_path_style: true
)
end
# Separate client whose endpoint is the public hostname; used only to mint
# presigned URLs that a browser can dereference. Bytes never travel through
# this client.
def presign_client
@presign_client ||= Aws::S3::Client.new(
region: ENV.fetch('S3_REGION', 'us-east-1'),
endpoint: ENV.fetch('S3_PUBLIC_ENDPOINT'),
access_key_id: ENV.fetch('S3_ACCESS_KEY'),
secret_access_key: ENV.fetch('S3_SECRET_KEY'),
force_path_style: true
)
end
def bucket
ENV.fetch('S3_BUCKET')
end
def put(key, bytes, content_type: 'application/pdf')
client.put_object(
bucket: bucket,
key: key,
body: bytes,
content_type: content_type
)
key
end
def get(key)
client.get_object(bucket: bucket, key: key).body.read.b # body is a UTF-8 StringIO
end
def exists?(key)
client.head_object(bucket: bucket, key: key)
true
rescue Aws::S3::Errors::NotFound, Aws::S3::Errors::NoSuchKey
false
end
def presigned_url(key, expires_in: 300, filename: nil)
params = { bucket: bucket, key: key }
if filename
params[:response_content_disposition] = %(attachment; filename="#{filename}")
end
Aws::S3::Presigner.new(client: presign_client).presigned_url(:get_object, **params, expires_in: expires_in)
end
end