Код на салфетке
2.22K subscribers
746 photos
14 videos
2 files
788 links
Канал для тех, кому интересно программирование на Python и не только.

Сайт: https://pressanybutton.ru/
Чат: https://t.iss.one/+Li2vbxfWo0Q4ZDk6
Заметки автора: @writeanynotes

Реклама и взаимопиар: @Murzyev1995
Сотрудничество и др.: @proDreams
Download Telegram
Далее необходимо включить подсистему Windows для Linux.
Запустите PowerShell от имени администратора. сделать это можно в меню "Пуск" > PowerShell > щелкните правой кнопкой мыши > Запуск от имени администратора.
И выполните следующую команду:
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart

А затем обновить включенный WSL до WSL2 следующей командой:
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
После этого перезапустите компьютер для завершения установки WLS2.

После перезагрузки, необходимо скачать и установить пакет обновления для WSL2.
Скачать пакет можно по ссылке: https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi

По завершении установки, снова запустите PowerShell и выполните следующую команду, для выбора WLS2 в качестве версии по умолчанию:
wsl --set-default-version 2

На этом подготовка завершена.

Отмечу от себя один момент. Не пренебрегайте установкой обновлений Windows. Именно там будут приходить обновления для WSL2. Да и в целом, обновления системы важная часть стабильной работы.

Файлы к посту, можно получить в боте по коду: 649348
Пост на сайте.
Поддержать канал.

#docker #windows #wsl #wsl2 #подготовка
👍2
Docker 2.1 Установка Docker Desktop на Windows

Подготовка позади, приступаем к установке Docker Desktop на Windows.

Скачиваем установщик по ссылке: https://desktop.docker.com/win/main/amd64/Docker%20Desktop%20Installer.exe
Откроется одно из самых минималистичных окон установки.
Там будет два пункта:
- Use WSL 2 instead of Hyper-V - обязательный параметр, позволит запускать контейнеры через WSL, а не через создание виртуальной машины.
- Add shortcut to desktop - добавлять ярлык на рабочий стол или нет, выбирайте по желанию.
Отметив первую галочку, нажимаем "Ok".
Начнётся процесс установки. Ждём.

По завершении установки нажимаем на большую синюю кнопку с надписью "Close".
Установка завершена.
👍3
Запустим Docker Desktop.
При первом запуске он попросит нас прочитать условия использования. Соглашаемся.
Далее будет опросник, можете поучавствовать, но я выбрал Skip.
Окно Docker Desktop можно закрыть. Убедитесь, что после закрытия окна, Docker остался в системном трее.

Пусть мы и установили Docker Desktop, работать мы будем в терминале, а именно в PowerShell.
Давайте убедимся, в корректности установки.
Запустим PowerShell и выполним команду:
docker --version
В ответ должны получить строку с текущей версией Docker. У меня это:
Docker version 24.0.2, build cb74dfc

Теперь проверим работу контейнеров на стандартном контейнере Hello-world. В терминале выполним команду:
docker run hello-world
Начнётся процесс скачивания и запуска образа. Затем в выводе должно появиться много текста, начинающегося с "Hello from Docker!".

Файлы к посту, можно получить в боте по коду: 743896
Пост на сайте.
Поддержать канал.

#docker #windows #установка #docker_desctop
Docker 2.2 Установка Docker на Linux

Если с Windows приходится повозится для установки Docker, то с линуксом всё просто до безобразия.

Я использую Debian 12 и всё, что напишу ниже будет относиться к нему. Команды для вашего дистрибутива, можно найти в официальной документации Docker по ссылке: https://docs.docker.com/engine/install/
👍3
Все действия выполняются в терминале. Откроем его.
Для начала удалим пакеты во избежание возможных конфликтов, выполнив следующую команду:
for pkg in docker.io docker-doc docker-compose podman-docker containerd runc; do sudo apt-get remove $pkg; done

Далее обновляем список доступных пакетов и устанавливаем поддержку HTTPS-репозиториев:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg

Устанавливаем ключи сертификатов:
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

Добавляем репозиторий:
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

Снова обновляем список доступных пакетов и устанавливаем Docker:
sudo apt-get update

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Теперь проверим работу контейнеров на стандартном контейнере Hello-world. В терминале выполним команду:
sudo docker run hello-world
Начнётся процесс скачивания и запуска образа. Затем в выводе должно появиться много текста, начинающегося с "Hello from Docker!".

В следующем посте, расскажу, как запустить контейнер с PostgreSQL.

Файлы к посту, можно получить в боте по коду: 695131
Пост на сайте.
Поддержать канал.

#docker #установка #lunux #debian
👍3
Docker 3. Контейнер с PostgreSQL

После всех подготовок и установок, наконец-то переходим к полезной практике.

Сегодня мы запустим Docker-контейнер с PostgreSQL.
Для этого нам нужна всего одна команда, но перед этим, мы создадим папку, в которой будут храниться файлы базы данных.
Поскольку, данные в контейнере сбрасываются до начального состояния образа, при перезапуске контейнера, нам нужна локальная папка для хранения файлов базы. Создать папку можно в любом месте, главное, что бы в пути не было кириллических символов. У меня это D:\psql.
👍1
Команда запуска:
docker run --name postgres-db -p 5432:5432 -e POSTGRES_USER=username -e POSTGRES_PASSWORD=password -e POSTGRES_DB=testdb -e PGDATA=/var/lib/postgresql/data/pgdata -v D:\psql:/var/lib/postgresql/data -d postgres:15.2
Разберём по порядку:
- docker run - команда Docker для запуска контейнера.
- --name - параметр определяющий имя контейнера для более удобного взаимодейсвтия с ним, в нашем случае это postgres-db.
- -p - параметр publish, определяет какой внутренний порт будет транслироваться из контейнера. Синтаксис <порт_вне_контейнера>:<порт_в_контейнере>. В нашем случае это стандартный порт PostgreSQL - 5432.
Внимание! Если у вас установлен PostgreSQL в системе вне Docker, значит порт 5432 занят. Изменяем <порт_вне_контейнера> на другой, например, 5433.

- -e - параметр передающий в контейнер переменные окружения. В нашем случае это:
- POSTGRES_USER - определяет имя пользователя БД.
- POSTGRES_PASSWORD - определяет пароль БД.
- POSTGRES_DB - определяет название БД.
- PGDATA - определяет место, где БД будет хранить данные.
- -v - параметр volume, необходим для подключения внешней(вне контейнера) директории, по внутреннему(в контейнере) пути. В моём случае это - D:\psql:/var/lib/postgresql/data, где D:\psql директория на моём компьютере, а /var/lib/postgresql/data место хранения данных в контейнере.
- -d - параметр сообщающий докеру, что мы хотим запустить контейнер в режиме демона, т.е. в фоновом режиме.
- В самом конце команды определяем используемый базовый образ и его версию. Без указания версии, будет использоваться последняя доступная версия. В нашем случае, мы будем использовать официальный Docker-образ postgres версии 15.2

Давайте выполним эту большую команду в терминале. Для запуска на Windows, убедитесь, что у вас запущен Docker Desktop
Начнётся скачивание базового образа из Docker Hub. После скачивания и запуска, терминал вернётся в режим ввода пользователя. Если не было никаких ошибок, значит контейнер запущен успешно. Убедиться в этом можно выполнив команду:
docker ps -a
Мы должны увидеть два контейнера. Hello-world, который мы запускали в прошлом посте и наш свеже-созданный postgres-db. В колонке STATUS в строке с БД, должно быть написано Up X minutes. Контейнер запущен и функционирует корректно.

Для остановки контейнера, нужно выполнить команду:
docker stop postgres-db
А для запуска остановленного контейнера:
docker start postgres-db

В следующем посте, расскажу про способы подключения к БД.

Файлы к посту, можно получить в боте по коду: 921886
Пост на сайте.
Поддержать канал.

#docker #postgresql #postgres #sql #установка #контейнер
🔥3👍1
Docker 4. Взаимодействие с контейнером PostgreSQL

Контейнер запустили, теперь давайте научимся с ним взаимодействовать.

