add base bot

parent 143f4348
BOT_TOKEN=123:abc
.env
.venv
*.db
__pycache__/
\ No newline at end of file
......@@ -636,6 +636,17 @@ files = [
]
[[package]]
name = "peewee"
version = "3.18.2"
description = "a little orm"
optional = false
python-versions = "*"
groups = ["main"]
files = [
{file = "peewee-3.18.2.tar.gz", hash = "sha256:77a54263eb61aff2ea72f63d2eeb91b140c25c1884148e28e4c0f7c4f64996a0"},
]
[[package]]
name = "propcache"
version = "0.3.2"
description = "Accelerated property cache"
......@@ -984,6 +995,45 @@ files = [
typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0"
[[package]]
name = "pydantic-settings"
version = "2.10.1"
description = "Settings management using Pydantic"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "pydantic_settings-2.10.1-py3-none-any.whl", hash = "sha256:a60952460b99cf661dc25c29c0ef171721f98bfcb52ef8d9ea4c943d7c8cc796"},
{file = "pydantic_settings-2.10.1.tar.gz", hash = "sha256:06f0062169818d0f5524420a360d632d5857b83cffd4d42fe29597807a1614ee"},
]
[package.dependencies]
pydantic = ">=2.7.0"
python-dotenv = ">=0.21.0"
typing-inspection = ">=0.4.0"
[package.extras]
aws-secrets-manager = ["boto3 (>=1.35.0)", "boto3-stubs[secretsmanager]"]
azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0)"]
gcp-secret-manager = ["google-cloud-secret-manager (>=2.23.1)"]
toml = ["tomli (>=2.0.1)"]
yaml = ["pyyaml (>=6.0.1)"]
[[package]]
name = "python-dotenv"
version = "1.1.1"
description = "Read key-value pairs from a .env file and set them as environment variables"
optional = false
python-versions = ">=3.9"
groups = ["main"]
files = [
{file = "python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc"},
{file = "python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab"},
]
[package.extras]
cli = ["click (>=5.0)"]
[[package]]
name = "telegrinder"
version = "0.5.1"
description = "Modern visionary telegram bot framework."
......@@ -1178,4 +1228,4 @@ propcache = ">=0.2.1"
[metadata]
lock-version = "2.1"
python-versions = ">=3.12,<4.0"
content-hash = "ba9bd54ec8d59becfd1c0b8e43db3f386bfbd222b22bca0a3e5b5a1802f72f25"
content-hash = "a510528d6af1e3839834d33b34c1b07dd8842f5755c5d861429e32bf4432e0af"
......@@ -10,7 +10,9 @@ readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"telegrinder (>=0.5.1,<0.6.0)",
"pydantic (>=2.11.7,<3.0.0)"
"pydantic (>=2.11.7,<3.0.0)",
"pydantic-settings (>=2.10.1,<3.0.0)",
"peewee (>=3.18.2,<4.0.0)"
]
[project.urls]
......
from .methods import PackagesAPI
api = PackagesAPI()
import aiohttp
from urllib.parse import urlencode
from . import models
class BaseAPI:
BASE_URL = "https://rdb.altlinux.org/api"
def __init__(self):
self.session: aiohttp.ClientSession | None = None
async def init(self):
if self.session is None:
self.session = aiohttp.ClientSession()
async def get(self, path: str, params: dict = None):
url = f"{self.BASE_URL}/{path.lstrip('/')}"
if params:
query = urlencode({k: ",".join(v) if isinstance(v, list) else v for k, v in params.items()})
url += f"?{query}"
async with self.session.get(url) as resp:
resp.raise_for_status()
return await resp.json()
async def close(self):
await self.session.close()
class APIInfo:
def __init__(self, client: BaseAPI):
self.client = client
async def version(self) -> models.APIVersion:
data = await self.client.get("/version")
return models.APIVersion(**data)
class PackagesAPI:
def __init__(self):
self._client = BaseAPI()
self.api = APIInfo(self._client)
async def init(self):
await self._client.init()
async def close(self):
await self._client.close()
from pydantic import BaseModel
class APIVersion(BaseModel):
name: str
version: str
description: str
from pydantic_settings import BaseSettings, SettingsConfigDict
class Config(BaseSettings):
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
extra="ignore"
)
BOT_TOKEN: str
config = Config()
from .models import User
class UserMethod:
@classmethod
def add(
cls,
user_id: int,
maintainer: str,
):
"""создание записи пользователя"""
if cls.get(user_id=user_id) is None:
user = User(user_id=user_id, maintainer=maintainer)
user.save()
return True
return False
@classmethod
def get(cls, user_id: int) -> User | None:
"""получение записи пользователя"""
user: User | None = User.get_or_none(User.user_id == user_id)
return user
@classmethod
def delete(cls, user_id: int):
"""удаление записи пользователя"""
user = cls.get(user_id)
if user is None:
return False
user.delete_instance()
return True
class DB:
user = UserMethod
from peewee import (
SqliteDatabase,
Model,
AutoField,
IntegerField,
TextField
)
db = SqliteDatabase("alt-packages-bot.db")
class BaseModel(Model):
"""базовая модель"""
id = AutoField()
class Meta:
database = db
class User(BaseModel):
"""модель пользователя"""
user_id = IntegerField() # id пользователя
maintainer = TextField() # никнейм сопровождающего
class Meta:
table_name = "users"
from telegrinder import Dispatch, Message
from telegrinder.rules import Command
from api import api
dp = Dispatch()
@dp.message(Command("info"))
async def info_handler(m: Message) -> None:
api_data = await api.api.version()
await m.answer(
"Telegram бот для портала packages.altlinux.org\n"
f"Версия API: {api_data.version}"
)
from telegrinder import MESSAGE_FROM_USER, Dispatch, Message, WaiterMachine
from telegrinder.rules import StartCommand, HasText
from database.func import DB
from database.models import User
dp = Dispatch()
wm = WaiterMachine(dp)
@dp.message(StartCommand())
async def start_handler(m: Message, user: User | None) -> None:
if user is None:
await m.answer(
"Введите никнейм сопровождающего:"
)
msg, _ = await wm.wait(MESSAGE_FROM_USER, m.from_user.id, release=HasText())
maintainer = msg.text.unwrap()
await m.answer(
f"Вы выбрали {maintainer}"
)
DB.user.add(
m.from_user.id,
maintainer
)
return
from telegrinder import API, Telegrinder, Token
from telegrinder.modules import logger
from config import config
from api import api
from database.models import db, User
from middlewares import UserMiddleware
logger.set_level("INFO")
bot = Telegrinder(API(token=Token(config.BOT_TOKEN)))
bot.dispatch.load_from_dir("src/handlers")
bot.on.message.register_middleware(UserMiddleware)
@bot.loop_wrapper.lifespan.on_startup
async def startup():
db.create_tables([User])
await api.init()
@bot.loop_wrapper.lifespan.on_shutdown
async def shutdown():
await api.close()
bot.run_forever(skip_updates=True)
from .user_middleware import UserMiddleware
from telegrinder import API, ABCMiddleware, Message
from telegrinder.bot import Context
from database.func import DB
class UserMiddleware(ABCMiddleware):
def pre(self, m: Message, context: Context) -> bool:
user = DB.user.get(m.from_user.id)
context.user = user
return True
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment