From 60e5a7e163154faac48e5c90503c5226b8089e85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=97=D0=B0=D0=B6=D0=B8=D0=B3=D0=B8=D0=BD=20=D0=91=D0=BE?= =?UTF-8?q?=D0=B3=D0=B4=D0=B0=D0=BD=20=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B5?= =?UTF-8?q?=D0=B5=D0=B2=D0=B8=D1=87?= Date: Wed, 14 Dec 2022 00:48:24 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BA=D0=BE=D0=BC=D0=B0=D0=BD=D0=B4=D0=B0=20?= =?UTF-8?q?=D1=80=D0=B5=D0=B3=D0=B8=D1=81=D1=82=D1=80=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D0=B8=20=D0=BA=D1=80=D0=B0=D1=81=D0=B8=D0=B2=D0=BE=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D0=B5=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/readme.md | 2 +- docs/settings.md | 24 +++ docs/start.md | 2 +- env | 14 +- src/bot-telegram_zaboal-employment.ts | 39 ----- src/bot/bot.ts | 137 ++++++++++++++++++ src/bot/settings/commands.json | 10 ++ .../default_administrator_rights.json | 14 ++ src/dockerfile | 21 ++- src/package.json | 9 +- src/tsconfig.json | 1 - start.sh | 17 ++- 12 files changed, 226 insertions(+), 64 deletions(-) create mode 100644 docs/settings.md delete mode 100644 src/bot-telegram_zaboal-employment.ts create mode 100644 src/bot/bot.ts create mode 100644 src/bot/settings/commands.json create mode 100644 src/bot/settings/default_administrator_rights.json diff --git a/docs/readme.md b/docs/readme.md index 41d65fa..f792488 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -1,5 +1,5 @@ # Бот в Telegram для управления Личным кабинетом в ИТ-студии Зажигина -Бот описан в [`src/bot.ts`](../src/index.ts) на [TypeScript](https://www.typescriptlang.org/docs "Документация TypeScript") с помощью фреймворка [Grammy](https://grammy.dev/guide "Документация Grammy") над [Telegram Bot API](https://core.telegram.org/bots/api "Документация Telegram Bot API"). Предназначен для запуска в контейнере [Docker](https://docs.docker.com/reference "Документация Docker") через [NodeJS](https://nodejs.org/api/ "Документация NodeJS"), файл сборки можно видеть под названием [`src/dockerfile`](../src/dockerfile). Главный метод запуска проекта — через файл [Bash](https://www.gnu.org/software/bash/manual/bash.html "Документация Bash") скрипта [`start.sh`](../start.sh) от имени администратора. +Бот описан в [`src/bot/bot.ts`](../src/index.ts) на [TypeScript](https://www.typescriptlang.org/docs "Документация TypeScript") с помощью фреймворка [Grammy](https://grammy.dev/guide "Документация Grammy") над [Telegram Bot API](https://core.telegram.org/bots/api "Документация Telegram Bot API"). Предназначен для запуска в контейнере [Docker](https://docs.docker.com/reference "Документация Docker") через [NodeJS](https://nodejs.org/api/ "Документация NodeJS"), файл сборки можно видеть под названием [`src/dockerfile`](../src/dockerfile). Главный метод запуска проекта — через файл [Bash](https://www.gnu.org/software/bash/manual/bash.html "Документация Bash") скрипта [`start.sh`](../start.sh) от имени администратора. Официально запускается от имени [@emp_zaboal_bot](https://emp_zaboal_bot.t.me) и администрируется [Богданом](https://zaboal.t.me). Руководство по запуску описано в [`docs/start.md`](start.md). \ No newline at end of file diff --git a/docs/settings.md b/docs/settings.md new file mode 100644 index 0000000..809e2a6 --- /dev/null +++ b/docs/settings.md @@ -0,0 +1,24 @@ +## Настройки бота + +Настройки бота расположены в директории [`src/bot/settings`](../src/bot/bot.ts) для Telegram Bot API и в файле переменных окружения [`env`](../env) для команды `source`. Файл переменных окружения имеет жизненно необходимые значения, их обязательно требуется указать. + + +### [`env`](../env) — переменные окружения + +Для запуска бота требуется три константы в формате Bash: + +* `BOT_TOKEN` — токен бота, получаемый от [BotFather](https://t.me/BotFather); +* `BOT_DB_PATH` — путь к базе данных SQLite бота на хосте, с данными об идентификаторах пользователя Телеграм людей зарегистрированных в организации (схема базы данных описана [здесь](/home/zaboal/work/templates/database-schemas/sql/organizational_structure/organizational_structure.sql)); +* `ORG_BD_PATH` — путь к базе данных SQLite орагнизации, с данными об подразделениях, рабочих и т.д. (схема базы данных описана [здесь](/home/zaboal/work/templates/database-schemas/sql/organizational_structure/organizational_structure.sql)). + +Данные будут переданы в контейнер Docker в процессе Bash скрипта запуска проекта [`start.sh`](../start.sh). По путям к базам данных на хосте в контейнер будут примонтированы соответствующие файлы SQLite под программными названиями. + + +### [`src/bot/settings`](../src/bot/bot.ts) — переменные для Telegram Bot API + +При запуске бот передаст Telegram Bot API файлы конфигурации в формате json из директории [`settings`](../src/bot/settings/): + +* [`commands.json`](../src/bot/settings/commands.json) — список команд и их описаний бота; +* [`default_administrator_rights.json`](../src/bot/settings/default_administrator_rights.json) — предлагаемый набор прав администратора бота при добавлении в группу. + +Эти настройки формируются согласно изменениям кода самого бота. Изменять их рекомендуются только разработчикам, внёсшим изменения. \ No newline at end of file diff --git a/docs/start.md b/docs/start.md index efde9bc..da13730 100644 --- a/docs/start.md +++ b/docs/start.md @@ -1,6 +1,6 @@ ## Запуск бота -Для запуска требуются 2 переменных окружения: `BOT_TOKEN`, токен бота Telegram получаемый от [BotFather](https://t.me/BotFather), и `DB_PATH`, путь к базе данных SQLite на хосте. Указывать их нужно в файле [env](../env) сковывая в двойные кавычки. С помощью команды `source` в [`start.sh`](../start.sh) на основе этих переменных в создаваемый контейнер от образа [`dockerfile`](../src/dockerfile) будет примонтирован файл базы данных и передан токен. +Перед запуском требуется заполнить переменные окружения в [`env`](../env), руководство — [`settings.md`](./settings.md#env--переменные-окружения). С помощью команды `source` в [`start.sh`](../start.sh) на основе этих переменных в создаваемый контейнер от образа [`dockerfile`](../src/dockerfile) будет примонтированы файлы баз данных и передан токен. Если все переменные указаны верно, можно запускать файл [`start.sh`](../start.sh) от имени администратора: ```bash diff --git a/env b/env index e0b3d5f..bfad64d 100644 --- a/env +++ b/env @@ -1,5 +1,11 @@ -# Токен Telegram Bot API получаемый от BotFather (https://t.me/BotFather) -BOT_TOKEN="5715517585:AAFgAdmzsDokDcCEfy6hO_cI7nrsVeMTx8M" +# Файл переменных окружения проекта +# Настройка проекта подробно описана в docs/settings.md. -# Путь к базе данных управляемой SQLite на хосте -DB_PATH="/home/zaboal/work/organizations/zazhigin-s_it-studio/databases/local_organizational-structure.db" \ No newline at end of file +# Токен Telegram Bot API получаемый от BotFather +BOT_TOKEN="" + +# Путь к базе данных SQLite бота на хосте +BOT_DB_PATH="" + +# Путь к базе данных SQLite организации на хосте +ORG_DB_PATH="" \ No newline at end of file diff --git a/src/bot-telegram_zaboal-employment.ts b/src/bot-telegram_zaboal-employment.ts deleted file mode 100644 index 3af831f..0000000 --- a/src/bot-telegram_zaboal-employment.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Bot } from "grammy"; -const bot = new Bot(`${process.env.BOT_TOKEN}`); - -import { Database } from "sqlite3"; -const database = new Database(`${process.env.DB_PATH}`) - - - -bot.command("start", (ctx) => { - ctx.reply( - "Вы можете ознакомиться с тем как использовать данного бота по команде `/help`", - { parse_mode: "MarkdownV2" } - ); -}); - -bot.command("help", (ctx) => { - ctx.reply( - "Список команд доступен в сплывающем меню от знака «/» в поле ввода сообщения\\. Но если Вы ещё не зарегистрированы в системе, сделайте это в первую очередь в формате SQL по команде: `/register \"[полное имя]\", \"[электропочта]\"`", - { parse_mode: "MarkdownV2" }, - ); -}); - -bot.command("register", (ctx) => { - // В ctx.match берутся аргументы команды /register и используются как данные вводимые в таблицу - database.run(`INSERT INTO people(per_name, per_email) VALUES (${ctx.match})`, (error) => { - if (error == null) { - ctx.reply(`Регистрация прошла успешно`) - } else { - // Отправить «сухую» ошибку пользователю - ctx.reply( - `Регистрация не удалась, SQLite сообщает об ошибке: «\`${error}\`»\\. Вы можете запросить трактовку и рекомендации у @zaboal`, - { parse_mode: "MarkdownV2" } - ); - } - }); -}); - - -bot.start(); \ No newline at end of file diff --git a/src/bot/bot.ts b/src/bot/bot.ts new file mode 100644 index 0000000..317c88c --- /dev/null +++ b/src/bot/bot.ts @@ -0,0 +1,137 @@ +import { Bot } from "grammy"; +const bot = new Bot(`${process.env.BOT_TOKEN}`); + +import { Database } from "sqlite3"; +const database = new Database(`${process.env.BOT_DB_PATH}`); + + + + +// Применение настроек из директории «settings» +import commands from "./settings/commands.json"; +bot.api.setMyCommands(commands, { + scope: { type: "all_private_chats" }, + language_code: "ru" +}); + +import rights from "./settings/default_administrator_rights.json"; +bot.api.setMyDefaultAdministratorRights({rights, + for_channels: false +}); + + +// Подключение базы данных организации +database.run(`ATTACH DATABASE "/usr/src/app/${process.env.ORG_DB_PATH}" AS org`); + + + +// Обработка команд бота +bot.command("start", ctx => { // Команда начала диалога, подсказывает первые шаги + ctx.reply( + "Вы можете ознакомиться с тем как использовать данного бота по команде `/help`", + { parse_mode: "MarkdownV2" } + ); +}); + +bot.command("help", ctx => { // Команда инструктирования + ctx.reply( + "Список команд доступен в сплывающем меню от знака «/» в поле ввода сообщения" + + "\\. Но если Вы ещё не зарегистрированы в системе, сделайте это в первую очередь в формате SQL по команде: " + + "`/register [полное имя], [электропочта]`", + { parse_mode: "MarkdownV2" }, + ); +}); + +bot.command("register", ctx => { // Команда регистрации в организации + // В ctx.match берутся аргументы команды /register и используются как данные вводимые в таблицу + const command_arguments = ctx.match.split(", ") + const name: string = command_arguments[0]; + const email: string = command_arguments[1]; + // Заносятся соответствующие данные в БД организации, полученный идентификатор запоминает бот + database.get(`SELECT user_per_rowid FROM users WHERE user_id = "${ctx.msg.chat.id}"`, (error, result) => { + if (result == undefined) { + if (ctx.match == "") { + ctx.reply( + "Данная команда требует аргументы, через запятую: `[полное имя]` и `[электро@поч.та]`", + { parse_mode: "MarkdownV2" } + ); + } else { + database.run(`INSERT INTO people(per_name, per_email) VALUES ("${name}", "${email}")`, (error) => { + if (error == null) { + ctx.reply(`Регистрация прошла успешно`); + database.get(`SELECT rowid FROM people where per_email = "${email}"`, (error, select) => { + if (error == null){ + database.run(`INSERT INTO users VALUES ("${select.rowid}", "${ctx.msg.chat.id}")`); + } else { + ctx.reply( + `Регистрация не удалась, SQLite сообщает об ошибке: «\`${error}\`»` + + "\\. [Богдан](tg://user?id=987595197) может Вам её разъяснить и помочь с решением", + { parse_mode: "MarkdownV2" } + ); + } + }); + } else { + ctx.reply( + `Регистрация не удалась, SQLite сообщает об ошибке: «\`${error}\`»` + + "\\. [Богдан](tg://user?id=987595197) может Вам её разъяснить и помочь с решением", + { parse_mode: "MarkdownV2" } + ); + } + }); + } + } else { + ctx.reply( + "Вы уже зарегистрированы", + { parse_mode: "MarkdownV2" } + ); + } + }); +}); + +bot.command("sqlite", ctx => { // Команда исследования баз данных (для разработчиков) + database.get(`${ctx.match}`, (err, row) => { + if (err == null) { + ctx.reply( + "`" + ((row == undefined) ? "Ничего не найдено" : JSON.stringify(row)) + "`", + { parse_mode: "MarkdownV2" } + ); + } else { + ctx.reply( + "`" + JSON.stringify(err) + "`", + { parse_mode: "MarkdownV2" } + ); + } + }); +}) + + +// Запуск бота +bot.start({ + limit: 1, + timeout: 1, + allowed_updates: ["message"], + drop_pending_updates: true, + onStart: bot => { + console.log( + `Бот запущен как «${bot.first_name}»` + + ` под именем пользователя @${bot.username}` + + ` с идентификатором ${bot.id}.`, + (bot.can_join_groups == true) ? "Он может присоединяться к группам," : "Он не может присоединяться к группам,", + (bot.can_read_all_group_messages == true) ? "читает сообщения в которых уже есть;" : "не читает сообщения в них;", + (bot.supports_inline_queries == true) ? "поддерживает инлайн-режим." : "не поддерживает инлайн-режим." + + "\n" + ); + } +}); + + + +process.on("exit", code => { + console.log("Запущен протокол выхода…"); + bot.stop(); +}); + +process.on("SIGINT", () => { + console.log("\n\nПолучен сигнал POSIX — «SIGINT»."); + process.exit(0); +}); \ No newline at end of file diff --git a/src/bot/settings/commands.json b/src/bot/settings/commands.json new file mode 100644 index 0000000..4ca96ae --- /dev/null +++ b/src/bot/settings/commands.json @@ -0,0 +1,10 @@ +[ + { + "command": "register", + "description": "регистрация в организации" + }, + { + "command": "employ", + "description": "собеседование по вакансии" + } +] \ No newline at end of file diff --git a/src/bot/settings/default_administrator_rights.json b/src/bot/settings/default_administrator_rights.json new file mode 100644 index 0000000..c529815 --- /dev/null +++ b/src/bot/settings/default_administrator_rights.json @@ -0,0 +1,14 @@ +{ + "is_anonymous": false, + "can_manage_chat": false, + "can_delete_messages": false, + "can_manage_video_chats": false, + "can_restrict_members": false, + "can_promote_members": false, + "can_change_info": false, + "can_invite_users": false, + "can_post_messages": false, + "can_edit_messages": false, + "can_pin_messages": false, + "can_manage_topics": false +} \ No newline at end of file diff --git a/src/dockerfile b/src/dockerfile index 6cc2c5d..feb9622 100644 --- a/src/dockerfile +++ b/src/dockerfile @@ -1,19 +1,26 @@ +# Файл сборки Docker контейнера проекта + +# Установка образа и рабочей директории FROM node:lts-buster-slim - - WORKDIR /usr/src/app + +# Установка зависимостей COPY package.json . RUN npm install -COPY bot-telegram_zaboal-employment.ts . +# Добавление оставшихся файлов проекта +COPY tsconfig.json . +ADD bot bot -# Требуемые переменные окружения -# Токен бота Telegram от бота @BotFather +# Объявление переменных окружения ARG BOT_TOKEN -# Путь к базе данных внутри контейнера, монтируется из файловой системы хоста -ENV DB_PATH="./dbase.db" + +# Имена подключаемых баз данных внутри контейнера +ENV BOT_DB_PATH="bot_db.sqlite" +ENV ORG_DB_PATH="org_db.sqlite" +# Запуск контейнера CMD npm run start \ No newline at end of file diff --git a/src/package.json b/src/package.json index 6471ec2..ff15b3d 100644 --- a/src/package.json +++ b/src/package.json @@ -1,10 +1,10 @@ { - "name": "bot-telegram_zaboal-employment", + "name": "bot-telegram_zaboal-account", "version": "alpha", - "description": "Бот в Telegram для трудоустройства в ИТ-студию Зажигина.", - "main": "bot-telegram_zaboal-employment.ts", + "description": "Бот в Telegram для управления личным кабинетом в Информационно-технологической стартап-студии имени Богдана Зажигина.", + "main": "bot/bot.ts", "scripts": { - "start": "ts-node bot-telegram_zaboal-employment.ts" + "start": "ts-node bot/bot.ts" }, "author": "Зажигин Богдан Алексеевич ", "dependencies": { @@ -13,7 +13,6 @@ }, "devDependencies": { "ts-node": "^10.9.1", - "ts-node-dev": "^2.0.0", "typescript": "^4.7.4" } } \ No newline at end of file diff --git a/src/tsconfig.json b/src/tsconfig.json index 7247516..31232ef 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -5,7 +5,6 @@ "ES2021" ], "module": "commonjs", - "rootDir": "./", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, diff --git a/start.sh b/start.sh index fec11e0..c1c246e 100644 --- a/start.sh +++ b/start.sh @@ -1,17 +1,22 @@ +# Скрипт запуска проекта +# Процедура запуска проекта подробно описана в docs/start.md. + # Получение необходимых переменных окружения и вывод их в консоль source ./env; -echo -e \ - "Полученные переменные окружения:\n" \ - "\t\033[1mтокен Telegram Bot API\033[0m — \033[4m$BOT_TOKEN\033[0m,\n" \ - "\t\033[1mпуть к базе данных SQLite на хосте\033[0m — \033[4m$DB_PATH\033[0m.\n\n"; +echo -e \ + "Полученные переменные окружения:\n" \ + "\tтокен Telegram Bot API — $BOT_TOKEN,\n" \ + "\tпуть к базе данных бота — $BOT_DB_PATH,\n" \ + "\tпуть к базе данных организации — $ORG_DB_PATH.\n\n"; # Сборка и запуск контейнера Docker docker build src \ --tag bot-telegram_zaboal-employment:latest; -docker run \ +docker run -it \ --env BOT_TOKEN=$BOT_TOKEN \ - --volume $DB_PATH:/usr/src/app/dbase.db \ + --volume $BOT_DB_PATH:/usr/src/app/bot_db.sqlite \ + --volume $ORG_DB_PATH:/usr/src/app/org_db.sqlite \ bot-telegram_zaboal-employment:latest; \ No newline at end of file