Самый прямой способ взаимодействия, это зайти в контейнер и подключиться к CLI(Command Line Interface) PostgreSQL. Проще говоря, подключиться к БД в терминале.
Для этого необходимо в терминале выполнить следующую команду:
docker exec -it  <container-name> psql -U <dataBaseUserName> <dataBaseName>

Для варианта запуска, показанного в прошлом посте, строка будет выглядеть так:
docker exec -it  postgres-db psql -U username testdb
Подробнее про каждый пункт:
- docker exec - комманда позволяющая зайти в контейнер и выполнить указанную далее команду.
- -it - параметр, сообщающий докеру, что мы хотим подключиться в интерактивном режиме. Бывают случаи, когда терминал занят другим приложением, например выводом запущенного бота и чтобы выйти из контейнера не завершая работу запущенного приложения, необходимо нажать сочетание клавиш CTRL+Q+CTRL+P
- <container-name> - имя или идентификатор контейнера, к которому хотим подключиться
- psql - команда для выполнения в контейнере. В нашем случае это подключение к PostgreSQL в консоли.
- -U <dataBaseUserName> <dataBaseName> - параметры предыдущей команды. Тут мы передаём флаг -U, указывающий, что далее будет введено имя пользователя для авторизации и имя базы данных к которой необходимо подключиться.

В итоге команда должна выглядеть следующим образом:
docker exec -it postgres-db psql -U username testdb
Так, мы попадём в консольный интерфейс PostgreSQL. Можно работать с БД.
Для выхода достаточно ввести команду exit.

Другой способ подключиться к БД, это использовать менеджеры баз данных.
Таких программ много, например PgAdmin, DBeaver и другие.
Установив любой менеджер поддерживающий PostgreSQL, для подключения к БД необходимо указать следующие данные:
- host: localhost
- port: 5432
- username: username
- password: password
- database: testdb

Точно так же, можно использовать запущенную БД в наших проектах, например в Django:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': testdb,
'USER': username,
'PASSWORD': password,
'HOST': 'localhost',
'PORT': '5432',
}
}

На этом всё. Если возникнут вопросы по данной теме, не стесняйтесь задавать их в комментариях, обязательно постараюсь ответить.

Файлы к посту, можно получить в боте по коду: 684611
Пост на сайте.
Поддержать канал.

#docker #postgresql #postgres #sql #контейнер
👍2
Django 5. Инициализация приложения блога

Я не просто так назвал данный пост "Инициализация приложения блога". В Django, проектом считается сам установленный и инициализированный Django. Этим мы занимались во втором посте. А вот страницы сайта или отдельные модули называются приложениями. Именно созданием приложения мы займемся сегодня.

Для создания приложения необходимо в терминале выполнить команду: python manage.py startapp blog. Убедитесь, что в терминале вы находитесь в той же директории, что и файл manage.py. В дальнейшем я не буду заострять на этом внимание.
В папке с проектом появилась директория blog с набором пустых файлов приложения.
🔥2
Пройдёмся по основным файлам приложения:
- Файл admin.py - в данном файле будем указывать всё, что непосредственно связано с панелью администратора. В основном, это регистрация моделей.
- Папка migrations - в ней будут собираться файлы с описаниями миграций базы данных, относящихся именно к приложению.
- Файл models.py - в данном файле будем описывать модели и менеджеров базы данных.
- Файл views.py - в данном файле описываются представления соответствующие страницам на сайте.
- В дальнейшем будут созданы и другие файлы разной функциональной направленности.

Приложение создано, но ещё не активировано. Для активации необходимо вернуться в файл settings.py и в параметр INSTALLED_APPS добавить строку с указанием конфигурации приложения.
INSTALLED_APPS = [
# Содержимое списка
# ...
'blog.apps.BlogConfig',
]
Как мы получили данную строку?
Первый параметр blog - название приложения, указанное при его создании.
Второй параметр apps - указание на файл apps.py в директории приложения.
Третий параметр BlogConfig - указание на класс BlogConfig в упомянутом ранее файле.

Далее принято делать модели базы данных, но я несколько отойду от принятого. В следующем посте сделаем заготовку для главной страницы, она же, по началу будет выступать в роли заглушки сайта.

