Skip to content

Commit

Permalink
Ban & rabbitmq
Browse files Browse the repository at this point in the history
  • Loading branch information
Zoom-Developer committed Nov 3, 2024
1 parent 6ad2372 commit f80976a
Show file tree
Hide file tree
Showing 39 changed files with 310 additions and 31 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
__pycache__/
.venv/
.venv*/
.env.development
.env
data/
6 changes: 1 addition & 5 deletions .vscode/settings.json → backend/.vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,5 @@
"python.analysis.extraPaths": [
"./backend/src"
],
"flake8.args": [
"--ignore=E251",
"--max-line-length=110",
"--per-file-ignores=__init__.py:F403,F401"
]
"python.defaultInterpreterPath": "../.venv/Scripts/python.exe"
}
Binary file modified backend/requirements.txt
Binary file not shown.
6 changes: 3 additions & 3 deletions backend/src/application/likes/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ async def answer_focus(self, user: User, status: bool) -> None:
await TelegramService().send_message(
"🥰 Твоя анкета кому-то понравилась"
"\n⚡️ Скорее заходи в приложение и посмотри кто это!",
user_id = user.focus_user.id
chat_id = user.focus_user.id
)
await UserService().select_focus(user)

Expand All @@ -36,12 +36,12 @@ async def answer_like(self, like: Like, status: bool) -> None:
await TelegramService().send_message(
f"❤️‍🔥 У вас взаимная симпатия с {like.user.fullname} из {like.user.literal}!"
f"\n💬 Скорее переходите в {like.user.custom_mention("ЛС")} и общайтесь",
user_id = like.target_user.id
chat_id = like.target_user.id
)
await TelegramService().send_message(
f"❤️‍🔥 У вас взаимная симпатия с {like.target_user.fullname} из {like.target_user.literal}!"
f"\n💬 Скорее переходите в {like.target_user.custom_mention("ЛС")} и общайтесь",
user_id = like.user.id
chat_id = like.user.id
)
else:
await self.repo.delete(like)
Expand Down
32 changes: 19 additions & 13 deletions backend/src/application/tg/service.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import asyncio
import aiohttp

from config import TG_API_URL, TG_ADMIN_CHAT, TG_CHANNEL_ID
from domain.telegram import SendMediaTelegramMessage, SendTelegramMessage
from config import TG_API_URL, TG_CHANNEL_ID
from infrastructure.db import User
from infrastructure.rabbit.router import broker


class TelegramService:
Expand All @@ -10,23 +12,27 @@ async def _request(self, path: str, data: dict) -> aiohttp.ClientResponse:
async with aiohttp.ClientSession() as session:
return await session.post(TG_API_URL + path, json=data)

async def _send_message(self, text: str, *, chat_id: int | None = None, user_id: int | None = None) -> None:
peer_id = chat_id or user_id
await self._request("/sendMessage", {
"chat_id": peer_id,
"text": text,
"parse_mode": "html"
})

async def check_subscribed(self, user_id: int) -> bool:
res = await self._request("/getChatMember", {
"chat_id": TG_CHANNEL_ID,
"user_id": user_id
})
return res.ok and (await res.json())['result']['status'] not in ["left", "kicked"]

async def send_message(self, text: str, *, chat_id: int | None = None, user_id: int | None = None) -> None:
asyncio.ensure_future(self._send_message(text, chat_id=chat_id, user_id=user_id))
async def send_message(self, text: str, *, chat_id: int) -> None:
await broker.publish(
SendTelegramMessage(chat_id = chat_id, text = text),
"tg_msg"
)

async def send_to_chat(self, text: str) -> None:
await self.send_message(text, chat_id = TG_ADMIN_CHAT)
await self.send_message(text, chat_id = -1)

async def send_media_to_chat(self, text: str, files: list[str]) -> None:
await broker.publish(
SendMediaTelegramMessage(chat_id = -1, text = text, files = files),
"tg_media"
)

