1
0
This repository has been archived on 2022-11-26. You can view files and clone it, but cannot push or open issues or pull requests.

594 lines
16 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
});
}