From 257b8ebb12d113b0670fa73c7f60ac7d65112910 Mon Sep 17 00:00:00 2001 From: Beesquit Date: Fri, 18 Jul 2025 14:42:11 +0300 Subject: [PATCH] Initial commit --- .dockerignore | 11 +++++ .env example | 2 + .gitignore | 85 +++++++++++++++++++++++++++++++++++ README.md | 8 ++++ compose.yml | 11 +++++ dockerfile | 0 requirements.txt | 0 src/__main__.py | 10 +++++ src/config/credentials.py | 6 +++ src/config/options.py | 3 ++ src/config/strings.py | 15 +++++++ src/config/whitelist.py | 11 +++++ src/telegram/controller.py | 90 ++++++++++++++++++++++++++++++++++++++ todo.md | 18 ++++++++ 14 files changed, 270 insertions(+) create mode 100644 .dockerignore create mode 100644 .env example create mode 100644 .gitignore create mode 100644 README.md create mode 100644 compose.yml create mode 100644 dockerfile create mode 100644 requirements.txt create mode 100644 src/__main__.py create mode 100644 src/config/credentials.py create mode 100644 src/config/options.py create mode 100644 src/config/strings.py create mode 100644 src/config/whitelist.py create mode 100644 src/telegram/controller.py create mode 100644 todo.md diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..cd5b5fe --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +#.dockerignore +# Docker +.dockerignore +dockerfile +compose.yaml +compose.yml + +# Git +.gitignore +*.md +example.env diff --git a/.env example b/.env example new file mode 100644 index 0000000..56f2847 --- /dev/null +++ b/.env example @@ -0,0 +1,2 @@ +BOT_TOKEN = "" +WHITELIST = "chatid1, chatid2" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5285038 --- /dev/null +++ b/.gitignore @@ -0,0 +1,85 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +env/ +venv/ +*.venv + +# Rope project settings +.ropeproject + +# mypy +.mypy_cache/ + +# VSCode +.vscode/ + +# JetBrains +.idea/ + +# .env +.env + +# test file +test.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..675524e --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# LIFE - LIFE is full ecosystem. +**Life-bot** - это бот связанный с `Telegram`. Он собирает статистику из разных сфер жизни. + +Конечная цель данной системы - получение информации с максимального числа сервисов через API, её обработка и отображение в удобном формате. Система должна работать по принципу *минимума усилий*. То есть заполнение информации должно быть максимально простым и комфортным, а в идеале потребность системы в нём должна отсутствовать. +### На момент 18.07.2025: + - В качестве платформы для отображения информации и доступа к файлам (не исходникам) внутри системы выбран `Obsidian` + - Для синхронизации с `Obsidian` выбран WebDAV протокол + - Бот поддерживает только одного пользователя diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..d3012cc --- /dev/null +++ b/compose.yml @@ -0,0 +1,11 @@ +services: + life-bot: + image: git.frik.su/eugenebee/life-bot:latest + container_name: life-bot + environment: + BOT_TOKEN: "telegram-bot-token" + WHITELIST: "chat-id-1, chat-id-2" + volumes: + - ./data:/app/data + - ./logs:/app/logs + restart: unless-stopped \ No newline at end of file diff --git a/dockerfile b/dockerfile new file mode 100644 index 0000000..e69de29 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e69de29 diff --git a/src/__main__.py b/src/__main__.py new file mode 100644 index 0000000..38f0f5f --- /dev/null +++ b/src/__main__.py @@ -0,0 +1,10 @@ +import asyncio + +from loguru import logger + +from telegram.controller import startup as telegramStartup + +if __name__ == "__main__": + logger.info("Starting python programm!") + asyncio.run(telegramStartup()) + logger.info("Python programm stopped!") diff --git a/src/config/credentials.py b/src/config/credentials.py new file mode 100644 index 0000000..3aaac53 --- /dev/null +++ b/src/config/credentials.py @@ -0,0 +1,6 @@ +from decouple import config + + +# Telegram + +bot_token = config('BOT_TOKEN', default='') diff --git a/src/config/options.py b/src/config/options.py new file mode 100644 index 0000000..07e6367 --- /dev/null +++ b/src/config/options.py @@ -0,0 +1,3 @@ +from decouple import config + +# todo diff --git a/src/config/strings.py b/src/config/strings.py new file mode 100644 index 0000000..5921341 --- /dev/null +++ b/src/config/strings.py @@ -0,0 +1,15 @@ +# Bot Statuses + +startBot = "Бот запущен!" + +stopBot = "Бот остановлен!" + +unexpectedError = "Возникла непредвиденная ошибка. :c" + +# Commands + +startCommand = "Привет! Я твой личный бот-трекер из системы LIFE." + +helpCommand = "Для описания финансов пишите +число или -число. " + +infoCommand = "Потрачено за сегодня:\nПолучено за сегодня:" diff --git a/src/config/whitelist.py b/src/config/whitelist.py new file mode 100644 index 0000000..f7afc2c --- /dev/null +++ b/src/config/whitelist.py @@ -0,0 +1,11 @@ +from decouple import config +import re + + +def checkWhiteList(id): + # Checks if id exists in the whitelist. Returnes 1 if exists and 0 if not + return id in chatIDs + + +chatIDsstring = config('WHITELIST', default='') +chatIDs = [int(x) for x in re.split(r',\s*', chatIDsstring)] diff --git a/src/telegram/controller.py b/src/telegram/controller.py new file mode 100644 index 0000000..8897208 --- /dev/null +++ b/src/telegram/controller.py @@ -0,0 +1,90 @@ +import asyncio + +from aiogram import Bot, Dispatcher +from aiogram.filters import Command +from aiogram.types import Message +from aiogram.client.default import DefaultBotProperties +from aiogram.enums import ParseMode +from aiogram.types import BotCommand, BotCommandScopeDefault + +from aiogram.fsm.context import FSMContext +from aiogram import Router, F +from aiogram.fsm.state import State, StatesGroup +from aiogram.fsm.storage.memory import MemoryStorage + +from loguru import logger + +from config import credentials, whitelist, options, strings + + +async def setCommands(): + commands = [BotCommand(command='start', description='Старт'), + BotCommand(command='help', description='Инструкция'), + BotCommand(command='info', description='Информация за день'), + ] + await bot.set_my_commands(commands, BotCommandScopeDefault()) + + +class startForm(StatesGroup): + pair = State() + params = State() + +class stopForm(StatesGroup): + pair = State() + + +dp = Dispatcher(storage=MemoryStorage()) +bot = Bot( + token=credentials.bot_token, + default=DefaultBotProperties(parse_mode=ParseMode.HTML), +) + +strategyRouter = Router() +stopRouter = Router() + + +@dp.message(Command("start")) +async def commandStart(message: Message) -> None: + await message.answer(strings.startCommand) + +@dp.message(Command("help"), F.chat.id.in_(whitelist.chatIDs)) +async def commandHelp(message: Message) -> None: + await message.answer(strings.helpCommand) + + +@dp.message(Command("info"), F.chat.id.in_(whitelist.chatIDs)) +async def commandInfo(message: Message) -> None: + msgText = strings.helpCommand + await message.answer(msgText) + + +@dp.message() +async def messageAny(message: Message) -> None: + await message.answer("you are a cat") + + +async def startBot(): + await setCommands() + try: + for i in whitelist.chatIDs: + await bot.send_message(chat_id=i, text=strings.startBot) + except Exception as e: + logger.error(f"Failed to start bot: {e}") + return + logger.success("Started bot!") + +async def stopBot(): + try: + for i in whitelist.chatIDs: + await bot.send_message(chat_id=i, text=strings.stopBot) + except Exception as e: + logger.error(f"Failed to stop bot: {e}") + return + logger.success("Stopped bot!") + +async def startup() -> None: + dp.include_router(strategyRouter) + dp.include_router(stopRouter) + dp.startup.register(startBot) + dp.shutdown.register(stopBot) + await dp.start_polling(bot) diff --git a/todo.md b/todo.md new file mode 100644 index 0000000..e85ff67 --- /dev/null +++ b/todo.md @@ -0,0 +1,18 @@ +Версия 0.x.x +### ToFix + - [ ] Мяу + +### Новые функции + - [ ] Реализация взаимодействия с ботом через телеграмм + - - [ ] Реализация команд + - - - [x] Start + - - - [x] Help + - - - [ ] Info + - - [ ] Обработка других сообщений + - [ ] Реализация взаимодействия бота с WebDAV + - [ ] Конфигурация Obsidian + - [ ] Реализация развёртывания программы + - - [ ] Написать хорошую README.md + - - [ ] Написать compose.yml + - - [ ] Добавить requirements.txt + - - [ ] Добавить работу с gitea-runner