Файлы к посту, можно получить в боте по коду: 966714
Пост на сайте.
Поддержать канал.

#django #python #приложение
👍3
Django 6. Базовый шаблон

Сегодня мы создадим базовый шаблон. В базовый шаблон прописывается то, что должно быть на всех страницах сайта. Подключаются все необходимые файлы стилей и скриптов, прописываются мета-теги.

Для создания шаблона, мы будем использовать CSS-фреймворк Bootstrap5.
Давайте его скачаем. Нам нужен CSS-файл и JS-файл.
CSS: https://bootswatch.com/5/lumen/bootstrap.css
JS: https://raw.githubusercontent.com/twbs/bootstrap/v5.3.0/dist/js/bootstrap.bundle.js
Если у вас в браузере, файл не скачивается, а открылся для просмотра, просто нажмите сочетание клавиш CTRL+S
👍3
В директории приложения blog создаём папку static, а в ней ещё две папки css и js.
Помещаем скачанные файлы в соответствующие папки в директории static.

В директории приложения blog, создаём папку templates, а в ней папку с названием приложения, то есть, тоже blog.
Должна получиться такая иерархия <проект>/blog/templates/blog. Если вы использовали иное название для приложения, то замените `blog`, на соответствующее.

Директория blog в папке templates, это место, где будут храниться шаблоны связанные с приложением blog. Создадим там файл base.html со следующим содержимым:
{% load static %}
<!DOCTYPE html>
<html lang="ru" data-bs-theme="dark" class="h-100">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Press Any Button</title>
<link href="{% static "css/bootstrap.css" %}" rel="stylesheet">
</head>
<body class="d-flex flex-column h-100">
<section class="al mt-3">
<div class="container justify-content-center">
<div class="alert alert-dismissible alert-warning">
<h4 class="alert-heading">Приветствую вас!</h4>
<h5 class="mb-0">Сайт находится в процессе разработки.<br>
Следить за процессом разработки и повторять действия, можно в <a href="https://t.iss.one/press_any_button">Telegram-канале
"Код на салфетке"</a></h5>
</div>
</div>
</section>
<script src="{% static "js/bootstrap.bundle.js" %}"></script>
</body>
</html>
Как видим, используется обычная HTML-разметка, с добавление специальных Django-тегов.
Тэг {% load static %} сообщает Django, что в шаблоне используются статические файлы из папки static.
В месте, где мы подключаем CSS и JS файлы, используется тег {% static "путь_до_файла_в_папке_static" %}

Это будет наш базовый шаблон. В последствии мы его модернизируем и от него будут наследоваться шаблоны других страниц. В следующем посте, пропишем представление для него и добавим маршрутизацию URL-адресов и протестируем.

Файлы к посту, можно получить в боте по коду: 153069
Пост на сайте.
Поддержать канал.

#django #python #шаблон #базовый_шаблон #html #css #bootstrap
👍5
Django 7. Первое представление

В интернете всё построено на запросах. Открывая любую страницу, мы делаем запрос к серверу "хочу попасть на такую-то страницу", а сервер уже обрабатывает его и возвращает ответ на запрос с содержимым страницы.
Для формирования ответа на запрос с доступом к той или иной странице в Django отвечают, так называемые "представления", они же "views".
Давайте создадим наше первое простое представление, для возврата содержимого базового шаблона посетителю сайта.

Переходим в файл views.py расположенный в директории приложения.
Под имеющимся в файле импортом добавим функцию со следующим кодом:
def index(request):
return render(request,
'blog/base.html')

Мы создали представление index, получающего запрос от пользователя.
Поскольку у нас пока заглушка и данные передавать нам никакие не нужно, сразу переходим к возврату ответа пользователю. За это отвечает функция render, в которую мы передаём запрос, а так же путь до файла шаблона.
👍3
Теперь получив запрос на отображение главной страницы сайта, Django вернёт её содержимое. Только вот Django, пока ничего не знает, о том, где у нас главная страница и как строить маршрутизацию по URL-адресам.

