Fix: обновление или удаление сообщений

This commit is contained in:
urec56 2025-03-09 17:07:15 +03:00
parent 1c8003254c
commit f21cedbb81
11 changed files with 76 additions and 47 deletions

View file

@ -11,8 +11,8 @@ class SMessage(BaseModel):
chat_id: int
user_id: int
username: str
created_at: datetime
avatar_image: str
created_at: datetime
answer_id: UUID | None
answer_message: str | None
answer_image_url: str | None

View file

@ -55,7 +55,10 @@ class ConnectionManager:
message = SSendMessage.model_validate(message)
new_message = await MessageService.send_message(
uow=uow, user_id=user_id, chat_id=chat_id, message=message, image_url=message.image_url
uow=uow,
user_id=user_id,
chat_id=chat_id,
message=message,
)
new_message = new_message.model_dump()
new_message["id"] = str(new_message["id"])
@ -83,7 +86,10 @@ class ConnectionManager:
raise UserDontHavePermissionException
await MessageService.edit_message(
uow=uow, message_id=message.id, new_message=message.new_message, new_image_url=message.new_image_url
uow=uow,
message_id=message.id,
new_message=message.new_message,
new_image_url=message.new_image_url,
)
new_message = {
"flag": "edit",
@ -97,7 +103,10 @@ class ConnectionManager:
async def _pin(uow: UnitOfWork, _: int, chat_id: int, message: dict) -> dict:
message = SPinMessage.model_validate(message)
pinned_message = await MessageService.pin_message(
uow=uow, chat_id=chat_id, user_id=message.user_id, message_id=message.id
uow=uow,
chat_id=chat_id,
user_id=message.user_id,
message_id=message.id,
)
new_message = pinned_message.model_dump()
new_message["id"] = str(new_message["id"])

View file

@ -9,14 +9,14 @@ class MessageDAO:
self.message = mongo_db.message
async def send_message(
self,
user_id: int,
chat_id: int,
message: str | None,
image_url: str | None,
answer_id: UUID | None = None,
answer_message: str | None = None,
answer_image_url: str | None = None,
self,
user_id: int,
chat_id: int,
message: str | None,
image_url: str | None,
answer_id: UUID | None = None,
answer_message: str | None = None,
answer_image_url: str | None = None,
) -> UUID:
message_id = uuid4()
await self.message.insert_one(
@ -41,7 +41,7 @@ class MessageDAO:
async def delete_message(self, message_id: UUID) -> None:
await self.message.update_one({"id": str(message_id)}, {"$set": {"visibility": False}})
await self.message.update_one(
await self.message.update_many(
{"answer_id": str(message_id)},
{"$set": {"answer_message": None, "answer_image_url": None}}
)
@ -56,12 +56,12 @@ class MessageDAO:
{"id": str(message_id)},
{"$set": {"message": new_message, "image_url": new_image_url}}
)
await self.message.update_one(
await self.message.update_many(
{"answer_id": str(message_id)},
{"$set": {"answer_message": new_message, "answer_image_url": new_image_url}}
)
async def get_messages_from_ids(self, messages_ids: list[UUID]) -> SMessageRawList:
async def get_messages_by_ids(self, messages_ids: list[UUID]) -> SMessageRawList:
cursor = self.message.find({"visibility": True, "id": {"$in": [str(message_id) for message_id in messages_ids]}})
return SMessageRawList.model_validate({"message_raw_list": await cursor.to_list(length=None) or None})

View file

@ -9,7 +9,7 @@ class Chat(Base):
id: Mapped[int] = mapped_column(primary_key=True)
created_by: Mapped[int] = mapped_column(ForeignKey("users.id"))
chat_for = mapped_column(ForeignKey("users.id"))
chat_for: Mapped[int] = mapped_column(ForeignKey("users.id"))
chat_name: Mapped[str]
avatar_image: Mapped[str]
visibility: Mapped[bool] = mapped_column(server_default="true")

View file

@ -1,5 +1,5 @@
from sqlalchemy import ForeignKey
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import mapped_column, Mapped
from app.database import Base
@ -7,5 +7,5 @@ from app.database import Base
class PinnedChat(Base):
__tablename__ = "pinned_chat"
user_id = mapped_column(ForeignKey("users.id"), primary_key=True)
chat_id = mapped_column(ForeignKey("chat.id"), primary_key=True)
user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), primary_key=True)
chat_id: Mapped[int] = mapped_column(ForeignKey("chat.id"), primary_key=True)

View file

@ -9,6 +9,6 @@ from app.database import Base
class PinnedMessage(Base):
__tablename__ = "pinned_message"
chat_id = mapped_column(ForeignKey("chat.id"))
chat_id: Mapped[int] = mapped_column(ForeignKey("chat.id"))
message_id: Mapped[UUID] = mapped_column(primary_key=True)
user_id = mapped_column(ForeignKey("users.id"), primary_key=True)
user_id: Mapped[int] = mapped_column(ForeignKey("users.id"), primary_key=True)

View file

@ -15,19 +15,18 @@ from app.chat.exceptions import ChatNotFoundException, UserCanNotReadThisChatExc
from app.utils.unit_of_work import UnitOfWork
from app.users.schemas import SUser, SInvitationData
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") # bcrypt не умеет больше 72 байт хешировать. Остальное обрезаем
cipher_suite = Fernet(settings.INVITATION_LINK_TOKEN_KEY)
class AuthService:
@staticmethod
def get_password_hash(password: str) -> str:
return pwd_context.hash(password)
return pwd_context.hash(password.encode("utf-8")[:72])
@staticmethod
def verify_password(plain_password: str, hashed_password: str) -> bool:
return pwd_context.verify(plain_password, hashed_password)
return pwd_context.verify(plain_password.encode("utf-8")[:72], hashed_password)
@staticmethod
def create_access_token(data: dict[str, str | datetime]) -> str:

View file

@ -20,7 +20,7 @@ class MessageService:
return user
@classmethod
async def add_avatar_image_and_username_to_message(cls, uow: UnitOfWork, message: SMessageRaw) -> SMessage:
async def _add_avatar_image_and_username_to_message(cls, uow: UnitOfWork, message: SMessageRaw) -> SMessage:
user = await cls._get_cached_user(uow=uow, user_id=message.user_id)
message = message.model_dump()
message["avatar_image"] = str(user.avatar_image)
@ -28,13 +28,15 @@ class MessageService:
return SMessage.model_validate(message)
@classmethod
async def add_avatar_image_and_username_to_message_list(
cls, uow: UnitOfWork, messages: SMessageRawList
async def _add_avatar_image_and_username_to_message_list(
cls,
uow: UnitOfWork,
messages: SMessageRawList,
) -> SMessageList:
return SMessageList.model_validate(
{
"messages": [
await cls.add_avatar_image_and_username_to_message(uow=uow, message=message)
await cls._add_avatar_image_and_username_to_message(uow=uow, message=message)
for message in messages.message_raw_list
] if messages.message_raw_list else None
}
@ -42,7 +44,11 @@ class MessageService:
@classmethod
async def send_message(
cls, uow: UnitOfWork, user_id: int, chat_id: int, message: SSendMessage, image_url: str | None = None
cls,
uow: UnitOfWork,
user_id: int,
chat_id: int,
message: SSendMessage,
) -> SMessage:
async with uow:
if message.answer:
@ -51,7 +57,7 @@ class MessageService:
user_id=user_id,
chat_id=chat_id,
message=message.message,
image_url=image_url,
image_url=message.image_url,
answer_id=answer_message.id,
answer_message=answer_message.message,
answer_image_url=answer_message.answer_image_url,
@ -61,10 +67,10 @@ class MessageService:
user_id=user_id,
chat_id=chat_id,
message=message.message,
image_url=image_url,
image_url=message.image_url,
)
raw_message = await uow.message.get_message_by_id(message_id=message_id)
new_message = await cls.add_avatar_image_and_username_to_message(uow=uow, message=raw_message)
new_message = await cls._add_avatar_image_and_username_to_message(uow=uow, message=raw_message)
return new_message
@ -77,7 +83,9 @@ class MessageService:
async def edit_message(uow: UnitOfWork, message_id: UUID, new_message: str, new_image_url: str) -> None:
async with uow:
await uow.message.edit_message(
message_id=message_id, new_message=new_message, new_image_url=new_image_url
message_id=message_id,
new_message=new_message,
new_image_url=new_image_url,
)
@classmethod
@ -87,7 +95,7 @@ class MessageService:
await uow.commit()
raw_message = await uow.message.get_message_by_id(message_id=message_id)
pinned_message = await cls.add_avatar_image_and_username_to_message(uow=uow, message=raw_message)
pinned_message = await cls._add_avatar_image_and_username_to_message(uow=uow, message=raw_message)
return pinned_message
@ -101,24 +109,30 @@ class MessageService:
async def get_message_by_id(cls, uow: UnitOfWork, message_id: UUID) -> SMessage:
async with uow:
raw_message = await uow.message.get_message_by_id(message_id=message_id)
message = await cls.add_avatar_image_and_username_to_message(uow=uow, message=raw_message)
message = await cls._add_avatar_image_and_username_to_message(uow=uow, message=raw_message)
return message
@classmethod
async def get_pinned_messages(cls, uow: UnitOfWork, chat_id: int) -> SPinnedMessages:
async with uow:
pinned_messages_ids = await uow.chat.get_pinned_messages_ids(chat_id=chat_id)
raw_messages = await uow.message.get_messages_from_ids(messages_ids=pinned_messages_ids)
pinned_messages = await cls.add_avatar_image_and_username_to_message_list(uow=uow, messages=raw_messages)
raw_messages = await uow.message.get_messages_by_ids(messages_ids=pinned_messages_ids)
pinned_messages = await cls._add_avatar_image_and_username_to_message_list(uow=uow, messages=raw_messages)
return SPinnedMessages.model_validate({"pinned_messages": pinned_messages.messages})
@classmethod
async def get_some_messages(
cls, uow: UnitOfWork, chat_id: int, message_number_from: int, messages_to_get: int
cls,
uow: UnitOfWork,
chat_id: int,
message_number_from: int,
messages_to_get: int,
) -> SMessageList:
async with uow:
messages = await uow.message.get_some_messages(
chat_id=chat_id, message_number_from=message_number_from, messages_to_get=messages_to_get
chat_id=chat_id,
message_number_from=message_number_from,
messages_to_get=messages_to_get,
)
messages = await cls.add_avatar_image_and_username_to_message_list(uow=uow, messages=messages)
messages = await cls._add_avatar_image_and_username_to_message_list(uow=uow, messages=messages)
return messages

View file

@ -3,6 +3,7 @@ from datetime import timedelta
from pydantic import ValidationError
from app.config import settings
from app.exceptions import BlackPhoenixException
from app.services.redis_service import RedisService
from app.tasks.tasks import generate_confirmation_code, send_confirmation_email, send_data_change_email
from app.utils.unit_of_work import UnitOfWork
@ -15,15 +16,17 @@ class UserService:
@staticmethod
async def find_user(uow: UnitOfWork, **find_by) -> SUser:
try:
async with RedisService() as redis:
async with RedisService(is_raise=True) as redis:
user = await redis.get_value(key=f"user: {find_by}", model=SUser)
return user
except ValidationError:
except (ValidationError, BlackPhoenixException):
async with uow:
user = await uow.user.find_one(**find_by)
async with RedisService() as redis:
await redis.set_key(
key=f"user: {find_by}", expire_time=timedelta(minutes=30), value=user.model_dump_json()
key=f"user: {find_by}",
expire_time=timedelta(minutes=30),
value=user.model_dump_json(),
)
return user

View file

@ -194,7 +194,9 @@ async def email_verification(user_code: SUserCode, user: SUser = Depends(get_cur
)
async def login_user(user_data: SUserLogin, uow=Depends(UnitOfWork)):
user = await AuthService.authenticate_user(
uow=uow, email_or_username=user_data.email_or_username, password=user_data.password
uow=uow,
email_or_username=user_data.email_or_username,
password=user_data.password,
)
access_token = AuthService.create_access_token({"sub": str(user.id)})
return {"authorization": f"Bearer {access_token}"}
@ -310,6 +312,8 @@ async def send_confirmation_code(user_data: SUserSendConfirmationCode, user: SUs
},
)
async def change_user_data(
user_data: SUserChangeData, user: SUser = Depends(get_current_user), uow=Depends(UnitOfWork)
user_data: SUserChangeData,
user: SUser = Depends(get_current_user),
uow=Depends(UnitOfWork),
):
await UserService.change_data(uow=uow, user=user, user_data=user_data)

View file

@ -120,7 +120,7 @@ class SGetUsersFilter(BaseModel):
@classmethod
def validate_username(cls, v):
if not v:
return "%"
return "%%"
else:
return f"%{v}%"