Fix: обновление или удаление сообщений
This commit is contained in:
parent
1c8003254c
commit
f21cedbb81
11 changed files with 76 additions and 47 deletions
|
@ -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
|
||||
|
|
|
@ -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"])
|
||||
|
|
|
@ -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})
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -120,7 +120,7 @@ class SGetUsersFilter(BaseModel):
|
|||
@classmethod
|
||||
def validate_username(cls, v):
|
||||
if not v:
|
||||
return "%"
|
||||
return "%%"
|
||||
else:
|
||||
return f"%{v}%"
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue