После нескольких писем, отправленных с сайта себе на почту, понял что это достаточно неудобно, не современно (возможно), как минимум не прикольно. Задался целью отказаться от использования smtp для формы в пользу api Телеграма.
Так как мое приложение работает на ноде, подумал почему бы не прокачать форму. Общая логика до боли проста. При отправке формы делается запрос к api приложения, где хранится токен бота, обрабатываются данные и далее делается запрос к api телеграмма, который отправляет сообщение в чат.
Но давайте обо всем по порядку.
Для начала, естественно, необходимо создать бота, который будет получать данные из формы и отправлять вам. По сути, он является всего лишь посредником между вами и api телеграмма.
Итак, стучимся к родителю всех ботов, а именно к @BotFather и просим его создать нам одного (вводим /newbot). Вводим имя, ник и получаем токен бота. Как раз он нам и нужен. Заметьте, что ник бота должен быть <your>_bot или <Your>Bot.
Создали, хорошо, но надо оживить его. Ищем его в поиске по нику и пишем /start. Все, теперь можем обращаться к нему через api.
Далее необходимо создать группу, куда бот будет кидать сообщения, не забываем добавить его в чат.
Вводим /join @ник_бота в созданном чате, потому что бывает, что не добавляется в логи запись о приглашении бота в группу.
Идем в браузер и в адресной строке вводим:
https://api.telegram.org/botXXXXXXXXXXXXXXXXXXXXXXX/getUpdates
где XXXXXXXXXXXXXXXXXXXXXXX — токен бота, который любезно дал вам @BotFather.
Если все прошло успешно, то получим примерно такую простыню из букв, где необходимо найти объект «chat»:{«id:XXXXXXXXXX…}. Обычно id группового чата начинается с минуса.
Отлично, получили токен бота и id чата, куда будут приходить сообщения.
Теперь давайте приступим к приложению.
Front
Начнем сначала с фронта.
Я использовал для работы Node обёртку Express, который в свою очередь умеет рендерить файлы различных шаблонизаторов. Решил воспользоваться Pug. Он достаточно прост в освоении, поэтому если впервые сталкиваетесь с ним, труда познакомится с ним не возникнет. Для примера не стал использовать сборщики, поэтому скрипты подключаются по старинке.
Структура приложения сгенерирована с помощью Express Generator.
Разметка формы
views/layout.pug:
doctype html
html
head
title= title
link(rel="stylesheet", href="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.1.3/sweetalert.min.css")
link(rel='stylesheet', href='/stylesheets/style.css')
body
block content
views/index.pug:
extends layout
block content
.wrapper
.wrapper__bg
img.wrapper__bg-img(src='/images/bg.jpg' alt='bg')
form(action="/telegram", method="post" class="form" id='telegramForm' enctype="application/x-www-form-urlencoded")
.form__container
.form__blur
.form__title
.form__title-line
h3.form__title-text Связаться со мной
.form__title-line
.form__inputs
input(type="text" name='name' placeholder="Имя" class="form__input" required)
input(type="email" name='email' placeholder="Email" class="form__input" required)
textarea(name="text" placeholder="Ваше сообщение" class="form__input form__message" required)
.form__buttons
input(type="submit" class="form__submit" value="Отправить")
.form__clean Очистить
script(src="https://cdnjs.cloudflare.com/ajax/libs/sweetalert/1.1.3/sweetalert.min.js")
script(src="/javascripts/app.js")
Не забываем что в Pug вложенность элементов определяется отступами, как в питоне, так что учитывайте это.
Добавляем стили и вот такая форма у меня получилась.
Сообщение будет отправляться без перезагрузки страницы, поэтому вешаем обработчик на форму, собираем данные, преобразуем в json и отправляем их асинхронно себе в api + выводим сообщение о статусе запроса.
public/javascripts/app.js:
const formId = 'telegramForm'
const form = document.getElementById(formId)
//функция для захвата данных из тегов формы и синтеза JSON-обьекта
function toJSONString(form) {
var obj = {}
var elements = form.querySelectorAll('input, select, textarea')
for (var i = 0; i < elements.length; ++i) {
var element = elements[i]
var name = element.name
var value = element.value
if (name) {
obj[ name ] = value
}
}
return JSON.stringify(obj)
}
if (form) {
form.addEventListener('submit', event => {
event.preventDefault()
//получаем данные из формы
const json = toJSONString(form)
//создаем соединение
const formReq = new XMLHttpRequest()
formReq.open('POST', '/telegram', true)
///////////////////////////////////
/////////////SweetAlert//////////
///////////////////////////////////
//обрабатываем ответ сервера
formReq.onload = function(oEvent) {
if (formReq.status === 200) {
swal({
title: 'Успешно отправлено!',
icon: 'success',
timer: 2000
})
document.querySelector('.sa-success').style.display = 'block'
document.querySelector('.sa-button-container').style.opacity = '0'
}
if (formReq.status !== 200) {
swal({
title: 'Произошла ошибка!',
icon: 'error',
timer: 2000
})
document.querySelector('.sa-error').style.display = 'block'
document.querySelector('.sa-button-container').style.opacity = '0'
}
}
////////////////////////////
////////////////////////////
formReq.setRequestHeader('Content-Type', 'application/json')
//отправляем
formReq.send(json)
})
}
Back
На стороне сервера для начала нужно отловить запрос со стороны клиента, для этого в роутере пишем:
routes/index.js:
//Я вынес логику обработки данных в отдельный файл
const ctrlTelegram = require('../api/telegramMsg');
router.post('/telegram', ctrlTelegram.sendMsg);
api/telegramMsg.js:
module.exports.sendMsg = (req, res) => {
//токен и id чата берутся из config.json
const config = require('../config/config.json');
let http = require('request')
let reqBody = req.body
//каждый элемент обьекта запихиваем в массив
let fields = [
'<b>Name</b>: ' + reqBody.name,
'<b>Email</b>: ' + reqBody.email,
reqBody.text
]
let msg = ''
//проходимся по массиву и склеиваем все в одну строку
fields.forEach(field => {
msg += field + '\n'
});
//кодируем результат в текст, понятный адресной строке
msg = encodeURI(msg)
//делаем запрос
http.post(`https://api.telegram.org/bot${config.telegram.token}/sendMessage?chat_id=${config.telegram.chat}&parse_mode=html&text=${msg}`, function (error, response, body) {
//не забываем обработать ответ
console.log('error:', error);
console.log('statusCode:', response && response.statusCode);
console.log('body:', body);
if(response.statusCode===200){
res.status(200).json({status: 'ok', message: 'Успешно отправлено!'});
}
if(response.statusCode!==200){
res.status(400).json({status: 'error', message: 'Произошла ошибка!'});
}
});
}
Для упрощения процесса запроса установлен пакет 'request'.
npm i request
?config/config.json:
{
"telegram": {
"token": "bot_token",
"chat": "chat_id"
}
}
Итак, что же здесь происходит?
В запросе мы передали json, поэтому на стороне сервера с данными можем работать как с обычным объектом.
Для удобства каждое значение объекта запихиваем в массив.
API телеграмма позволяет передать данные посредством текста в адресной строке, поэтому проходим по массиву и создаём длинную строку. Чтобы можно было передать HTML теги, необходимо закодировать строку в универсальный идентификатор (метод encodeURI()), чтобы не вылезала ошибка.
Теперь можно наконец отправить это всё на сервер телеграмма. Делаем запрос (нажимаем кнопку 'Отправить') и вуаля, сообщение отправлено. Не забываем обработать ответ, а то мало ли что.
После всех манипуляций, ответ приходит на фронт и уведомляет прошло все норм или не очень.
Из-за того, что для примера не использовал сборщик, а библиотечка всплывашки рассчитана на модульную сборку, пришлось немного поколхозить при ее вызове на фронте.
Если посмотреть в логи приложения на сервере, можно увидеть примерно следующее:
Поздравляю! Теперь вы знаете как отправлять сообщения с вашего сайта в Telegram.
Я описал только общую концепцию данного процесса, поэтому настоятельно рекомендую ознакомится с исходным кодом данного примера.
aavezel
1. Лучше использовать приватный канал для таких дел
2. Зачем прокси через node.js? В простейшем случае можно писать напрямую с сайта в api.telegram.org, «благо» Access-Control-Allow-Origin:*.
RoMan_111 Автор
1. Наверное лучше использовать канал, да. Я хотел организовать все быстро и чтобы работало.
2. Мое приложение работает на ноде, поэтому решил почему бы не свалить этот процесс на нее.
Miju
Злобный хацкер спалил в консоли браузера токен и начнёт использовать бота в своих хацкеравских целях.
RoMan_111 Автор
Именно \O/
aavezel
Каких? Послать рекламу казино в канал для 5 человек? Или вы еще для чего то будете использовать бота? Завести 2х ботов не позволяет религия?
RoMan_111 Автор
Злобный хацкер например может всякие незаконные анонимные действия совершать(продажа оружия, веществ, террор, поддельные документы), а бот зарегистрирован на тебя и если телега прогнется все-таки под государство, то анонимности конец.
Возможно можно сформулировать мысль иначе, но смысл думаю понятен
max_rip
2, т.е. вы предлагаете использовать токен от бота в фронте?
Sergey78
А в чем преимущество канала?
В обычном чате с ботом можно добавить какую-то функциональность к сообщениям. Ответить там, или переслать или сохранить где-то. Зачем в данном случае нужен канал?
aavezel
Канал тоже позволяет сохранить или переслать куда-то. Притом имя бота не будет светиться в канале в отличии от чата, т.е. пересылать с закрытого канала более секьюрно.
Сама суть в том, что на канал можно не мьютить, в отличии от чата, в котором постоянно будут возникать флуды не по делу, что в конце концов заставит вас замьютить чат и пропустить важное сообщение.
Ну и токен бота, который постит в канал можно распечатать хоть на заборе, читать из канала чужие сообщения он не сможет, посмотреть кто подписан на канал — тоже.
sdwvit
Отправить и очистить следует сменить местами и разукрасить в разный цвет. Я, смотря на гифку, мысленно представил как каждый раз жму очистить вместо отправить X)
Проверить как правильно делается можно открыв консоль хрома и ввести confirm(1)
ExploZeR
Всё намного проще. На самом деле, сообщение можно отправить прямо из JS на страничке. Не нужен node.js, не нужны запросы на сервер. Просто 20 коротких строк JS.
Понятно, что светить токен бота и чат айди — не кошерно. Однако, знать это всё равно неплохо.
При желании, функцию sendMsg (из этого скрипта) для отправки JSON данных методом POST по такой же схеме можно реализовать на php. Например, через curl.
Разметка формы:
your_eyes_lie
Отдавать токен бота всем — наверное, не лучшая идея
vlx
можно еще посмотреть в сторону
npm install node-telegram-bot-api
github.com/yagop/node-telegram-bot-api
Methos
Угу, ничего сложного.
Делал чат для сайта с использованием телеграма.