mirror of
https://github.com/moritzsternemann/QtTelegramBot.git
synced 2025-06-25 02:31:33 +02:00
Initial commit
This commit is contained in:
36
.gitignore
vendored
Normal file
36
.gitignore
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
### Qt ###
|
||||
# C++ objects and libs
|
||||
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.a
|
||||
*.la
|
||||
*.lai
|
||||
*.so
|
||||
*.dll
|
||||
*.dylib
|
||||
|
||||
# Qt-es
|
||||
|
||||
/.qmake.cache
|
||||
/.qmake.stash
|
||||
*.pro.user
|
||||
*.pro.user.*
|
||||
*.qbs.user
|
||||
*.qbs.user.*
|
||||
*.moc
|
||||
moc_*.cpp
|
||||
qrc_*.cpp
|
||||
ui_*.h
|
||||
Makefile*
|
||||
*-build-*
|
||||
|
||||
# QtCreator
|
||||
|
||||
*.autosave
|
||||
|
||||
#QtCtreator Qml
|
||||
*.qmlproject.user
|
||||
*.qmlproject.user.*
|
||||
**/bin
|
22
LICENSE
Normal file
22
LICENSE
Normal file
@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Moritz Sternemann
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
43
QtTelegramBot.pri
Normal file
43
QtTelegramBot.pri
Normal file
@ -0,0 +1,43 @@
|
||||
INCLUDEPATH += $$PWD
|
||||
|
||||
QT += core network
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/qttelegrambot.cpp \
|
||||
$$PWD/networking.cpp \
|
||||
$$PWD/types/message.cpp \
|
||||
$$PWD/types/update.cpp \
|
||||
$$PWD/types/chat.cpp \
|
||||
$$PWD/types/user.cpp \
|
||||
$$PWD/types/document.cpp \
|
||||
$$PWD/types/photosize.cpp \
|
||||
$$PWD/types/audio.cpp \
|
||||
$$PWD/types/sticker.cpp \
|
||||
$$PWD/types/video.cpp \
|
||||
$$PWD/types/voice.cpp \
|
||||
$$PWD/types/contact.cpp \
|
||||
$$PWD/types/location.cpp
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/qttelegrambot.h \
|
||||
$$PWD/networking.h \
|
||||
$$PWD/types/message.h \
|
||||
$$PWD/types/update.h \
|
||||
$$PWD/types/chat.h \
|
||||
$$PWD/types/user.h \
|
||||
$$PWD/types/file.h \
|
||||
$$PWD/types/document.h \
|
||||
$$PWD/types/photosize.h \
|
||||
$$PWD/types/audio.h \
|
||||
$$PWD/types/sticker.h \
|
||||
$$PWD/types/video.h \
|
||||
$$PWD/types/voice.h \
|
||||
$$PWD/types/contact.h \
|
||||
$$PWD/types/location.h \
|
||||
$$PWD/types/reply/genericreply.h \
|
||||
$$PWD/types/reply/replykeyboardmarkup.h \
|
||||
$$PWD/types/reply/replykeyboardhide.h \
|
||||
$$PWD/types/reply/forcereply.h
|
||||
|
||||
OTHER_FILES += \
|
||||
$$PWD/README.md
|
27
README.md
Normal file
27
README.md
Normal file
@ -0,0 +1,27 @@
|
||||
## Introduction
|
||||
Qt5 library for the Telegram Bot API ([https://core.telegram.org/bots/api]()).
|
||||
It can be used to interact with the API directly and/or configured to automatically notify you on updates using Qt’s signals and slots.
|
||||
You need a bot token to make API calls. Text the [@botfather](https://telegram.me/BotFather) to create a new bot and obtain a token.
|
||||
|
||||
## Usage
|
||||
Create a lib directory in your project directory and cd into it:
|
||||
mkdir lib && cd lib
|
||||
|
||||
Clone the repo to your projects source directory:
|
||||
git clone https://github.com/iMoritz/QtTelegramBot.git
|
||||
|
||||
Alternatively you can add QtTelegramBot as a git submodule to always stay up-to-date:
|
||||
git submodule add https://github.com/iMoritz/QtTelegramBot.git
|
||||
|
||||
In your project file (*project*.pro) add this include:
|
||||
include($$PWD/lib/QtTelegramBot/QtTelegramBot.pri)
|
||||
|
||||
Now you can use the Bot classes using:
|
||||
#include "qttelegrambot.h"
|
||||
|
||||
|
||||
Everything in *QtTelegramBot* is in the `Telegram` namespace.
|
||||
|
||||
|
||||
## Examples
|
||||
Examples can be found in the `examples` directory. You can build them in QtCreator or using the command line.
|
73
examples/echo/.gitignore
vendored
Normal file
73
examples/echo/.gitignore
vendored
Normal file
@ -0,0 +1,73 @@
|
||||
# This file is used to ignore files which are generated
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
*~
|
||||
*.autosave
|
||||
*.a
|
||||
*.core
|
||||
*.moc
|
||||
*.o
|
||||
*.obj
|
||||
*.orig
|
||||
*.rej
|
||||
*.so
|
||||
*.so.*
|
||||
*_pch.h.cpp
|
||||
*_resource.rc
|
||||
*.qm
|
||||
.#*
|
||||
*.*#
|
||||
core
|
||||
!core/
|
||||
tags
|
||||
.DS_Store
|
||||
*.debug
|
||||
Makefile*
|
||||
*.prl
|
||||
*.app
|
||||
moc_*.cpp
|
||||
ui_*.h
|
||||
qrc_*.cpp
|
||||
Thumbs.db
|
||||
*.res
|
||||
*.rc
|
||||
/.qmake.cache
|
||||
/.qmake.stash
|
||||
|
||||
# qtcreator generated files
|
||||
*.pro.user*
|
||||
|
||||
# xemacs temporary files
|
||||
*.flc
|
||||
|
||||
# Vim temporary files
|
||||
.*.swp
|
||||
|
||||
# Visual Studio generated files
|
||||
*.ib_pdb_index
|
||||
*.idb
|
||||
*.ilk
|
||||
*.pdb
|
||||
*.sln
|
||||
*.suo
|
||||
*.vcproj
|
||||
*vcproj.*.*.user
|
||||
*.ncb
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.vcxproj
|
||||
*vcxproj.*
|
||||
|
||||
# MinGW generated files
|
||||
*.Debug
|
||||
*.Release
|
||||
|
||||
# Python byte code
|
||||
*.pyc
|
||||
|
||||
# Binaries
|
||||
# --------
|
||||
*.dll
|
||||
*.exe
|
||||
|
||||
|
12
examples/echo/echo.pro
Normal file
12
examples/echo/echo.pro
Normal file
@ -0,0 +1,12 @@
|
||||
QT += core
|
||||
QT -= gui
|
||||
|
||||
TARGET = echo
|
||||
CONFIG += console
|
||||
CONFIG -= app_bundle
|
||||
|
||||
TEMPLATE = app
|
||||
|
||||
SOURCES += main.cpp
|
||||
|
||||
include(../../QtTelegramBot.pri)
|
27
examples/echo/main.cpp
Normal file
27
examples/echo/main.cpp
Normal file
@ -0,0 +1,27 @@
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
#include "qttelegrambot.h"
|
||||
|
||||
#define TOKEN "YOUR BOT TOKEN"
|
||||
|
||||
Telegram::Bot *bot;
|
||||
|
||||
void newMessage(Telegram::Message message)
|
||||
{
|
||||
qDebug() << "new message:" << message;
|
||||
|
||||
if (bot && message.type == Telegram::Message::TextType) {
|
||||
bot->sendMessage(message.from.id, message.string);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication a(argc, argv);
|
||||
|
||||
bot = new Telegram::Bot(TOKEN, false, 500, 4);
|
||||
QObject::connect(bot, &Telegram::Bot::message, &newMessage);
|
||||
qDebug() << "Started Telegram Bot";
|
||||
|
||||
return a.exec();
|
||||
}
|
3
examples/examples.pro
Normal file
3
examples/examples.pro
Normal file
@ -0,0 +1,3 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS += \
|
||||
echo
|
157
networking.cpp
Normal file
157
networking.cpp
Normal file
@ -0,0 +1,157 @@
|
||||
#include "networking.h"
|
||||
|
||||
using namespace Telegram;
|
||||
|
||||
Networking::Networking(QString token, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_nam(new QNetworkAccessManager(this)),
|
||||
m_token(token)
|
||||
{
|
||||
}
|
||||
|
||||
Networking::~Networking()
|
||||
{
|
||||
delete m_nam;
|
||||
}
|
||||
|
||||
QByteArray Networking::request(QString endpoint, ParameterList params, Networking::Method method)
|
||||
{
|
||||
if (endpoint.isEmpty()) {
|
||||
qWarning("Cannot do request without endpoint");
|
||||
return QByteArray();
|
||||
}
|
||||
if (m_token.isEmpty()) {
|
||||
qWarning("Cannot do request without a Telegram Bot Token");
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QNetworkRequest req;
|
||||
QUrl url = buildUrl(endpoint);
|
||||
req.setUrl(url);
|
||||
|
||||
#ifdef DEBUG
|
||||
qDebug("HTTP request: %s", qUtf8Printable(req.url().toString()));
|
||||
#endif
|
||||
|
||||
QEventLoop loop;
|
||||
|
||||
QNetworkReply *reply;
|
||||
|
||||
if (method == GET) {
|
||||
url.setQuery(parameterListToString(params));
|
||||
req.setUrl(url);
|
||||
reply = m_nam->get(req);
|
||||
} else if (method == POST) {
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
reply = m_nam->post(req, parameterListToString(params));
|
||||
} else if (method == UPLOAD) {
|
||||
QByteArray boundary = generateMultipartBoundary(params);
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary=" + boundary);
|
||||
QByteArray requestData = generateMultipartFormData(params, boundary);
|
||||
req.setHeader(QNetworkRequest::ContentLengthHeader, requestData.length());
|
||||
reply = m_nam->post(req, requestData);
|
||||
} else {
|
||||
qCritical("No valid method!");
|
||||
reply = NULL;
|
||||
}
|
||||
|
||||
if (reply == NULL) {
|
||||
qWarning("Reply is NULL");
|
||||
delete reply;
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QObject::connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
loop.exec();
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
qCritical("%s", qPrintable(QString("[%1] %2").arg(reply->error()).arg(reply->errorString())));
|
||||
delete reply;
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
QByteArray ret = reply->readAll();
|
||||
delete reply;
|
||||
return ret;
|
||||
}
|
||||
|
||||
QUrl Networking::buildUrl(QString endpoint)
|
||||
{
|
||||
QUrl url = QUrl();
|
||||
url.setScheme("https");
|
||||
url.setHost(API_HOST);
|
||||
url.setPath("/bot" + m_token + endpoint);
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
QByteArray Networking::parameterListToString(ParameterList list)
|
||||
{
|
||||
QByteArray ret;
|
||||
|
||||
ParameterList::iterator i = list.begin();
|
||||
while (i != list.end()) {
|
||||
ret.append(i.key() + "=" + i.value().value + "&");
|
||||
++i;
|
||||
}
|
||||
ret = ret.left(ret.length() - 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QByteArray Networking::generateMultipartBoundary(ParameterList list)
|
||||
{
|
||||
// Generates a boundary that is not existent in the data
|
||||
QByteArray result;
|
||||
|
||||
srand((unsigned int) time(NULL));
|
||||
ParameterList::iterator i = list.begin();
|
||||
while (i != list.end()) {
|
||||
if (i.value().isFile) {
|
||||
while (result.isEmpty() || i.value().value.contains(result)) {
|
||||
result.append(generateRandomString(4));
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QByteArray Networking::generateMultipartFormData(ParameterList list, QByteArray boundary)
|
||||
{
|
||||
QByteArray result;
|
||||
|
||||
ParameterList::iterator i = list.begin();
|
||||
while (i != list.end()) {
|
||||
HttpParameter param = i.value();
|
||||
result.append("--" + boundary + "\r\n");
|
||||
result.append("Content-Disposition: form-data; name=\"" + i.key());
|
||||
if (param.isFile) {
|
||||
result.append("\"; filename=\"" + param.filename);
|
||||
}
|
||||
result.append("\"\r\n");
|
||||
if (param.isFile) {
|
||||
result.append("Content-Type: " + param.mimeType + "\r\n");
|
||||
}
|
||||
result.append("\r\n");
|
||||
result.append(param.value);
|
||||
result.append("\r\n");
|
||||
|
||||
++i;
|
||||
}
|
||||
result.append("--" + boundary + "--");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QString Networking::generateRandomString(int length)
|
||||
{
|
||||
static const std::string chars("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890-=[]\\;',./!@#$%^&*()_+{}|:\"<>?`~");
|
||||
static const size_t charsLen = chars.length();
|
||||
QString result;
|
||||
for (int i = 0; i < length; ++i) {
|
||||
result += QChar(chars[rand() % charsLen]);
|
||||
}
|
||||
return result;
|
||||
}
|
69
networking.h
Normal file
69
networking.h
Normal file
@ -0,0 +1,69 @@
|
||||
#ifndef NETWORKING_H
|
||||
#define NETWORKING_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QEventLoop>
|
||||
|
||||
#define API_HOST "api.telegram.org"
|
||||
|
||||
#define ENDPOINT_GET_ME "/getMe"
|
||||
#define ENDPOINT_SEND_MESSAGE "/sendMessage"
|
||||
#define ENDPOINT_FORWARD_MESSAGE "/forwardMessage"
|
||||
#define ENDPOINT_SEND_PHOTO "/sendPhoto"
|
||||
#define ENDPOINT_SEND_AUDIO "/sendAudio"
|
||||
#define ENDPOINT_SEND_DOCUMENT "/sendDocument"
|
||||
#define ENDPOINT_SEND_STICKER "/sendSticker"
|
||||
#define ENDPOINT_SEND_VIDEO "/sendVideo"
|
||||
#define ENDPOINT_SEND_VOICE "/sendVoice"
|
||||
#define ENDPOINT_SEND_LOCATION "/sendLocation"
|
||||
#define ENDPOINT_SEND_CHAT_ACTION "/sendChatAction"
|
||||
#define ENDPOINT_GET_USER_PROFILE_PHOTOS "/getUserProfilePhotos"
|
||||
#define ENDPOINT_GET_UPDATES "/getUpdates"
|
||||
#define ENDPOINT_SET_WEBHOOK "/setWebhook"
|
||||
#define ENDPOINT_GET_FILE "/getFile"
|
||||
|
||||
namespace Telegram {
|
||||
|
||||
class HttpParameter {
|
||||
public:
|
||||
HttpParameter() {}
|
||||
HttpParameter(QVariant value, bool isFile = false, QString mimeType = "text/plain", QString filename = "") :
|
||||
value(value.toByteArray()), isFile(isFile), mimeType(mimeType), filename(filename) {}
|
||||
|
||||
QByteArray value;
|
||||
bool isFile;
|
||||
QString mimeType;
|
||||
QString filename;
|
||||
};
|
||||
|
||||
typedef QMap<QString, HttpParameter> ParameterList;
|
||||
|
||||
class Networking : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
Networking(QString token, QObject *parent = 0);
|
||||
~Networking();
|
||||
|
||||
enum Method { GET, POST, UPLOAD };
|
||||
|
||||
QByteArray request(QString endpoint, ParameterList params, Method method);
|
||||
|
||||
private:
|
||||
QNetworkAccessManager *m_nam;
|
||||
QString m_token;
|
||||
|
||||
QUrl buildUrl(QString endpoint);
|
||||
QByteArray parameterListToString(ParameterList list);
|
||||
|
||||
QByteArray generateMultipartBoundary(ParameterList list);
|
||||
QByteArray generateMultipartFormData(ParameterList list, QByteArray boundary);
|
||||
QString generateRandomString(int length);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // NETWORKING_H
|
402
qttelegrambot.cpp
Normal file
402
qttelegrambot.cpp
Normal file
@ -0,0 +1,402 @@
|
||||
#include "qttelegrambot.h"
|
||||
|
||||
using namespace Telegram;
|
||||
|
||||
Bot::Bot(QString token, bool updates, quint32 updateInterval, quint32 pollingTimeout, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_net(new Networking(token)),
|
||||
m_internalUpdateTimer(new QTimer(this)),
|
||||
m_updateInterval(updateInterval),
|
||||
m_pollingTimeout(pollingTimeout)
|
||||
{
|
||||
QLoggingCategory::setFilterRules("qt.network.ssl.warning=false");
|
||||
|
||||
if (updates) {
|
||||
m_internalUpdateTimer->setSingleShot(true);
|
||||
connect(m_internalUpdateTimer, &QTimer::timeout, this, &Bot::internalGetUpdates);
|
||||
internalGetUpdates();
|
||||
}
|
||||
}
|
||||
|
||||
Bot::~Bot()
|
||||
{
|
||||
delete m_net;
|
||||
}
|
||||
|
||||
User Bot::getMe()
|
||||
{
|
||||
QJsonObject json = this->jsonObjectFromByteArray(
|
||||
m_net->request(ENDPOINT_GET_ME, ParameterList(), Networking::GET));
|
||||
|
||||
User ret;
|
||||
ret.id = json.value("id").toInt();
|
||||
ret.firstname = json.value("first_name").toString();
|
||||
ret.lastname = json.value("last_name").toString();
|
||||
ret.username = json.value("username").toString();
|
||||
|
||||
if (ret.id == 0 || ret.firstname.isEmpty()) {
|
||||
qCritical("%s", qPrintable("Got invalid user in " + QString(ENDPOINT_GET_ME)));
|
||||
return User();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Bot::sendMessage(QVariant chatId, QString text, bool markdown, bool disableWebPagePreview, qint32 replyToMessageId, const GenericReply &replyMarkup)
|
||||
{
|
||||
ParameterList params;
|
||||
if (markdown) params.insert("parse_mode", HttpParameter("Markdown"));
|
||||
if (disableWebPagePreview) params.insert("disable_web_page_preview", HttpParameter(disableWebPagePreview));
|
||||
|
||||
return this->_sendPayload(chatId, text, ParameterList(), replyToMessageId, replyMarkup, "text", ENDPOINT_SEND_MESSAGE);
|
||||
}
|
||||
|
||||
bool Bot::forwardMessage(QVariant chatId, quint32 fromChatId, quint32 messageId)
|
||||
{
|
||||
if (chatId.type() != QVariant::String && chatId.type() != QVariant::Int) {
|
||||
qCritical("Please provide a QString or int as chatId");
|
||||
return false;
|
||||
}
|
||||
ParameterList params;
|
||||
params.insert("chat_id", HttpParameter(chatId));
|
||||
params.insert("from_chat_id", HttpParameter(fromChatId));
|
||||
params.insert("message_id", HttpParameter(messageId));
|
||||
|
||||
bool success = this->responseOk(m_net->request(ENDPOINT_FORWARD_MESSAGE, params, Networking::POST));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool Bot::sendPhoto(QVariant chatId, QFile *file, QString caption, qint32 replyToMessageId, const GenericReply &replyMarkup)
|
||||
{
|
||||
ParameterList params;
|
||||
if (!caption.isEmpty()) params.insert("caption", HttpParameter(caption));
|
||||
|
||||
return this->_sendPayload(chatId, file, params, replyToMessageId, replyMarkup, "photo", ENDPOINT_SEND_PHOTO);
|
||||
}
|
||||
|
||||
bool Bot::sendPhoto(QVariant chatId, QString fileId, QString caption, qint32 replyToMessageId, const GenericReply &replyMarkup)
|
||||
{
|
||||
ParameterList params;
|
||||
if (!caption.isEmpty()) params.insert("caption", HttpParameter(caption));
|
||||
|
||||
return this->_sendPayload(chatId, fileId, params, replyToMessageId, replyMarkup, "photo", ENDPOINT_SEND_PHOTO);
|
||||
}
|
||||
|
||||
bool Bot::sendAudio(QVariant chatId, QFile *file, qint64 duration, QString performer, QString title, qint32 replyToMessageId, const GenericReply &replyMarkup)
|
||||
{
|
||||
ParameterList params;
|
||||
if (duration >= 0) params.insert("duration", HttpParameter(duration));
|
||||
if (!performer.isEmpty()) params.insert("performer", HttpParameter(performer));
|
||||
if (!title.isEmpty()) params.insert("title", HttpParameter(title));
|
||||
|
||||
return this->_sendPayload(chatId, file, params, replyToMessageId, replyMarkup, "audio", ENDPOINT_SEND_AUDIO);
|
||||
}
|
||||
|
||||
bool Bot::sendAudio(QVariant chatId, QString fileId, qint64 duration, QString performer, QString title, qint32 replyToMessageId, const GenericReply &replyMarkup)
|
||||
{
|
||||
ParameterList params;
|
||||
if (duration >= 0) params.insert("duration", HttpParameter(duration));
|
||||
if (!performer.isEmpty()) params.insert("performer", HttpParameter(performer));
|
||||
if (!title.isEmpty()) params.insert("title", HttpParameter(title));
|
||||
|
||||
return this->_sendPayload(chatId, fileId, params, replyToMessageId, replyMarkup, "audio", ENDPOINT_SEND_AUDIO);
|
||||
}
|
||||
|
||||
bool Bot::sendDocument(QVariant chatId, QFile *file, qint32 replyToMessageId, const GenericReply &replyMarkup)
|
||||
{
|
||||
return this->_sendPayload(chatId, file, ParameterList(), replyToMessageId, replyMarkup, "document", ENDPOINT_SEND_DOCUMENT);
|
||||
}
|
||||
|
||||
bool Bot::sendDocument(QVariant chatId, QString fileId, qint32 replyToMessageId, const GenericReply &replyMarkup)
|
||||
{
|
||||
return this->_sendPayload(chatId, fileId, ParameterList(), replyToMessageId, replyMarkup, "document", ENDPOINT_SEND_DOCUMENT);
|
||||
}
|
||||
|
||||
bool Bot::sendSticker(QVariant chatId, QFile *file, qint32 replyToMessageId, const GenericReply &replyMarkup)
|
||||
{
|
||||
return this->_sendPayload(chatId, file, ParameterList(), replyToMessageId, replyMarkup, "sticker", ENDPOINT_SEND_STICKER);
|
||||
}
|
||||
|
||||
bool Bot::sendSticker(QVariant chatId, QString fileId, qint32 replyToMessageId, const GenericReply &replyMarkup)
|
||||
{
|
||||
return this->_sendPayload(chatId, fileId, ParameterList(), replyToMessageId, replyMarkup, "sticker", ENDPOINT_SEND_STICKER);
|
||||
}
|
||||
|
||||
bool Bot::sendVideo(QVariant chatId, QFile *file, qint64 duration, QString caption, qint32 replyToMessageId, const GenericReply &replyMarkup)
|
||||
{
|
||||
ParameterList params;
|
||||
params.insert("duration", HttpParameter(duration));
|
||||
params.insert("caption", HttpParameter(caption));
|
||||
|
||||
return this->_sendPayload(chatId, file, params, replyToMessageId, replyMarkup, "video", ENDPOINT_SEND_VIDEO);
|
||||
}
|
||||
|
||||
bool Bot::sendVideo(QVariant chatId, QString fileId, qint64 duration, QString caption, qint32 replyToMessageId, const GenericReply &replyMarkup)
|
||||
{
|
||||
ParameterList params;
|
||||
params.insert("duration", HttpParameter(duration));
|
||||
params.insert("caption", HttpParameter(caption));
|
||||
|
||||
return this->_sendPayload(chatId, fileId, params, replyToMessageId, replyMarkup, "video", ENDPOINT_SEND_VIDEO);
|
||||
}
|
||||
|
||||
bool Bot::sendVoice(QVariant chatId, QFile *file, qint64 duration, qint32 replyToMessageId, const GenericReply &replyMarkup)
|
||||
{
|
||||
ParameterList params;
|
||||
params.insert("duration", HttpParameter(duration));
|
||||
|
||||
return this->_sendPayload(chatId, file, params, replyToMessageId, replyMarkup, "voice", ENDPOINT_SEND_VOICE);
|
||||
}
|
||||
|
||||
bool Bot::sendVoice(QVariant chatId, QString fileId, qint64 duration, qint32 replyToMessageId, const GenericReply &replyMarkup)
|
||||
{
|
||||
ParameterList params;
|
||||
params.insert("duration", HttpParameter(duration));
|
||||
|
||||
return this->_sendPayload(chatId, fileId, params, replyToMessageId, replyMarkup, "voice", ENDPOINT_SEND_VOICE);
|
||||
}
|
||||
|
||||
bool Bot::sendLocation(QVariant chatId, float latitude, float longitude, qint32 replyToMessageId, const GenericReply &replyMarkup)
|
||||
{
|
||||
Q_UNUSED(replyMarkup); // TODO
|
||||
if (chatId.type() != QVariant::String && chatId.type() != QVariant::Int) {
|
||||
qCritical("Please provide a QString or int as chatId");
|
||||
return false;
|
||||
}
|
||||
ParameterList params;
|
||||
params.insert("chat_id", HttpParameter(chatId));
|
||||
params.insert("latitude", HttpParameter(latitude));
|
||||
params.insert("longitude", HttpParameter(longitude));
|
||||
if (replyToMessageId >= 0) params.insert("reply_to_message_id", HttpParameter(replyToMessageId));
|
||||
|
||||
bool success = this->responseOk(m_net->request(ENDPOINT_SEND_LOCATION, params, Networking::POST));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool Bot::sendChatAction(QVariant chatId, Bot::ChatAction action)
|
||||
{
|
||||
if (chatId.type() != QVariant::String && chatId.type() != QVariant::Int) {
|
||||
qCritical("Please provide a QString or int as chatId");
|
||||
return false;
|
||||
}
|
||||
|
||||
ParameterList params;
|
||||
params.insert("chat_id", HttpParameter(chatId));
|
||||
switch (action) {
|
||||
case Typing:
|
||||
params.insert("action", HttpParameter("typing"));
|
||||
break;
|
||||
case UploadingPhoto:
|
||||
params.insert("action", HttpParameter("upload_photo"));
|
||||
break;
|
||||
case RecordingVideo:
|
||||
params.insert("action", HttpParameter("record_video"));
|
||||
break;
|
||||
case UploadingVideo:
|
||||
params.insert("action", HttpParameter("upload_video"));
|
||||
break;
|
||||
case RecordingAudio:
|
||||
params.insert("action", HttpParameter("record_audio"));
|
||||
break;
|
||||
case UploadingAudio:
|
||||
params.insert("action", HttpParameter("upload_audio"));
|
||||
break;
|
||||
case UploadingDocument:
|
||||
params.insert("action", HttpParameter("upload_document"));
|
||||
break;
|
||||
case FindingLocation:
|
||||
params.insert("action", HttpParameter("find_location"));
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool success = this->responseOk(m_net->request(ENDPOINT_SEND_CHAT_ACTION, params, Networking::POST));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
UserProfilePhotos Bot::getUserProfilePhotos(quint32 userId, qint16 offset, qint8 limit)
|
||||
{
|
||||
ParameterList params;
|
||||
params.insert("user_id", HttpParameter(userId));
|
||||
if (offset > -1) params.insert("offset", HttpParameter(offset));
|
||||
if (limit > -1) params.insert("limit", HttpParameter(limit));
|
||||
|
||||
QJsonObject json = this->jsonObjectFromByteArray(m_net->request(ENDPOINT_GET_USER_PROFILE_PHOTOS, params, Networking::GET));
|
||||
|
||||
UserProfilePhotos ret;
|
||||
|
||||
QList<PhotoSize> photo;
|
||||
foreach (QJsonValue val, json.value("photos").toArray()) {
|
||||
photo = QList<PhotoSize>();
|
||||
|
||||
foreach (QJsonValue p, val.toArray()) {
|
||||
PhotoSize ps;
|
||||
ps.fileId = p.toObject().value("file_id").toString();
|
||||
ps.width = p.toObject().value("width").toInt();
|
||||
ps.height = p.toObject().value("height").toInt();
|
||||
if (p.toObject().contains("file_size")) ps.fileSize = p.toObject().value("file_size").toInt();
|
||||
photo.append(ps);
|
||||
}
|
||||
|
||||
ret.append(photo);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QList<Update> Bot::getUpdates(quint32 timeout, quint32 limit, quint32 offset)
|
||||
{
|
||||
ParameterList params;
|
||||
params.insert("offset", HttpParameter(offset));
|
||||
params.insert("limit", HttpParameter(limit));
|
||||
params.insert("timeout", HttpParameter(timeout));
|
||||
QJsonArray json = this->jsonArrayFromByteArray(m_net->request(ENDPOINT_GET_UPDATES, params, Networking::GET));
|
||||
|
||||
QList<Update> ret = QList<Update>();
|
||||
foreach (QJsonValue value, json) {
|
||||
ret.append(Update(value.toObject()));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Bot::setWebhook(QString url, QFile *certificate)
|
||||
{
|
||||
ParameterList params;
|
||||
params.insert("url", HttpParameter(url));
|
||||
|
||||
QMimeDatabase db;
|
||||
bool openedFile = false;
|
||||
if (!certificate->isOpen()) {
|
||||
if (!certificate->open(QFile::ReadOnly)) {
|
||||
qCritical("Could not open file %s [%s]", qPrintable(certificate->fileName()), qPrintable(certificate->errorString()));
|
||||
return false;
|
||||
}
|
||||
openedFile = true;
|
||||
}
|
||||
QByteArray data = certificate->readAll();
|
||||
if (openedFile) certificate->close();
|
||||
params.insert("certificate", HttpParameter(data, true, db.mimeTypeForData(data).name(), certificate->fileName()));
|
||||
|
||||
bool success = this->responseOk(m_net->request(ENDPOINT_SET_WEBHOOK, params, Networking::UPLOAD));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
File Bot::getFile(QString fileId)
|
||||
{
|
||||
ParameterList params;
|
||||
params.insert("file_id", HttpParameter(fileId));
|
||||
|
||||
QJsonObject json = this->jsonObjectFromByteArray(m_net->request(ENDPOINT_GET_FILE, params, Networking::GET));
|
||||
|
||||
return File(json.value("file_id").toString(), json.value("file_size").toInt(-1), json.value("file_path").toString());
|
||||
}
|
||||
|
||||
bool Bot::_sendPayload(QVariant chatId, QFile *filePayload, ParameterList params, qint32 replyToMessageId, const GenericReply &replyMarkup, QString payloadField, QString endpoint)
|
||||
{
|
||||
if (chatId.type() != QVariant::String && chatId.type() != QVariant::Int) {
|
||||
qCritical("Please provide a QString or int as chatId");
|
||||
return false;
|
||||
}
|
||||
|
||||
params.insert("chat_id", HttpParameter(chatId));
|
||||
|
||||
QMimeDatabase db;
|
||||
bool openedFile = false;
|
||||
if (!filePayload->isOpen()) {
|
||||
if (!filePayload->open(QFile::ReadOnly)) {
|
||||
qCritical("Could not open file %s [%s]", qPrintable(filePayload->fileName()), qPrintable(filePayload->errorString()));
|
||||
return false;
|
||||
}
|
||||
openedFile = true;
|
||||
}
|
||||
QByteArray data = filePayload->readAll();
|
||||
if (openedFile) filePayload->close();
|
||||
params.insert(payloadField, HttpParameter(data, true, db.mimeTypeForData(data).name(), filePayload->fileName()));
|
||||
|
||||
if (replyToMessageId >= 0) params.insert("reply_to_message_id", HttpParameter(replyToMessageId));
|
||||
if (replyMarkup.isValid()) params.insert("reply_markup", HttpParameter(replyMarkup.serialize()));
|
||||
|
||||
bool success = this->responseOk(m_net->request(endpoint, params, Networking::UPLOAD));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool Bot::_sendPayload(QVariant chatId, QString textPayload, ParameterList params, qint32 replyToMessageId, const GenericReply &replyMarkup, QString payloadField, QString endpoint)
|
||||
{
|
||||
if (chatId.type() != QVariant::String && chatId.type() != QVariant::Int) {
|
||||
qCritical("Please provide a QString or int as chatId");
|
||||
return false;
|
||||
}
|
||||
params.insert("chat_id", HttpParameter(chatId));
|
||||
params.insert(payloadField, HttpParameter(textPayload));
|
||||
if (replyToMessageId >= 0) params.insert("reply_to_message_id", HttpParameter(replyToMessageId));
|
||||
if (replyMarkup.isValid()) params.insert("reply_markup", HttpParameter(replyMarkup.serialize()));
|
||||
|
||||
bool success = this->responseOk(m_net->request(endpoint, params, Networking::POST));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
QJsonObject Bot::jsonObjectFromByteArray(QByteArray json)
|
||||
{
|
||||
QJsonDocument d = QJsonDocument::fromJson(json);
|
||||
QJsonObject obj = d.object();
|
||||
|
||||
if (obj.isEmpty()) {
|
||||
qCritical("Got an empty response object");
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (obj.value("ok").toBool() != true) {
|
||||
qWarning("Result is not Ok");
|
||||
return obj;
|
||||
}
|
||||
|
||||
return obj.value("result").toObject();
|
||||
}
|
||||
|
||||
QJsonArray Bot::jsonArrayFromByteArray(QByteArray json)
|
||||
{
|
||||
QJsonDocument d = QJsonDocument::fromJson(json);
|
||||
QJsonObject obj = d.object();
|
||||
|
||||
if (obj.isEmpty()) {
|
||||
qCritical("Got an empty response object");
|
||||
return QJsonArray();
|
||||
}
|
||||
|
||||
if (obj.value("ok").toBool() != true) {
|
||||
qWarning("Result is not Ok");
|
||||
return QJsonArray();
|
||||
}
|
||||
|
||||
return obj.value("result").toArray();
|
||||
}
|
||||
|
||||
bool Bot::responseOk(QByteArray json)
|
||||
{
|
||||
QJsonDocument d = QJsonDocument::fromJson(json);
|
||||
QJsonObject obj = d.object();
|
||||
|
||||
return (!obj.isEmpty() && obj.value("ok").toBool() == true);
|
||||
}
|
||||
|
||||
void Bot::internalGetUpdates()
|
||||
{
|
||||
QList<Update> updates = getUpdates(m_pollingTimeout, 50, m_updateOffset);
|
||||
|
||||
foreach (Update u, updates) {
|
||||
// change updateOffset to u.id to avoid duplicate updates
|
||||
m_updateOffset = (u.id >= m_updateOffset ? u.id + 1 : m_updateOffset);
|
||||
|
||||
emit message(u.message);
|
||||
}
|
||||
|
||||
m_internalUpdateTimer->start(m_updateInterval);
|
||||
}
|
309
qttelegrambot.h
Normal file
309
qttelegrambot.h
Normal file
@ -0,0 +1,309 @@
|
||||
#ifndef QTTELEGRAMBOT_H
|
||||
#define QTTELEGRAMBOT_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QLoggingCategory>
|
||||
#include <QUrl>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QHttpPart>
|
||||
#include <QEventLoop>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
#include <QFile>
|
||||
#include <QMimeDatabase>
|
||||
#include <QTimer>
|
||||
|
||||
#include "networking.h"
|
||||
#include "types/chat.h"
|
||||
#include "types/update.h"
|
||||
#include "types/user.h"
|
||||
#include "types/file.h"
|
||||
#include "types/message.h"
|
||||
#include "types/reply/genericreply.h"
|
||||
#include "types/reply/replykeyboardmarkup.h"
|
||||
#include "types/reply/replykeyboardhide.h"
|
||||
#include "types/reply/forcereply.h"
|
||||
|
||||
namespace Telegram {
|
||||
|
||||
typedef QList<QList<PhotoSize> > UserProfilePhotos;
|
||||
|
||||
class Bot : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Bot constructor
|
||||
* @param token
|
||||
* @param updates - enable automatic update polling
|
||||
* @param updateInterval - interval between update polls in msec
|
||||
* @param pollingTimeout - timeout in sec
|
||||
* @param parent
|
||||
*/
|
||||
explicit Bot(QString token, bool updates = false, quint32 updateInterval = 1000, quint32 pollingTimeout = 0, QObject *parent = 0);
|
||||
~Bot();
|
||||
|
||||
enum ChatAction { Typing, UploadingPhoto, RecordingVideo, UploadingVideo, RecordingAudio, UploadingAudio, UploadingDocument, FindingLocation };
|
||||
|
||||
/**
|
||||
* Returns basic information about the bot in form of a `User` object.
|
||||
* @return User Object
|
||||
* @see https://core.telegram.org/bots/api#getme
|
||||
*/
|
||||
User getMe();
|
||||
|
||||
/**
|
||||
* Send text message.
|
||||
* @param chatId - Unique identifier for the message recipient or @channelname
|
||||
* @param text - Text of the message to be sent
|
||||
* @param markdown - Use markdown in message display (only Telegram for Android supports this)
|
||||
* @param disableWebPagePreview - Disables link previews for links in this message
|
||||
* @param replyToMessageId - If the message is a reply, ID of the original message
|
||||
* @param replyMarkup - Additional interface options
|
||||
* @return success
|
||||
* @see https://core.telegram.org/bots/api#sendmessage
|
||||
*/
|
||||
bool sendMessage(QVariant chatId, QString text, bool markdown = false, bool disableWebPagePreview = false, qint32 replyToMessageId = -1, const GenericReply &replyMarkup = GenericReply());
|
||||
|
||||
/**
|
||||
* Forward messages of any kind.
|
||||
* @param chatId - Unique identifier for the message recipient or @channelname
|
||||
* @param fromChatId - Unique identifier for the chat where the original message was sent
|
||||
* @param messageId - Unique message identifier
|
||||
* @return success
|
||||
* @see https://core.telegram.org/bots/api#forwardmessage
|
||||
*/
|
||||
bool forwardMessage(QVariant chatId, quint32 fromChatId, quint32 messageId);
|
||||
|
||||
/**
|
||||
* Send a photo
|
||||
* @param chatId - Unique identifier for the message recipient or @channelname
|
||||
* @param file - A file to send
|
||||
* @param caption - Photo caption
|
||||
* @param replyToMessageId - If the message is a reply, ID of the original message
|
||||
* @param replyMarkup - Additional interface options
|
||||
* @return success
|
||||
* @see https://core.telegram.org/bots/api#sendphoto
|
||||
*/
|
||||
bool sendPhoto(QVariant chatId, QFile *file, QString caption = QString(), qint32 replyToMessageId = -1, const GenericReply &replyMarkup = GenericReply());
|
||||
|
||||
/**
|
||||
* Send a photo
|
||||
* @param chatId - Unique identifier for the message recipient or @channelname
|
||||
* @param fileId - Telegram file_id of already sent photo
|
||||
* @param caption - Photo caption
|
||||
* @param replyToMessageId - If the message is a reply, ID of the original message
|
||||
* @param replyMarkup - Additional interface options
|
||||
* @return success
|
||||
* @see https://core.telegram.org/bots/api#sendphoto
|
||||
*/
|
||||
bool sendPhoto(QVariant chatId, QString fileId, QString caption = QString(), qint32 replyToMessageId = -1, const GenericReply &replyMarkup = GenericReply());
|
||||
|
||||
/**
|
||||
* Send audio
|
||||
* @param chatId - Unique identifier for the message recipient or @channelname
|
||||
* @param file - A file to send
|
||||
* @param duration - Duration of the audio in seconds
|
||||
* @param performer - Performer of the audio
|
||||
* @param title - Track name of the audio
|
||||
* @param replyToMessageId - If the message is a reply, ID of the original message
|
||||
* @param replyMarkup - Additional interface options
|
||||
* @return success
|
||||
* @see https://core.telegram.org/bots/api#sendaudio
|
||||
*/
|
||||
bool sendAudio(QVariant chatId, QFile *file, qint64 duration = -1, QString performer = QString(), QString title = QString(), qint32 replyToMessageId = -1, const GenericReply &replyMarkup = GenericReply());
|
||||
|
||||
/**
|
||||
* Send audio
|
||||
* @param chatId - Unique identifier for the message recipient or @channelname
|
||||
* @param fileId - Telegram file_id of already sent audio
|
||||
* @param duration - Duration of the audio in seconds
|
||||
* @param performer - Performer of the audio
|
||||
* @param title - Track name of the audio
|
||||
* @param replyToMessageId - If the message is a reply, ID of the original message
|
||||
* @param replyMarkup - Additional interface options
|
||||
* @return success
|
||||
* @see https://core.telegram.org/bots/api#sendaudio
|
||||
*/
|
||||
bool sendAudio(QVariant chatId, QString fileId, qint64 duration = -1, QString performer = QString(), QString title = QString(), qint32 replyToMessageId = -1, const GenericReply &replyMarkup = GenericReply());
|
||||
|
||||
/**
|
||||
* Send a document
|
||||
* @param chatId - Unique identifier for the message recipient or @channelname
|
||||
* @param file - A file to send
|
||||
* @param replyToMessageId - If the message is a reply, ID of the original message
|
||||
* @param replyMarkup - Additional interface options
|
||||
* @return success
|
||||
* @see https://core.telegram.org/bots/api#senddocument
|
||||
*/
|
||||
bool sendDocument(QVariant chatId, QFile *file, qint32 replyToMessageId = -1, const GenericReply &replyMarkup = GenericReply());
|
||||
|
||||
/**
|
||||
* Send a document
|
||||
* @param chatId - Unique identifier for the message recipient or @channelname
|
||||
* @param fileId - Telegram file_id of already sent photo
|
||||
* @param replyToMessageId - If the message is a reply, ID of the original message
|
||||
* @param replyMarkup - Additional interface options
|
||||
* @return success
|
||||
* @see https://core.telegram.org/bots/api#senddocument
|
||||
*/
|
||||
bool sendDocument(QVariant chatId, QString fileId, qint32 replyToMessageId = -1, const GenericReply &replyMarkup = GenericReply());
|
||||
|
||||
/**
|
||||
* Send a sticker
|
||||
* @param chatId - Unique identifier for the message recipient or @channelname
|
||||
* @param file - A file to send
|
||||
* @param replyToMessageId - If the message is a reply, ID of the original message
|
||||
* @param replyMarkup - Additional interface options
|
||||
* @return success
|
||||
* @see https://core.telegram.org/bots/api#sendsticker
|
||||
*/
|
||||
bool sendSticker(QVariant chatId, QFile *file, qint32 replyToMessageId = -1, const GenericReply &replyMarkup = GenericReply());
|
||||
|
||||
/**
|
||||
* Send a sticker
|
||||
* @param chatId - Unique identifier for the message recipient or @channelname
|
||||
* @param fileId - Telegram file_id of already sent photo
|
||||
* @param replyToMessageId - If the message is a reply, ID of the original message
|
||||
* @param replyMarkup - Additional interface options
|
||||
* @return success
|
||||
* @see https://core.telegram.org/bots/api#sendsticker
|
||||
*/
|
||||
bool sendSticker(QVariant chatId, QString fileId, qint32 replyToMessageId = -1, const GenericReply &replyMarkup = GenericReply());
|
||||
|
||||
/**
|
||||
* Send a video
|
||||
* @param chatId - Unique identifier for the message recipient or @channelname
|
||||
* @param fileId - Telegram file_id of already sent photo
|
||||
* @param duration - Duration of sent video in seconds
|
||||
* @param caption - Video caption
|
||||
* @param replyToMessageId - If the message is a reply, ID of the original message
|
||||
* @param replyMarkup - Additional interface options
|
||||
* @return success
|
||||
* @see https://core.telegram.org/bots/api#sendvideo
|
||||
*/
|
||||
bool sendVideo(QVariant chatId, QFile *file, qint64 duration = -1, QString caption = QString(), qint32 replyToMessageId = -1, const GenericReply &replyMarkup = GenericReply());
|
||||
|
||||
/**
|
||||
* Send a video
|
||||
* @param chatId - Unique identifier for the message recipient or @channelname
|
||||
* @param fileId - Telegram file_id of already sent photo
|
||||
* @param duration - Duration of sent video in seconds
|
||||
* @param caption - Video caption
|
||||
* @param replyToMessageId - If the message is a reply, ID of the original message
|
||||
* @param replyMarkup - Additional interface options
|
||||
* @return success
|
||||
* @see https://core.telegram.org/bots/api#sendvideo
|
||||
*/
|
||||
bool sendVideo(QVariant chatId, QString fileId, qint64 duration = -1, QString caption = QString(), qint32 replyToMessageId = -1, const GenericReply &replyMarkup = GenericReply());
|
||||
|
||||
/**
|
||||
* Send a voice
|
||||
* @param chatId - Unique identifier for the message recipient or @channelname
|
||||
* @param fileId - Telegram file_id of already sent photo
|
||||
* @param duration - Duration of sent audio in seconds
|
||||
* @param replyToMessageId - If the message is a reply, ID of the original message
|
||||
* @param replyMarkup - Additional interface options
|
||||
* @return success
|
||||
* @see https://core.telegram.org/bots/api#sendvoice
|
||||
*/
|
||||
bool sendVoice(QVariant chatId, QFile *file, qint64 duration = -1, qint32 replyToMessageId = -1, const GenericReply &replyMarkup = GenericReply());
|
||||
|
||||
/**
|
||||
* Send a voice
|
||||
* @param chatId - Unique identifier for the message recipient or @channelname
|
||||
* @param fileId - Telegram file_id of already sent photo
|
||||
* @param duration - Duration of sent audio in seconds
|
||||
* @param replyToMessageId - If the message is a reply, ID of the original message
|
||||
* @param replyMarkup - Additional interface options
|
||||
* @return success
|
||||
* @see https://core.telegram.org/bots/api#sendvoice
|
||||
*/
|
||||
bool sendVoice(QVariant chatId, QString fileId, qint64 duration = -1, qint32 replyToMessageId = -1, const GenericReply &replyMarkup = GenericReply());
|
||||
|
||||
/**
|
||||
* Send a location
|
||||
* @param chatId - Unique identifier for the message recipient or @channelname
|
||||
* @param latitude - latitude of the location
|
||||
* @param longitude - longitude of the location
|
||||
* @param replyToMessageId - If the message is a reply, ID of the original message
|
||||
* @param replyMarkup - Additional interface options
|
||||
* @return success
|
||||
* @see https://core.telegram.org/bots/api#sendlocation
|
||||
*/
|
||||
bool sendLocation(QVariant chatId, float latitude, float longitude, qint32 replyToMessageId = -1, const GenericReply &replyMarkup = GenericReply());
|
||||
|
||||
/**
|
||||
* Use this method when you need to tell the user that something is happening on the bot's side.
|
||||
* @param chatId - Unique identifier for the message recipient or @channelname
|
||||
* @param action - Type of action to broadcast
|
||||
* @return success
|
||||
* @see https://core.telegram.org/bots/api#sendchataction
|
||||
*/
|
||||
bool sendChatAction(QVariant chatId, ChatAction action);
|
||||
|
||||
/**
|
||||
* Use this method to get a list of profile pictures for a user.
|
||||
* @param userId - Unique identifier of the target user
|
||||
* @param offset - Sequential number of the first photo to be returned.
|
||||
* @param limit - Limits the number of photos to be retrieved. Values between 1—100 are accepted. Defaults to 100.
|
||||
* @return UserProfilePhotos list
|
||||
* @see Use this method to get a list of profile pictures for a user.
|
||||
*/
|
||||
UserProfilePhotos getUserProfilePhotos(quint32 userId, qint16 offset = -1, qint8 limit = -1);
|
||||
|
||||
/**
|
||||
* Use this method to receive incoming updates using long polling
|
||||
* @param timeout - Timeout in seconds for long polling.
|
||||
* @param limit - Limits the number of updates to be retrieved.
|
||||
* @param offset - Identifier of the first update to be returned.
|
||||
* @return List of Update objects
|
||||
* @see https://core.telegram.org/bots/api#getupdates
|
||||
*/
|
||||
QList<Update> getUpdates(quint32 timeout, quint32 limit, quint32 offset);
|
||||
|
||||
/**
|
||||
* Use this method to specify a url and receive incoming updates via an outgoing webhook.
|
||||
* @param url - HTTPS url to send updates to. Use an empty string to remove webhook integration
|
||||
* @param certificate - Upload your public key certificate so that the root certificate in use can be checked.
|
||||
* @return success
|
||||
* @see https://core.telegram.org/bots/api#setwebhook
|
||||
*/
|
||||
bool setWebhook(QString url, QFile *certificate);
|
||||
|
||||
/**
|
||||
* Use this method to get basic info about a file and prepare it for downloading.
|
||||
* @param fileId - File identifier to get info about
|
||||
* @return File object
|
||||
* @see https://core.telegram.org/bots/api#getfile
|
||||
*/
|
||||
File getFile(QString fileId);
|
||||
|
||||
private:
|
||||
Networking *m_net;
|
||||
|
||||
bool _sendPayload(QVariant chatId, QFile *filePayload, ParameterList params, qint32 replyToMessageId, const GenericReply &replyMarkup, QString payloadField, QString endpoint);
|
||||
bool _sendPayload(QVariant chatId, QString textPayload, ParameterList params, qint32 replyToMessageId, const GenericReply &replyMarkup, QString payloadField, QString endpoint);
|
||||
|
||||
QJsonObject jsonObjectFromByteArray(QByteArray json);
|
||||
QJsonArray jsonArrayFromByteArray(QByteArray json);
|
||||
bool responseOk(QByteArray json);
|
||||
|
||||
void internalGetUpdates();
|
||||
QTimer *m_internalUpdateTimer;
|
||||
quint32 m_updateInterval;
|
||||
quint32 m_updateOffset;
|
||||
quint32 m_pollingTimeout;
|
||||
|
||||
|
||||
|
||||
signals:
|
||||
void message(Message message);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // QTTELEGRAMBOT_H
|
13
types/audio.cpp
Normal file
13
types/audio.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include "audio.h"
|
||||
|
||||
using namespace Telegram;
|
||||
|
||||
Audio::Audio(QJsonObject audio)
|
||||
{
|
||||
fileId = audio.value("file_id").toString();
|
||||
duration = audio.value("duration").toInt();
|
||||
performer = audio.value("performer").toString();
|
||||
title = audio.value("title").toString();
|
||||
mimeType = audio.value("mime_type").toString();
|
||||
fileSize = audio.value("file_size").toInt();
|
||||
}
|
39
types/audio.h
Normal file
39
types/audio.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef AUDIO_H
|
||||
#define AUDIO_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace Telegram {
|
||||
|
||||
class Audio
|
||||
{
|
||||
public:
|
||||
Audio() {}
|
||||
Audio(QJsonObject audio);
|
||||
|
||||
QString fileId;
|
||||
quint64 duration;
|
||||
QString performer;
|
||||
QString title;
|
||||
QString mimeType;
|
||||
quint64 fileSize;
|
||||
};
|
||||
|
||||
inline QDebug operator<< (QDebug dbg, const Audio &audio)
|
||||
{
|
||||
dbg.nospace() << qUtf8Printable(QString("Telegram::Audio(fileId=%1; duration=%2; performer=%3; title=%4; mimeType=%5; fileSize=%6)")
|
||||
.arg(audio.fileId)
|
||||
.arg(audio.duration)
|
||||
.arg(audio.performer)
|
||||
.arg(audio.title)
|
||||
.arg(audio.mimeType)
|
||||
.arg(audio.fileSize));
|
||||
|
||||
return dbg.maybeSpace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // AUDIO_H
|
15
types/chat.cpp
Normal file
15
types/chat.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include "chat.h"
|
||||
|
||||
using namespace Telegram;
|
||||
|
||||
Chat::Chat(QJsonObject chat)
|
||||
{
|
||||
id = chat.value("id").toInt();
|
||||
QString chatType = chat.value("type").toString();
|
||||
if (chatType == "private") type = Private;
|
||||
else if (chatType == "group") type = Group;
|
||||
else if (chatType == "channel") type = Channel;
|
||||
username = chat.value("username").toString();
|
||||
firstname = chat.value("first_name").toString();
|
||||
lastname = chat.value("last_name").toString();
|
||||
}
|
43
types/chat.h
Normal file
43
types/chat.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef CHAT_H
|
||||
#define CHAT_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace Telegram {
|
||||
|
||||
class Chat
|
||||
{
|
||||
public:
|
||||
Chat() {}
|
||||
Chat(QJsonObject chat);
|
||||
|
||||
enum ChatType {
|
||||
Private, Group, Channel
|
||||
};
|
||||
|
||||
quint32 id;
|
||||
ChatType type;
|
||||
QString title;
|
||||
QString username;
|
||||
QString firstname;
|
||||
QString lastname;
|
||||
};
|
||||
|
||||
inline QDebug operator<< (QDebug dbg, const Chat &chat)
|
||||
{
|
||||
dbg.nospace() << qUtf8Printable(QString("Telegram::Chat(id=%1; type=%2; title=%3; username=%4; firstname=%5; lastname=%6)")
|
||||
.arg(chat.id)
|
||||
.arg(chat.type)
|
||||
.arg(chat.title)
|
||||
.arg(chat.username)
|
||||
.arg(chat.firstname)
|
||||
.arg(chat.lastname));
|
||||
|
||||
return dbg.maybeSpace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // CHAT_H
|
11
types/contact.cpp
Normal file
11
types/contact.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "contact.h"
|
||||
|
||||
using namespace Telegram;
|
||||
|
||||
Contact::Contact(QJsonObject contact)
|
||||
{
|
||||
phoneNumber = contact.value("phone_number").toString();
|
||||
firstname = contact.value("first_name").toString();
|
||||
lastname = contact.value("last_name").toString();
|
||||
userId = contact.value("user_id").toInt();
|
||||
}
|
35
types/contact.h
Normal file
35
types/contact.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef CONTACT_H
|
||||
#define CONTACT_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace Telegram {
|
||||
|
||||
class Contact
|
||||
{
|
||||
public:
|
||||
Contact() {}
|
||||
Contact(QJsonObject contact);
|
||||
|
||||
QString phoneNumber;
|
||||
QString firstname;
|
||||
QString lastname;
|
||||
quint32 userId;
|
||||
};
|
||||
|
||||
inline QDebug operator<< (QDebug dbg, const Contact &contact)
|
||||
{
|
||||
dbg.nospace() << qUtf8Printable(QString("Telegram::Contact(phoneNumber=%1; firstname=%2; lastname=%3; userId=%4)")
|
||||
.arg(contact.phoneNumber)
|
||||
.arg(contact.firstname)
|
||||
.arg(contact.lastname)
|
||||
.arg(contact.userId));
|
||||
|
||||
return dbg.maybeSpace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // CONTACT_H
|
12
types/document.cpp
Normal file
12
types/document.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
#include "document.h"
|
||||
|
||||
using namespace Telegram;
|
||||
|
||||
Document::Document(QJsonObject document)
|
||||
{
|
||||
fileId = document.value("file_id").toString();
|
||||
thumb = PhotoSize(document.value("thumb").toObject());
|
||||
fileName = document.value("file_name").toString();
|
||||
mimeType = document.value("mime_type").toString();
|
||||
fileSize = document.value("file_size").toInt();
|
||||
}
|
38
types/document.h
Normal file
38
types/document.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef DOCUMENT_H
|
||||
#define DOCUMENT_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <QJsonObject>
|
||||
#include "photosize.h"
|
||||
|
||||
namespace Telegram {
|
||||
|
||||
class Document
|
||||
{
|
||||
public:
|
||||
Document() {}
|
||||
Document(QJsonObject document);
|
||||
|
||||
QString fileId;
|
||||
PhotoSize thumb;
|
||||
QString fileName;
|
||||
QString mimeType;
|
||||
quint64 fileSize;
|
||||
};
|
||||
|
||||
inline QDebug operator<< (QDebug dbg, const Document &document)
|
||||
{
|
||||
dbg.nospace() << qUtf8Printable(QString("Telegram::Document(fileId=%1; thumb=%2; fileName=%3; mimeType=%4; fileSize=%5)")
|
||||
.arg(document.fileId)
|
||||
.arg("PhotoSize(" + document.thumb.fileId + ")")
|
||||
.arg(document.fileName)
|
||||
.arg(document.mimeType)
|
||||
.arg(document.fileSize));
|
||||
|
||||
return dbg.maybeSpace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // DOCUMENT_H
|
32
types/file.h
Normal file
32
types/file.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef FILE_H
|
||||
#define FILE_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
|
||||
namespace Telegram {
|
||||
|
||||
class File
|
||||
{
|
||||
public:
|
||||
File(QString fileId, qint64 fileSize = -1, QString filePath = QString()) :
|
||||
fileId(fileId), fileSize(fileSize), filePath(filePath) {}
|
||||
|
||||
QString fileId;
|
||||
qint64 fileSize;
|
||||
QString filePath;
|
||||
};
|
||||
|
||||
inline QDebug operator<< (QDebug dbg, const File &file)
|
||||
{
|
||||
dbg.nospace() << qUtf8Printable(QString("Telegram::File(fileId=%1; fileSize=%2; filePath=%3)")
|
||||
.arg(file.fileId)
|
||||
.arg(file.fileSize)
|
||||
.arg(file.filePath));
|
||||
|
||||
return dbg.maybeSpace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // FILE_H
|
9
types/location.cpp
Normal file
9
types/location.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include "location.h"
|
||||
|
||||
using namespace Telegram;
|
||||
|
||||
Location::Location(QJsonObject location)
|
||||
{
|
||||
longitude = location.value("longitude").toDouble();
|
||||
latitude = location.value("latitude").toDouble();
|
||||
}
|
31
types/location.h
Normal file
31
types/location.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef LOCATION_H
|
||||
#define LOCATION_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace Telegram {
|
||||
|
||||
class Location
|
||||
{
|
||||
public:
|
||||
Location() {}
|
||||
Location(QJsonObject location);
|
||||
|
||||
float longitude;
|
||||
float latitude;
|
||||
};
|
||||
|
||||
inline QDebug operator<< (QDebug dbg, const Location &location)
|
||||
{
|
||||
dbg.nospace() << qUtf8Printable(QString("Telegram::Location(longitude=%1; latitude=%2)")
|
||||
.arg(location.longitude)
|
||||
.arg(location.latitude));
|
||||
|
||||
return dbg.maybeSpace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // LOCATION_H
|
116
types/message.cpp
Normal file
116
types/message.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
#include "message.h"
|
||||
|
||||
using namespace Telegram;
|
||||
|
||||
Message::Message(QJsonObject message)
|
||||
{
|
||||
id = message.value("message_id").toInt();
|
||||
date = QDateTime::fromMSecsSinceEpoch(message.value("date").toInt());
|
||||
chat = Chat(message.value("chat").toObject());
|
||||
|
||||
/**
|
||||
x audio Audio Optional. Message is an audio file, information about the file
|
||||
document Document Optional. Message is a general file, information about the file
|
||||
photo Array of PhotoSize Optional. Message is a photo, available sizes of the photo
|
||||
sticker Sticker Optional. Message is a sticker, information about the sticker
|
||||
video Video Optional. Message is a video, information about the video
|
||||
voice Voice Optional. Message is a voice message, information about the file
|
||||
caption String Optional. Caption for the photo or video
|
||||
contact Contact Optional. Message is a shared contact, information about the contact
|
||||
location Location Optional. Message is a shared location, information about the location
|
||||
new_chat_participant User Optional. A new member was added to the group, information about them (this member may be bot itself)
|
||||
left_chat_participant User Optional. A member was removed from the group, information about them (this member may be bot itself)
|
||||
new_chat_photo Array of PhotoSize Optional. A chat photo was change to this value
|
||||
delete_chat_photo True Optional. Informs that the chat photo was deleted
|
||||
group_chat_created True Optional. Informs that the group has been created
|
||||
*/
|
||||
|
||||
if (message.contains("from")) {
|
||||
from = User(message.value("from").toObject());
|
||||
}
|
||||
if (message.contains("forward_from")) {
|
||||
forwardFrom = User(message.value("forward_from").toObject());
|
||||
}
|
||||
if (message.contains("forward_date")) {
|
||||
forwardDate = QDateTime::fromMSecsSinceEpoch(message.value("forward_date").toInt());
|
||||
}
|
||||
if (message.contains("reply_to_message")) {
|
||||
replyToMessage = new Message(message.value("reply_to_message").toObject());
|
||||
}
|
||||
|
||||
// Parse payload
|
||||
QJsonObject obj;
|
||||
if (message.contains("text")) {
|
||||
string = message.value("text").toString();
|
||||
type = Message::TextType;
|
||||
}
|
||||
if (message.contains("audio")) {
|
||||
obj = message.value("audio").toObject();
|
||||
audio = Audio(obj);
|
||||
type = Message::AudioType;
|
||||
}
|
||||
if (message.contains("document")) {
|
||||
obj = message.value("document").toObject();
|
||||
document = Document(obj);
|
||||
type = Message::DocumentType;
|
||||
}
|
||||
if (message.contains("photo")) {
|
||||
foreach (QJsonValue val, message.value("photo").toArray()) {
|
||||
photo.append(PhotoSize(val.toObject()));
|
||||
}
|
||||
type = Message::PhotoType;
|
||||
}
|
||||
if (message.contains("sticker")) {
|
||||
obj = message.value("sticker").toObject();
|
||||
sticker = Sticker(obj);
|
||||
type = Message::StickerType;
|
||||
}
|
||||
if (message.contains("video")) {
|
||||
obj = message.value("video").toObject();
|
||||
video = Video(obj);
|
||||
type = Message::VideoType;
|
||||
}
|
||||
if (message.contains("voice")) {
|
||||
obj = message.value("voice").toObject();
|
||||
voice = Voice(obj);
|
||||
type = Message::VoiceType;
|
||||
}
|
||||
if (message.contains("contact")) {
|
||||
obj = message.value("contact").toObject();
|
||||
contact = Contact(obj);
|
||||
type = Message::ContactType;
|
||||
}
|
||||
if (message.contains("location")) {
|
||||
obj = message.value("location").toObject();
|
||||
location = Location(obj);
|
||||
type = Message::LocationType;
|
||||
}
|
||||
if (message.contains("new_chat_participant")) {
|
||||
obj = message.value("new_chat_participant").toObject();
|
||||
user = User(obj);
|
||||
type = Message::NewChatParticipantType;
|
||||
}
|
||||
if (message.contains("left_chat_participant")) {
|
||||
obj = message.value("left_chat_participant").toObject();
|
||||
user = User(obj);
|
||||
type = Message::LeftChatParticipantType;
|
||||
}
|
||||
if (message.contains("new_chat_title")) {
|
||||
string = message.value("new_chat_title").toString();
|
||||
type = Message::NewChatTitleType;
|
||||
}
|
||||
if (message.contains("new_chat_photo")) {
|
||||
foreach (QJsonValue val, message.value("new_chat_photo").toArray()) {
|
||||
photo.append(PhotoSize(val.toObject()));
|
||||
}
|
||||
type = Message::NewChatPhotoType;
|
||||
}
|
||||
if (message.contains("delete_chat_photo")) {
|
||||
boolean = true;
|
||||
type = Message::DeleteChatPhotoType;
|
||||
}
|
||||
if (message.contains("group_chat_created")) {
|
||||
boolean = true;
|
||||
type = Message::GroupChatCreatedType;
|
||||
}
|
||||
}
|
79
types/message.h
Normal file
79
types/message.h
Normal file
@ -0,0 +1,79 @@
|
||||
#ifndef MESSAGE_H
|
||||
#define MESSAGE_H
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <QString>
|
||||
#include <QDateTime>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
|
||||
#include "audio.h"
|
||||
#include "document.h"
|
||||
#include "photosize.h"
|
||||
#include "sticker.h"
|
||||
#include "video.h"
|
||||
#include "voice.h"
|
||||
#include "contact.h"
|
||||
#include "location.h"
|
||||
#include "chat.h"
|
||||
#include "user.h"
|
||||
|
||||
namespace Telegram {
|
||||
|
||||
class Message
|
||||
{
|
||||
public:
|
||||
Message() {}
|
||||
Message(QJsonObject message);
|
||||
|
||||
/**
|
||||
* @brief Telegram message events
|
||||
*/
|
||||
enum MessageType {
|
||||
TextType, AudioType, DocumentType, PhotoType, StickerType, VideoType, VoiceType, ContactType,
|
||||
LocationType, NewChatParticipantType, LeftChatParticipantType, NewChatTitleType,
|
||||
NewChatPhotoType, DeleteChatPhotoType, GroupChatCreatedType
|
||||
};
|
||||
|
||||
// required
|
||||
quint32 id;
|
||||
QDateTime date;
|
||||
Chat chat;
|
||||
|
||||
// optional
|
||||
User from;
|
||||
User forwardFrom;
|
||||
QDateTime forwardDate;
|
||||
Message *replyToMessage;
|
||||
|
||||
MessageType type;
|
||||
|
||||
// payload
|
||||
QString string;
|
||||
User user;
|
||||
Audio audio;
|
||||
Document document;
|
||||
QList<PhotoSize> photo;
|
||||
Sticker sticker;
|
||||
Video video;
|
||||
Voice voice;
|
||||
Contact contact;
|
||||
Location location;
|
||||
bool boolean;
|
||||
};
|
||||
|
||||
inline QDebug operator<< (QDebug dbg, const Message &message)
|
||||
{
|
||||
dbg.nospace() << qUtf8Printable(QString("Telegram::Message(id=%1; date=%2; chat=%3; type=%4)")
|
||||
.arg(message.id)
|
||||
.arg(message.date.toString("dd.MM.yyyy hh:mm:ss"))
|
||||
.arg("Chat(" + QString::number(message.chat.id) + ")")
|
||||
.arg(message.type));
|
||||
|
||||
return dbg.maybeSpace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // MESSAGE_H
|
11
types/photosize.cpp
Normal file
11
types/photosize.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "photosize.h"
|
||||
|
||||
using namespace Telegram;
|
||||
|
||||
PhotoSize::PhotoSize(QJsonObject photoSize)
|
||||
{
|
||||
fileId = photoSize.value("file_id").toString();
|
||||
width = photoSize.value("width").toInt();
|
||||
height = photoSize.value("height").toInt();
|
||||
fileSize = photoSize.value("file_size").toInt();
|
||||
}
|
35
types/photosize.h
Normal file
35
types/photosize.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef PHOTOSIZE_H
|
||||
#define PHOTOSIZE_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace Telegram {
|
||||
|
||||
class PhotoSize
|
||||
{
|
||||
public:
|
||||
PhotoSize() {}
|
||||
PhotoSize(QJsonObject photoSize);
|
||||
|
||||
QString fileId;
|
||||
quint16 width;
|
||||
quint16 height;
|
||||
quint64 fileSize;
|
||||
};
|
||||
|
||||
inline QDebug operator<< (QDebug dbg, const PhotoSize &photoSize)
|
||||
{
|
||||
dbg.nospace() << qUtf8Printable(QString("Telegram::PhotoSize(fileId=%1; width=%2; height=%3; fileSize=%4)")
|
||||
.arg(photoSize.fileId)
|
||||
.arg(photoSize.width)
|
||||
.arg(photoSize.height)
|
||||
.arg(photoSize.fileSize));
|
||||
|
||||
return dbg.maybeSpace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // PHOTOSIZE_H
|
31
types/reply/forcereply.h
Normal file
31
types/reply/forcereply.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef FORCEREPLY
|
||||
#define FORCEREPLY
|
||||
|
||||
#include "genericreply.h"
|
||||
|
||||
namespace Telegram {
|
||||
|
||||
class ForceReply : public GenericReply
|
||||
{
|
||||
public:
|
||||
ForceReply(bool selective = false)
|
||||
: GenericReply(selective),
|
||||
forceReply(true) {}
|
||||
|
||||
/**
|
||||
* Shows reply interface to the user, as if they manually selected the bot‘s message and tapped ’Reply'
|
||||
*/
|
||||
const bool forceReply;
|
||||
|
||||
virtual QString serialize() const {
|
||||
QJsonObject o = QJsonObject();
|
||||
o.insert("force_reply", forceReply);
|
||||
o.insert("selective", selective);
|
||||
return serializeJson(o);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FORCEREPLY
|
||||
|
44
types/reply/genericreply.h
Normal file
44
types/reply/genericreply.h
Normal file
@ -0,0 +1,44 @@
|
||||
#ifndef GENERICREPLY_H
|
||||
#define GENERICREPLY_H
|
||||
|
||||
#include <QString>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
|
||||
namespace Telegram {
|
||||
|
||||
class GenericReply
|
||||
{
|
||||
public:
|
||||
GenericReply() : valid(false) {}
|
||||
GenericReply(bool selective) : selective(selective), valid(true) {}
|
||||
|
||||
/**
|
||||
* Optional. Use this parameter if you want to show the keyboard to specific users only.
|
||||
* Targets: 1) users that are @mentioned in the text of the Message object;
|
||||
* 2) if the bot's message is a reply (has reply_to_message_id), sender of the original message.
|
||||
*/
|
||||
bool selective;
|
||||
|
||||
virtual QString serialize() const {
|
||||
return QString();
|
||||
}
|
||||
|
||||
bool isValid() const {
|
||||
return valid;
|
||||
}
|
||||
|
||||
private:
|
||||
bool valid;
|
||||
|
||||
protected:
|
||||
QByteArray serializeJson(QJsonObject o) const {
|
||||
QJsonDocument d = QJsonDocument(o);
|
||||
return d.toJson(QJsonDocument::Compact);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // GENERICREPLY_H
|
30
types/reply/replykeyboardhide.h
Normal file
30
types/reply/replykeyboardhide.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef REPLYKEYBOARDHIDE
|
||||
#define REPLYKEYBOARDHIDE
|
||||
|
||||
#include "genericreply.h"
|
||||
|
||||
namespace Telegram {
|
||||
|
||||
class ReplyKeyboardHide : public GenericReply
|
||||
{
|
||||
public:
|
||||
ReplyKeyboardHide(bool selective = false)
|
||||
: GenericReply(selective),
|
||||
hideKeyboard(true) {}
|
||||
|
||||
/**
|
||||
* Requests clients to hide the custom keyboard
|
||||
*/
|
||||
const bool hideKeyboard;
|
||||
|
||||
virtual QString serialize() const {
|
||||
QJsonObject o = QJsonObject();
|
||||
o.insert("hide_keyboard", hideKeyboard);
|
||||
o.insert("selective", selective);
|
||||
return serializeJson(o);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // REPLYKEYBOARDHIDE
|
54
types/reply/replykeyboardmarkup.h
Normal file
54
types/reply/replykeyboardmarkup.h
Normal file
@ -0,0 +1,54 @@
|
||||
#ifndef REPLYKEYBOARDMARKUP_H
|
||||
#define REPLYKEYBOARDMARKUP_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "genericreply.h"
|
||||
|
||||
namespace Telegram {
|
||||
|
||||
typedef QList<QStringList> KeyboardMarkup;
|
||||
|
||||
class ReplyKeyboardMarkup : public GenericReply
|
||||
{
|
||||
public:
|
||||
ReplyKeyboardMarkup(KeyboardMarkup keyboard, bool resizeKeyboard = false, bool oneTimeKeyboard = false, bool selective = false)
|
||||
: GenericReply(selective),
|
||||
keyboard(keyboard),
|
||||
resizeKeyboard(resizeKeyboard),
|
||||
oneTimeKeyboard(oneTimeKeyboard) {}
|
||||
|
||||
/**
|
||||
* Array of button rows, each represented by an Array of Strings
|
||||
*/
|
||||
KeyboardMarkup keyboard;
|
||||
|
||||
/**
|
||||
* Optional. Requests clients to resize the keyboard vertically for optimal fit (e.g., make the keyboard smaller if there are just two rows of buttons).
|
||||
* Defaults to false, in which case the custom keyboard is always of the same height as the app's standard keyboard.
|
||||
*/
|
||||
bool resizeKeyboard;
|
||||
|
||||
/**
|
||||
* Optional. Requests clients to hide the keyboard as soon as it's been used.
|
||||
* Defaults to false.
|
||||
*/
|
||||
bool oneTimeKeyboard;
|
||||
|
||||
virtual QString serialize() const {
|
||||
QJsonObject o = QJsonObject();
|
||||
QJsonArray keyboardMarkup = QJsonArray();
|
||||
foreach (QStringList list, keyboard) {
|
||||
keyboardMarkup.append(QJsonArray::fromStringList(list));
|
||||
}
|
||||
o.insert("keyboard", keyboardMarkup);
|
||||
o.insert("resize_keyboard", resizeKeyboard);
|
||||
o.insert("one_time_keyboard", oneTimeKeyboard);
|
||||
o.insert("selective", selective);
|
||||
return serializeJson(o);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // REPLYKEYBOARDMARKUP_H
|
12
types/sticker.cpp
Normal file
12
types/sticker.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
#include "sticker.h"
|
||||
|
||||
using namespace Telegram;
|
||||
|
||||
Sticker::Sticker(QJsonObject sticker)
|
||||
{
|
||||
fileId = sticker.value("file_id").toString();
|
||||
width = sticker.value("width").toInt();
|
||||
height = sticker.value("height").toInt();
|
||||
thumb = PhotoSize(sticker.value("thumb").toObject());
|
||||
fileSize = sticker.value("file_size").toInt();
|
||||
}
|
38
types/sticker.h
Normal file
38
types/sticker.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef STICKER_H
|
||||
#define STICKER_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <QJsonObject>
|
||||
#include "photosize.h"
|
||||
|
||||
namespace Telegram {
|
||||
|
||||
class Sticker
|
||||
{
|
||||
public:
|
||||
Sticker() {}
|
||||
Sticker(QJsonObject sticker);
|
||||
|
||||
QString fileId;
|
||||
quint16 width;
|
||||
quint16 height;
|
||||
PhotoSize thumb;
|
||||
quint64 fileSize;
|
||||
};
|
||||
|
||||
inline QDebug operator<< (QDebug dbg, const Sticker &sticker)
|
||||
{
|
||||
dbg.nospace() << qUtf8Printable(QString("Telegram::Sticker(fileId=%1; width=%2; height=%3; thumb=%4; fileSize=%5)")
|
||||
.arg(sticker.fileId)
|
||||
.arg(sticker.width)
|
||||
.arg(sticker.height)
|
||||
.arg("PhotoSize(" + sticker.thumb.fileId + ")")
|
||||
.arg(sticker.fileSize));
|
||||
|
||||
return dbg.maybeSpace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // STICKER_H
|
9
types/update.cpp
Normal file
9
types/update.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include "update.h"
|
||||
|
||||
using namespace Telegram;
|
||||
|
||||
Update::Update(QJsonObject update)
|
||||
{
|
||||
id = update.value("update_id").toInt();
|
||||
message = Message(update.value("message").toObject());
|
||||
}
|
31
types/update.h
Normal file
31
types/update.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef UPDATE_H
|
||||
#define UPDATE_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QJsonObject>
|
||||
#include "message.h"
|
||||
|
||||
namespace Telegram {
|
||||
|
||||
class Update
|
||||
{
|
||||
public:
|
||||
Update() {}
|
||||
Update(QJsonObject update);
|
||||
|
||||
quint32 id;
|
||||
Message message;
|
||||
};
|
||||
|
||||
inline QDebug operator<< (QDebug dbg, const Update &update)
|
||||
{
|
||||
dbg.nospace() << qUtf8Printable(QString("Telegram::Update(id=%1; message=%2)")
|
||||
.arg(update.id)
|
||||
.arg("Message(" + QString::number(update.message.id) + ")"));
|
||||
|
||||
return dbg.maybeSpace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // UPDATE_H
|
11
types/user.cpp
Normal file
11
types/user.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "user.h"
|
||||
|
||||
using namespace Telegram;
|
||||
|
||||
Telegram::User::User(QJsonObject user)
|
||||
{
|
||||
id = user.value("id").toInt();
|
||||
firstname = user.value("first_name").toString();
|
||||
lastname = user.value("last_name").toString();
|
||||
username = user.value("username").toString();
|
||||
}
|
35
types/user.h
Normal file
35
types/user.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef USER_H
|
||||
#define USER_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace Telegram {
|
||||
|
||||
class User
|
||||
{
|
||||
public:
|
||||
User() : id(0), firstname(QString()), lastname(QString()), username(QString()) {}
|
||||
User(QJsonObject user);
|
||||
|
||||
quint32 id;
|
||||
QString firstname;
|
||||
QString lastname;
|
||||
QString username;
|
||||
};
|
||||
|
||||
inline QDebug operator<< (QDebug dbg, const User &user)
|
||||
{
|
||||
dbg.nospace() << qUtf8Printable(QString("Telegram::User(id=%1; firstname=%2; lastname=%3; username=%4)")
|
||||
.arg(user.id)
|
||||
.arg(user.firstname)
|
||||
.arg(user.lastname)
|
||||
.arg(user.username));
|
||||
|
||||
return dbg.maybeSpace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // USER_H
|
14
types/video.cpp
Normal file
14
types/video.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#include "video.h"
|
||||
|
||||
using namespace Telegram;
|
||||
|
||||
Video::Video(QJsonObject video)
|
||||
{
|
||||
fileId = video.value("file_id").toString();
|
||||
width = video.value("width").toInt();
|
||||
height = video.value("height").toInt();
|
||||
duration = video.value("duration").toInt();
|
||||
thumb = PhotoSize(video.value("thumb").toObject());
|
||||
mimeType = video.value("mime_type").toString();
|
||||
fileSize = video.value("file_size").toInt();
|
||||
}
|
41
types/video.h
Normal file
41
types/video.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef VIDEO_H
|
||||
#define VIDEO_H
|
||||
|
||||
#include <QString>
|
||||
#include <QJsonObject>
|
||||
#include "photosize.h"
|
||||
|
||||
namespace Telegram {
|
||||
|
||||
class Video
|
||||
{
|
||||
public:
|
||||
Video() {}
|
||||
Video(QJsonObject video);
|
||||
|
||||
QString fileId;
|
||||
quint16 width;
|
||||
quint16 height;
|
||||
quint64 duration;
|
||||
PhotoSize thumb;
|
||||
QString mimeType;
|
||||
QString fileSize;
|
||||
};
|
||||
|
||||
inline QDebug operator<< (QDebug dbg, const Video &video)
|
||||
{
|
||||
dbg.nospace() << qUtf8Printable(QString("Telegram::Video(fileId=%1; width=%2; height=%3; duration=%4; thumb=%5; mimeType=%6; fileSize=%7)")
|
||||
.arg(video.fileId)
|
||||
.arg(video.width)
|
||||
.arg(video.height)
|
||||
.arg(video.duration)
|
||||
.arg("PhotoSize(" + video.thumb.fileId + ")")
|
||||
.arg(video.mimeType)
|
||||
.arg(video.fileSize));
|
||||
|
||||
return dbg.maybeSpace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // VIDEO_H
|
11
types/voice.cpp
Normal file
11
types/voice.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "voice.h"
|
||||
|
||||
using namespace Telegram;
|
||||
|
||||
Voice::Voice(QJsonObject voice)
|
||||
{
|
||||
fileId = voice.value("file_id").toString();
|
||||
duration = voice.value("duration").toInt();
|
||||
mimeType = voice.value("mime_type").toString();
|
||||
fileSize = voice.value("file_size").toInt();
|
||||
}
|
35
types/voice.h
Normal file
35
types/voice.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef VOICE_H
|
||||
#define VOICE_H
|
||||
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
#include <QJsonObject>
|
||||
|
||||
namespace Telegram {
|
||||
|
||||
class Voice
|
||||
{
|
||||
public:
|
||||
Voice() {}
|
||||
Voice(QJsonObject voice);
|
||||
|
||||
QString fileId;
|
||||
quint64 duration;
|
||||
QString mimeType;
|
||||
quint64 fileSize;
|
||||
};
|
||||
|
||||
inline QDebug operator<< (QDebug dbg, const Voice &voice)
|
||||
{
|
||||
dbg.nospace() << qUtf8Printable(QString("Telegram::Voice(fileId=%1; duration=%2; mimeType=%3; fileSize=%4)")
|
||||
.arg(voice.fileId)
|
||||
.arg(voice.duration)
|
||||
.arg(voice.mimeType)
|
||||
.arg(voice.fileSize));
|
||||
|
||||
return dbg.maybeSpace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // VOICE_H
|
Reference in New Issue
Block a user