feat: Добавлено лого команды и filename
This commit is contained in:
parent
562166086e
commit
21bc00ee33
@ -1,10 +1,12 @@
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends
|
from fastapi import APIRouter, Depends, UploadFile, File
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from starlette.responses import FileResponse
|
||||||
|
|
||||||
from app.database.session import get_db
|
from app.database.session import get_db
|
||||||
from app.domain.entities.team import TeamEntity
|
from app.domain.entities.team import TeamEntity
|
||||||
|
from app.domain.entities.team_logo import TeamLogoEntity
|
||||||
from app.infrastructure.dependencies import get_current_user, require_admin
|
from app.infrastructure.dependencies import get_current_user, require_admin
|
||||||
from app.infrastructure.teams_service import TeamsService
|
from app.infrastructure.teams_service import TeamsService
|
||||||
|
|
||||||
@ -97,3 +99,33 @@ async def delete_team(
|
|||||||
):
|
):
|
||||||
teams_service = TeamsService(db)
|
teams_service = TeamsService(db)
|
||||||
return await teams_service.delete_team(team_id)
|
return await teams_service.delete_team(team_id)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get(
|
||||||
|
"/{team_id}/file/",
|
||||||
|
response_class=FileResponse,
|
||||||
|
summary="Download logo file by team ID",
|
||||||
|
description="Returns the image file for the given team ID",
|
||||||
|
)
|
||||||
|
async def download_photo_file(
|
||||||
|
team_id: int,
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
):
|
||||||
|
teams_service = TeamsService(db)
|
||||||
|
return await teams_service.get_photo_file_by_team_id(team_id)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post(
|
||||||
|
"/{team_id}/upload/",
|
||||||
|
response_model=TeamLogoEntity,
|
||||||
|
summary="Upload a new photo for a profile",
|
||||||
|
description="Uploads a new photo file and associates it with the given profile ID",
|
||||||
|
)
|
||||||
|
async def upload_photo(
|
||||||
|
team_id: int,
|
||||||
|
file: UploadFile = File(...),
|
||||||
|
db: AsyncSession = Depends(get_db),
|
||||||
|
user=Depends(get_current_user),
|
||||||
|
):
|
||||||
|
teams_service = TeamsService(db)
|
||||||
|
return await teams_service.upload_photo(team_id, file)
|
||||||
|
|||||||
@ -0,0 +1,32 @@
|
|||||||
|
"""0007_добавил filename для лого команды
|
||||||
|
|
||||||
|
Revision ID: b6c6c906cd2b
|
||||||
|
Revises: 61271acdd22f
|
||||||
|
Create Date: 2025-06-03 14:01:32.752389
|
||||||
|
|
||||||
|
"""
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision: str = 'b6c6c906cd2b'
|
||||||
|
down_revision: Union[str, None] = '61271acdd22f'
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
"""Upgrade schema."""
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column('teams', sa.Column('logo_filename', sa.String(), nullable=True))
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
"""Downgrade schema."""
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_column('teams', 'logo_filename')
|
||||||
|
# ### end Alembic commands ###
|
||||||
@ -10,6 +10,7 @@ class TeamEntity(BaseModel):
|
|||||||
title: str
|
title: str
|
||||||
description: Optional[str] = None
|
description: Optional[str] = None
|
||||||
logo: Optional[str] = None
|
logo: Optional[str] = None
|
||||||
|
logo_filename: Optional[str] = None
|
||||||
git_url: Optional[str] = None
|
git_url: Optional[str] = None
|
||||||
is_active: bool
|
is_active: bool
|
||||||
|
|
||||||
|
|||||||
6
API/app/domain/entities/team_logo.py
Normal file
6
API/app/domain/entities/team_logo.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
from pydantic import BaseModel
|
||||||
|
|
||||||
|
|
||||||
|
class TeamLogoEntity(BaseModel):
|
||||||
|
filename: str
|
||||||
|
file_path: str
|
||||||
@ -10,6 +10,7 @@ class Team(AdvancedBaseModel):
|
|||||||
title = Column(VARCHAR(150), nullable=False)
|
title = Column(VARCHAR(150), nullable=False)
|
||||||
description = Column(VARCHAR(150))
|
description = Column(VARCHAR(150))
|
||||||
logo = Column(String)
|
logo = Column(String)
|
||||||
|
logo_filename = Column(String)
|
||||||
git_url = Column(String)
|
git_url = Column(String)
|
||||||
is_active = Column(Boolean, default=False, nullable=False, server_default='false')
|
is_active = Column(Boolean, default=False, nullable=False, server_default='false')
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,17 @@
|
|||||||
|
import os
|
||||||
|
import uuid
|
||||||
from typing import Optional, Any, Coroutine
|
from typing import Optional, Any, Coroutine
|
||||||
|
|
||||||
from fastapi import HTTPException, status
|
import aiofiles
|
||||||
|
from fastapi import HTTPException, status, UploadFile
|
||||||
|
from magic import magic
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
from starlette.responses import FileResponse
|
||||||
|
from werkzeug.utils import secure_filename
|
||||||
|
|
||||||
from app.application.teams_repository import TeamsRepository
|
from app.application.teams_repository import TeamsRepository
|
||||||
from app.domain.entities.team import TeamEntity
|
from app.domain.entities.team import TeamEntity
|
||||||
|
from app.domain.entities.team_logo import TeamLogoEntity
|
||||||
from app.domain.models import Team
|
from app.domain.models import Team
|
||||||
|
|
||||||
|
|
||||||
@ -75,6 +82,36 @@ class TeamsService:
|
|||||||
|
|
||||||
return self.model_to_entity(result)
|
return self.model_to_entity(result)
|
||||||
|
|
||||||
|
async def get_photo_file_by_team_id(self, team_id: int) -> FileResponse:
|
||||||
|
team = await self.teams_repository.get_by_id(team_id)
|
||||||
|
|
||||||
|
if not team:
|
||||||
|
raise HTTPException(404, "Команда с таким ID не найдена")
|
||||||
|
|
||||||
|
if not os.path.exists(team.logo):
|
||||||
|
raise HTTPException(404, "Файл логотипа не найден")
|
||||||
|
|
||||||
|
return FileResponse(
|
||||||
|
team.logo,
|
||||||
|
media_type=self.get_media_type(team.logo),
|
||||||
|
filename=team.logo_filename,
|
||||||
|
)
|
||||||
|
|
||||||
|
async def upload_photo(self, team_id: int, file: UploadFile):
|
||||||
|
team = await self.teams_repository.get_by_id(team_id)
|
||||||
|
|
||||||
|
self.validate_file_type(file)
|
||||||
|
|
||||||
|
team.logo = await self.save_file(file)
|
||||||
|
team.logo_filename = self.generate_filename(file)
|
||||||
|
|
||||||
|
team = await self.teams_repository.update(team)
|
||||||
|
|
||||||
|
return TeamLogoEntity(
|
||||||
|
filename=team.logo_filename,
|
||||||
|
file_path=team.logo,
|
||||||
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def model_to_entity(team_model: Team) -> TeamEntity:
|
def model_to_entity(team_model: Team) -> TeamEntity:
|
||||||
return TeamEntity(
|
return TeamEntity(
|
||||||
@ -82,6 +119,7 @@ class TeamsService:
|
|||||||
title=team_model.title,
|
title=team_model.title,
|
||||||
description=team_model.description,
|
description=team_model.description,
|
||||||
logo=team_model.logo,
|
logo=team_model.logo,
|
||||||
|
logo_filename=team_model.logo_filename,
|
||||||
git_url=team_model.git_url,
|
git_url=team_model.git_url,
|
||||||
is_active=team_model.is_active,
|
is_active=team_model.is_active,
|
||||||
)
|
)
|
||||||
@ -92,6 +130,7 @@ class TeamsService:
|
|||||||
title=team_entity.title,
|
title=team_entity.title,
|
||||||
description=team_entity.description,
|
description=team_entity.description,
|
||||||
logo=team_entity.logo,
|
logo=team_entity.logo,
|
||||||
|
logo_filename=team_entity.logo_filename,
|
||||||
git_url=team_entity.git_url,
|
git_url=team_entity.git_url,
|
||||||
is_active=team_entity.is_active,
|
is_active=team_entity.is_active,
|
||||||
)
|
)
|
||||||
@ -100,3 +139,31 @@ class TeamsService:
|
|||||||
team_model.id = team_entity.id
|
team_model.id = team_entity.id
|
||||||
|
|
||||||
return team_model
|
return team_model
|
||||||
|
|
||||||
|
async def save_file(self, file: UploadFile, upload_dir: str = "uploads/team_logos") -> str:
|
||||||
|
os.makedirs(upload_dir, exist_ok=True)
|
||||||
|
filename = self.generate_filename(file)
|
||||||
|
file_path = os.path.join(upload_dir, filename)
|
||||||
|
|
||||||
|
async with aiofiles.open(file_path, 'wb') as out_file:
|
||||||
|
content = await file.read()
|
||||||
|
await out_file.write(content)
|
||||||
|
return file_path
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def validate_file_type(file: UploadFile):
|
||||||
|
mime = magic.Magic(mime=True)
|
||||||
|
file_type = mime.from_buffer(file.file.read(1024))
|
||||||
|
file.file.seek(0)
|
||||||
|
|
||||||
|
if file_type not in ["image/jpeg", "image/png"]:
|
||||||
|
raise HTTPException(400, "Invalid file type")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generate_filename(file: UploadFile):
|
||||||
|
return secure_filename(f"{uuid.uuid4()}_{file.filename}")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_media_type(filename: str) -> str:
|
||||||
|
extension = filename.split('.')[-1].lower()
|
||||||
|
return f"image/{extension}" if extension in ['jpeg', 'jpg', 'png'] else "application/octet-stream"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user