16#include <QNetworkAccessManager>
27#include <QNetworkReply>
28#include <QSharedPointer>
32#include <QJsonDocument>
49 if (
token.isEmpty()) {
55 _loginReplay =
sendRequest(QSharedPointer<TelegramGetMe>::create());
57 connect(_loginReplay.get(), &QNetworkReply::finished,
58 this, &ITelegramBot::handleLogin,
59 Qt::DirectConnection);
60 connect(_loginReplay.get(), &QNetworkReply::errorOccurred,
61 this, &ITelegramBot::handleLoginErr,
62 Qt::DirectConnection);
74 bool onetimeKeyboard) {
76 auto replyMarkup = QSharedPointer<QJsonObject>::create();
78 QJsonObject contactButton;
79 contactButton[
"text"] = buttonText;
80 contactButton[
"request_location"] =
true;
82 row.append(contactButton);
84 replyMarkup->insert(
"keyboard", keyboard);
85 replyMarkup->insert(
"resize_keyboard",
true);
86 replyMarkup->insert(
"one_time_keyboard", onetimeKeyboard);
92 bool onetimeKeyboard) {
93 auto replyMarkup = QSharedPointer<QJsonObject>::create();
95 QJsonObject contactButton;
96 contactButton[
"text"] = buttonText;
97 contactButton[
"request_contact"] =
true;
99 row.append(contactButton);
100 keyboard.append(row);
101 replyMarkup->insert(
"keyboard", keyboard);
102 replyMarkup->insert(
"resize_keyboard",
true);
103 replyMarkup->insert(
"one_time_keyboard", onetimeKeyboard);
114 if (args.
text.isEmpty()) {
118 auto msg = QSharedPointer<TelegramSendMsg>::create(args, extraObjects);
129 if (!chatId.isValid() || chatId.isNull())
132 if (!messageId.isValid() || messageId.isNull())
135 auto msg = QSharedPointer<TelegramDeleteMessage>::create(chatId,
143 const QList<QList<QString> > &keyboard,
145 bool autoResizeKeyboard) {
150 if (!messageId.isValid() || messageId.isNull())
153 auto msg = QSharedPointer<TelegramEditMessage>::create(messageId,
155 prepareKeyboard(autoResizeKeyboard,
166 auto&& keyboardJson = QSharedPointer<QJsonObject>::create();
167 QJsonArray keyboardArray;
169 for (
const auto& map : keyboard) {
170 QJsonArray keyboardLineArray;
171 for (
auto it = map.begin(); it != map.end(); it = std::next(it)) {
172 auto&& callBackKey = QString(
"callback_data_%0").arg(rand());
173 keyboardLineArray.push_back(QJsonObject{ {
"text", it.key()}, {
"callback_data", callBackKey } });
174 _handleButtons[callBackKey] = {it.value()};
176 keyboardArray.push_back(keyboardLineArray);
180 (*keyboardJson)[
"inline_keyboard"] = keyboardArray;
182 extraObjects[
"reply_markup"] = keyboardJson;
188qTbot::ITelegramBot::prepareKeyboard(
bool autoResizeKeyboard,
190 const QList<QList<QString>> &keyboard) {
192 auto&& keyboardJson = QSharedPointer<QJsonObject>::create();
193 QJsonArray keyboardArray;
195 for (
const auto &row :keyboard) {
196 QJsonArray keyboardLineArray;
198 for (
auto it = row.begin(); it != row.end(); it = std::next(it)) {
199 keyboardLineArray.push_back(QJsonObject{ {
"text", *it} });
201 keyboardArray.push_back(keyboardLineArray);
205 (*keyboardJson)[
"keyboard"] = keyboardArray;
207 (*keyboardJson)[
"resize_keyboard"] = autoResizeKeyboard;
208 (*keyboardJson)[
"one_time_keyboard"] = onTimeKeyboard;
210 extraObjects[
"reply_markup"] = keyboardJson;
223 if (!messageId.isValid() || messageId.isNull())
226 auto msg = QSharedPointer<TelegramEditMessage>::create(messageId,
228 prepareInlineKeyBoard(keyboard));
235 const QVariant &chatId,
237 const QString &callBackQueryId) {
238 if (!chatId.isValid() || chatId.isNull())
241 if (!messageId.isValid() || messageId.isNull())
244 auto msg = QSharedPointer<TelegramEditMessageReplyMarkup>::create(messageId,
245 TelegramArgs(chatId,
"", 0,
"html",
false, callBackQueryId),
246 prepareInlineKeyBoard(keyboard));
258 if (!messageId.isValid() || messageId.isNull())
261 if (args.
text.isEmpty())
264 auto msg = QSharedPointer<TelegramEditMessage>::create(messageId,
273 const QList<QList<QString> > &keyboard,
275 bool autoResizeKeyboard) {
280 if (args.
text.isEmpty()) {
284 return sendSpecificMessage(args, prepareKeyboard(autoResizeKeyboard, onTimeKeyboard, keyboard));
289 QSharedPointer<iFile> result =
nullptr;
291 if (fileId.isEmpty()) {
295 auto localFilePath = findFileInlocatStorage(fileId);
297 if (!localFilePath.isEmpty()) {
300 QFile localFile(localFilePath);
301 if (localFile.open(QIODevice::ReadOnly)) {
302 auto&& virtualFile = QSharedPointer<VirtualFile>::create(
nullptr);
303 virtualFile->setArray(localFile.readAll());
306 result = virtualFile;
310 result = QSharedPointer<File>::create(
nullptr, localFilePath);
313 result->setDownloadProgress(1);
314 result->setFinished(
true);
322 auto&& path = metaInfo->takePath();
324 auto&& msg = QSharedPointer<TelegrammDownloadFile>::create(path);
329 if (localFilePath.isEmpty())
335 result = QSharedPointer<VirtualFile>::create(replay);
337 result = QSharedPointer<File>::create(replay, localFilePath);
347 result = QSharedPointer<VirtualFile>::create();
349 result = QSharedPointer<File>::create(localFilePath);
352 auto&& metaReploay =
getFileMeta(fileId, result.toWeakRef());
357 auto msg = QSharedPointer<TelegramGetFile>::create(fileId);
360 connect(ptr.get(), &QNetworkReply::finished,
361 this, std::bind(&ITelegramBot::handleFileHeader,
this, ptr.toWeakRef(), receiver));
381 if (!file.isReadable()) {
386 QSharedPointer<TelegramSendPhoto>::create(args,
394 if (!fileName.size()) {
406 const QFileInfo &photo,
411 if (!photo.isReadable()) {
416 QSharedPointer<TelegramSendPhoto>::create(args,
418 prepareInlineKeyBoard(keyboard)), args.
msgIdCB);
422 const QByteArray &photo,
423 const QString &fileName,
430 if (!fileName.size()) {
439 QSharedPointer<TelegramSendPhoto>::create(args,
442 prepareInlineKeyBoard(keyboard)),
450 throw "the sendFileById is not implemented";
464 if (!(longitude && latitude)) {
471 prepareInlineKeyBoard(keyboard)));
475 const QString &phone,
476 const QString &firstName,
477 const QString &secondName) {
488 if (
auto && file = _filesMetaInfo.value(
id)) {
489 return file->fileSize();
496 return _filesMetaInfo.value(
id,
nullptr);
500 qWarning() << QString(
"code: %0 - %1").
501 arg(ansverWithError->errorCode()).
502 arg(ansverWithError->errorDescription());
511 if (
auto&& queryUpd = tupdate->callbackQueryUpdate()) {
512 auto &&handleButtonKey = queryUpd->callBackData();
514 if (
auto&& cb = _handleButtons.value(handleButtonKey)) {
515 cb(handleButtonKey, queryUpd->messageId());
522 const std::function<
void (
int)> &msgIdCB) {
525 connect(reply.get(), &QNetworkReply::finished,
this,
526 [ reply, msgIdCB,
this]() {
528 if (reply->error() == QNetworkReply::NoError) {
529 QByteArray&& responseData = reply->readAll();
530 QJsonDocument json = QJsonDocument::fromJson(responseData);
532 const QJsonObject&& obj = json.object();
533 if (obj.contains(
"result")) {
534 unsigned long long chatId = obj[
"result"][
"chat"][
"id"].toInteger();
535 int messageID = obj[
"result"][
"message_id"].toInt();
541 _lastMessageId[chatId] = messageID;
557void ITelegramBot::handleLogin() {
560 auto&& ans = makeMesasge<TelegramUpdateAnswer>(_loginReplay->readAll());
562 if (!ans->isValid()) {
563 qWarning() <<
"login error occured: ";
566 auto&& result = ans->result().toObject();
568 setId(result.value(
"id").toInteger());
569 setName( result.value(
"first_name").toString());
570 setUsername( result.value(
"username").toString());
572 _loginReplay.reset();
577void ITelegramBot::handleLoginErr(QNetworkReply::NetworkError err) {
579 qDebug() <<
"Network error occured. code: " << err;
581 _loginReplay.reset();
584void ITelegramBot::handleFileHeader(
const QWeakPointer<QNetworkReply> &sender,
585 const QWeakPointer<iFile>& receiver) {
586 if (
auto&& sharedPtr = sender.lock()) {
587 auto&& ansver = makeMesasge<TelegramUpdateAnswer>(sharedPtr->readAll());
589 if (!ansver->isValid()) {
590 onRequestError(ansver);
594 auto &&fileMetaInfo = makeMesasge<TelegramFile>(ansver->result().toObject());
596 _filesMetaInfo.insert(fileMetaInfo->fileId(), fileMetaInfo);
598 if (
auto&& sharedPtr = receiver.lock()) {
599 auto&& downloadRequest = QSharedPointer<TelegrammDownloadFile>::create(fileMetaInfo->takePath());
600 sharedPtr->setDownloadRequest(sendRequest(downloadRequest));
605QString ITelegramBot::findFileInlocatStorage(
const QString &fileId)
const {
606 QDir defaultFileDir(defaultFileStorageLocation());
608 auto &&localStorageList = defaultFileDir.entryInfoList(QDir::Filter::NoDotAndDotDot | QDir::Files);
609 for (
const auto& file: localStorageList) {
610 int size = file.size();
611 if (file.fileName().contains(fileId) && size && size == getFileSizeByUniqueId(fileId)) {
612 return file.absoluteFilePath();
619void ITelegramBot::setUsername(
const QString &newUsername) {
620 _username = newUsername;
623QString ITelegramBot::makeUrl(
const QSharedPointer<iRequest> &request)
const {
624 return request->baseAddress() +
"/bot" + token() + request->makeUpload();
627void ITelegramBot::setId(
unsigned long long newId) {
631const QString &ITelegramBot::username()
const {
635int ITelegramBot::gelLastMessageId(
unsigned long long &chatId)
const {
636 return _lastMessageId.value(chatId, 0);
639unsigned long long ITelegramBot::id()
const {
const QByteArray & token() const
token This is token value for authication on the remote server (bot)
virtual void handleIncomeNewUpdate(const QSharedPointer< iUpdate > &)
handleIncomeNewUpdate This method just emit the sigReceiveUpdate signal.
virtual QString defaultFileStorageLocation() const
defaultFileStorageLocation This method return default file storage location.
void setToken(const QByteArray &newToken)
setToken This is setter of the IBot::token value.
QSharedPointer< QNetworkReply > sendRequest(const QSharedPointer< iRequest > &rquest)
sendRequest This method sent custom requests to the server.
bool sendFile(const QFileInfo &file, const QVariant &chatId) override
send file .
bool sendMessage(const QVariant &chatId, const QString &text) override
sendMessage This method sents text to the selected chat.
bool sendFileById(const QString &fileID, const QVariant &chatId)
sendFileById This is specific method of the telegram bot. sents file by id.
QSharedPointer< QNetworkReply > getFileMeta(const QString &fileId, const QWeakPointer< iFile > &receiver={nullptr})
getFileMeta This method receive meta information of the file.
int getFileSizeByUniqueId(const QString &id) const
getFileSizeByUniqueId This method return size of the file by id
bool editMessageKeyboard(const QVariant &messageId, const QVariant &chatId, const KeyboardOnMessage &keyboard={}, const QString &callBackQueryId="")
Edits a keyboard of message in a chat.
QSharedPointer< TelegramFile > getFileInfoByUniqueId(const QString &id) const
getFileInfoByUniqueId return a local saved meta information about the file.
bool sendFileMessage(const TelegramArgs &args, const QFileInfo &file)
sendFileMessage This method sents a message with file.
virtual void onRequestError(const QSharedPointer< TelegramUpdateAnswer > &ansverWithError) const
onRequestError This method invokent when telegram server sent error responce. Default implementation ...
QSharedPointer< iFile > getFile(const QString &fileId, iFile::Type fileType=iFile::Type::Ram) override
Get a file by its ID.
bool editSpecificMessage(const QVariant &messageId, const TelegramArgs &args)
Edits a specific message in a chat.
bool sendSpecificMessageWithKeyboard(const TelegramArgs &args, const KeyboardOnMessage &keyboard)
Sends a specific message with a custom keyboard to a chat. This function sends a specific message to ...
void handleIncomeNewUpdate(const QSharedPointer< iUpdate > &) override
handleIncomeNewUpdate This method just emit the sigReceiveUpdate signal.
bool sendLocation(const TelegramArgs &args, float latitude, float longitude, const KeyboardOnMessage &keyboard={})
sendLocation This method sents locatin to user.
bool sendLocationRequest(const QVariant &chatId, const QString &text, const QString &buttonText, bool onetimeKeyboard)
sendLocationRequest This method setn into chat button that will automaticaly sent geo location to bot...
bool sendSelfContactRequest(const QVariant &chatId, const QString &text, const QString &buttonText, bool onetimeKeyboard)
sendSelfContactRequest This method sent into chat button that will automaticaly sent self contact inf...
virtual bool sendMessageRequest(const QSharedPointer< iRequest > &rquest, const std::function< void(int msgId)> &msgIdCB={})
sendMessageRequest This method invoke when bot will be sent eny messages into chat.
bool sendContact(const TelegramArgs &args, const QString &phone, const QString &firstName, const QString &secondName="")
sendContact This method sents a contact data.
bool sendPhoto(const TelegramArgs &args, const QFileInfo &photo, const KeyboardOnMessage &keyboard={})
sendPhoto This method will send image into chat with chatId
bool login(const QByteArray &token) override
login This method get bae information of the bot from remote server.
bool sendSpecificMessage(const TelegramArgs &args, const qTbot::ExtraJsonObjects &extraObjects={})
Sends a specific message to a chat.
bool deleteMessage(const QVariant &chatId, const QVariant &messageId) override
deleteMessage This is main method to delete messages.
bool editSpecificMessageWithKeyboard(const QVariant &messageId, const TelegramArgs &args, const QList< QList< QString > > &keyboard={}, bool onTimeKeyboard=false, bool autoResizeKeyboard=false)
Edits a specific message with a custom keyboard in a chat.
The TelegramUpdate class contains base information about updates from telegram.
Type
The Type enum is type of the file object.
@ Ram
This is memory saved file. All received bytes will be saved into QByteArray object.
@ Local
This is local file, all receive bytes will be save directed into file.
QHash< QString, QSharedPointer< QJsonObject > > ExtraJsonObjects
ExtraJsonObjects hash map of the extra objects of the message.
QList< QHash< QString, ButtonCB > > KeyboardOnMessage
The TelegramArgs class is base structure for the all tellegram message arguments.
std::function< void(int msgId)> msgIdCB
msgIdCB This is id message call bak function. Will be inwoked when request finished successful.
QVariant chatId
Chat ID where the message will be sent. Default: {}.
QString text
Text of the message. Default: "".