Добавил редис

This commit is contained in:
urec56 2024-07-17 16:52:00 +04:00
parent ad1fe5487c
commit 857ff4c780
3 changed files with 103 additions and 30 deletions

View file

@ -1,8 +1,12 @@
from datetime import timedelta
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.config import settings
from app.services.redis_service import RedisService
from app.services.user_service import UserService
from app.utils.unit_of_work import UnitOfWork
from app.users.schemas import SInvitationData
@ -18,9 +22,20 @@ class ChatService:
@staticmethod
async def get_all_chats(uow: UnitOfWork, user_id: int) -> SAllowedChats:
async with uow:
allowed_chats = await uow.user.get_user_allowed_chats(user_id=user_id)
return allowed_chats
try:
async with RedisService() as redis:
allowed_chats = await redis.get_value(key=f"user_allowed_chats: {user_id}", model=SAllowedChats)
return allowed_chats
except ValidationError:
async with uow:
allowed_chats = await uow.user.get_user_allowed_chats(user_id=user_id)
async with RedisService() as redis:
await redis.set_key(
key=f"user_allowed_chats: {user_id}",
expire_time=timedelta(minutes=30),
value=allowed_chats.model_dump_json()
)
return allowed_chats
@staticmethod
async def create_chat(uow: UnitOfWork, user_id: int, user_to_exclude_id: int, chat_name: str) -> int:
@ -36,6 +51,8 @@ class ChatService:
)
await uow.chat.add_user_to_chat(user_id, chat_id)
await uow.chat.add_user_to_chat(settings.ADMIN_USER_ID, chat_id)
async with RedisService(is_raise=True) as redis:
await redis.delete_key(key=f"user_allowed_chats: {user_id}")
await uow.commit()
return chat_id
@ -48,6 +65,8 @@ class ChatService:
await uow.chat.change_data(
chat_id=user_data.chat_id, chat_name=user_data.chat_name, avatar_image=user_data.avatar_image
)
async with RedisService(is_raise=True) as redis:
await redis.delete_key(key=f"user_allowed_chats: {user_id}")
await uow.commit()
@staticmethod
@ -65,6 +84,8 @@ class ChatService:
raise UserCanNotReadThisChatException
async with uow:
await uow.chat.add_user_to_chat(chat_id=invitation_data.chat_id, user_id=user_id)
async with RedisService(is_raise=True) as redis:
await redis.delete_key(key=f"user_allowed_chats: {user_id}")
await uow.commit()
@classmethod
@ -74,6 +95,8 @@ class ChatService:
raise UserDontHavePermissionException
async with uow:
await uow.chat.delete_chat(chat_id)
async with RedisService(is_raise=True) as redis:
await redis.delete_key(key=f"user_allowed_chats: {user_id}")
await uow.commit()
@classmethod
@ -83,6 +106,8 @@ class ChatService:
raise UserDontHavePermissionException
async with uow:
await uow.chat.delete_user_from_chat(chat_id=chat_id, user_id=user_id_for_delete)
async with RedisService(is_raise=True) as redis:
await redis.delete_key(key=f"user_allowed_chats: {user_id_for_delete}")
await uow.commit()
@staticmethod

View file

@ -1,8 +1,11 @@
from datetime import timedelta
from pydantic import BaseModel
from redis.asyncio.client import Redis
from redis.exceptions import RedisError
from app.config import settings
from app.exceptions import BlackPhoenixException
def get_redis_session() -> Redis:
@ -10,17 +13,26 @@ def get_redis_session() -> Redis:
class RedisService:
@staticmethod
async def set_verification_code(redis: Redis, user_id: int, verification_code: str) -> None:
await redis.setex(f"user_verification_code: {user_id}", timedelta(minutes=5), verification_code)
def __init__(self, is_raise=None):
self.redis_session_factory = get_redis_session
self.is_raise = is_raise
@staticmethod
async def get_verification_code(redis: Redis, user_id: int) -> str:
verification_code = await redis.get(f"user_verification_code: {user_id}")
return verification_code.decode()
async def __aenter__(self):
self.redis_session = self.redis_session_factory()
return self
@staticmethod
async def delete_verification_code(redis: Redis, user_id: int) -> None:
await redis.delete(f"user_verification_code: {user_id}")
async def __aexit__(self, exc_type, exc, tb):
if isinstance(exc, RedisError):
if self.is_raise:
raise BlackPhoenixException
return True
async def set_key(self, key: str, expire_time: timedelta, value: str) -> None:
await self.redis_session.setex(key, expire_time, value)
async def get_value[T: type[BaseModel]](self, key: str, model: T | None = None) -> T | str:
value = await self.redis_session.get(key)
return model.model_validate_json(value) if model else value.decode()
async def delete_key(self, key: str) -> None:
await self.redis_session.delete(key)