В директории приложения создадим файл urls.py.
Файл urls.py в Django имеет важное значение. Он определяет, как URL-запросы будут соотноситься с определенными представлениями и функциями. В этом файле определяются URL-шаблоны, которые связывают входящие URL-запросы с соответствующими представлениями. Представления обрабатывают запросы и возвращают соответствующие HTTP-ответы.

Добавим следующий код:
from django.urls import path

from blog import views

app_name = 'blog'
urlpatterns = [
path('', views.index, name='index'),
]
В переменной app_name указываем имя приложения, для корректного сопоставления URL-адресов.
В переменную urlpatterns присваиваем список. Внутри списка вфзфывем функцию path, формирующую маршрут и URL-адрес.
В неё передаём:
- Первым параметром URL-паттерн. Пустые кавычки означают, что паттерн будет применён к основному адресу сайта, например pressanybutton.ru, а если пропишем "blog", тогда он будет срабатывать, когда будем переходить по адресу pressanybutton.ru/blog
- Вторым параметром указываем, какое представление необходимо вызвать при запросе данного адреса.
- В третьем параметре указываем имя для пути.
Также обратите внимание на вторую строку импорта, замените blog на имя вашего приложения

Теперь, надо сообщить Django о том, что у нас есть приложение со своим набором URL-паттернов. Для этого, перейдём в директорию проекта и откроем файл urls.py.
Там уже будет переменная urlpatterns с прописанным паттерном панели администратора.
Добавим в имеющийся список новую строку с адресами приложения:
from django.urls import path, include

urlpatterns = [
# ...
path('', include('blog.urls', namespace='blog')),
]
В данной строке, мы сообщаем Django, что по пути сайта мы будем использовать URL-паттерны из приложения.

И сразу добавим сюда определение путей для медиа и статических файлов. В этом же файле, только ниже добавьте следующие строки:
from django.conf.urls.static import static  
from django.conf import settings

urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Запустим Django командой python manage.py runserver и перейдём на страницу.
Должна отобразиться страница с заглушкой. Такая-же как https://pressanybutton.ru

В следующем посте, начнём делать структуру Telegram-бота

Файлы к посту, можно получить в боте по коду: 772660
Пост на сайте.
Поддержать канал.

#django #python #представление #views #render #url_паттерны
👍3
AIOgram3 5.1. Создание структуры

Большинство проектов не ограничиваются одним лишь файлом main.py, напротив, часто проекты состоят из множества файлов с кодом конкретной логики. Для этого в Python предусмотрена "пакетная" система. Пакет является директорией, которая содержит в себе модули и подпакеты. Он позволяет логически объединять связанный функционал и предоставляет простой способ управления зависимостями и кодом в рамках проекта.

Создадим основной пакет botlogic со всей будущей логикой.
Если, вы работаете в PyCharm или другой Python-направленной IDE, то достаточно в контекстном меню директории выбрать "New - Python Package".
Но создать пакет можно и вручную.
Для этого необходимо создать директорию с необходимым именем пакета. Внутри директории создать пустой файл __init__.py. Данный файл сообщит интерпретатору, что директория является пакетом.
При каждом создании пакета, необходимо создавать внутри пустой файл __init__.py
👍3
В этом пакете создадим файл settings.py.
В этом файле будут располагаться, при необходимости, настройки бота. Пока, что мы перенесём в него токен бота и добавим ID администратора.

Тут, для удобства применим ООП.
Те, кто уже успели испугаться, расслабьтесь, в создании бота ООП либо крайне мало, либо нет вовсе. Тут я применяю его банально для удобства.

Создадим дата-класс Secrets и в нём два поля token и admin_id:
from dataclasses import dataclass


@dataclass
class Secrets:
token: str = 'ваш_токен'
admin_id: int = 12345
Разберём, что тут происходит.
Мы создали класс Secrets и определили два поля:
- Строковое token в котором указываем полученный от BotFather токен бота.
- Целочисленное admin_id в котором необходимо указать ваш Telegram-ID, но это будет несколькими постами далее, пока просто заполните любым числом.

