temp images on products

This commit is contained in:
2024-05-24 09:45:54 +03:00
parent 3a4f91d751
commit 88679089b6
11 changed files with 115 additions and 31 deletions

View File

@@ -15,3 +15,4 @@ PG_HOST = os.environ.get('PG_HOST')
TELEGRAM_BOT_TOKEN = os.environ.get('TELEGRAM_BOT_TOKEN')
SECRET_KEY = os.environ.get('SECRET_KEY')
S3_API_KEY = '1cc46590-4532-4046-97aa-baf3e49f20ad-AUF'

0
external/__init__.py vendored Normal file
View File

0
external/s3_uploader/__init__.py vendored Normal file
View File

49
external/s3_uploader/uploader.py vendored Normal file
View File

@@ -0,0 +1,49 @@
import uuid
from io import BytesIO
from typing import Union
import aiohttp
class S3Uploader:
def __init__(self, api_key: str):
# constants
self.base_url = 'https://s3.denco.store'
self.prefix = 'crm'
self.api_key = api_key
self.headers = {
'X-API-Key': self.api_key,
}
async def _method(self, http_method, method, **kwargs):
async with aiohttp.ClientSession(headers=self.headers) as session:
async with session.request(http_method, self.base_url + method, **kwargs) as response:
return await response.json()
async def _create(self):
method = '/create'
json_data = {
'prefix': self.prefix,
'immediate': True
}
return await self._method('POST', method, json=json_data)
async def upload(self, file: bytes, file_id: Union[int, None] = None) -> dict:
"""
Args:
file_id: database id created by _create
file: bytes of image to upload
Returns:
url to file
"""
if not file_id:
create_response = await self._create()
file_id = create_response['databaseId']
data = {
'file': BytesIO(file),
}
method = f'/upload/{file_id}'
return await self._method('POST', method, data=data)

View File

@@ -24,6 +24,19 @@ class Product(BaseModel):
composition = Column(String, nullable=True, comment='Состав')
size = Column(String, nullable=True, comment='Размер')
additional_info = Column(String, nullable=True, comment='Дополнительное поле')
images = relationship('ProductImage',
back_populates='product',
cascade="all, delete-orphan")
class ProductImage(BaseModel):
__tablename__ = 'product_images'
id = Column(Integer, autoincrement=True, primary_key=True, index=True)
product_id = Column(Integer, ForeignKey('products.id'), nullable=False)
product = relationship('Product', back_populates='images')
image_url = Column(String, nullable=False)
class ProductBarcode(BaseModel):

View File

@@ -4,6 +4,7 @@ pydantic
uvicorn
uvicorn[standard]
gunicorn
python-multipart
# Security
python-jose[cryptography]

View File

@@ -1,6 +1,6 @@
from typing import Annotated, Union
from fastapi import APIRouter, Depends
from fastapi import APIRouter, Depends, UploadFile
from sqlalchemy.ext.asyncio import AsyncSession
import utils.dependecies
@@ -15,7 +15,7 @@ from services.product import ProductService
product_router = APIRouter(
prefix="/product",
tags=["product"],
dependencies=[Depends(get_current_user)]
# dependencies=[Depends(get_current_user)]
)
@@ -125,3 +125,18 @@ async def get_product_barcode(
session: Annotated[AsyncSession, Depends(get_session)]
):
return await BarcodeService(session).get_barcode(request)
@product_router.post(
'/images/upload/{product_id}',
response_model=ProductUploadImageResponse,
operation_id='upload_product_image'
)
async def upload_product_image(
product_id: int,
upload_file: UploadFile,
session: Annotated[AsyncSession, Depends(get_session)]
):
file_bytes = upload_file.file.read()
return await ProductService(session).upload_image(product_id, file_bytes)

View File

@@ -94,4 +94,8 @@ class ProductGenerateBarcodeResponse(OkMessageSchema):
class ProductExistsBarcodeResponse(CustomModelCamel):
exists: bool
class ProductUploadImageResponse(OkMessageSchema):
image_url: str | None = None
# endregion

View File

@@ -3,7 +3,9 @@ from sqlalchemy import select, func, Integer, update
from sqlalchemy.orm import selectinload
import utils.barcodes
from models.product import Product, ProductBarcode
from backend import config
from external.s3_uploader.uploader import S3Uploader
from models.product import Product, ProductBarcode, ProductImage
from schemas.base import PaginationSchema
from services.base import BaseService
from schemas.product import *
@@ -146,6 +148,28 @@ class ProductService(BaseService):
raise HTTPException(status_code=404, detail='Товар не найден')
return ProductSchema.model_validate(product)
async def upload_image(self, product_id: int, file_bytes: bytes) -> ProductUploadImageResponse:
try:
product = await self.get_by_id(product_id)
if not product:
raise Exception("Неудалось найти товар с указанным ID")
s3_uploader = S3Uploader(config.S3_API_KEY)
response = await s3_uploader.upload(file_bytes)
response_url = response.get('link')
if not response_url:
raise Exception("Неудалось загрузить изображение")
product_image = ProductImage(
product_id=product_id,
image_url=response_url,
)
self.session.add(product_image)
await self.session.commit()
return ProductUploadImageResponse(ok=True,
message='Изображение успешно загружено',
image_url=response_url)
except Exception as e:
return ProductUploadImageResponse(ok=False, message=str(e))
# region Barcodes
async def add_barcode(self, request: ProductAddBarcodeRequest):
try:

View File

@@ -5,6 +5,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import joinedload
from backend.session import session_maker
from external.s3_uploader.uploader import S3Uploader
from models import Deal, DealProduct, Service
import models
@@ -12,34 +13,10 @@ import models.secondary
async def main(session: AsyncSession):
deal_services_subquery = (
select(
models.secondary.DealService.deal_id,
func.sum(models.secondary.DealService.quantity * Service.price).label('total_price')
)
.join(Service)
.group_by(models.secondary.DealService.deal_id)
)
product_services_subquery = select(
select(
models.secondary.DealProductService.deal_id,
func.sum(models.DealProduct.quantity * models.secondary.DealProductService.price).label('total_price')
)
.join(models.secondary.DealProduct)
.group_by(models.secondary.DealProductService.deal_id)
.subquery()
)
union_subqueries = deal_services_subquery.union(product_services_subquery).subquery()
final_subquery = (
select(
union_subqueries.c.deal_id,
func.sum(union_subqueries.c.total_price).label('total_sum')
)
.group_by(union_subqueries.c.deal_id)
.subquery()
)
print(final_subquery)
file_bytes = open('photo_2024-04-01 10.26.39.jpeg', 'rb').read()
uploader = S3Uploader('1cc46590-4532-4046-97aa-baf3e49f20ad-AUF')
response = await uploader.upload(file_bytes)
print(response)
async def preload():

Binary file not shown.