117 lines
3.4 KiB
Python
117 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
import os
|
|
import boto3
|
|
from botocore.exceptions import ClientError
|
|
from typing import List, Optional
|
|
|
|
|
|
# S3 Configuration
|
|
S3_BUCKET_NAME = os.environ.get("S3_BUCKET_NAME", "math-exercises")
|
|
|
|
|
|
def get_s3_client():
|
|
"""Create and return an S3 client using environment variables"""
|
|
s3_access_key = os.environ.get("S3_ACCESS_KEY")
|
|
s3_secret_key = os.environ.get("S3_SECRET_KEY")
|
|
s3_host_base = os.environ.get("S3_HOST_BASE")
|
|
|
|
if not all([s3_access_key, s3_secret_key, s3_host_base]):
|
|
raise ValueError("S3 environment variables not properly set")
|
|
|
|
s3 = boto3.client(
|
|
"s3",
|
|
aws_access_key_id=s3_access_key,
|
|
aws_secret_access_key=s3_secret_key,
|
|
endpoint_url=s3_host_base,
|
|
region_name="us-east-1", # Required but unused for Infomaniak
|
|
)
|
|
return s3
|
|
|
|
|
|
def create_bucket_if_not_exists(bucket_name: str):
|
|
"""Create S3 bucket if it doesn't exist"""
|
|
s3_client = get_s3_client()
|
|
|
|
try:
|
|
s3_client.head_bucket(Bucket=bucket_name)
|
|
except ClientError as e:
|
|
error_code = int(e.response["Error"]["Code"])
|
|
if error_code == 404:
|
|
# Bucket doesn't exist, create it
|
|
try:
|
|
s3_client.create_bucket(Bucket=bucket_name)
|
|
print(f"Bucket {bucket_name} created successfully")
|
|
except ClientError as create_error:
|
|
print(f"Error creating bucket: {create_error}")
|
|
raise
|
|
else:
|
|
# Some other error
|
|
print(f"Error checking bucket: {e}")
|
|
raise
|
|
|
|
|
|
def upload_to_s3(
|
|
file_data: bytes,
|
|
bucket_name: str,
|
|
object_name: str,
|
|
content_type: str = "application/pdf",
|
|
) -> bool:
|
|
"""Upload file data to S3 bucket"""
|
|
s3_client = get_s3_client()
|
|
|
|
try:
|
|
s3_client.put_object(
|
|
Bucket=bucket_name,
|
|
Key=object_name,
|
|
Body=file_data,
|
|
ContentType=content_type,
|
|
)
|
|
return True
|
|
except ClientError as e:
|
|
print(f"Error uploading to S3: {e}")
|
|
return False
|
|
|
|
|
|
def download_from_s3(bucket_name: str, object_name: str) -> Optional[bytes]:
|
|
"""Download file data from S3 bucket"""
|
|
s3_client = get_s3_client()
|
|
|
|
try:
|
|
response = s3_client.get_object(Bucket=bucket_name, Key=object_name)
|
|
return response["Body"].read()
|
|
except ClientError as e:
|
|
print(f"Error downloading from S3: {e}")
|
|
return None
|
|
|
|
|
|
def list_objects_in_s3(bucket_name: str) -> List[dict]:
|
|
"""List all objects in S3 bucket (sorted from newest to oldest)"""
|
|
s3_client = get_s3_client()
|
|
|
|
try:
|
|
response = s3_client.list_objects_v2(Bucket=bucket_name)
|
|
if "Contents" in response:
|
|
# Filter for PDF files only and sort by last modified (newest first)
|
|
pdf_files = [
|
|
obj for obj in response["Contents"] if obj["Key"].endswith(".pdf")
|
|
]
|
|
pdf_files.sort(key=lambda x: x["LastModified"], reverse=True)
|
|
return pdf_files
|
|
else:
|
|
return []
|
|
except ClientError as e:
|
|
print(f"Error listing objects in S3: {e}")
|
|
return []
|
|
|
|
|
|
def delete_from_s3(bucket_name: str, object_name: str) -> bool:
|
|
"""Delete file from S3 bucket"""
|
|
s3_client = get_s3_client()
|
|
|
|
try:
|
|
s3_client.delete_object(Bucket=bucket_name, Key=object_name)
|
|
return True
|
|
except ClientError as e:
|
|
print(f"Error deleting from S3: {e}")
|
|
return False
|