From 2c02ce1048b12a6cb7a487ab6b712b84f2b66aad Mon Sep 17 00:00:00 2001 From: itqop Date: Mon, 15 Apr 2024 14:18:31 +0300 Subject: [PATCH] Rework --- app/handlers.py | 17 ++++++- config.py | 11 +++++ db/__init__.py | 2 +- db/database.py | 91 ++++++++++++++++++++++++++++++++++--- db/schemas/UserSchema.py | 2 + db/sql_schemas/Subscribe.py | 11 +++++ db/sql_schemas/Whitelist.py | 13 ++++++ db/sql_schemas/__init__.py | 4 +- 8 files changed, 141 insertions(+), 10 deletions(-) create mode 100644 db/sql_schemas/Subscribe.py create mode 100644 db/sql_schemas/Whitelist.py diff --git a/app/handlers.py b/app/handlers.py index 6aea2c8..d004133 100644 --- a/app/handlers.py +++ b/app/handlers.py @@ -19,7 +19,7 @@ async def get_uuid(request: RequestSchema): @app.post("/check_subscription/") async def check_subscription(request: RequestSchema): profile = await get_profile(schema=request) - subscription_status = await database.check_subscription_by_uuid(user=profile) + subscription_status = await database.check_subscription_by_nickname(user=profile) return {"has_subscription": subscription_status} @app.post("/check_ban_status/") @@ -53,15 +53,28 @@ async def grant_tab(request: RequestSchema): await database.grant_tab_by_username(user=profile, tab=request.tab) return {"message": "Tab granted successfully"} +@app.post("/grant_subscribe/") +async def grant_tab(request: RequestSchema): + profile = await get_profile(schema=request) + await database.update_subscription(user=profile) + async def get_profile(schema: RequestSchema) -> UserSchema: await database.delete_expired_tab_users() uuid = await database.get_uuid_by_username(schema) if not uuid: raise HTTPException(status_code=404, detail="User not found") + discord_id = await database.get_discord(schema) + if not discord_id: + raise HTTPException(status_code=404, detail="User not found in whitelist") + has_sub = await database.check_subscription_by_nickname(schema) profile = UserSchema.model_construct( username=schema.username, uuid=uuid, - expiry=schema.validated_expiry + discord_id=discord_id, + expiry=schema.validated_expiry, + has_sub=has_sub, + tab=schema.tab ) + print(profile) return profile \ No newline at end of file diff --git a/config.py b/config.py index 2dc70a8..312422b 100644 --- a/config.py +++ b/config.py @@ -1,6 +1,7 @@ from pydantic_settings import BaseSettings, SettingsConfigDict from pydantic import PositiveInt, computed_field, MySQLDsn from pydantic_core import Url +import httpx class Configs(BaseSettings): @@ -9,6 +10,9 @@ class Configs(BaseSettings): DATABASE: str USERNAME: str PASSWORD: str + HOST_DS: str + PORT_DS: PositiveInt + TOKEN_DS: str @computed_field def DB_URI(self) -> MySQLDsn: @@ -16,6 +20,13 @@ class Configs(BaseSettings): f"mysql+aiomysql://{self.USERNAME}:{self.PASSWORD}@{self.HOST}:{self.PORT}/{self.DATABASE}?charset=utf8mb4" ) + @computed_field + def DS_URL(self) -> httpx.URL: + return httpx.URL( + f"http://{self.HOST_DS}:{self.PORT_DS}/force-assign-role" + ) + + model_config = SettingsConfigDict(env_file='.env', env_file_encoding='utf-8') configs = Configs() \ No newline at end of file diff --git a/db/__init__.py b/db/__init__.py index 9ecca01..b0ddf1f 100644 --- a/db/__init__.py +++ b/db/__init__.py @@ -1,3 +1,3 @@ -from db.sql_schemas import TabUser, LuckpermsUserPermission, LitebansBan, LuckpermsPlayer +from db.sql_schemas import TabUser, LuckpermsUserPermission, LitebansBan, LuckpermsPlayer, Subscribe, Whitelist from db.database import Database from db.schemas import UUIDSchema, MySQLConfig, UserSchema, RequestSchema, TabSchema \ No newline at end of file diff --git a/db/database.py b/db/database.py index 3bc8609..caa2647 100644 --- a/db/database.py +++ b/db/database.py @@ -1,12 +1,15 @@ from sqlalchemy import select, delete from sqlalchemy.ext.asyncio import create_async_engine from sqlalchemy.orm import sessionmaker -from db import LuckpermsPlayer, LitebansBan, LuckpermsUserPermission, TabUser +from db import LuckpermsPlayer, LitebansBan, LuckpermsUserPermission, TabUser, Subscribe, Whitelist from db.schemas import MySQLConfig, UserSchema, RequestSchema, TabSchema from sqlalchemy.ext.asyncio import AsyncSession from aiocache import cached, SimpleMemoryCache from aiocache.serializers import PickleSerializer import datetime +import httpx +from config import configs + class Database: def __init__(self, uri: MySQLConfig): @@ -55,18 +58,18 @@ class Database: session.add(permission) await session.commit() - async def grant_tab_by_username(self, user: UserSchema, tab: TabSchema): + async def grant_tab_by_username(self, user: UserSchema): async with self.AsyncSessionLocal() as session: prefix = TabUser( user=user.username, - property=tab.property, - value=tab.value, + property=user.tab.property, + value=user.tab.value, expiry=user.expiry ) session.add(prefix) await session.commit() - async def check_subscription_by_uuid(self, user: UserSchema) -> bool: + async def check_subscription_by_uuid_old(self, user: UserSchema) -> bool: async with self.AsyncSessionLocal() as session: subscription = await session.execute( select(LuckpermsUserPermission).filter( @@ -78,6 +81,19 @@ class Database: return True else: return False + + async def check_subscription_by_nickname(self, user: UserSchema) -> bool: + async with self.AsyncSessionLocal() as session: + subscription = await session.execute( + select(Subscribe).filter( + Subscribe.nickname == user.username, + Subscribe.expiry > datetime.datetime.now() + ) + ) + if subscription.scalar(): + return True + else: + return False @cached(ttl=2, cache=SimpleMemoryCache, serializer=PickleSerializer()) async def check_ban_status_by_uuid(self, user: UserSchema) -> bool: @@ -102,4 +118,67 @@ class Database: .where(TabUser.expiry < current_timestamp) .where(TabUser.expiry != 0) ) - await session.commit() \ No newline at end of file + await session.commit() + + async def get_discord(self, user: UserSchema): + discord = None + async with self.AsyncSessionLocal() as session: + try: + result = await session.execute(select(Whitelist).where(Whitelist.player == user.username)) + record = result.fetchone() + if record: + discord = record[0].discord + else: + discord = None + except Exception as e: + print("Ошибка при выполнении запроса:", e) + + if isinstance(discord, str) and len(discord) > 8: + return discord + else: + return None + + async def update_subscription(self, user: UserSchema): + async with self.AsyncSessionLocal() as session: + try: + expiry_datetime = datetime.datetime.fromtimestamp(user.expiry, datetime.timezone.utc) + if user.has_sub: + subscription = await session.execute(select(Subscribe).where(Subscribe.discord == user.discord_id and Subscribe.nickname == user.username)) + subscription = subscription.fetchone()[0] + if subscription: + updated_expiry = subscription.expiry + (expiry_datetime - datetime.datetime.now(datetime.timezone.utc)) + subscription.expiry = updated_expiry + else: + new_subscription = Subscribe(discord=user.discord_id, nickname=user.username, expiry=expiry_datetime) + session.add(new_subscription) + else: + new_subscription = Subscribe(discord=user.discord_id, nickname=user.username, expiry=expiry_datetime) + session.add(new_subscription) + await session.commit() + await self.grant_tab_by_username(user=user) + await self.grant_permissions_by_uuid(user=user) + await discord_role(user.discord_id) + except Exception as e: + print("Ошибка при выполнении запроса:", e) + await session.rollback() + + async def delete_expired_subscriptions(self): + async with self.AsyncSessionLocal() as session: + try: + await session.execute(delete(Subscribe).where(Subscribe.expiry < datetime.now(datetime.timezone.utc))) + await session.commit() + except Exception as e: + print("Ошибка при удалении устаревших подписок:", e) + await session.rollback() + +async def discord_role(discord_id: int): + params = {"user_id": discord_id, "token": configs.TOKEN_DS} + + async with httpx.AsyncClient() as client: + try: + response = await client.get(configs.DS_URL, params=params) + data = response.json() + return data + except httpx.HTTPError as e: + print(f"Ошибка при отправке запроса: {e}") + return {"error": "Произошла ошибка при выполнении запроса"} \ No newline at end of file diff --git a/db/schemas/UserSchema.py b/db/schemas/UserSchema.py index 3d2e46f..5f93eb5 100644 --- a/db/schemas/UserSchema.py +++ b/db/schemas/UserSchema.py @@ -4,4 +4,6 @@ from .UUIDSchema import UUIDSchema class UserSchema(UUIDSchema): username: str + discord_id: str + has_sub: bool expiry: PositiveInt = 1 \ No newline at end of file diff --git a/db/sql_schemas/Subscribe.py b/db/sql_schemas/Subscribe.py new file mode 100644 index 0000000..07d3a12 --- /dev/null +++ b/db/sql_schemas/Subscribe.py @@ -0,0 +1,11 @@ +from sqlalchemy import Column, Integer, String, TIMESTAMP +from .Base import Base + + +class Subscribe(Base): + __tablename__ = 'subscribe' + + id = Column(Integer, primary_key=True, autoincrement=True) + discord = Column(String(36)) + nickname = Column(String(20)) + expiry = Column(TIMESTAMP) \ No newline at end of file diff --git a/db/sql_schemas/Whitelist.py b/db/sql_schemas/Whitelist.py new file mode 100644 index 0000000..1e5662d --- /dev/null +++ b/db/sql_schemas/Whitelist.py @@ -0,0 +1,13 @@ +from .Base import Base + +from sqlalchemy import Column, Integer, String, TIMESTAMP +from sqlalchemy.sql import func + + +class Whitelist(Base): + __tablename__ = 'whitelist' + + id = Column(Integer, primary_key=True, autoincrement=True) + player = Column(String(16), nullable=False) + discord = Column(String(36), nullable=True, default=None) + added_on = Column(TIMESTAMP, server_default=func.now()) diff --git a/db/sql_schemas/__init__.py b/db/sql_schemas/__init__.py index 44d4fb3..e487d6d 100644 --- a/db/sql_schemas/__init__.py +++ b/db/sql_schemas/__init__.py @@ -1,4 +1,6 @@ from .LitebansBan import LitebansBan from .LuckpermsPlayer import LuckpermsPlayer from .LuckpermsUserPermission import LuckpermsUserPermission -from .TabUser import TabUser \ No newline at end of file +from .TabUser import TabUser +from .Subscribe import Subscribe +from .Whitelist import Whitelist \ No newline at end of file