Далее должно было быть несколько методов, таких как __init__ и геттеры полей, но нам тут всё это не нужно. Для избегания большого количества кода, мы используем декоратор @dataclass.
Декоратор @dataclass - позволяет автоматически сгенерировать методы класса для работы с данными.
Когда применяется декоратор @dataclass к классу, он автоматически добавляет реализацию необходимых методов, таких как:
1. __init__: Создает конструктор класса, принимающий значения для каждого атрибута.
2. __repr__: Создает строковое представление объекта, которое используется при вызове repr().
И ряда других.
Кроме того, декоратор @dataclass позволяет использовать аннотации типов для объявления типов полей класса, что упрощает чтение кода.

Продолжение в следующем посте.

Файлы к посту, можно получить в боте по коду: 488659
Пост на сайте.
Поддержать канал.

#aiogram #python #python_package #структура #dataclass
👍4
AIOgram3 5.2. Создание структуры, продолжение

Не уходя из файла settings.py
Перенесём сюда инициализацию бота, а именно строку и сразу заменим содержимое на получение данных из класса Secrets:
from aiogram import Bot

bot = Bot(token=Secrets.token)

Таким образом, мы сможем обращаться к экземпляру бота не только из главного файла.

С файлом settings.py мы пока закончили.
Перейдём в файл main.py и изменим импорты.
Было:
from aiogram import Bot, Dispatcher

Поменяем на:
from aiogram import Dispatcher  

from botlogic.settings import bot
👍4
Как вы помните, при запуске бота, не понятно, запустился он или нет, поскольку в терминале не было никаких данных. Давайте это исправим, добавив базовый логгер.
Перед переменной dp добавляем пустую строку и вставляем туда код логгера, а в начло файла добавляем строку импорта:
import logging

logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - [%(levelname)s] - %(name)s - (%(filename)s).%(funcName)s(%(lineno)d) - %(message)s"
)
При запуске бота, будет инициализироваться метод basicConfig из втроенной библиотеки logging. В него мы передаём два параметра:
- level - определяющий уровень выводимой информации. Основные уровни информирования: DEBUG, INFO, WARNING, ERROR.
- format - определяющий формат выводимой информации.
С уровнем логирования всё понятно, он будет выводить данные уровня INFO, то о переменных в формате стоит рассказать подробнее.
Строка лога состоит из 7ми переменных:
- %(asctime)s — заменяется на текущее время в формате "год-месяц-день час:минута:секунда";
- %(levelname)s — заменяется на уровень важности лога, в нашем случае INFO;
- %(name)s — заменяется на имя логгера, который записывает сообщение;
- %(filename)s — заменяется на имя файла, в котором была вызвана функция логирования;
- %(funcName)s — заменяется на имя функции, в которой была вызвана функция логирования;
- %(lineno)d — заменяется на номер строки, в которой была вызвана функция логирования;
- %(message)s — заменяется на текст сообщения, переданного для записи в лог.

В следующем посте, продолжим формировать структуру и сделаем оповещение администратора о запуске или остановке бота.

Файлы к посту, можно получить в боте по коду: 488659
Пост на сайте.
Поддержать канал.

#aiogram #python #python_package #структура #logging
👍5
AIOgram3 6. Информирование администратора

Теперь давайте добавим функционал информирование админа бота о его запуске или остановке.

Перейдём в файл settings.py и в поле admin_id в классе Secrets пропишем ваш Telegram-ID. Получить его можно у бота https://t.iss.one/getmyid_bot

В пакете botlogic создадим новый пакет handlers.
Напоминаю, что пакет можно создать средствами IDE, выбрав создать новый Python Package или создать вручную, создав директорию и в ней пустой файл __init__.py.
В нём у нас будут находится обработчики сообщений пользователей, команд или различных событий.

В пакете handlers создадим файл events.py. В данном файле, будут находиться обработчики событий. Сейчас мы напишем два обработчика реагирующих на событие запуска и остановки бота.
from botlogic.settings import bot, Secrets


async def start_bot():
await bot.send_message(Secrets.admin_id, 'Бот запущен')


async def stop_bot():
await bot.send_message(Secrets.admin_id, 'Бот остановлен')
👍3