This commit is contained in:
mihalin 2021-06-11 21:56:03 +03:00
commit 3a022ec588
14 changed files with 247 additions and 0 deletions

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
venv
.env
.venv
.idea
__pycache__
*.pyc

11
README.md Normal file
View File

@ -0,0 +1,11 @@
# OLGram
Open-source self-hosted Livegram alternative
#####
таблицы
Боты: токен, имя, владелец
Пользователи: идентификатор

29
bot.py Normal file
View File

@ -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()

15
docker-compose.yaml Normal file
View File

@ -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:

0
olgram/bot/__init__.py Normal file
View File

16
olgram/bot/bots.py Normal file
View File

@ -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("Добавь тогда ок")

17
olgram/bot/start.py Normal file
View File

@ -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"
)

11
olgram/models/bot.py Normal file
View File

@ -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'

9
olgram/models/user.py Normal file
View File

@ -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'

0
olgram/utils/__init__.py Normal file
View File

15
olgram/utils/database.py Normal file
View File

@ -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()

79
olgram/utils/router.py Normal file
View File

@ -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
)

4
requirements.txt Normal file
View File

@ -0,0 +1,4 @@
aiogram
tortoise-orm[asyncpg]
aerich
python-dotenv

35
settings.py Normal file
View File

@ -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")