Телеграм бот конвертер регистров — Google Apps Script. Часть 1 из 2.

Мне, иногда, приходится конвертировать регистр текста. Раньше, я пользовался сторонними сервисами, но понял, что иметь под рукой такой конвертер регистров в телеграм будет приятней. Использовать буду Google Apps Script и функции с недавно опубликованной статьи о способах конвертирования регистра в JS.

Погнали!

Первым делом идем регистрировать бота.
Детально описано здесь: Создание нового бота в Телеграм (Telegram Bot)

Создаем новую Google Таблицу по ссылке https://docs.google.com/spreadsheets/.
Это будет наша мини база данных, в которой мы будем собирать информацию о пользователях и логи.

Переименовываем и открываем в верхнем меню Расширения → Apps Script.

Развёртывание приложения

Кликаем Начать развертываниеНовое развертывание.

Выбираем тип развертывания → Веб-приложение

Пишем Описание (не обязательно), выбираем У кого есть доступВсе (!это важно) и кликаем Начать развертывание.

Скопируем адрес URL приложения, кликнув по кнопке ОК

Управление развертываниями

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

Кликаем по кнопке Начать развертываниеУправление развертываниями.

Кликаем по иконке Редактирование и выбираем из списка Новая версия.

Config.gs

Создадим новый файл скрипта с названием config.gs. Здесь, в объекте config, будут хранится все переменные по нашему проекту.

Код с комментариями

config.gs — Apps Script
const config = {
  // id таблицы берем с url таблицы Convert Case Bot:
  // 1 часть адреса: https://docs.google.com/spreadsheets/d/
  // 2 часть - id: 1g67JUOchcKAYbGEr1Ey3JG9olM1NqUZSWXsnIMYB_CM
  // 3 часть адреса: /edit#gid=0
  spreadsheet: '1QBoDWMy7UkxlYmjIPKp0S4hVonPLC_yZK7WB-IitfTI',
  
  // Вставляем адрес URL приложения которое мы скопировали на предыдущем шаге
  webUrl: "https://script.google.com/macros/s/v94KAKfycbwMq6R_3NwycbltDnmNJsBTepj_imr-mtatV1_uLj3Vw2xowQtsdyc79h6z2J8Qaur/exec",
  
  // Вставляем токен телеграм бота
  tokenTelegram: "5909769673:BBGjXRGbyaa8y99xfpAs3gTSrvmDweI-vBs",
  
  // Здесь ничего не меняем
  apiUrlTelegram: "https://api.telegram.org/bot",

  sheets: {
    // Указываем имя листа с пользователями
    sheetUsers: "users",
    // Указываем имя листа для логов
    sheetLog: "log",
  },
  
  // Для удобства я вынес номера колонок в которых будут храниться данные пользователей
  db: {
    uid: 1,
    name: 2,
    userName: 3,
    created_at: 4,
    updated_at: 5,
  },
  // Описываю все команды, на которые будет реагировать бот
  botCommands: {
    start: "/start",
  },
}

Код без комментариев

config.gs — Apps Script
const config = {
  spreadsheet: '1QBoDWMy7UkxlYmjIPKp0S4hVonPLC_yZK7WB-IitfTI',
  webUrl: "https://script.google.com/macros/s/v94KAKfycbwMq6R_3NwycbltDnmNJsBTepj_imr-mtatV1_uLj3Vw2xowQtsdyc79h6z2J8Qaur/exec",
  tokenTelegram: "5909769673:BBGjXRGbyaa8y99xfpAs3gTSrvmDweI-vBs",
  apiUrlTelegram: "https://api.telegram.org/bot",
  sheets: {
    sheetUsers: "users",
    sheetLog: "log",
  },
  db: {
    uid: 1,
    name: 2,
    userName: 3,
    created_at: 4,
    updated_at: 5,
  },
  botCommands: {
    start: "/start",
  },
}

Устанавливаем webhook

Создаем новый файл скрипта helper.gs.
Запишем в него две функции: установку вебхука и его удаление:

helper.gs — Apps Script
function setWebhook(){
  let response = UrlFetchApp.fetch(config.apiUrlTelegram + config.tokenTelegram + '/setWebhook?url=' + config.webUrl);
  Logger.log('telegram response status is ' + response.getContentText());
}

function removeWebhook(){
  let response = UrlFetchApp.fetch(config.apiUrlTelegram + config.tokenTelegram + '/setWebhook?url=');
  Logger.log('telegram response status is ' + response.getContentText());
}

Сохраняем проект. Из списка выбираем функцию setWebhook и кликаем Выполнить:

Появляется окошко авторизации. Кликаем Проверить разрешения:

Дальнейшие действия я указал стрелками на скринах ниже:

После предоставления разрешений, в Журнале выполнений у вас должна появится запись:

Пишем бота

Создаем новый файл скрипта bot.gs.
Функция doPost(e) будет принимать отправленную информацию с нашего телеграм бота.
Парсим ответ и сохраняем его в переменную ctx

bot.gs — Apps Script
function doPost(e) {
  const ctx = JSON.parse(e.postData.contents);
}

Открываем наш документ по ID на листе с название log. В первую ячейку будем заносить ctx:

bot.gs — Apps Script
function doPost(e) {
  const ctx = JSON.parse(e.postData.contents);
  
  const ss = SpreadsheetApp.openById(config.spreadsheet);
  const sheetLog = ss.getSheetByName(config.sheets.sheetLog);
  sheetLog.getRange(1, 1).setValue(JSON.stringify(ctx, null, 5));
}

