From 92147644848382ec50a2a58e0cd9b5d4e94f9d40 Mon Sep 17 00:00:00 2001 From: Philip Cheung Date: Mon, 7 Oct 2024 22:50:33 +0800 Subject: [PATCH] changed save image --- .env | 5 +++ backend/app/core/config.py | 3 ++ backend/app/utils.py | 54 ++++++++++++++++++++++-------- backend/poetry.lock | 68 +++++++++++++++++++++++++++++++++++++- backend/pyproject.toml | 1 + 5 files changed, 116 insertions(+), 15 deletions(-) diff --git a/.env b/.env index a80c899..37a3948 100644 --- a/.env +++ b/.env @@ -35,3 +35,8 @@ SENTRY_DSN= # Configure these with your own Docker registry images DOCKER_IMAGE_BACKEND=backend DOCKER_IMAGE_FRONTEND=frontend + +# Cloudflare S2 +AccountID=98465b0b97949027e9bedaa97c32bab7 +access_key_id=358d3f5c58b64c93a0bc52371dcd2866 +secret_access_key=2bb3d573ca1abaee7b5dc91678f88509070f2914bdd68b869e5a325a13cfbd67 diff --git a/backend/app/core/config.py b/backend/app/core/config.py index 1e3a440..29496be 100644 --- a/backend/app/core/config.py +++ b/backend/app/core/config.py @@ -53,6 +53,9 @@ class Settings(BaseSettings): POSTGRES_USER: str POSTGRES_PASSWORD: str = "" POSTGRES_DB: str = "" + AccountID: str = "" + access_key_id: str = "" + secret_access_key: str = "" @computed_field # type: ignore[prop-decorator] @property diff --git a/backend/app/utils.py b/backend/app/utils.py index f905aaf..7446184 100644 --- a/backend/app/utils.py +++ b/backend/app/utils.py @@ -1,5 +1,7 @@ import os import logging +import boto3 +from botocore.exceptions import ClientError from dataclasses import dataclass from datetime import datetime, timedelta, timezone from pathlib import Path @@ -153,25 +155,49 @@ def validate_file_size_type(file: IO): if real_file_size > FILE_SIZE: raise HTTPException(status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE, detail="Too large") -async def save_picture(file, folderName: str = '', fileName: str = None): - randon_uid = str(uuid4()) - _, f_ext = os.path.splitext(file.filename) +# async def save_picture(file, folderName: str = '', fileName: str = None): +# randon_uid = str(uuid4()) +# _, f_ext = os.path.splitext(file.filename) - picture_name = (randon_uid if fileName==None else fileName.lower().replace(' ', '')) + f_ext +# picture_name = (randon_uid if fileName==None else fileName.lower().replace(' ', '')) + f_ext - path = os.path.join(static,folderName) - if not os.path.exists(path): - os.makedirs(path) +# path = os.path.join(static,folderName) +# if not os.path.exists(path): +# os.makedirs(path) - picture_path = os.path.join(path,picture_name) +# picture_path = os.path.join(path,picture_name) + +# #output_size = (125,125) +# img = Image.open(file.file) + +# #img.thumbnail(output_size) +# img.save(picture_path) + +# return f'{static}/{folderName}/{picture_name}' + +async def save_picture(file, folderName: str = "", fileName: str = None): + random_uid = str(uuid4()) + _, f_ext = os.path.splitext(file.filename) + + picture_name = (fileName.lower().replace(" ", "") if fileName else random_uid) + f_ext + + r2 = boto3.client( + "s3", + endpoint_url=f"https://{settings.AccountID}.r2.cloudflarestorage.com", + aws_access_key_id=settings.access_key_id, + aws_secret_access_key=settings.secret_access_key, + ) - #output_size = (125,125) img = Image.open(file.file) - - #img.thumbnail(output_size) - img.save(picture_path) - - return f'{static}/{folderName}/{picture_name}' + img_byte_arr = io.BytesIO() + img.save(img_byte_arr, format='PNG') + img_byte_arr = img_byte_arr.getvalue() + + r2.put_object(Bucket=settings.bucket_name, Key=f"{folderName}/{picture_name}", Body=img_byte_arr) + + r2_url = f"https://{settings.AccountID}.r2.cloudflarestorage.com/{settings.bucket_name}/{folderName}/{picture_name}" + return r2_url + async def del_picture(picture_path): try: diff --git a/backend/poetry.lock b/backend/poetry.lock index 24f9b68..1e6c7fc 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -86,6 +86,44 @@ files = [ tests = ["pytest (>=3.2.1,!=3.3.0)"] typecheck = ["mypy"] +[[package]] +name = "boto3" +version = "1.35.34" +description = "The AWS SDK for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "boto3-1.35.34-py3-none-any.whl", hash = "sha256:291e7b97a34967ed93297e6171f1bebb8529e64633dd48426760e3fdef1cdea8"}, + {file = "boto3-1.35.34.tar.gz", hash = "sha256:57e6ee8504e7929bc094bb2afc879943906064179a1e88c23b4812e2c6f61532"}, +] + +[package.dependencies] +botocore = ">=1.35.34,<1.36.0" +jmespath = ">=0.7.1,<2.0.0" +s3transfer = ">=0.10.0,<0.11.0" + +[package.extras] +crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] + +[[package]] +name = "botocore" +version = "1.35.34" +description = "Low-level, data-driven core of boto 3." +optional = false +python-versions = ">=3.8" +files = [ + {file = "botocore-1.35.34-py3-none-any.whl", hash = "sha256:ccb0fe397b11b81c9abc0c87029d17298e17bf658d8db5c0c5a551a12a207e7a"}, + {file = "botocore-1.35.34.tar.gz", hash = "sha256:789b6501a3bb4a9591c1fe10da200cc315c1fa5df5ada19c720d8ef06439b3e3"}, +] + +[package.dependencies] +jmespath = ">=0.7.1,<2.0.0" +python-dateutil = ">=2.1,<3.0.0" +urllib3 = {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""} + +[package.extras] +crt = ["awscrt (==0.22.0)"] + [[package]] name = "cachetools" version = "5.4.0" @@ -721,6 +759,17 @@ MarkupSafe = ">=2.0" [package.extras] i18n = ["Babel (>=2.7)"] +[[package]] +name = "jmespath" +version = "1.0.1" +description = "JSON Matching Expressions" +optional = false +python-versions = ">=3.7" +files = [ + {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, + {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, +] + [[package]] name = "lxml" version = "5.2.2" @@ -1663,6 +1712,23 @@ files = [ {file = "ruff-0.2.2.tar.gz", hash = "sha256:e62ed7f36b3068a30ba39193a14274cd706bc486fad521276458022f7bccb31d"}, ] +[[package]] +name = "s3transfer" +version = "0.10.2" +description = "An Amazon S3 Transfer Manager" +optional = false +python-versions = ">=3.8" +files = [ + {file = "s3transfer-0.10.2-py3-none-any.whl", hash = "sha256:eca1c20de70a39daee580aef4986996620f365c4e0fda6a86100231d62f1bf69"}, + {file = "s3transfer-0.10.2.tar.gz", hash = "sha256:0711534e9356d3cc692fdde846b4a1e4b0cb6519971860796e6bc4c7aea00ef6"}, +] + +[package.dependencies] +botocore = ">=1.33.2,<2.0a.0" + +[package.extras] +crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] + [[package]] name = "sentry-sdk" version = "1.45.1" @@ -2189,4 +2255,4 @@ files = [ [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "c1e03dd5757ff36536296fee003cad60b1cc5685cffa372719edaecf39b296e2" +content-hash = "2a4f5367894949f9be3871b94d161fb28167992720544719fa40e0463fe32ada" diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 9c42630..47688c8 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -29,6 +29,7 @@ pyjwt = "^2.8.0" sqlalchemy = "^2.0.32" pillow = "^10.4.0" filetype = "^1.2.0" +boto3 = "^1.35.34" [tool.poetry.group.dev.dependencies] pytest = "^7.4.3"