/**
* Настройки Бота
*/
const config = {
sheet: "ID_ТАБЛИЦИ",
webUrl: "ссылка_(URL)_на_веб-приложение",
token: "TOKEN_BOT",
userNameBot: "USERNAME_BOT",
apiUrl: "https://api.telegram.org/bot",
botAdmin: ВАШ_ID,
langParams: {
ru: {
admin: {
hello: "Начинаем ждать сообщений от пользователей",
answer: {
self: "Ответ на свое сообщение",
bot: "Ответ на сообщение бота",
button: {
reply: "Надо поставить сообщение пользователя в ответ.",
},
error: {
send: "Не удалось отправить сообщение пользователю"
}
}
},
user: {
hello: "Приветствую Вас, {name}.\nЯ очень жду вашего сообщения.\n------\nСпасибо."
}
}
},
linkCommands: [
{
template: /^\/start$/,
method: 'start'
}
],
db: {
users: {
table: "Users",
uid: 1,
name: 2,
userName: 3,
lang: 4,
created_at: 5,
updated_at: 6
}
}
}
function getMe() {
let response = UrlFetchApp.fetch(config.apiUrl + config.token + "/getMe");
console.log(response.getContentText());
}
function getWebHookInfo() {
let response = UrlFetchApp.fetch(config.apiUrl + config.token + "/getWebHookInfo");
console.log(response.getContentText());
}
function setWebHook() {
let response = UrlFetchApp.fetch(config.apiUrl + config.token + "/setWebHook?url=" + config.webUrl);
console.log(response.getContentText());
}
/**
* Получаем данные от Телеграм
*/
function doPost(request) {
// получаем данные
let update = JSON.parse(request.postData.contents);
// направляем данные в объект WebHook
new WebHook(update);
}
/**
* Класс WebHook
*/
class WebHook {
/**
* Создаем объект WebHook
*/
constructor(update) {
// создаем объект бота
this.bot = new Bot(config.token, update);
// создаем объект пользователя
this.user = new User(this.bot.getUserData());
// создаем объект языковых настроек
this.lang = new Lang(this.user.lang);
// получаем набор команд с шаблонами
this.linkCommands = config.linkCommands;
// запускаем роутер
this.route();
}
/**
* Получаем объект команды
*/
checkCommand(text) {
// текстовые ссылки
if (this.linkCommands.length > 0) {
// перебираем команды
for (let linkCommand of this.linkCommands)
// если есть совпадения
if (linkCommand.template.test(text)) {
// добавим флаг
linkCommand.result = true;
// вернем объект с методом
return linkCommand;
}
}
// если дошли до этой строчки то вернем флаг ошибки
return {
result: false
};
}
/**
* Маршрутизируем
*/
route() {
// проверим на частный запрос
if(this.bot.data.message.chat.type != "private") {
// выйдем если это группа или канал
return;
}
// если это сообщение
if(Helper.isSet(this.bot.data.message)) {
// если это текстовое сообщение
if(Helper.isSet(this.bot.data.message.text)) {
// проверяем на команды
let command = this.checkCommand(this.bot.data.message.text);
// если есть совпадение по шаблону
if (command.result) {
// вызываем метод
this[command.method]();
// выходим
return;
}
}
// если пишет админ
if (this.isAdmin()) {
// если это ответ на сообщение
if (Helper.isSet(this.bot.data.message.reply_to_message)) {
// получаем текст из отвечаемого сообщения
let text_ = Helper.isSet(this.bot.data.message.reply_to_message.text)
? this.bot.data.message.reply_to_message.text // текстовое сообщение
: this.bot.data.message.reply_to_message.caption; // медиа сообщение
// если ответ самому себе
if (this.user.uid == this.bot.data.message.reply_to_message.from.id) {
// уведомляем админа, что ответ самому себе
this.bot.sendMessage(config.botAdmin, this.lang.getParam("admin.answer.self"));
} // если ответ на сообщение бота
else if (this.isReplyBot() && !/^USER_ID::[\d]+::/.test(text_)) {
// уведомляем, что ответ боту
this.bot.sendMessage(config.botAdmin, this.lang.getParam("admin.answer.bot"));
}
else {
// получить id пользователя из сообщения
let matches = text_.match(/^USER_ID::(\d+)::/);
// проверяем
if (matches) {
// все нормально отправляем копию сообщения пользователю
this.bot.copyMessage(matches[1], config.botAdmin, this.bot.data.message.message_id);
} else {
// уведомляем, что не удалось направить сообщение пользователю
this.bot.sendMessage(config.botAdmin, this.lang.getParam("admin.answer.error.send"));
}
}
} else {
// уведомление нажать кнопку ответить
this.bot.sendMessage(config.botAdmin, this.lang.getParam("admin.answer.button.reply"));
}
} else {
// Если это написал пользователь то отправляем копию админу
this.sendCopyToAdmin();
}
}
}
/**
* Проверяем на Админа
*/
isAdmin() {
// сравним текущего пользователя с админом из настроек
return config.botAdmin == this.user.uid;
}
/**
* Локальная проверка на бота
*/
isReplyBot() {
// вернем кто владелец сообщения на которое отвечаем
return this.bot.data.message.reply_to_message.from.is_bot;
}
/**
* Старт бота
*/
start() {
// определяем текст
let text = this.isAdmin() // проверяем кто стартанул
? this.lang.getParam("admin.hello") // если стартанул админ
: this.lang.getParam("user.hello", { // если стартанул пользователь
name: this.user.name // добавим для парсинга его имя
}) ;
// выводим сообщение
this.bot.sendMessage(this.user.uid, text);
}
/**
* Отправляем копию
*/
sendCopyToAdmin() {
// создаем ссылку на просмотр профиля
let link = (this.user.userName.length > 0)
? "@" + this.user.userName // если есть username
: "<a href='tg://user?id=" + this.user.uid + "'>" + this.user.name + "</a>";
// дополнение к сообщению с id пользователя
let dop = "USER_ID::" + this.user.uid + "::\nот <b>" + this.user.name + "</b> | " + link + "\n-----\n";
// определяем данные по умолчанию
let typeMessage = this.bot.getMessageType(); // тип сообщения
let dopSend = false; // по умолчанию доп отправлять отдельно не нужно
let data = { // формируем данные сообщения
chat_id: String(config.botAdmin), // пользователь админ
disable_web_page_preview: true, // закроем превью ссылок
parse_mode: "HTML", // форматирование html
method: null // метод по умолчанию не определен
};
// если это текстовое сообщение
if (typeMessage == "text") {
// формируем доп с текстом
data.text = dop + this.bot.prepareMessageWithEntities(this.bot.getMessageText(), this.bot.getEntities());
// переопределяем метод
data.method = "sendMessage";
} else { // если это остальные типы сообщений
// проверяем нужно ли отправлять dop отдельным сообщением
dopSend = Helper.isNull(this.bot.getMessageText());
// заполняем данные
if(typeMessage == "location") {
// определяем координаты
data.longitude = this.bot.data.message.location.longitude;
data.latitude = this.bot.data.message.location.latitude;
} else {
// запоняем файлом
data[typeMessage] = this.bot.getMessageFileId();
}
// если не надо доп, значит описание не пустое
if (!dopSend) {
// дополняем описание
data.caption = dop + this.bot.prepareMessageWithEntities(this.bot.getMessageText(), this.bot.getEntities());
}
// переопределяем метод
data.method = "send" + this.prepareMethod(typeMessage);
}
// если метод определен
if (!Helper.isNull(data.method)) {
// и нужно отправить доп отдельным сообщением
if (dopSend) {
// отправляем админу доп
this.bot.sendMessage(config.botAdmin, dop);
}
// отправляем копию
this.bot.query({
method: "post",
payload: data
});
}
}
/**
* Преобразуем переданную строку в camelCase
*/
prepareMethod(method) {
return method.split('_') // разделяем по знаку _ в массив
.map(function(word,index){ // перебираем все значения
// преобразуем первый символ в верхний регистр, остальное в нижний
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
})
.join(''); // собираем в одно слово без пробелов
}
}
/**
* Класс Пользователь
*/
class User {
/**
* Создаем обект пользователя
*/
constructor(userData) {
// заполняем uid
this.uid = userData.uid;
// name сразу склеиваем из первого и второго имени
this.name = (userData.firstName + " " + userData.lastName).trim();
// заполняем lang из телеги
this.lang = userData.lang;
// username если есть
this.userName = userData.userName;
// сохраняем данные
this.save()
}
/**
* Получаем строку в таблице по uid
*/
getRowByUid(sheet, uid, range_ = "A1:A") {
// определяем диапазон ячеек в таблице
const range = sheet.getRange(range_);
// получаем через поиск по переданному uid
const result = range.createTextFinder(uid).matchEntireCell(tr