commit 3a022ec58804b6bd8408e7275d343e297f03e8a2 Author: mihalin Date: Fri Jun 11 21:56:03 2021 +0300 initial diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bee3282 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +venv +.env +.venv +.idea +__pycache__ +*.pyc diff --git a/README.md b/README.md new file mode 100644 index 0000000..b3242b6 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +# OLGram + +Open-source self-hosted Livegram alternative + + +##### + +таблицы + +Боты: токен, имя, владелец +Пользователи: идентификатор diff --git a/bot.py b/bot.py new file mode 100644 index 0000000..65ea281 --- /dev/null +++ b/bot.py @@ -0,0 +1,29 @@ +import asyncio +from aiogram import Bot, Dispatcher, executor +from aiogram.contrib.fsm_storage.memory import MemoryStorage + +from settings import BotSettings + +from olgram.bot.bots import router as bots_router +from olgram.bot.start import router as start_router + +from olgram.utils.database import init_database + + +def main(): + """ + Classic polling + """ + asyncio.get_event_loop().run_until_complete(init_database()) + + bot = Bot(BotSettings.token()) + dp = Dispatcher(bot, storage=MemoryStorage()) + + start_router.setup(dp) + bots_router.setup(dp) + + executor.start_polling(dp, skip_updates=True) + + +if __name__ == '__main__': + main() diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..0ce7388 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,15 @@ +version: '3' +services: + postgres: + image: kartoza/postgis + environment: + - POSTGRES_USER=test_user + - POSTGRES_PASSWORD=test_passwd + - POSTGRES_DB=olgram + ports: + - '5431:5432' + volumes: + - database:/var/lib/postgresql/data + +volumes: + database: diff --git a/olgram/bot/__init__.py b/olgram/bot/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/olgram/bot/bots.py b/olgram/bot/bots.py new file mode 100644 index 0000000..d0ed1a1 --- /dev/null +++ b/olgram/bot/bots.py @@ -0,0 +1,16 @@ +from aiogram import Bot, Dispatcher, executor, types +from aiogram.dispatcher import FSMContext + +from ..utils.router import Router + +router = Router() + + +@router.message_handler(commands=["my_bots"]) +async def my_bots(message: types.Message, state: FSMContext): + await message.answer("У тебя много ботов )") + + +@router.message_handler(commands=["add_bot"]) +async def add_bot(message: types.Message, state: FSMContext): + await message.answer("Добавь тогда ок") diff --git a/olgram/bot/start.py b/olgram/bot/start.py new file mode 100644 index 0000000..c4cba39 --- /dev/null +++ b/olgram/bot/start.py @@ -0,0 +1,17 @@ +from aiogram import Bot, Dispatcher, executor, types +from aiogram.dispatcher import FSMContext + +from ..utils.router import Router + +router = Router() + + +@router.message_handler(commands=["start"]) +async def start(message: types.Message, state: FSMContext): + """ + Start command handler + """ + + await message.answer( + "Привет. Я бот Olgram" + ) diff --git a/olgram/models/bot.py b/olgram/models/bot.py new file mode 100644 index 0000000..f5a2753 --- /dev/null +++ b/olgram/models/bot.py @@ -0,0 +1,11 @@ +from tortoise.models import Model +from tortoise import fields + + +class Bot(Model): + id = fields.IntField(pk=True) + token = fields.CharField(max_length=50, unique=True) + owner = fields.ForeignKeyField("models.User", related_name="bots") + + class Meta: + table = 'bot' diff --git a/olgram/models/user.py b/olgram/models/user.py new file mode 100644 index 0000000..16e07a1 --- /dev/null +++ b/olgram/models/user.py @@ -0,0 +1,9 @@ +from tortoise import Model, fields + + +class User(Model): + id = fields.IntField(pk=True) + telegram_id = fields.IntField(index=True) + + class Meta: + table = 'user' diff --git a/olgram/utils/__init__.py b/olgram/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/olgram/utils/database.py b/olgram/utils/database.py new file mode 100644 index 0000000..585b5df --- /dev/null +++ b/olgram/utils/database.py @@ -0,0 +1,15 @@ +from tortoise import Tortoise +from settings import DatabaseSettings + + +async def init_database(): + # Here we create a SQLite DB using file "db.sqlite3" + # also specify the app name of "models" + # which contain models from "app.models" + await Tortoise.init( + db_url=f'postgres://{DatabaseSettings.user()}:{DatabaseSettings.password()}' + f'@localhost:5431/{DatabaseSettings.database_name()}', + modules={'models': ['olgram.models.bot', 'olgram.models.user']} + ) + # Generate the schema + await Tortoise.generate_schemas() diff --git a/olgram/utils/router.py b/olgram/utils/router.py new file mode 100644 index 0000000..fd62b47 --- /dev/null +++ b/olgram/utils/router.py @@ -0,0 +1,79 @@ +from dataclasses import dataclass +from typing import Any, Dict, List, Tuple + +from aiogram.dispatcher import Dispatcher + + +@dataclass() +class Handler: + callback: Any + custom_filters: Tuple[Any] + kwargs: Dict[Any, Any] + commands: Any = None + regexp: Any = None + content_types: Any = None + state: Any = None + run_task: Any = None + + +class Router: + def __init__(self): + self._message_handlers: List[Handler] = [] + self._inline_handlers: List[Handler] = [] + self._callback_handlers: List[Handler] = [] + + def message_handler( + self, *custom_filters, commands=None, regexp=None, content_types=None, state=None, run_task=None, **kwargs + ): + def decorator(callback): + self._message_handlers.append( + Handler(callback, custom_filters, kwargs, commands, regexp, content_types, state, run_task) + ) + return callback + + return decorator + + def inline_handler(self, *custom_filters, state=None, run_task=None, **kwargs): + def decorator(callback): + self._inline_handlers.append(Handler(callback, custom_filters, kwargs, state=state, run_task=run_task)) + return callback + + return decorator + + def callback_query_handler(self, *custom_filters, state=None, run_task=None, **kwargs): + def decorator(callback): + self._callback_handlers.append(Handler(callback, custom_filters, kwargs, state=state, run_task=run_task)) + return callback + + return decorator + + def setup(self, dp: Dispatcher): + for handler in self._message_handlers: + dp.register_message_handler( + handler.callback, + *handler.custom_filters, + commands=handler.commands, + regexp=handler.regexp, + content_types=handler.content_types, + state=handler.state, + run_task=handler.run_task, + **handler.kwargs + ) + + for handler in self._inline_handlers: + dp.register_inline_handler( + handler.callback, + *handler.custom_filters, + state=handler.state, + run_task=handler.run_task, + **handler.kwargs + ) + + for handler in self._callback_handlers: + dp.register_callback_query_handler( + handler.callback, + *handler.custom_filters, + state=handler.state, + run_task=handler.run_task, + **handler.kwargs + ) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f07d7da --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +aiogram +tortoise-orm[asyncpg] +aerich +python-dotenv diff --git a/settings.py b/settings.py new file mode 100644 index 0000000..fcd3f8d --- /dev/null +++ b/settings.py @@ -0,0 +1,35 @@ +from abc import ABC +from dotenv import load_dotenv +import os + + +load_dotenv() + + +class _Settings(ABC): + @classmethod + def _get_env(cls, parameter: str) -> str: + parameter = os.getenv(parameter, None) + if not parameter: + raise ValueError(f"{parameter} not defined in ENV") + return parameter + + +class BotSettings(_Settings): + @classmethod + def token(cls) -> str: + return cls._get_env("BOT_TOKEN") + + +class DatabaseSettings(_Settings): + @classmethod + def user(cls) -> str: + return cls._get_env("POSTGRES_USER") + + @classmethod + def password(cls) -> str: + return cls._get_env("POSTGRES_PASSWORD") + + @classmethod + def database_name(cls) -> str: + return cls._get_env("POSTGRES_DB")