From 259a83f337689f5ace9774408dd66ef49aa7b64c Mon Sep 17 00:00:00 2001 From: urec56 Date: Sun, 16 Mar 2025 12:04:09 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D0=BD=D0=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/chat/router.py | 22 +++++----- app/chat/websocket.py | 32 +++++++++++---- app/dao/chat.py | 13 +++--- app/dao/message.py | 4 +- app/dao/user.py | 8 ++-- app/dependencies.py | 13 +++--- app/images/router.py | 6 +-- app/main.py | 3 +- app/migrations/env.py | 9 ++--- .../2024-08-20_12-30-52_database_creation.py | 3 +- app/models/chat.py | 2 +- app/models/pinned_chat.py | 2 +- app/models/pinned_message.py | 10 ++++- app/models/users.py | 2 +- app/services/auth_service.py | 14 +++---- app/services/chat_service.py | 11 +++-- app/services/image_service.py | 2 +- app/services/message_service.py | 12 ++++-- app/services/user_service.py | 15 +++++-- app/tasks/celery.py | 1 - app/tasks/tasks.py | 12 +++--- app/users/router.py | 40 ++++++++++--------- app/users/schemas.py | 6 +-- app/utils/unit_of_work.py | 2 +- pyproject.toml | 5 +++ tests/integration_tests/conftest.py | 6 +-- 26 files changed, 149 insertions(+), 106 deletions(-) create mode 100644 pyproject.toml diff --git a/app/chat/router.py b/app/chat/router.py index 3fb4a13..8985334 100644 --- a/app/chat/router.py +++ b/app/chat/router.py @@ -3,20 +3,20 @@ from uuid import UUID from fastapi import APIRouter, Depends, status from app.chat.shemas import ( - SMessage, - SLastMessages, - SAllowedChats, - SMessageList, - SPinnedChats, - SPinnedMessages, - SChangeData, - SChatId, - Responses, + Responses, + SAllowedChats, + SChangeData, + SChatId, + SLastMessages, + SMessage, + SMessageList, + SPinnedChats, + SPinnedMessages, ) -from app.services import chat_service, message_service, auth_service -from app.utils.unit_of_work import UnitOfWork from app.dependencies import get_verificated_user +from app.services import auth_service, chat_service, message_service from app.users.schemas import SCreateInvitationLink, SUser +from app.utils.unit_of_work import UnitOfWork router = APIRouter(prefix="/chat", tags=["Чат"]) diff --git a/app/chat/websocket.py b/app/chat/websocket.py index 93088bd..4fcb58e 100644 --- a/app/chat/websocket.py +++ b/app/chat/websocket.py @@ -3,17 +3,33 @@ import logging from collections import defaultdict import websockets -from fastapi import WebSocket, WebSocketDisconnect, Depends, HTTPException, status +from fastapi import Depends, HTTPException, WebSocket, WebSocketDisconnect, status -from app.chat.exceptions import UseWSException, MessageNotFoundException, MessageAlreadyPinnedException -from app.exceptions import IncorrectDataException -from app.chat.exceptions import UserDontHavePermissionException -from app.services import message_service, auth_service -from app.utils.unit_of_work import UnitOfWork +from app.chat.exceptions import ( + MessageAlreadyPinnedException, + MessageNotFoundException, + UserDontHavePermissionException, + UseWSException, +) from app.chat.router import router -from app.chat.shemas import SSendMessage, SDeleteMessage, SEditMessage, SPinMessage, SUnpinMessage, Responses -from app.dependencies import get_current_user_ws, get_token, get_subprotocol_ws, get_verificated_user +from app.chat.shemas import ( + Responses, + SDeleteMessage, + SEditMessage, + SPinMessage, + SSendMessage, + SUnpinMessage, +) +from app.dependencies import ( + get_current_user_ws, + get_subprotocol_ws, + get_token, + get_verificated_user, +) +from app.exceptions import IncorrectDataException +from app.services import auth_service, message_service from app.users.schemas import SUser +from app.utils.unit_of_work import UnitOfWork class ConnectionManager: diff --git a/app/dao/chat.py b/app/dao/chat.py index 312591d..c6cffd5 100644 --- a/app/dao/chat.py +++ b/app/dao/chat.py @@ -1,16 +1,16 @@ from uuid import UUID from pydantic import HttpUrl -from sqlalchemy import insert, select, update, delete, func +from sqlalchemy import delete, func, insert, select, update from sqlalchemy.exc import IntegrityError, NoResultFound -from app.dao.base import BaseDAO from app.chat.exceptions import ( - UserAlreadyPinnedChatException, - MessageAlreadyPinnedException, - ChatNotFoundException, + ChatNotFoundException, + MessageAlreadyPinnedException, + UserAlreadyPinnedChatException, ) -from app.chat.shemas import SPinnedChats, SChat +from app.chat.shemas import SChat, SPinnedChats +from app.dao.base import BaseDAO from app.models.chat import Chat from app.models.pinned_chat import PinnedChat from app.models.pinned_message import PinnedMessage @@ -107,7 +107,6 @@ class ChatDAO(BaseDAO): await self.session.execute(stmt) async def get_pinned_chats(self, user_id: int) -> SPinnedChats: - query = ( select( func.json_build_object( diff --git a/app/dao/message.py b/app/dao/message.py index 04b7fa0..2d4dcca 100644 --- a/app/dao/message.py +++ b/app/dao/message.py @@ -1,5 +1,5 @@ -from datetime import datetime, UTC -from uuid import uuid4, UUID +from datetime import UTC, datetime +from uuid import UUID, uuid4 from app.chat.shemas import SMessageRaw, SMessageRawList diff --git a/app/dao/user.py b/app/dao/user.py index ad50023..c2ce7ba 100644 --- a/app/dao/user.py +++ b/app/dao/user.py @@ -1,15 +1,15 @@ from pydantic import EmailStr -from sqlalchemy import update, select, insert, func, or_ -from sqlalchemy.exc import MultipleResultsFound, IntegrityError, NoResultFound +from sqlalchemy import func, insert, or_, select, update +from sqlalchemy.exc import IntegrityError, MultipleResultsFound, NoResultFound from app.chat.shemas import SAllowedChats from app.dao.base import BaseDAO from app.exceptions import IncorrectDataException -from app.users.exceptions import UserAlreadyExistsException, UserNotFoundException from app.models.chat import Chat from app.models.user_avatar import UserAvatar -from app.models.users import Users from app.models.user_chat import UserChat +from app.models.users import Users +from app.users.exceptions import UserAlreadyExistsException, UserNotFoundException from app.users.schemas import SUser, SUserAvatars, SUsers diff --git a/app/dependencies.py b/app/dependencies.py index 25bbcbf..bcbfe9d 100644 --- a/app/dependencies.py +++ b/app/dependencies.py @@ -2,15 +2,18 @@ from typing import Annotated from fastapi import Depends, Header from fastapi.security import HTTPBearer -from jose import JWTError, jwt, ExpiredSignatureError +from jose import ExpiredSignatureError, JWTError, jwt from app.config import settings -from app.exceptions import IncorrectTokenFormatException, TokenMissingException, TokenExpiredException - +from app.exceptions import ( + IncorrectTokenFormatException, + TokenExpiredException, + TokenMissingException, +) from app.services import user_service -from app.utils.unit_of_work import UnitOfWork +from app.users.exceptions import UserMustConfirmEmailException, UserNotFoundException from app.users.schemas import SUser -from app.users.exceptions import UserNotFoundException, UserMustConfirmEmailException +from app.utils.unit_of_work import UnitOfWork auth_schema = HTTPBearer() diff --git a/app/images/router.py b/app/images/router.py index b7f8776..f9c83ee 100644 --- a/app/images/router.py +++ b/app/images/router.py @@ -1,8 +1,8 @@ -from fastapi import APIRouter, UploadFile, status, Depends +from fastapi import APIRouter, Depends, UploadFile, status -from app.images.shemas import SImageUrl, Responses -from app.services import image_service from app.dependencies import get_verificated_user +from app.images.shemas import Responses, SImageUrl +from app.services import image_service router = APIRouter(prefix="/images", tags=["Загрузка картинок"]) diff --git a/app/main.py b/app/main.py index ebf3ecc..f4d9719 100644 --- a/app/main.py +++ b/app/main.py @@ -1,10 +1,9 @@ from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware -from app.users.router import router as user_router from app.chat.websocket import router as websocket_router from app.images.router import router as image_router - +from app.users.router import router as user_router # sentry_sdk.init( # dsn=settings.SENTRY_DSN, diff --git a/app/migrations/env.py b/app/migrations/env.py index baf231c..c9695cb 100644 --- a/app/migrations/env.py +++ b/app/migrations/env.py @@ -1,16 +1,15 @@ from logging.config import fileConfig -from sqlalchemy import engine_from_config, pool from alembic import context - +from sqlalchemy import engine_from_config, pool from app.database import DATABASE_URL, Base -from app.models.users import Users # noqa from app.models.chat import Chat # noqa from app.models.pinned_chat import PinnedChat # noqa -from app.models.pinned_message import PinnedMessage # noqa -from app.models.user_chat import UserChat # noqa +from app.models.pinned_message import PinnedMessage # noqa from app.models.user_avatar import UserAvatar # noqa +from app.models.user_chat import UserChat # noqa +from app.models.users import Users # noqa # this is the Alembic Config object, which provides # access to the values within the .ini file in use. diff --git a/app/migrations/versions/2024-08-20_12-30-52_database_creation.py b/app/migrations/versions/2024-08-20_12-30-52_database_creation.py index 753f398..3d14fca 100644 --- a/app/migrations/versions/2024-08-20_12-30-52_database_creation.py +++ b/app/migrations/versions/2024-08-20_12-30-52_database_creation.py @@ -7,9 +7,8 @@ Create Date: 2024-08-20 12:30:52.435668 """ from typing import Sequence, Union -from alembic import op import sqlalchemy as sa - +from alembic import op # revision identifiers, used by Alembic. revision: str = '53fd6f2b93a4' diff --git a/app/models/chat.py b/app/models/chat.py index 3771f97..88cb8cc 100644 --- a/app/models/chat.py +++ b/app/models/chat.py @@ -1,5 +1,5 @@ from sqlalchemy import ForeignKey -from sqlalchemy.orm import mapped_column, Mapped +from sqlalchemy.orm import Mapped, mapped_column from app.database import Base diff --git a/app/models/pinned_chat.py b/app/models/pinned_chat.py index e855798..327a01b 100644 --- a/app/models/pinned_chat.py +++ b/app/models/pinned_chat.py @@ -1,5 +1,5 @@ from sqlalchemy import ForeignKey -from sqlalchemy.orm import mapped_column, Mapped +from sqlalchemy.orm import Mapped, mapped_column from app.database import Base diff --git a/app/models/pinned_message.py b/app/models/pinned_message.py index 59df228..1f681d0 100644 --- a/app/models/pinned_message.py +++ b/app/models/pinned_message.py @@ -1,7 +1,13 @@ -from uuid import UUID +from uuid import U[tool.isort] + +profile = "black" +multi_line_output = 3 +force_grid_wrap = 0 +combine_as_imports = true +use_parentheses = trueUID from sqlalchemy import ForeignKey -from sqlalchemy.orm import mapped_column, Mapped +from sqlalchemy.orm import Mapped, mapped_column from app.database import Base diff --git a/app/models/users.py b/app/models/users.py index 02486e8..20b061b 100644 --- a/app/models/users.py +++ b/app/models/users.py @@ -1,7 +1,7 @@ from datetime import date from sqlalchemy import func -from sqlalchemy.orm import mapped_column, Mapped +from sqlalchemy.orm import Mapped, mapped_column from app.database import Base diff --git a/app/services/auth_service.py b/app/services/auth_service.py index c0ee066..1f40152 100644 --- a/app/services/auth_service.py +++ b/app/services/auth_service.py @@ -1,19 +1,19 @@ -from datetime import datetime, timedelta, UTC +from datetime import UTC, datetime, timedelta from cryptography.fernet import Fernet, InvalidToken from jose import jwt from passlib.context import CryptContext +from app.chat.exceptions import ChatNotFoundException, UserCanNotReadThisChatException from app.config import settings from app.users.exceptions import ( - IncorrectAuthDataException, - UserNotFoundException, - UserMustConfirmEmailException, - WrongCodeException, + IncorrectAuthDataException, + UserMustConfirmEmailException, + UserNotFoundException, + WrongCodeException, ) -from app.chat.exceptions import ChatNotFoundException, UserCanNotReadThisChatException +from app.users.schemas import SInvitationData, SUser from app.utils.unit_of_work import UnitOfWork -from app.users.schemas import SUser, SInvitationData pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") # bcrypt не умеет больше 72 байт хешировать. Остальное обрезаем diff --git a/app/services/chat_service.py b/app/services/chat_service.py index c796ef3..19acd63 100644 --- a/app/services/chat_service.py +++ b/app/services/chat_service.py @@ -3,13 +3,16 @@ from urllib.parse import urljoin from pydantic import ValidationError -from app.chat.exceptions import UserDontHavePermissionException, UserCanNotReadThisChatException -from app.chat.shemas import SAllowedChats, SChangeData, SPinnedChats, SChat +from app.chat.exceptions import ( + UserCanNotReadThisChatException, + UserDontHavePermissionException, +) +from app.chat.shemas import SAllowedChats, SChangeData, SChat, SPinnedChats from app.config import settings +from app.services import auth_service, user_service from app.services.redis_service import RedisService -from app.services import user_service, auth_service -from app.utils.unit_of_work import UnitOfWork from app.users.schemas import SInvitationData +from app.utils.unit_of_work import UnitOfWork async def find_chat(uow: UnitOfWork, chat_id: int, user_id: int) -> SChat: diff --git a/app/services/image_service.py b/app/services/image_service.py index 3be34ef..d689494 100644 --- a/app/services/image_service.py +++ b/app/services/image_service.py @@ -1,6 +1,6 @@ from urllib.parse import urljoin -from fastapi import UploadFile, HTTPException +from fastapi import HTTPException, UploadFile from httpx import AsyncClient, Response from app.config import settings diff --git a/app/services/message_service.py b/app/services/message_service.py index b62735f..51e39e0 100644 --- a/app/services/message_service.py +++ b/app/services/message_service.py @@ -1,12 +1,18 @@ -from datetime import datetime, UTC, timedelta +from datetime import UTC, datetime, timedelta from uuid import UUID -from app.chat.shemas import SMessage, SSendMessage, SPinnedMessages, SMessageList, SMessageRaw, SMessageRawList +from app.chat.shemas import ( + SMessage, + SMessageList, + SMessageRaw, + SMessageRawList, + SPinnedMessages, + SSendMessage, +) from app.services import user_service from app.users.schemas import SUser from app.utils.unit_of_work import UnitOfWork - _users: dict[int, tuple[SUser, datetime]] = {} async def _get_cached_user(uow: UnitOfWork, user_id: int) -> SUser: diff --git a/app/services/user_service.py b/app/services/user_service.py index 7e6882f..254c691 100644 --- a/app/services/user_service.py +++ b/app/services/user_service.py @@ -4,12 +4,19 @@ from pydantic import ValidationError from app.config import settings from app.exceptions import BlackPhoenixException -from app.tasks import tasks -from app.utils.unit_of_work import UnitOfWork -from app.users.exceptions import PasswordsMismatchException, WrongCodeException -from app.users.schemas import SUser, SUsers, SUserRegister, SConfirmationData, SUserAvatars, SUserChangeData from app.services import auth_service from app.services.redis_service import RedisService +from app.tasks import tasks +from app.users.exceptions import PasswordsMismatchException, WrongCodeException +from app.users.schemas import ( + SConfirmationData, + SUser, + SUserAvatars, + SUserChangeData, + SUserRegister, + SUsers, +) +from app.utils.unit_of_work import UnitOfWork async def find_user(uow: UnitOfWork, **find_by) -> SUser: diff --git a/app/tasks/celery.py b/app/tasks/celery.py index 567a98f..b0fd391 100644 --- a/app/tasks/celery.py +++ b/app/tasks/celery.py @@ -2,7 +2,6 @@ from celery import Celery from app.config import settings - celery = Celery("tasks", broker=f"redis://{settings.REDIS_HOST}:{settings.REDIS_PORT}", include=["app.tasks.tasks"]) celery.conf.update(result_backend=f"redis://{settings.REDIS_HOST}:{settings.REDIS_PORT}") diff --git a/app/tasks/tasks.py b/app/tasks/tasks.py index f136b00..6108a53 100644 --- a/app/tasks/tasks.py +++ b/app/tasks/tasks.py @@ -1,22 +1,20 @@ -import smtplib import random +import smtplib import string from urllib.parse import urljoin from pydantic import EmailStr - from app.config import settings +from app.services import auth_service from app.tasks.celery import celery from app.tasks.email_templates import ( - create_registration_confirmation_template, - create_data_change_confirmation_email, - create_data_change_email, + create_data_change_confirmation_email, + create_data_change_email, + create_registration_confirmation_template, ) -from app.services import auth_service from app.users.schemas import SConfirmationData - confirmation_mail_templates = { "registration": create_registration_confirmation_template, "data_change_confirmation": create_data_change_confirmation_email, diff --git a/app/users/router.py b/app/users/router.py index 0c1f103..81b47ed 100644 --- a/app/users/router.py +++ b/app/users/router.py @@ -2,26 +2,30 @@ from random import randrange from fastapi import APIRouter, Depends, status -from app.services import user_service, auth_service -from app.users.exceptions import UserAlreadyExistsException, PasswordAlreadyInUseException, UserNotFoundException -from app.utils.unit_of_work import UnitOfWork from app.dependencies import get_current_user -from app.users.schemas import ( - SUserLogin, - SUserRegister, - SUserResponse, - SUserAvatars, - SUserFilter, - SUser, - SUserChangeData, - SUserSendConfirmationCode, - STokenLogin, - SUsers, - SUserPassword, - SGetUsersFilter, - SUserCode, - Responses, +from app.services import auth_service, user_service +from app.users.exceptions import ( + PasswordAlreadyInUseException, + UserAlreadyExistsException, + UserNotFoundException, ) +from app.users.schemas import ( + Responses, + SGetUsersFilter, + STokenLogin, + SUser, + SUserAvatars, + SUserChangeData, + SUserCode, + SUserFilter, + SUserLogin, + SUserPassword, + SUserRegister, + SUserResponse, + SUsers, + SUserSendConfirmationCode, +) +from app.utils.unit_of_work import UnitOfWork router = APIRouter(prefix="/users", tags=["Пользователи"]) diff --git a/app/users/schemas.py b/app/users/schemas.py index ad058cc..1c98f1e 100644 --- a/app/users/schemas.py +++ b/app/users/schemas.py @@ -1,9 +1,9 @@ -from datetime import date, timedelta, datetime, time +from datetime import date, datetime, time, timedelta from typing import Annotated -from pydantic_core import PydanticCustomError -from pydantic import BaseModel, EmailStr, field_validator, HttpUrl, StringConstraints from fastapi import Query +from pydantic import BaseModel, EmailStr, HttpUrl, StringConstraints, field_validator +from pydantic_core import PydanticCustomError class SUserLogin(BaseModel): diff --git a/app/utils/unit_of_work.py b/app/utils/unit_of_work.py index 37f6552..081c2c0 100644 --- a/app/utils/unit_of_work.py +++ b/app/utils/unit_of_work.py @@ -4,8 +4,8 @@ from sqlalchemy.exc import SQLAlchemyError from app.dao.chat import ChatDAO from app.dao.message import MessageDAO -from app.database import async_session_maker, mongo_db from app.dao.user import UserDAO +from app.database import async_session_maker, mongo_db from app.exceptions import BlackPhoenixException diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..87c1e73 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,5 @@ +[tool.isort] +profile = "black" +multi_line_output = 3 +force_grid_wrap = 0 +use_parentheses = true diff --git a/tests/integration_tests/conftest.py b/tests/integration_tests/conftest.py index 90d17c0..50d882a 100644 --- a/tests/integration_tests/conftest.py +++ b/tests/integration_tests/conftest.py @@ -2,16 +2,16 @@ import json from datetime import datetime import pytest -from sqlalchemy import insert, update from httpx import AsyncClient +from sqlalchemy import insert, update from app.config import settings from app.database import Base, async_session_maker, engine -from app.models.users import Users +from app.main import app as fastapi_app from app.models.chat import Chat from app.models.message import Message from app.models.user_chat import UserChat -from app.main import app as fastapi_app +from app.models.users import Users @pytest.fixture(autouse=True, scope="module")