async def send_report(self, user: User, target: User, reason: str) -> None:
pass
13 changes: 10 additions & 3 deletions backend/src/application/user/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@ async def register(self, userdata: dict, data: BaseUser, avatar: bytes) -> User:
)
await AttachmentService().upload(avatar, user)
await self.select_focus(user)
await TelegramService().send_to_chat(
await TelegramService().send_media_to_chat(
"<b>Новый пользователь</b>"
f"\n<b>Имя:</b> {user.mention} <b>(<code>{user.id}</code>)</b>"
f"\n<b>Класс:</b> {user.literal}"
f"\n<b>Описание:</b> <i>{user.desc}</i>"
f"\n<b>Пол:</b> {'Мужской' if user.male else 'Женский'}"
f"\n<b>Описание:</b> <i>{user.desc}</i>",
[attachment.url for attachment in user.attachments]
)
return user

Expand Down Expand Up @@ -109,4 +111,9 @@ async def check_user(self, user: User, username: str) -> None:
async def check_user_subcription(self, user: User) -> None:
if not await TelegramService().check_subscribed(user.id):
user.is_active = False
raise SubscriptionRequiredException
raise SubscriptionRequiredException

async def ban(self, user: User, reason: str) -> None:
user.is_banned = True
user.ban_reason = reason
user.is_active = False
4 changes: 4 additions & 0 deletions backend/src/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@
TG_CHANNEL_LINK = os.environ.get("TG_CHANNEL_LINK")
TG_API_URL = "https://api.telegram.org/bot" + TG_TOKEN

# ----- [[ TELEGRAM ]] -----

RABBIT_URL = os.environ.get("RABBIT_URL")

# ----- [[ SETTINGS ]] -----

MAX_AVATAR_SIZE = 1024 * 1024 * 3 # Bytes
Expand Down
1 change: 1 addition & 0 deletions backend/src/domain/telegram/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .models import *
10 changes: 10 additions & 0 deletions backend/src/domain/telegram/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from pydantic import BaseModel


class SendTelegramMessage(BaseModel):
chat_id: int
text: str
parse_mode: str = "html"

class SendMediaTelegramMessage(SendTelegramMessage):
files: list[str]
11 changes: 10 additions & 1 deletion backend/src/domain/user/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,13 @@ class PatchUser(BaseUser):
is_active: bool = Field(description="Активна-ли анкета")

class ReportUser(BaseModel):
reason: str = Field(min_length=3, max_length=64)
reason: str = Field(min_length=3, max_length=64)

class BanUser(BaseModel):
msg_id: int
user_id: int
reason: str

class BannedUser(BaseModel):
msg_id: int
success: bool
1 change: 1 addition & 0 deletions backend/src/infrastructure/rabbit/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .router import *
12 changes: 12 additions & 0 deletions backend/src/infrastructure/rabbit/middlewares.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from faststream import BaseMiddleware

from infrastructure.db import CTX_SESSION, get_session

class DatabaseMiddleware(BaseMiddleware):
async def on_receive(self):
CTX_SESSION.set(get_session())
return await super().on_receive()

async def after_processed(self, exc_type, exc_val, exc_tb):
await CTX_SESSION.get().close()
return await super().after_processed(exc_type, exc_val, exc_tb)
8 changes: 8 additions & 0 deletions backend/src/infrastructure/rabbit/router.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from faststream.rabbit.fastapi import RabbitRouter

from config import RABBIT_URL
from .middlewares import DatabaseMiddleware


rabbit = RabbitRouter(RABBIT_URL, include_in_schema=False, middlewares=[DatabaseMiddleware])
broker = rabbit.broker
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions backend/src/api/user.py → backend/src/interface/api/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ async def get_user_info(user: User = Depends(get_user)) -> FullUserDTO:
responses={
400: {
"description": "Exceeded max file size (limit %s KB) (2002) / Invalid image file (2003)"
% {MAX_AVATAR_SIZE / 1024}
% (MAX_AVATAR_SIZE / 1024)
},
401: {"description": "undefined in endpoint"},
403: {"description": "Already registered (3001) / Subscription to channel required (3004) / Your account has been banned (3005)"}
Expand Down Expand Up @@ -69,7 +69,7 @@ async def edit_user(data: PatchUser, user: User = Depends(get_user)) -> FullUser
responses={
400: {
"description": "Exceeded max file size (limit %s KB) (2002) / Invalid image file (2003)"
% {MAX_AVATAR_SIZE / 1024}
% (MAX_AVATAR_SIZE / 1024)
},
}
)
Expand Down
1 change: 1 addition & 0 deletions backend/src/interface/rabbit/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .admin import router as AdminRouter
18 changes: 18 additions & 0 deletions backend/src/interface/rabbit/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from faststream.rabbit import RabbitRouter

from application.user import UserService
from domain.user import BanUser, BannedUser, UserRepository
from infrastructure.db import CTX_SESSION


router = RabbitRouter(prefix="adm_")

@router.subscriber("ban")
@router.publisher("banned")
async def ban_user(data: BanUser) -> BannedUser:
user = await UserRepository().get(data.user_id)
if not user:
return BannedUser(msg_id = data.msg_id, success = False)
await UserService().ban(user, data.reason)
await CTX_SESSION.get().commit()
return BannedUser(msg_id = data.msg_id, success = True)
9 changes: 7 additions & 2 deletions backend/src/main.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,18 @@
from infrastructure.application import create_app
from api import UserRouter, AttachmentRouter, LikesRouter, SystemRouter
from infrastructure.rabbit import rabbit
from interface.rabbit import AdminRouter
from interface.api import UserRouter, AttachmentRouter, LikesRouter, SystemRouter
from config import ROOT_PATH

rabbit.include_router(AdminRouter)

app = create_app(
routers=[
UserRouter,
LikesRouter,
AttachmentRouter,
SystemRouter
SystemRouter,
rabbit
],
root_path=ROOT_PATH,
ignoring_log_endpoints=[("/system/ping", "GET")]
Expand Down
9 changes: 9 additions & 0 deletions bot/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"python.autoComplete.extraPaths": [
"./src"
],
"python.analysis.extraPaths": [
"./src"
],
"python.defaultInterpreterPath": "../.venv-bot/Scripts/python.exe"
}
11 changes: 11 additions & 0 deletions bot/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM python:3.12-alpine

WORKDIR /bot
COPY ./requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir -r /app/requirements.txt
COPY ./src /bot

ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

CMD [ "python", "main.py" ]
Binary file added bot/requirements.txt
Binary file not shown.
9 changes: 9 additions & 0 deletions bot/src/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import os, dotenv

IS_PROD = os.getenv("IS_PROD", False)
if not IS_PROD:
dotenv.load_dotenv(".env.development")

TG_TOKEN = os.environ.get("TG_TOKEN")
TG_ADMIN_CHAT = int(os.environ.get("TG_ADMIN_CHAT"))
RABBIT_URL = os.environ.get("RABBIT_URL")
13 changes: 13 additions & 0 deletions bot/src/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import asyncio
import logging
from rabbit.app import app
from telegram.dispatcher import dp
from telegram.bot import bot

logging.basicConfig(level=logging.INFO)

async def run():
asyncio.ensure_future(dp.start_polling(bot))
await app.run()

asyncio.run(run())
2 changes: 2 additions & 0 deletions bot/src/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .telegram import *
from .admin import *
11 changes: 11 additions & 0 deletions bot/src/models/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from pydantic import BaseModel


class BanUser(BaseModel):
msg_id: int
user_id: int
reason: str

class BannedUser(BaseModel):
msg_id: int
success: bool
17 changes: 17 additions & 0 deletions bot/src/models/telegram.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from typing import Literal
from pydantic import BaseModel


class SendMessage(BaseModel):
chat_id: int
text: str
parse_mode: str = "html"

class SendAdminMessage(SendMessage):
chat_id: Literal[-1]

class SendMediaMessage(SendMessage):
files: list[str]

class SendAdminMediaMessage(SendAdminMessage, SendMediaMessage):
pass
8 changes: 8 additions & 0 deletions bot/src/rabbit/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from faststream import FastStream

from .broker import broker
from .routers import TelegramRouter, AdminRouter


app = FastStream(broker)
broker.include_routers(TelegramRouter, AdminRouter)
6 changes: 6 additions & 0 deletions bot/src/rabbit/broker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from faststream.rabbit import RabbitBroker

from config import RABBIT_URL


broker = RabbitBroker(RABBIT_URL)
2 changes: 2 additions & 0 deletions bot/src/rabbit/routers/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .telegram import router as TelegramRouter
from .admin import router as AdminRouter
17 changes: 17 additions & 0 deletions bot/src/rabbit/routers/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from faststream.rabbit import RabbitRouter
from aiogram.types import InputMediaPhoto, URLInputFile

from config import TG_ADMIN_CHAT
from models import BannedUser
from telegram.bot import bot


router = RabbitRouter("adm_")

@router.subscriber("banned")
async def msg(ban: BannedUser) -> None:
await bot.send_message(
chat_id = TG_ADMIN_CHAT,
reply_to_message_id = ban.msg_id,
text = "🚫 Пользователь заблокирован" if ban.success else "❕ Неверный пользователь"
)
Loading

0 comments on commit f80976a

Please sign in to comment.