View file

@ -1,5 +1,9 @@
from datetime import timedelta
from pydantic import ValidationError
from app.config import settings
from app.services.redis_service import get_redis_session, RedisService
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
from app.users.exceptions import PasswordsMismatchException, WrongCodeException
@ -10,15 +14,33 @@ from app.services.auth_service import AuthService
class UserService:
@staticmethod
async def find_user(uow: UnitOfWork, **find_by) -> SUser:
async with uow:
user = await uow.user.find_one(**find_by)
return user
try:
async with RedisService() as redis:
user = await redis.get_value(key=f"user: {find_by}", model=SUser)
return user
except ValidationError:
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(hours=1), value=user.model_dump_json()
)
return user
@staticmethod
async def find_all(uow: UnitOfWork, username: str) -> SUsers:
async with uow:
users = await uow.user.find_all(username=username)
return users
try:
async with RedisService() as redis:
users = await redis.get_value(key=f"users: {username}", model=SUsers)
return users
except ValidationError:
async with uow:
users = await uow.user.find_all(username=username)
async with RedisService() as redis:
await redis.set_key(
key=f"users: {username}", expire_time=timedelta(hours=1), value=users.model_dump_json()
)
return users
@staticmethod
async def add_user(uow: UnitOfWork, user_data: SUserRegister) -> SUser:
@ -39,10 +61,10 @@ class UserService:
@staticmethod
async def send_confirmation_email(user: SUser, mail_type: str, email: str | None = None) -> None:
redis_session = get_redis_session()
user_code = generate_confirmation_code()
await RedisService.delete_verification_code(redis=redis_session, user_id=user.id)
await RedisService.set_verification_code(redis=redis_session, user_id=user.id, verification_code=user_code)
async with RedisService(is_raise=True) as redis:
await redis.delete_key(key=f"user_verification_code: {user.id}")
await redis.set_key(key=f"user_verification_code: {user.id}", expire_time=timedelta(minutes=5), value=user_code)
user_mail_data = SConfirmationData.model_validate(
{
@ -57,13 +79,20 @@ class UserService:
@staticmethod
async def verificate_user(uow: UnitOfWork, user: SUser, confirmation_code: str) -> None:
redis_session = get_redis_session()
verification_code = await RedisService.get_verification_code(redis=redis_session, user_id=user.id)
try:
async with RedisService(is_raise=True) as redis:
verification_code = await redis.get_value(key=f"user_verification_code: {user.id}")
except AttributeError:
raise WrongCodeException
if verification_code != confirmation_code:
raise WrongCodeException
async with uow:
await uow.user.change_data(user_id=user.id, role=settings.VERIFICATED_USER)
async with RedisService() as redis:
await redis.delete_key(key=f"user: {dict(id=user.id)}")
await redis.set_key(
key=f"user: {dict(id=user.id)}", expire_time=timedelta(hours=1), value=user.model_dump_json()
)
await uow.commit()
@staticmethod
@ -74,11 +103,16 @@ class UserService:
@staticmethod
async def change_data(uow: UnitOfWork, user: SUser, user_data: SUserChangeData) -> None:
redis_session = get_redis_session()
verification_code = await RedisService.get_verification_code(redis=redis_session, user_id=user.id)
try:
async with RedisService(is_raise=True) as redis:
verification_code = await redis.get_value(key=f"user_verification_code: {user.id}")
except AttributeError:
raise WrongCodeException
if verification_code != user_data.verification_code:
raise WrongCodeException
hashed_password = AuthService.get_password_hash(user_data.new_password) if user_data.new_password else user.hashed_password
hashed_password = (
AuthService.get_password_hash(user_data.new_password) if user_data.new_password else user.hashed_password
)
async with uow:
await uow.user.change_data(
user_id=user.id,
@ -90,5 +124,7 @@ class UserService:
(await uow.user.add_user_avatar(user_id=user.id, avatar=str(user_data.avatar_url))) if user_data.avatar_url else None
await uow.commit()
async with RedisService() as redis:
await redis.delete_key(key=f"user: {dict(id=user.id)}")
send_data_change_email.delay(user_data.username, user_data.email)
await RedisService.delete_verification_code(redis=redis_session, user_id=user.id)