594 lines
16 KiB
JavaScript
594 lines
16 KiB
JavaScript
const DEF_DELAY = 1000;
|
||
function sleep(ms) {
|
||
return new Promise(resolve => setTimeout(resolve, ms || DEF_DELAY));
|
||
}
|
||
|
||
var config = require('./config');
|
||
|
||
var Bot = require('node-telegram-bot-api');
|
||
var bot = new Bot(process.env.TOKEN||config.token, { polling: true });
|
||
|
||
console.log('Бот был запущен');
|
||
|
||
const Courier = require('./curier_api');
|
||
var users = {};
|
||
|
||
bot.onText(/^/, function (msg) {
|
||
var id = msg.chat.id;
|
||
const args = msg.text.slice("/").trim().split(/ +/g);
|
||
const command = args.shift().toLowerCase();
|
||
var text = args.join(" ");
|
||
start_answering(id,command,text);
|
||
});
|
||
|
||
//Запуск нужной функции
|
||
async function launchFunctionByName(data){
|
||
switch(data.name){
|
||
case 'login':
|
||
var answer = await command_login(data);
|
||
return answer;
|
||
break;
|
||
case 'relogin':
|
||
var answer = await command_relogin(data);
|
||
return answer;
|
||
break;
|
||
case 'relogin_all':
|
||
var answer = await command_relogin_all(data);
|
||
return answer;
|
||
break;
|
||
case 'logout':
|
||
var answer = await command_logout(data);
|
||
return answer;
|
||
break;
|
||
case 'help':
|
||
var answer = await command_help(data);
|
||
return answer;
|
||
break;
|
||
case 'myslots':
|
||
var answer = await command_myslots(data);
|
||
return answer;
|
||
break;
|
||
case 'freeslots':
|
||
var answer = await command_freeslots(data);
|
||
return answer;
|
||
break;
|
||
case 'orders':
|
||
var answer = await command_orders(data);
|
||
return answer;
|
||
break;
|
||
case 'query':
|
||
var answer = await command_query(data);
|
||
return answer;
|
||
break;
|
||
case 'reload_bd':
|
||
var answer = await command_reload_bd(data);
|
||
return answer;
|
||
break;
|
||
case 'search_point':
|
||
var answer = await command_search_point(data);
|
||
return answer;
|
||
break;
|
||
case 'test':
|
||
var answer = await command_test(data);
|
||
return answer;
|
||
break;
|
||
case 'newfreeslots':
|
||
var answer = await command_newfreeslots(data);
|
||
return answer;
|
||
break;
|
||
default:
|
||
return data.answer;
|
||
break;
|
||
}
|
||
}
|
||
|
||
//Выполнить операцию с таблицей
|
||
async function command_query(data){
|
||
var answer = data.answer;
|
||
|
||
var client = await new Client({
|
||
connectionString: process.env.DATABASE_URL,
|
||
ssl: {
|
||
rejectUnauthorized: false
|
||
}
|
||
})
|
||
await client.connect()
|
||
.catch(e => {
|
||
console.error(e);
|
||
})
|
||
|
||
try {
|
||
var client_answer = await client.query(data.text);
|
||
//delete client_answer["builtins"];
|
||
delete client_answer["_types"];
|
||
delete client_answer["fields"];
|
||
delete client_answer["_parsers"];
|
||
delete client_answer["RowCtor"];
|
||
delete client_answer["rowAsArray"];
|
||
delete client_answer["oid"];
|
||
answer += JSON.stringify(client_answer).replace(/{/g,'{\n').replace(/}/g,'\n}').replace(/,/g,',\n')
|
||
await client.end();
|
||
}
|
||
catch(e){
|
||
console.error(e);
|
||
await client.end();
|
||
answer += 'Ошибка запроса'
|
||
};
|
||
return answer;
|
||
}
|
||
|
||
//Получить список всех доступных комманд
|
||
function command_help(data){
|
||
var answer = data.answer;
|
||
config.commands.forEach(function (values,keys) {
|
||
if(values.have_description)
|
||
if((values.need_admin==data.is_Admin)||(!values.need_admin))
|
||
if((values.need_auth==data.is_Auth)||(values.show_after_login&&data.is_Auth))
|
||
answer += `\n ${keys} - ${values.description}`;
|
||
});
|
||
if(data.is_Admin){
|
||
answer += `\n----------------------
|
||
<b>Команды администратора:</b>`;
|
||
config.admin_commands.forEach(function (values,keys) {
|
||
if(values.have_description)
|
||
if((values.need_auth==data.is_Auth)||(values.show_after_login&&data.is_Auth))
|
||
answer += `\n ${keys} - ${values.description}`;
|
||
});
|
||
}
|
||
return answer;
|
||
}
|
||
|
||
//Авторизоваться
|
||
async function command_login(data){
|
||
var answer = data.answer;
|
||
var dannie = data.text.split("-")
|
||
if(dannie.length == 2){
|
||
var new_user_data = {
|
||
id: data.id,
|
||
username: dannie[0].trim(),
|
||
password: dannie[1].trim()
|
||
}
|
||
var new_user = users[data.id];
|
||
if(!new_user) new_user = new Courier(new_user_data);
|
||
else new_user.updateUser(new_user_data);
|
||
|
||
if(await new_user.auth()&&await new_user.getInfo()){
|
||
answer = `<b>Вход выполнен успешно</b>
|
||
Авторизован: ${new_user.info.name}
|
||
`;
|
||
var zones = await new_user.getMyZones();
|
||
answer += `Зоны работы: `;
|
||
for(var zone in zones) answer += `<code>${zone}</code>; `
|
||
answer += `\n\n<i>Для изменений отслеживаемой зоны работы используйте</i> /setzone`;
|
||
}
|
||
else
|
||
answer = 'Возникла ошибка при авторизации';
|
||
|
||
users[data.id] = new_user;
|
||
newUsers.push(new_user.data());
|
||
console.log('Авторизован пользователь id=' + data.id)
|
||
}
|
||
return answer;
|
||
}
|
||
|
||
//Список запланнированных слотов
|
||
async function command_relogin(data){
|
||
var answer = data.answer;
|
||
if(await users[data.id].auth()&&await users[data.id].getInfo()){
|
||
answer += `Авторизован: ${users[data.id].info.name}`;
|
||
}
|
||
else
|
||
answer = `Возникла ошибка :(
|
||
Авторизуйтесь заново с помощью команды /login`;
|
||
update_users.push(data.id);
|
||
return answer;
|
||
}
|
||
|
||
//Обновить для всех авторизацию
|
||
async function command_relogin_all(data){
|
||
var answer = data.answer;
|
||
for await(var id of Object.keys(users)){
|
||
if(!await users[id].getInfo()){
|
||
if(await users[id].auth()&&await users[id].getInfo()){
|
||
answer += `Авторизован: ${users[id].info.name}`;
|
||
update_users.push(id);
|
||
}
|
||
else
|
||
answer += `Не авторизован: ${users[id].username}`;
|
||
answer += `\n`
|
||
}
|
||
}
|
||
if(answer == `<b>Переавторизация</b>\n`) answer = `Все пользователи авторизованы`
|
||
return answer;
|
||
}
|
||
|
||
//Список запланнированных слотов
|
||
async function command_logout(data){
|
||
await users[data.id].reset();
|
||
await update_users.push(data.id);
|
||
return data.answer;
|
||
}
|
||
|
||
//Список запланнированных слотов
|
||
async function command_myslots(data){
|
||
return await users[data.id].getPlanned();
|
||
}
|
||
|
||
//Список свободных слотов
|
||
async function command_freeslots(data){
|
||
return await users[data.id].getFreeSlotsWeek();
|
||
}
|
||
|
||
//Текущий заказ
|
||
async function command_orders(data){
|
||
return await users[data.id].getOrdersText();
|
||
}
|
||
|
||
//Список новых слотов
|
||
async function command_newfreeslots(data){
|
||
users[data.id].is_waiting = false;
|
||
return await users[data.id].getNewFreeSlotsWeek();
|
||
}
|
||
|
||
//Перезапуск бд
|
||
async function command_reload_bd(data){
|
||
await init_database()
|
||
return data.answer;
|
||
}
|
||
|
||
const fuzzysearch = require('fuzzysearch');
|
||
const levenshtein = require('js-levenshtein');
|
||
//Поиск нужной лавки
|
||
async function command_search_point(data){
|
||
var answer;
|
||
|
||
if(data.text.length==0) return `Для использования команды введите название лавки после /setzone
|
||
Например: /setzone Ветеранов`;
|
||
|
||
var names = [];
|
||
for(var zone_name in config.points){
|
||
if(data.text.toLowerCase().split(' ').join('') == zone_name.toLowerCase().split(' ').join('')) {
|
||
names = [zone_name];
|
||
break;
|
||
}
|
||
else if(fuzzysearch(data.text.toLowerCase().split(' ').join(''), zone_name.toLowerCase().split(' ').join(''))){
|
||
names.push(zone_name)
|
||
}
|
||
}
|
||
|
||
if(names.length == 1) {
|
||
answer = `<b>Выбрана точка:</b> ${names}(${config.points[names]})`
|
||
users[data.id].clearZones();
|
||
users[data.id].addZone(config.points[names]);
|
||
await update_users.push(data.id);
|
||
// console.log(users[data.id]);
|
||
}
|
||
else if(names.length == 0){
|
||
var minimal = 100;
|
||
for(var zone_name in config.points){
|
||
var a = levenshtein(data.text.toLowerCase().split(' ').join(''), zone_name.toLowerCase().split(' ').join(''));
|
||
if(a<minimal) {
|
||
answer = zone_name;
|
||
minimal = a;
|
||
}
|
||
}
|
||
var answer = `По вашему запросу ничего не найдено...
|
||
Возможно вы имели ввиду <code>${answer}</code>`;
|
||
} else if(answer == '') answer = 'Не найдено сопадений'
|
||
else {
|
||
answer = `<b>Найденные лавки:</b>
|
||
`;
|
||
for(var name of names){
|
||
answer+=`<code>${name}</code>\n`
|
||
}
|
||
}
|
||
return answer;
|
||
}
|
||
|
||
//Тестовая команда
|
||
async function command_test(data){
|
||
var answer = data.answer;
|
||
|
||
//console.log('Выбрана точка работы: ', await users[data.id].getMainZone());
|
||
|
||
return answer;
|
||
}
|
||
|
||
//Выбрать канал ответов для сообщения
|
||
function start_answering(id,command,text){
|
||
if(!users[id])
|
||
users[id] = new Courier({id:id});
|
||
if(!users[id].is_waiting){
|
||
var command_info = config.commands.get(command)||config.admin_commands.get(command);
|
||
if(!command_info) {
|
||
bot.sendMessage( id, config.defaulttext.unknown_command);
|
||
}
|
||
else {
|
||
if(command_info.need_api)
|
||
messages_wait_Yandex.push({
|
||
id : id,
|
||
text : text,
|
||
command_info : command_info
|
||
});
|
||
else
|
||
messages.push({
|
||
id : id,
|
||
text : text,
|
||
command_info : command_info
|
||
});
|
||
}
|
||
}
|
||
else bot.sendMessage( id, config.defaulttext.need_wait);
|
||
}
|
||
|
||
setTimeout(() => setInterval(() => start_answering(247608317,'/newfreeslots'), 20000), 5000);
|
||
|
||
//Ответ на сообщения не требующие API яндекса
|
||
messages = [];
|
||
answer_for_messages();
|
||
|
||
async function answer_for_messages(){
|
||
var message = messages.shift();
|
||
while (message) {
|
||
var id = message.id;
|
||
var command_info = message.command_info;
|
||
|
||
var answer = "";
|
||
var buttons = [];
|
||
|
||
var user_is_admin = (users[id].mode > 1);
|
||
if(command_info.need_admin&&!user_is_admin)
|
||
answer = config.defaulttext.need_admin;
|
||
else {
|
||
var user_is_auth = users[id].checkAuth();
|
||
if(command_info.need_auth&&!user_is_auth) {
|
||
answer = config.defaulttext.need_auth;
|
||
// buttons = getButtonsByNames(config.defaulttext.need_auth.buttons,id);
|
||
}
|
||
else {
|
||
answer = command_info.answer || 'no_answer';
|
||
// buttons = getButtonsByNames(command_info.buttons,id);
|
||
if(command_info.function_name){
|
||
var data = {
|
||
name : command_info.function_name,
|
||
id : id,
|
||
is_Auth : user_is_auth,
|
||
is_Admin : user_is_admin,
|
||
answer : answer,
|
||
text : message.text
|
||
}
|
||
try {
|
||
users[id].is_waiting = true;
|
||
answer = await launchFunctionByName(data);
|
||
} catch (e) {
|
||
console.log(e);
|
||
answer = 'Возникла ошибка';
|
||
users[id].is_waiting = false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
message = messages.shift();
|
||
users[id].is_waiting = false;
|
||
if(answer != 'no_answer'){
|
||
if (answer.length >= 4000)
|
||
while(answer.length>0){
|
||
await bot.sendMessage( id, answer.substring(0,4000), {
|
||
parse_mode: 'HTML',
|
||
reply_markup: {
|
||
inline_keyboard: buttons
|
||
}
|
||
});
|
||
answer = answer.substring(4000);
|
||
}
|
||
else
|
||
bot.sendMessage( id, answer, {
|
||
parse_mode: 'HTML',
|
||
reply_markup: {
|
||
inline_keyboard: buttons
|
||
}
|
||
});
|
||
}
|
||
|
||
}
|
||
setTimeout(answer_for_messages, 100);
|
||
}
|
||
|
||
var yandex_api = [1,1,1,1,1,1,1,1];
|
||
messages_wait_Yandex = [];
|
||
messages_with_Yandex = [];
|
||
|
||
add_messages_with_Yandex()
|
||
answer_for_messages_with_Yandex()
|
||
|
||
async function add_messages_with_Yandex(){
|
||
while((messages_wait_Yandex.length > 0) && (yandex_api.length > 0)){
|
||
var message = messages_wait_Yandex.shift();
|
||
var options = yandex_api.shift();
|
||
//console.log(options);
|
||
await messages_with_Yandex.push(message);
|
||
}
|
||
setTimeout(add_messages_with_Yandex, 100);
|
||
}
|
||
|
||
async function answer_for_messages_with_Yandex(){
|
||
var message = messages_with_Yandex.shift();
|
||
while (message) {
|
||
var id = message.id;
|
||
var command_info = message.command_info;
|
||
|
||
var answer = "";
|
||
var buttons = [];
|
||
|
||
var user_is_admin = (users[id].mode > 1);
|
||
if(command_info.need_admin&&!user_is_admin)
|
||
answer = config.defaulttext.need_admin;
|
||
else {
|
||
var user_is_auth = users[id].checkAuth();
|
||
if(command_info.need_auth&&!user_is_auth) {
|
||
answer = config.defaulttext.need_auth;
|
||
// buttons = getButtonsByNames(config.defaulttext.need_auth.buttons,id);
|
||
}
|
||
else {
|
||
answer = command_info.answer || 'no_answer';
|
||
// buttons = getButtonsByNames(command_info.buttons,id);
|
||
if(command_info.function_name){
|
||
var data = {
|
||
name : command_info.function_name,
|
||
id : id,
|
||
is_Auth : user_is_auth,
|
||
is_Admin : user_is_admin,
|
||
answer : answer,
|
||
text : message.text
|
||
}
|
||
try {
|
||
users[id].is_waiting = true;
|
||
answer = await launchFunctionByName(data);
|
||
} catch (e) {
|
||
console.log(e);
|
||
answer = 'Возникла ошибка';
|
||
users[id].is_waiting = false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
message = messages_with_Yandex.shift();
|
||
yandex_api.push(1);
|
||
users[id].is_waiting = false;
|
||
if(answer != 'no_answer'){
|
||
if (answer.length >= 4000)
|
||
while(answer.length>0){
|
||
await bot.sendMessage( id, answer.substring(0,4000), {
|
||
parse_mode: 'HTML',
|
||
reply_markup: {
|
||
inline_keyboard: buttons
|
||
}
|
||
});
|
||
answer = answer.substring(4000);
|
||
}
|
||
else
|
||
bot.sendMessage( id, answer, {
|
||
parse_mode: 'HTML',
|
||
reply_markup: {
|
||
inline_keyboard: buttons
|
||
}
|
||
});
|
||
}
|
||
|
||
}
|
||
setTimeout(answer_for_messages_with_Yandex, 100);
|
||
}
|
||
/******************--- databaseConnect ----**************************/
|
||
const { Client } = require('pg');
|
||
const client = new Client({
|
||
connectionString: process.env.DATABASE_URL,
|
||
ssl: {
|
||
rejectUnauthorized: false
|
||
}
|
||
})
|
||
client.connect()
|
||
.catch(e => {
|
||
console.error(e);
|
||
})
|
||
.then(()=>{init_database()});
|
||
|
||
var bd_loaded = false;
|
||
|
||
function init_database(){
|
||
(async () => {
|
||
var create_table = `CREATE TABLE IF NOT EXISTS USERS(
|
||
ID INT PRIMARY KEY NOT NULL,
|
||
TOKEN VARCHAR(1000) NOT NULL DEFAULT 'unauthorized',
|
||
USERNAME VARCHAR(45) NOT NULL DEFAULT 'no_username',
|
||
PASSWORD VARCHAR(20) NOT NULL DEFAULT 'no_password',
|
||
MODE INT NOT NULL DEFAULT 0,
|
||
ZONES TEXT NOT NULL DEFAULT 'no_zones'
|
||
);`;
|
||
await client.query(create_table)
|
||
|
||
var load_users = `SELECT * FROM USERS;`;
|
||
await client.query(load_users, async (err,res) => {
|
||
var users_ = res.rows;
|
||
var auth_needed = 0;
|
||
for await(var user of users_) {
|
||
if(user.zones === 'no_zones') user.zones = '';
|
||
user.zones = user.zones.split(',')
|
||
users[user.id] = new Courier(user);
|
||
if(!(await users[user.id].getInfo()))
|
||
auth_needed++;
|
||
}/*var i=0; i<users_.length;i++) {
|
||
var user_data = {
|
||
id: users_[i].id,
|
||
username: users_[i].username,
|
||
password: users_[i].password,
|
||
token: users_[i].token,
|
||
mode: users_[i].mode,
|
||
zones: users_[i].zones.split(',')
|
||
}
|
||
users[user_data.id] = new Courier(user_data);
|
||
if(!(await users[user_data.id].getInfo()))
|
||
auth_needed++;
|
||
}*/
|
||
console.log(`Из базы данных загружено пользователей: ${users_.length}, нужна повторная авторизация: ${auth_needed}`)
|
||
if(!bd_loaded){
|
||
setTimeout(saveNewUsers, 5000);
|
||
bd_loaded = false;
|
||
}
|
||
})
|
||
})()
|
||
.catch(e => {
|
||
console.error(e);
|
||
setTimeout(init_database, 5000);
|
||
});
|
||
}
|
||
/******************--- databaseConnect ----**************************/
|
||
|
||
var update_users = [];
|
||
const updateUsersClient = new Client({
|
||
connectionString: process.env.DATABASE_URL,
|
||
ssl: {
|
||
rejectUnauthorized: false
|
||
}
|
||
});
|
||
updateUsersClient.connect();
|
||
|
||
setTimeout(updateUsersOnServer, 5000);
|
||
|
||
async function updateUsersOnServer(){
|
||
(async () => {
|
||
var id = update_users.shift();
|
||
while(id){
|
||
let update = `UPDATE USERS SET TOKEN = '${users[id].token}', USERNAME = '${users[id].username}', PASSWORD = '${users[id].password}', MODE = ${users[id].mode}, ZONES = '${users[id].zones.join(",")}' WHERE ID = ${id};`
|
||
await updateUsersClient.query(update)
|
||
id = update_users.shift();
|
||
}
|
||
setTimeout(updateUsersOnServer, 5000);
|
||
})()
|
||
.catch(e => {
|
||
console.error(e);
|
||
setTimeout(updateUsersOnServer, 5000);
|
||
});
|
||
}
|
||
|
||
var newUsers = [];
|
||
|
||
function saveNewUsers(){
|
||
(async () => {
|
||
var user = newUsers.shift();
|
||
while (user){
|
||
var add_user = `INSERT INTO USERS(ID, TOKEN, USERNAME, PASSWORD, MODE, ZONES) VALUES(${user.id}, '${user.token}', '${user.username}', '${user.password}', ${user.mode}, '${user.zones.join(",")}') ON CONFLICT (ID) DO UPDATE SET TOKEN = EXCLUDED.TOKEN, USERNAME = EXCLUDED.USERNAME, PASSWORD = EXCLUDED.PASSWORD;`;
|
||
//console.log('save ',user)
|
||
await client.query(add_user);
|
||
user = newUsers.shift();
|
||
}
|
||
setTimeout(saveNewUsers, 5000);
|
||
})()
|
||
.catch(e => {
|
||
console.error(e);
|
||
});
|
||
}
|