akashi-esquizolandia/src/discord.cpp

174 lines
6.6 KiB
C++

//////////////////////////////////////////////////////////////////////////////////////
// akashi - a server for Attorney Online 2 //
// Copyright (C) 2020 scatterflower //
// //
// This program is free software: you can redistribute it and/or modify //
// it under the terms of the GNU Affero General Public License as //
// published by the Free Software Foundation, either version 3 of the //
// License, or (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU Affero General Public License for more details. //
// //
// You should have received a copy of the GNU Affero General Public License //
// along with this program. If not, see <https://www.gnu.org/licenses/>. //
//////////////////////////////////////////////////////////////////////////////////////
#include "discord.h"
#include "config_manager.h"
Discord::Discord(QObject *parent) :
QObject(parent)
{
m_nam = new QNetworkAccessManager();
connect(m_nam, &QNetworkAccessManager::finished,
this, &Discord::onReplyFinished);
m_uptimePostTimer = new QTimer;
connect(m_uptimePostTimer, &QTimer::timeout,
this, &Discord::onUptimeWebhookRequested);
}
void Discord::onModcallWebhookRequested(const QString &f_name, const QString &f_area, const QString &f_reason, const QQueue<QString> &f_buffer)
{
m_request.setUrl(QUrl(ConfigManager::discordModcallWebhookUrl()));
QJsonDocument l_json = constructModcallJson(f_name, f_area, f_reason);
postJsonWebhook(l_json);
if (ConfigManager::discordModcallWebhookSendFile()) {
QHttpMultiPart *l_multipart = constructLogMultipart(f_buffer);
postMultipartWebhook(*l_multipart);
}
}
void Discord::onBanWebhookRequested(const QString &f_ipid, const QString &f_moderator, const QString &f_duration, const QString &f_reason, const int &f_banID)
{
m_request.setUrl(QUrl(ConfigManager::discordBanWebhookUrl()));
QJsonDocument l_json = constructBanJson(f_ipid, f_moderator, f_duration, f_reason, f_banID);
postJsonWebhook(l_json);
}
void Discord::onUptimeWebhookRequested()
{
qint64 l_expiredTimeSeconds = ConfigManager::uptime() / 1000;
int minutes = (l_expiredTimeSeconds / 60) % 60;
int hours = (l_expiredTimeSeconds / (60 * 60)) % 24;
int days = (l_expiredTimeSeconds / (60 * 60 * 24)) % 365;
m_request.setUrl(QUrl(ConfigManager::discordUptimeWebhookUrl()));
QString f_timeExpired = QString::number(days) + " days, " + QString::number(hours) + " hours and " + QString::number(minutes) + " minutes.";
QJsonDocument l_json = constructUptimeJson(f_timeExpired);
postJsonWebhook(l_json);
}
QJsonDocument Discord::constructModcallJson(const QString &f_name, const QString &f_area, const QString &f_reason) const
{
QJsonObject l_json;
QJsonArray l_array;
QJsonObject l_object{
{"color", ConfigManager::discordWebhookColor()},
{"title", f_name + " filed a modcall in " + f_area},
{"description", f_reason}};
l_array.append(l_object);
if (!ConfigManager::discordModcallWebhookContent().isEmpty())
l_json["content"] = ConfigManager::discordModcallWebhookContent();
l_json["embeds"] = l_array;
return QJsonDocument(l_json);
}
QJsonDocument Discord::constructBanJson(const QString &f_ipid, const QString &f_moderator, const QString &f_duration, const QString &f_reason, const int &f_banID)
{
QJsonObject l_json;
QJsonArray l_array;
QJsonObject l_object{
{"color", ConfigManager::discordWebhookColor()},
{"title", "Ban issued by " + f_moderator},
{"description", "Client IPID : " + f_ipid + "\nBan ID: " + QString::number(f_banID) + "\nBan reason : " + f_reason + "\nBanned until : " + f_duration}};
l_array.append(l_object);
l_json["embeds"] = l_array;
return QJsonDocument(l_json);
}
QJsonDocument Discord::constructUptimeJson(const QString &f_timeExpired)
{
QJsonObject l_json;
QJsonArray l_array;
QJsonObject l_object{
{"color", ConfigManager::discordWebhookColor()},
{"title", "Your server is online!"},
{"description", "Your server has been online for " + f_timeExpired}};
l_array.append(l_object);
l_json["embeds"] = l_array;
return QJsonDocument(l_json);
}
QHttpMultiPart *Discord::constructLogMultipart(const QQueue<QString> &f_buffer) const
{
QHttpMultiPart *l_multipart = new QHttpMultiPart();
QHttpPart l_file;
l_file.setRawHeader(QByteArray("Content-Disposition"), QByteArray("form-data; name=\"file\"; filename=\"log.txt\""));
l_file.setRawHeader(QByteArray("Content-Type"), QByteArray("plain/text"));
QString l_log;
for (const QString &log_entry : f_buffer) {
l_log.append(log_entry + "\n");
}
l_file.setBody(l_log.toUtf8());
l_multipart->append(l_file);
return l_multipart;
}
void Discord::postJsonWebhook(const QJsonDocument &f_json)
{
if (!QUrl(m_request.url()).isValid()) {
qWarning("Invalid webhook URL!");
return;
}
m_request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
m_nam->post(m_request, f_json.toJson());
}
void Discord::postMultipartWebhook(QHttpMultiPart &f_multipart)
{
if (!QUrl(m_request.url()).isValid()) {
qWarning("Invalid webhook URL!");
f_multipart.deleteLater();
return;
}
m_request.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary=" + f_multipart.boundary());
QNetworkReply *l_reply = m_nam->post(m_request, &f_multipart);
f_multipart.setParent(l_reply);
}
void Discord::onReplyFinished(QNetworkReply *f_reply)
{
auto l_data = f_reply->readAll();
f_reply->deleteLater();
#ifdef DISCORD_DEBUG
QDebug() << l_data;
#else
Q_UNUSED(l_data);
#endif
}
Discord::~Discord()
{
m_nam->deleteLater();
}
void Discord::startUptimeTimer()
{
m_uptimePostTimer->start(ConfigManager::discordUptimeTime() * 60000);
onUptimeWebhookRequested();
}
void Discord::stopUptimeTimer()
{
m_uptimePostTimer->stop();
}