Теперь мы видим наглядно, что нам возвращает телеграм:

Инлайн клавиатура (Inline Keyboard)

Создаем новый файл скрипта keyboard.gs.
Инлайн клавиатура передается как массив массивов которые состоят из инлайн кнопок.
Один массив — один ряд кнопок.

Инлайн кнопка это объект, который включает в себя ключи text и callback_data.
Значения callback_data обязательно должны быть уникальны, потому что мы будем слушать нажатие кнопок именно по этому значению.

keyboard.gs — Apps Script
const inlineKeyboard = {
  'inline_keyboard': [
  [
    { 'text': "ВЕРХНИЙ РЕГИСТР", 'callback_data': "formatUpper" },
    { 'text': "нижний регистр", 'callback_data': "formatLower" }
  ],
  [
    { 'text': "Заглавные Буквы", 'callback_data': "formatTitle" },
    { 'text': "иНВЕРСИЯ рЕГИСТРА", 'callback_data': "formatInverse" }
  ],
  [
    { 'text': "Сделать. Как в предложении.", 'callback_data': "formatSentence" }
  ],
  ]
}

Функции

Создаем новый файл скрипта functions.gs в котором будут храниться все наши функции.

Отправка сообщения — sendMessage

functions.gs — Apps Script
function sendMessage(chat_id, textMessage, keyboard) {
  const options = {
    method: 'post',
    payload: {
      method: 'sendMessage',
      chat_id: String(chat_id),
      text: textMessage,
      parse_mode: 'HTML',
      disable_web_page_preview: true,
      reply_markup: JSON.stringify(keyboard)
    }
  }
  UrlFetchApp.fetch(config.apiUrlTelegram + config.tokenTelegram + "/", options);
}

Удаление сообщения — deleteMessage

functions.gs — Apps Script
function deleteMessage(chat_id, message_id) {
  const options = {
    method: 'post',
    payload: {
      method: 'deleteMessage',
      chat_id: String(chat_id),
      message_id: message_id,
      parse_mode: 'HTML',
      disable_web_page_preview: true,
    }
  }
  UrlFetchApp.fetch(config.apiUrlTelegram + config.tokenTelegram + "/", options);
}

Отправка уведомления — toastMessage

functions.gs — Apps Script
function toastMessage(cbqId, toastText) {
  const options = {
    method: 'post',
    payload: {
      callback_query_id: cbqId,
      show_alert: false,
      method: 'answerCallbackQuery',
      text: toastText,
      parse_mode: 'HTML',
    }
  }
  UrlFetchApp.fetch(config.apiUrlTelegram + config.tokenTelegram + "/", options);
}

Функция добавления пользователя в базу данных — saveUser

functions.gs — Apps Script
function saveUser(user) {
  const sheet = SpreadsheetApp.openById(config.spreadsheet).getSheetByName(config.sheets.sheetUsers)
  const row = getRowByUid(sheet, user.uid);
  const date = new Date();

  if (row) {
    sheet.getRange(row, config.db.name).setValue(user.firstName + " " + user.lastName)
    sheet.getRange(row, config.db.userName).setValue(user.userName)
    sheet.getRange(row, config.db.updated_at).setValue(date.toString())
  } else {
    sheet.appendRow(
      [
        user.uid,
        user.firstName + " " + user.lastName,
        user.userName,
        date.toString(),
        date.toString()
      ]
    )
  }
}

Поиска номера строки по id пользователя — getRowByUid

functions.gs — Apps Script
function getRowByUid(sheet, uid, range_ = "A1:A") {
  const range = sheet.getRange(range_);
  const result = range.createTextFinder(uid).matchEntireCell(true).findNext();
  return result ? result.getRow() : null;
}

Далее идут функции, работу которых я описывал в статье Как изменить регистр текста в JS — JavaScript.

Конвертирование в верхний регистр — formatUpper

functions.gs — Apps Script
function formatUpper(str) {
  return str.toUpperCase();
}

Конвертирование в нижний регистр — formatLower

functions.gs — Apps Script
function formatLower(str) {
  return str.toLowerCase();
}

Каждое слово с заглавной буквы — formatTitle

functions.gs — Apps Script
function formatTitle(str) {
  let rows = str.toLowerCase().split("\n");
  let result = "";

  rows.forEach(function (row) {
    let words = row.split(" ");
    let wordsResult = "";
    words.forEach(function (word) {
      word ? (wordsResult += " " + word.split("")[0].toUpperCase() + word.slice(1)) : "";
    });

    result += wordsResult.trim() + "\n";
  });

  return result;
}

Инверсия регистра — formatInverse

functions.gs — Apps Script
function formatInverse(str) {
  function isLower(variable) { return variable.toLowerCase() == variable }
  function isUpper(variable) { return variable.toUpperCase() == variable }

  let text = "";
  let char;
  for (var i = 0; i < str.length; i++) {
    char = str.charAt(i);
    if (isLower(char)) { char = char.toUpperCase() } else { if (isUpper(char)) char = char.toLowerCase() }
    text += char
  }
  return text
}

Конвертирование в формат предложений: новая строка с заглавной буквы — formatSentence

functions.gs — Apps Script
function formatSentence(str) {
  return str.toLowerCase().replace(/((^\s*\D|[\.\!\?\n]\s*\D))/g, function (c) {
    return c.toUpperCase();
  });
}

На этом с функциями все.

Во второй части осталось разобраться с логикой.

Читать: Телеграм бот конвертер регистров — Google Apps Script. Часть 2 из 2.