Merge remote-tracking branch 'refs/remotes/scatter/master'
Conflicts: akashi.pro core/include/logger.h core/src/commands/area.cpp core/src/packets.cpp include/logger.h src/commands/area.cpp src/packets.cpp
This commit is contained in:
commit
68b4174a40
@ -23,3 +23,8 @@ maximum_characters=256
|
||||
[Dice]
|
||||
max_value=100
|
||||
max_dice=100
|
||||
|
||||
[Discord]
|
||||
webhook_enabled=false
|
||||
webhook_url=Your webhook url here.
|
||||
webhook_sendfile=false
|
||||
|
@ -29,6 +29,7 @@ SOURCES += \
|
||||
src/commands/roleplay.cpp \
|
||||
src/config_manager.cpp \
|
||||
src/db_manager.cpp \
|
||||
src/discord.cpp \
|
||||
src/logger.cpp \
|
||||
src/packets.cpp \
|
||||
src/server.cpp \
|
||||
@ -42,6 +43,7 @@ HEADERS += include/advertiser.h \
|
||||
include/area_data.h \
|
||||
include/config_manager.h \
|
||||
include/db_manager.h \
|
||||
include/discord.h \
|
||||
include/logger.h \
|
||||
include/server.h \
|
||||
include/ws_client.h \
|
||||
|
@ -161,6 +161,13 @@ class AOClient : public QObject {
|
||||
*/
|
||||
bool global_enabled = true;
|
||||
|
||||
/**
|
||||
* @brief If true, the client's messages will be sent in first-person mode.
|
||||
*
|
||||
* @see AOClient::cmdFirstPerson
|
||||
*/
|
||||
bool first_person = false;
|
||||
|
||||
/**
|
||||
* @brief If true, the client may not use in-character chat.
|
||||
*/
|
||||
@ -1528,6 +1535,15 @@ class AOClient : public QObject {
|
||||
*/
|
||||
void cmdS(int argc, QStringList argv);
|
||||
|
||||
/**
|
||||
* @brief Toggle whether the client's messages will be sent in first person mode.
|
||||
*
|
||||
* @details No arguments.
|
||||
*
|
||||
* @iscommand
|
||||
*/
|
||||
void cmdFirstPerson(int argc, QStringList argv);
|
||||
|
||||
///@}
|
||||
|
||||
/**
|
||||
@ -1978,7 +1994,8 @@ class AOClient : public QObject {
|
||||
{"charselect", {ACLFlags.value("NONE"), 0, &AOClient::cmdCharSelect}},
|
||||
{"togglemusic", {ACLFlags.value("CM"), 0, &AOClient::cmdToggleMusic}},
|
||||
{"a", {ACLFlags.value("NONE"), 2, &AOClient::cmdA}},
|
||||
{"s", {ACLFlags.value("NONE"), 0, &AOClient::cmdS}}
|
||||
{"s", {ACLFlags.value("NONE"), 0, &AOClient::cmdS}},
|
||||
{"firstperson", {ACLFlags.value("NONE"), 0, &AOClient::cmdFirstPerson}},
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -334,6 +334,8 @@ class AreaData : public QObject {
|
||||
|
||||
void setEviMod(const EvidenceMod &eviMod);
|
||||
|
||||
QQueue<QString> buffer() const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief The list of timers available in the area.
|
||||
|
@ -68,7 +68,6 @@ class ConfigManager {
|
||||
QString name; //!< The name of the server as advertised on the server browser.
|
||||
QString description; //!< The description of the server as advertised on the server browser.
|
||||
bool advertise_server; //!< The server will only be announced to the master server (and thus appear on the master server list) if this is true.
|
||||
int zalgo_tolerance; //!< The amount of subscripts zalgo is stripped by.
|
||||
};
|
||||
|
||||
/**
|
||||
|
67
core/include/discord.h
Normal file
67
core/include/discord.h
Normal file
@ -0,0 +1,67 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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/>. //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef DISCORD_H
|
||||
#define DISCORD_H
|
||||
|
||||
#include <QtNetwork>
|
||||
#include <QCoreApplication>
|
||||
#include "server.h"
|
||||
|
||||
class Server;
|
||||
|
||||
class Discord : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Creates an instance of the Discord class.
|
||||
*
|
||||
* @param p_server A pointer to the Server instance Discord is constructed by.
|
||||
* @param parent Qt-based parent, passed along to inherited constructor from QObject.
|
||||
*/
|
||||
Discord(Server* p_server, QObject* parent = nullptr)
|
||||
: QObject(parent), server(p_server) {
|
||||
};
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
* @brief Sends a modcall to a discord webhook.
|
||||
*
|
||||
* @param name The character or OOC name of the client who sent the modcall.
|
||||
* @param area The area name of the area the modcall was sent from.
|
||||
* @param reason The reason the client specified for the modcall.
|
||||
* @param current_area The index of the area the modcall is made.
|
||||
*/
|
||||
void postModcallWebhook(QString name, QString reason, int current_area);
|
||||
|
||||
/**
|
||||
* @brief Sends the reply to the POST request sent by Discord::postModcallWebhook.
|
||||
*/
|
||||
void onFinish(QNetworkReply *reply);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief A pointer to the Server.
|
||||
*/
|
||||
Server* server;
|
||||
|
||||
};
|
||||
|
||||
#endif // DISCORD_H
|
@ -38,6 +38,11 @@ public:
|
||||
Logger(QString f_area_name, int f_max_length, const QString& f_logType_r) :
|
||||
m_areaName(f_area_name), m_maxLength(f_max_length), m_logType(f_logType_r) {};
|
||||
|
||||
/**
|
||||
*@brief Returns a copy of the logger's buffer.
|
||||
*/
|
||||
QQueue<QString> buffer() const;
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief Logs an IC message.
|
||||
@ -94,12 +99,12 @@ public slots:
|
||||
*/
|
||||
void flush();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Contains entries that have not yet been flushed out into a log file.
|
||||
*/
|
||||
QQueue<QString> m_buffer;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Convenience function to add an entry to #buffer.
|
||||
*
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "include/area_data.h"
|
||||
#include "include/ws_proxy.h"
|
||||
#include "include/db_manager.h"
|
||||
#include "include/discord.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
@ -37,6 +38,7 @@
|
||||
class AOClient;
|
||||
class DBManager;
|
||||
class AreaData;
|
||||
class Discord;
|
||||
|
||||
/**
|
||||
* @brief The class that represents the actual server as it is.
|
||||
@ -217,11 +219,6 @@ class Server : public QObject {
|
||||
*/
|
||||
QString modpass;
|
||||
|
||||
/**
|
||||
* @brief The amount of subscripts zalgo is stripped by.
|
||||
*/
|
||||
int zalgo_tolerance;
|
||||
|
||||
/**
|
||||
* @brief The highest value dice can have.
|
||||
*/
|
||||
@ -237,6 +234,21 @@ class Server : public QObject {
|
||||
*/
|
||||
int afk_timeout;
|
||||
|
||||
/**
|
||||
* @brief Whether discord webhooks are enabled on this server.
|
||||
*/
|
||||
bool webhook_enabled;
|
||||
|
||||
/**
|
||||
* @brief Requires an https Webhook link, including both ID and Token in the link.
|
||||
*/
|
||||
QString webhook_url;
|
||||
|
||||
/**
|
||||
* @brief If the modcall buffer is sent as a file.
|
||||
*/
|
||||
bool webhook_sendfile;
|
||||
|
||||
/**
|
||||
* @brief The server-wide global timer.
|
||||
*/
|
||||
@ -310,6 +322,15 @@ class Server : public QObject {
|
||||
*/
|
||||
void reloadRequest(QString p_name, QString p_desc);
|
||||
|
||||
/**
|
||||
* @brief Sends a modcall webhook request, emitted by AOClient::pktModcall.
|
||||
*
|
||||
* @param name The character or OOC name of the client who sent the modcall.
|
||||
* @param reason The reason the client specified for the modcall.
|
||||
* @param current_area Integer ID of the area the modcall is made.
|
||||
*/
|
||||
void webhookRequest(QString name, QString reason, int current_area);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief The proxy used for WebSocket connections.
|
||||
@ -332,6 +353,11 @@ class Server : public QObject {
|
||||
* @brief The port through which the server will accept WebSocket connections.
|
||||
*/
|
||||
int ws_port;
|
||||
|
||||
/**
|
||||
* @brief Handles discord webhooks.
|
||||
*/
|
||||
Discord* discord;
|
||||
};
|
||||
|
||||
#endif // SERVER_H
|
||||
|
@ -105,13 +105,6 @@ void AreaData::clientJoinedArea(int f_charId)
|
||||
|
||||
QList<int> AreaData::owners() const
|
||||
{
|
||||
QString l_test;
|
||||
const auto& l_buffer = m_logger->m_buffer;
|
||||
for (const auto& l_item : l_buffer)
|
||||
{
|
||||
l_test.append(l_item + "\n");
|
||||
}
|
||||
|
||||
return m_owners;
|
||||
}
|
||||
|
||||
@ -267,6 +260,11 @@ void AreaData::setEviMod(const EvidenceMod &eviMod)
|
||||
m_eviMod = eviMod;
|
||||
}
|
||||
|
||||
QQueue<QString> AreaData::buffer() const
|
||||
{
|
||||
return m_logger->buffer();
|
||||
}
|
||||
|
||||
void AreaData::setTestimonyRecording(const TestimonyRecording &testimonyRecording)
|
||||
{
|
||||
m_testimonyRecording = testimonyRecording;
|
||||
|
@ -258,7 +258,7 @@ void AOClient::cmdBgLock(int argc, QStringList argv)
|
||||
area->toggleBgLock();
|
||||
};
|
||||
|
||||
server->broadcast(AOPacket("CT", {"Server", current_char + " locked the background.", "1"}), current_area);
|
||||
server->broadcast(AOPacket("CT", {server->server_name, current_char + " locked the background.", "1"}), current_area);
|
||||
}
|
||||
|
||||
void AOClient::cmdBgUnlock(int argc, QStringList argv)
|
||||
@ -269,7 +269,7 @@ void AOClient::cmdBgUnlock(int argc, QStringList argv)
|
||||
area->toggleBgLock();
|
||||
};
|
||||
|
||||
server->broadcast(AOPacket("CT", {"Server", current_char + " unlocked the background.", "1"}), current_area);
|
||||
server->broadcast(AOPacket("CT", {server->server_name, current_char + " unlocked the background.", "1"}), current_area);
|
||||
}
|
||||
|
||||
void AOClient::cmdStatus(int argc, QStringList argv)
|
||||
@ -279,10 +279,9 @@ void AOClient::cmdStatus(int argc, QStringList argv)
|
||||
|
||||
if (area->changeStatus(arg)) {
|
||||
arup(ARUPType::STATUS, true);
|
||||
sendServerMessageArea(ooc_name + " changed status to " + arg);
|
||||
server->broadcast(AOPacket("CT", {server->server_name, current_char + " changed status to " + arg.toUpper(), "1"}), current_area);
|
||||
} else {
|
||||
sendServerMessage("That does not look like a valid status. Valid statuses are " + AreaData::map_statuses.keys().join(", "));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -445,3 +445,10 @@ void AOClient::cmdS(int argc, QStringList argv)
|
||||
server->broadcast(AOPacket("CT", {"[CM]" + sender_name, ooc_message}), i);
|
||||
}
|
||||
}
|
||||
|
||||
void AOClient::cmdFirstPerson(int argc, QStringList argv)
|
||||
{
|
||||
first_person = !first_person;
|
||||
QString str_en = first_person ? "enabled" : "disabled";
|
||||
sendServerMessage("First person mode " + str_en + ".");
|
||||
}
|
||||
|
@ -144,7 +144,6 @@ bool ConfigManager::loadServerSettings(server_settings* settings)
|
||||
bool port_conversion_success;
|
||||
bool ws_port_conversion_success;
|
||||
bool local_port_conversion_success;
|
||||
bool zalgo_tolerance_conversion_success;
|
||||
config.beginGroup("Options");
|
||||
settings->ms_ip =
|
||||
config.value("ms_ip", "master.aceattorneyonline.com").toString();
|
||||
@ -158,8 +157,6 @@ bool ConfigManager::loadServerSettings(server_settings* settings)
|
||||
settings->description =
|
||||
config.value("server_description", "This is my flashy new server")
|
||||
.toString();
|
||||
settings->zalgo_tolerance =
|
||||
config.value("zalgo_tolerance", "3").toInt(&zalgo_tolerance_conversion_success);
|
||||
config.endGroup();
|
||||
if (!port_conversion_success || !ws_port_conversion_success ||
|
||||
!local_port_conversion_success) {
|
||||
|
73
core/src/discord.cpp
Normal file
73
core/src/discord.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 "include/discord.h"
|
||||
|
||||
void Discord::postModcallWebhook(QString name, QString reason, int current_area)
|
||||
{
|
||||
if (!QUrl (server->webhook_url).isValid()) {
|
||||
qWarning() << "Invalid webhook url!";
|
||||
return;
|
||||
}
|
||||
|
||||
QNetworkRequest request(QUrl (server->webhook_url));
|
||||
QNetworkAccessManager* nam = new QNetworkAccessManager();
|
||||
connect(nam, &QNetworkAccessManager::finished,
|
||||
this, &Discord::onFinish);
|
||||
|
||||
// This is the kind of garbage Qt makes me write.
|
||||
// I am so tired. Qt has broken me.
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
QJsonObject json;
|
||||
QJsonArray jsonArray;
|
||||
QJsonObject jsonObject {
|
||||
{"color", "13312842"},
|
||||
{"title", name + " filed a modcall in " + server->areas[current_area]->name()},
|
||||
{"description", reason}
|
||||
};
|
||||
jsonArray.append(jsonObject);
|
||||
json["embeds"] = jsonArray;
|
||||
|
||||
nam->post(request, QJsonDocument(json).toJson());
|
||||
|
||||
if (server->webhook_sendfile) {
|
||||
QHttpMultiPart* construct = new QHttpMultiPart();
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary=" + construct->boundary());
|
||||
|
||||
//This cost me two days of my life. Thanks Qt and Discord. You have broken me.
|
||||
QHttpPart file;
|
||||
file.setRawHeader(QByteArray("Content-Disposition"), QByteArray("form-data; name=\"file\"; filename=\"log.txt\""));
|
||||
file.setRawHeader(QByteArray("Content-Type"), QByteArray("plain/text"));
|
||||
QQueue<QString> buffer = server->areas[current_area]->buffer(); // I feel no shame for doing this
|
||||
QString log;
|
||||
while (!buffer.isEmpty()) {
|
||||
log.append(buffer.dequeue() + "\n");
|
||||
}
|
||||
file.setBody(log.toUtf8());
|
||||
construct->append(file);
|
||||
|
||||
nam->post(request, construct);
|
||||
}
|
||||
}
|
||||
|
||||
void Discord::onFinish(QNetworkReply *reply)
|
||||
{
|
||||
QByteArray data = reply->readAll();
|
||||
QString str_reply = data;
|
||||
qDebug() << str_reply;
|
||||
}
|
@ -117,3 +117,8 @@ void Logger::flush()
|
||||
|
||||
l_logfile.close();
|
||||
}
|
||||
|
||||
QQueue<QString> Logger::buffer() const
|
||||
{
|
||||
return m_buffer;
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ void AOClient::pktOocChat(AreaData* area, int argc, QStringList argv, AOPacket p
|
||||
sendServerMessage("Your name is too long! Please limit it to under 30 characters.");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
QString message = dezalgo(argv[1]);
|
||||
if (message.length() == 0 || message.length() > server->max_chars)
|
||||
return;
|
||||
@ -330,6 +330,15 @@ void AOClient::pktModCall(AreaData* area, int argc, QStringList argv, AOPacket p
|
||||
client->sendPacket(packet);
|
||||
}
|
||||
area->log(current_char, ipid, packet);
|
||||
|
||||
if (server->webhook_enabled) {
|
||||
QString name = ooc_name;
|
||||
if (ooc_name.isEmpty())
|
||||
name = current_char;
|
||||
|
||||
server->webhookRequest(name, packet.contents[0], current_area);
|
||||
}
|
||||
|
||||
area->flushLogs();
|
||||
}
|
||||
|
||||
@ -505,6 +514,8 @@ AOPacket AOClient::validateIcPacket(AOPacket packet)
|
||||
|
||||
// emote
|
||||
emote = incoming_args[3].toString();
|
||||
if (first_person)
|
||||
emote = "";
|
||||
args.append(emote);
|
||||
|
||||
// message text
|
||||
@ -683,8 +694,16 @@ AOPacket AOClient::validateIcPacket(AOPacket packet)
|
||||
|
||||
// immediate text processing
|
||||
int immediate = incoming_args[18].toInt();
|
||||
if (area->forceImmediate())
|
||||
immediate = 1;
|
||||
if (area->forceImmediate()) {
|
||||
if (args[7] == "1" || args[7] == "2") {
|
||||
args[7] = "0";
|
||||
immediate = 1;
|
||||
}
|
||||
else if (args[7] == "6") {
|
||||
args[7] = "5";
|
||||
immediate = 1;
|
||||
}
|
||||
}
|
||||
if (immediate != 1 && immediate != 0)
|
||||
return invalid;
|
||||
args.append(QString::number(immediate));
|
||||
@ -781,7 +800,7 @@ AOPacket AOClient::validateIcPacket(AOPacket packet)
|
||||
|
||||
QString AOClient::dezalgo(QString p_text)
|
||||
{
|
||||
QRegExp rxp("([\u0300-\u036f\u1ab0-\u1aff\u1dc0-\u1dff\u20d0-\u20ff\ufe20-\ufe2f\u115f\u1160\u3164]{" + QRegExp::escape(QString::number(server->zalgo_tolerance)) + ",})");
|
||||
QRegularExpression rxp("([̴̵̶̷̸̡̢̧̨̛̖̗̘̙̜̝̞̟̠̣̤̥̦̩̪̫̬̭̮̯̰̱̲̳̹̺̻̼͇͈͉͍͎̀́̂̃̄̅̆̇̈̉̊̋̌̍̎̏̐̑̒̓̔̽̾̿̀́͂̓̈́͆͊͋͌̕̚ͅ͏͓͔͕͖͙͚͐͑͒͗͛ͣͤͥͦͧͨͩͪͫͬͭͮͯ͘͜͟͢͝͞͠͡])");
|
||||
QString filtered = p_text.replace(rxp, "");
|
||||
return filtered;
|
||||
}
|
||||
|
@ -53,6 +53,13 @@ void Server::start()
|
||||
|
||||
loadServerConfig();
|
||||
loadCommandConfig();
|
||||
|
||||
if (webhook_enabled) {
|
||||
discord = new Discord(this, this);
|
||||
connect(this, &Server::webhookRequest,
|
||||
discord, &Discord::postModcallWebhook);
|
||||
|
||||
}
|
||||
|
||||
proxy = new WSProxy(port, ws_port, this);
|
||||
if(ws_port != -1)
|
||||
@ -267,10 +274,6 @@ void Server::loadServerConfig()
|
||||
MOTD = config.value("motd","MOTD is not set.").toString();
|
||||
auth_type = config.value("auth","simple").toString();
|
||||
modpass = config.value("modpass","").toString();
|
||||
bool zalgo_tolerance_conversion_success;
|
||||
zalgo_tolerance = config.value("zalgo_tolerance", "3").toInt(&zalgo_tolerance_conversion_success);
|
||||
if (!zalgo_tolerance_conversion_success)
|
||||
zalgo_tolerance = 3;
|
||||
bool maximum_statements_conversion_success;
|
||||
maximum_statements = config.value("maximustatement()s", "10").toInt(&maximum_statements_conversion_success);
|
||||
if (!maximum_statements_conversion_success)
|
||||
@ -294,6 +297,13 @@ void Server::loadServerConfig()
|
||||
dice_value = config.value("value_type", "100").toInt();
|
||||
max_dice = config.value("max_dice","100").toInt();
|
||||
config.endGroup();
|
||||
|
||||
//Load discord webhook
|
||||
config.beginGroup("Discord");
|
||||
webhook_enabled = config.value("webhook_enabled", "false").toBool();
|
||||
webhook_url = config.value("webhook_url", "Your webhook url here.").toString();
|
||||
webhook_sendfile = config.value("webhook_sendfile", false).toBool();
|
||||
config.endGroup();
|
||||
}
|
||||
|
||||
Server::~Server()
|
||||
|
67
include/discord.h
Normal file
67
include/discord.h
Normal file
@ -0,0 +1,67 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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/>. //
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef DISCORD_H
|
||||
#define DISCORD_H
|
||||
|
||||
#include <QtNetwork>
|
||||
#include <QCoreApplication>
|
||||
#include "server.h"
|
||||
|
||||
class Server;
|
||||
|
||||
class Discord : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Creates an instance of the Discord class.
|
||||
*
|
||||
* @param p_server A pointer to the Server instance Discord is constructed by.
|
||||
* @param parent Qt-based parent, passed along to inherited constructor from QObject.
|
||||
*/
|
||||
Discord(Server* p_server, QObject* parent = nullptr)
|
||||
: QObject(parent), server(p_server) {
|
||||
};
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
* @brief Sends a modcall to a discord webhook.
|
||||
*
|
||||
* @param name The character or OOC name of the client who sent the modcall.
|
||||
* @param area The area name of the area the modcall was sent from.
|
||||
* @param reason The reason the client specified for the modcall.
|
||||
* @param current_area The index of the area the modcall is made.
|
||||
*/
|
||||
void postModcallWebhook(QString name, QString reason, int current_area);
|
||||
|
||||
/**
|
||||
* @brief Sends the reply to the POST request sent by Discord::postModcallWebhook.
|
||||
*/
|
||||
void onFinish(QNetworkReply *reply);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* @brief A pointer to the Server.
|
||||
*/
|
||||
Server* server;
|
||||
|
||||
};
|
||||
|
||||
#endif // DISCORD_H
|
73
src/discord.cpp
Normal file
73
src/discord.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
// 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 "include/discord.h"
|
||||
|
||||
void Discord::postModcallWebhook(QString name, QString reason, int current_area)
|
||||
{
|
||||
if (!QUrl (server->webhook_url).isValid()) {
|
||||
qWarning() << "Invalid webhook url!";
|
||||
return;
|
||||
}
|
||||
|
||||
QNetworkRequest request(QUrl (server->webhook_url));
|
||||
QNetworkAccessManager* nam = new QNetworkAccessManager();
|
||||
connect(nam, &QNetworkAccessManager::finished,
|
||||
this, &Discord::onFinish);
|
||||
|
||||
// This is the kind of garbage Qt makes me write.
|
||||
// I am so tired. Qt has broken me.
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
QJsonObject json;
|
||||
QJsonArray jsonArray;
|
||||
QJsonObject jsonObject {
|
||||
{"color", "13312842"},
|
||||
{"title", name + " filed a modcall in " + server->areas[current_area]->name},
|
||||
{"description", reason}
|
||||
};
|
||||
jsonArray.append(jsonObject);
|
||||
json["embeds"] = jsonArray;
|
||||
|
||||
nam->post(request, QJsonDocument(json).toJson());
|
||||
|
||||
if (server->webhook_sendfile) {
|
||||
QHttpMultiPart* construct = new QHttpMultiPart();
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data; boundary=" + construct->boundary());
|
||||
|
||||
//This cost me two days of my life. Thanks Qt and Discord. You have broken me.
|
||||
QHttpPart file;
|
||||
file.setRawHeader(QByteArray("Content-Disposition"), QByteArray("form-data; name=\"file\"; filename=\"log.txt\""));
|
||||
file.setRawHeader(QByteArray("Content-Type"), QByteArray("plain/text"));
|
||||
QQueue<QString> buffer = server->areas[current_area]->logger->getBuffer(); // I feel no shame for doing this
|
||||
QString log;
|
||||
while (!buffer.isEmpty()) {
|
||||
log.append(buffer.dequeue() + "\n");
|
||||
}
|
||||
file.setBody(log.toUtf8());
|
||||
construct->append(file);
|
||||
|
||||
nam->post(request, construct);
|
||||
}
|
||||
}
|
||||
|
||||
void Discord::onFinish(QNetworkReply *reply)
|
||||
{
|
||||
QByteArray data = reply->readAll();
|
||||
QString str_reply = data;
|
||||
qDebug() << str_reply;
|
||||
}
|
Loading…
Reference in New Issue
Block a user