update checkin image issue
This commit is contained in:
1
rog/utils/__init__.py
Normal file
1
rog/utils/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
# Python package marker
|
||||
153
rog/utils/s3_image_uploader.py
Normal file
153
rog/utils/s3_image_uploader.py
Normal file
@ -0,0 +1,153 @@
|
||||
"""
|
||||
S3画像アップロードユーティリティ
|
||||
チェックイン時の画像をS3にアップロードし、URLを生成します
|
||||
"""
|
||||
|
||||
import boto3
|
||||
import logging
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from django.conf import settings
|
||||
from botocore.exceptions import ClientError, NoCredentialsError
|
||||
import base64
|
||||
import io
|
||||
import requests
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class S3ImageUploader:
|
||||
def __init__(self):
|
||||
"""S3クライアントを初期化"""
|
||||
try:
|
||||
self.s3_client = boto3.client(
|
||||
's3',
|
||||
aws_access_key_id=getattr(settings, 'AWS_ACCESS_KEY', None),
|
||||
aws_secret_access_key=getattr(settings, 'AWS_SECRET_ACCESS_KEY', None),
|
||||
region_name=getattr(settings, 'AWS_REGION', 'us-west-2')
|
||||
)
|
||||
self.bucket_name = getattr(settings, 'S3_BUCKET_NAME', 'sumasenrogaining')
|
||||
logger.info(f"S3 client initialized for bucket: {self.bucket_name}")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to initialize S3 client: {e}")
|
||||
self.s3_client = None
|
||||
self.bucket_name = None
|
||||
|
||||
def upload_checkin_image(self, image_data, event_code, zekken_number, cp_number):
|
||||
"""
|
||||
チェックイン画像をS3にアップロード
|
||||
|
||||
Args:
|
||||
image_data: 画像データ(URLまたはBase64)
|
||||
event_code: イベントコード
|
||||
zekken_number: ゼッケン番号
|
||||
cp_number: チェックポイント番号
|
||||
|
||||
Returns:
|
||||
str: S3のURL、失敗時は元のimage_data
|
||||
"""
|
||||
if not self.s3_client or not image_data:
|
||||
logger.warning("S3 client not available or no image data, returning original")
|
||||
return image_data
|
||||
|
||||
try:
|
||||
# 画像データを取得
|
||||
image_binary = self._get_image_binary(image_data)
|
||||
if not image_binary:
|
||||
logger.error("Failed to get image binary data, returning original")
|
||||
return image_data
|
||||
|
||||
# S3キーを生成: {event_code}/{zekken_number}/{cp_number}.jpg
|
||||
s3_key = f"{event_code}/{zekken_number}/{cp_number}.jpg"
|
||||
|
||||
# S3にアップロード
|
||||
self.s3_client.put_object(
|
||||
Bucket=self.bucket_name,
|
||||
Key=s3_key,
|
||||
Body=image_binary,
|
||||
ContentType='image/jpeg',
|
||||
ACL='public-read' # 公開読み取り可能
|
||||
)
|
||||
|
||||
# S3 URLを生成
|
||||
aws_region = getattr(settings, 'AWS_REGION', 'us-west-2')
|
||||
s3_url = f"https://{self.bucket_name}.s3.{aws_region}.amazonaws.com/{s3_key}"
|
||||
|
||||
logger.info(f"Successfully uploaded image to S3: {s3_url}")
|
||||
return s3_url
|
||||
|
||||
except ClientError as e:
|
||||
logger.error(f"S3 upload failed: {e}, returning original URL")
|
||||
return image_data
|
||||
except Exception as e:
|
||||
logger.error(f"Unexpected error during S3 upload: {e}, returning original URL")
|
||||
return image_data
|
||||
|
||||
def _get_image_binary(self, image_data):
|
||||
"""
|
||||
画像データからバイナリデータを取得
|
||||
|
||||
Args:
|
||||
image_data: 画像URL(HTTP)またはBase64エンコードされた画像データ
|
||||
|
||||
Returns:
|
||||
bytes: 画像のバイナリデータ
|
||||
"""
|
||||
try:
|
||||
if isinstance(image_data, str):
|
||||
# HTTPURLの場合
|
||||
if image_data.startswith('http'):
|
||||
return self._download_image_from_url(image_data)
|
||||
# Base64の場合
|
||||
elif self._is_base64(image_data):
|
||||
return base64.b64decode(image_data)
|
||||
# data:image/jpeg;base64,の形式の場合
|
||||
elif image_data.startswith('data:image'):
|
||||
base64_data = image_data.split(',')[1]
|
||||
return base64.b64decode(base64_data)
|
||||
|
||||
logger.error(f"Unsupported image data format: {type(image_data)}")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error processing image data: {e}")
|
||||
return None
|
||||
|
||||
def _download_image_from_url(self, url):
|
||||
"""URLから画像をダウンロード"""
|
||||
try:
|
||||
response = requests.get(url, timeout=30)
|
||||
response.raise_for_status()
|
||||
return response.content
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to download image from URL {url}: {e}")
|
||||
return None
|
||||
|
||||
def _is_base64(self, data):
|
||||
"""文字列がBase64かどうかをチェック"""
|
||||
try:
|
||||
if isinstance(data, str):
|
||||
base64.b64decode(data, validate=True)
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
return False
|
||||
|
||||
def generate_s3_url(self, event_code, zekken_number, cp_number):
|
||||
"""
|
||||
S3 URLを生成(アップロード済みの画像用)
|
||||
|
||||
Args:
|
||||
event_code: イベントコード
|
||||
zekken_number: ゼッケン番号
|
||||
cp_number: チェックポイント番号
|
||||
|
||||
Returns:
|
||||
str: S3のURL
|
||||
"""
|
||||
aws_region = getattr(settings, 'AWS_REGION', 'us-west-2')
|
||||
s3_key = f"{event_code}/{zekken_number}/{cp_number}.jpg"
|
||||
return f"https://{self.bucket_name}.s3.{aws_region}.amazonaws.com/{s3_key}"
|
||||
|
||||
|
||||
# グローバルインスタンス
|
||||
s3_uploader = S3ImageUploader()
|
||||
Reference in New Issue
Block a user