KShare/uploaders/customuploader.cpp

345 lines
12 KiB
C++
Raw Normal View History

2017-04-24 23:14:01 +02:00
#include "customuploader.hpp"
#include <QApplication>
#include <QBuffer>
#include <QClipboard>
#include <QDebug>
#include <QFile>
#include <QJsonDocument>
#include <QNetworkReply>
#include <io/ioutils.hpp>
using std::runtime_error;
CustomUploader::CustomUploader(QString absFilePath)
{
types.insert("PNG", "image/png"); // Is a list of supported formats, too
types.insert("GIF", "image/gif");
types.insert("JPG", "image/jpeg");
types.insert("JPEG", "image/jpeg");
types.insert("WEBM", "video/webm");
types.insert("WEBM", "video/mp4");
// Let's go
QFile file(absFilePath);
file.open(QIODevice::ReadOnly | QIODevice::Text);
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
if (!doc.isObject())
{
throw runtime_error(QString("Invalid file: ").append(absFilePath).toStdString());
}
QJsonObject obj = doc.object();
if (!obj["name"].isString())
throw runtime_error((QString("Invalid file: ").append(absFilePath) + ": name is not a string").toStdString());
else
uName = obj["name"].toString();
if (!obj.contains("desc"))
{
if (!obj["desc"].isString())
throw runtime_error((QString("Invalid file: ").append(absFilePath) + ": desc not a string, or nonexisting").toStdString());
else
desc = obj["desc"].toString();
}
else
desc = absFilePath;
QJsonValue m = obj["method"];
if (!m.isUndefined() && !m.isNull())
{
if (!m.isString())
throw runtime_error((QString("Invalid file: ").append(absFilePath) + ": method not string").toStdString());
QString toCheck = m.toString().toLower();
if (toCheck == "post")
method = HttpMethod::POST;
else
throw runtime_error((QString("Invalid file: ").append(absFilePath) + ": Bad method").toStdString());
}
QJsonValue url = obj["target"];
if (!url.isString())
{
throw runtime_error((QString("Invalid file: ").append(absFilePath) + ": target missing").toStdString());
}
QUrl target(url.toString());
if (!target.isValid())
throw runtime_error((QString("Invalid file: ").append(absFilePath) + ": target not URL").toStdString());
this->target = target;
QJsonValue formatValue = obj["format"];
if (!formatValue.isUndefined() && !formatValue.isNull())
{
if (formatValue.isString())
{
QString formatString = formatValue.toString().toLower();
if (formatString == "x-www-form-urlencoded")
format = RequestFormat::X_WWW_FORM_URLENCODED;
else if (formatString == "json")
format = RequestFormat::JSON;
else if (formatString == "plain")
format = RequestFormat::PLAIN;
else
throw runtime_error((QString("Invalid file: ").append(absFilePath) + ": format invalid").toStdString());
}
}
else
throw runtime_error((QString("Invalid file: ").append(absFilePath) + ": format provided but not string").toStdString());
QJsonValue imageValue = obj["imageformat"];
if (!imageValue.isString())
{
throw runtime_error((QString("Invalid file: ").append(absFilePath) + ": imageformat invalid/missing").toStdString());
}
QString imageFormat = imageValue.toString();
if (imageFormat == "base64" || QRegExp("base64\\([^+]+\\+[^+]+)").exactMatch(imageFormat)
|| QRegExp("[^+]+\\+[^+]+").exactMatch(imageFormat))
{
this->iFormat = imageFormat;
}
else
throw runtime_error((QString("Invalid file: ").append(absFilePath) + ": imageformat bad").toStdString());
QJsonValue bodyValue = obj["body"];
if (format != RequestFormat::PLAIN)
{
if (bodyValue.isUndefined())
throw runtime_error((QString("Invalid file: ").append(absFilePath) + ": body unset").toStdString());
if (bodyValue.isObject())
body = bodyValue;
else
throw runtime_error((QString("Invalid file: ").append(absFilePath) + ": body must be object").toStdString());
}
else
{
if (bodyValue.isString())
{
body = bodyValue;
}
else
throw runtime_error((QString("Invalid file: ").append(absFilePath) + ": body must be string (due to PLAIN)").toStdString());
}
QJsonValue headerVal = obj["headers"];
if (!(headerVal.isUndefined() || headerVal.isNull()))
{
if (!headerVal.isObject())
throw runtime_error((QString("Invalid file: ").append(absFilePath) + ": headers must be object").toStdString());
headers = headerVal.toObject();
}
else
headers = QJsonObject();
QJsonValue returnPsVal = obj["return"];
if (returnPsVal.isString())
{
returnPathspec = returnPsVal.toString();
}
else
throw runtime_error((QString("Invalid file: ").append(absFilePath) + ": return invalid").toStdString());
}
QString CustomUploader::name()
{
return uName;
}
QString CustomUploader::description()
{
return desc;
}
QString getCType(RequestFormat format, QString plainType)
{
switch (format)
{
case RequestFormat::X_WWW_FORM_URLENCODED:
return "application/x-www-form-urlencoded";
case RequestFormat::JSON:
return "application/json";
case RequestFormat::PLAIN:
return plainType;
}
return plainType;
}
QList<QPair<QString, QString>> getHeaders(QJsonObject h, QString imageFormat, QMap<QString, QString> types, RequestFormat format)
{
QList<QPair<QString, QString>> headers;
for (QString s : h.keys())
{
if (s.toLower() == "content-type") continue;
QJsonValue v = h[s];
if (!v.isString())
headers << QPair<QString, QString>(s, QJsonDocument::fromVariant(v.toVariant()).toJson());
else
headers << QPair<QString, QString>(s, v.toString());
}
headers << QPair<QString, QString>("Content-Type", getCType(format, types.value(imageFormat)));
return headers;
}
QByteArray imageBytes(QPixmap *pixmap, QString format)
{
QByteArray returnVal;
QBuffer buff(&returnVal);
buff.open(QIODevice::WriteOnly);
pixmap->save(&buff, format.toUpper().toLocal8Bit().constData());
return returnVal;
}
QString CustomUploader::getFormatString(bool animated)
{
if (iFormat == "base64")
return animated ? "GIF" : "PNG";
else if (QRegExp("[^+]+\\+[^+]+").exactMatch(iFormat))
return iFormat.split('+')[(int)animated];
else if (QRegExp("base64\\([^+]+\\+[^+]+)").exactMatch(iFormat))
return iFormat.mid(7, iFormat.length() - 8).split('+')[(int)animated];
return "";
}
QJsonObject recurseAndReplace(QJsonObject &body, QByteArray &data, QString contentType)
{
QJsonObject o;
for (QString s : body.keys())
{
QJsonValue v = body[s];
if (v.isObject())
{
QJsonObject vo = v.toObject();
o.insert(s, recurseAndReplace(vo, data, contentType));
}
else if (v.isString())
{
QString str = v.toString();
if (str.startsWith("/") && str.endsWith("/"))
{
o.insert(s, str.replace("%image", data).replace("%contenttype", contentType));
}
}
}
return o;
}
QString parsePathspec(QJsonDocument &response, QString &pathspec)
{
if (!pathspec.startsWith("."))
{
// Does not point to anything
return "";
}
else
{
if (!response.isObject()) return "";
QStringList fields = pathspec.right(pathspec.length() - 1).split('.', QString::SkipEmptyParts);
QJsonObject o = response.object();
if (pathspec == ".")
{
return QString::fromUtf8(response.toJson());
}
QJsonValue val = o[fields.at(0)];
if (val.isUndefined() || val.isNull())
return "";
else if (val.isString())
return val.toString();
else if (!val.isObject())
return QString::fromUtf8(QJsonDocument::fromVariant(val.toVariant()).toJson());
for (int i = 1; i < fields.size(); i++)
{
if (val.isUndefined() || val.isNull())
return "";
else if (val.isString())
return val.toString();
else if (!val.isObject())
return QString::fromUtf8(QJsonDocument::fromVariant(val.toVariant()).toJson());
else
val = val.toObject()[fields.at(i)];
}
if (val.isUndefined() || val.isNull())
return "";
else if (val.isString())
return val.toString();
else if (!val.isObject())
return QString::fromUtf8(QJsonDocument::fromVariant(val.toVariant()).toJson());
}
return "";
}
void CustomUploader::doUpload(QPixmap *pixmap)
{
auto h = getHeaders(headers, getFormatString(false), types, this->format);
QString format = getFormatString(false); // Soon:tm:
QByteArray data;
QByteArray imgData = imageBytes(pixmap, format);
if (iFormat == "base64" || QRegExp("base64\\([^+]\\+[^+]\\)").exactMatch(iFormat)) imgData = imgData.toBase64();
switch (this->format)
{
case RequestFormat::PLAIN:
{
data = imgData;
}
break;
case RequestFormat::JSON:
{
if (body.isString())
{
QStringList split = body.toString().replace("%contenttype", types.value(format)).split("%imagedata");
for (int i = 0; i < split.size(); i++)
{
data.append(split[i]);
if (i < split.size() - 1) data.append(imgData);
}
}
else
{
QJsonObject vo = body.toObject();
data = QJsonDocument::fromVariant(recurseAndReplace(vo, imgData, types.value(format)).toVariantMap()).toJson();
}
}
break;
case RequestFormat::X_WWW_FORM_URLENCODED:
{
QJsonObject body = this->body.toObject();
for (QString key : body.keys())
{
QJsonValue val = body[key];
if (val.isString())
{
QString str = val.toString();
QByteArray strB;
if (str.startsWith("/") && str.endsWith("/"))
{
str = str.mid(1, str.length() - 2);
QStringList split = str.replace("%contenttype", types.value(format)).split("%imagedata");
for (int i = 0; i < split.size(); i++)
{
strB.append(split[i]);
if (i < split.size() - 1) strB.append(imgData);
}
}
data.append(QUrl::toPercentEncoding(key)).append('=').append(strB);
}
else
{
if (!data.isEmpty()) data.append('&');
data.append(QUrl::toPercentEncoding(key))
.append('=')
.append(QUrl::toPercentEncoding(QJsonDocument::fromVariant(body[key].toVariant()).toJson()));
}
}
}
break;
}
switch (method)
{
case HttpMethod::POST:
if (returnPathspec == "|")
{
ioutils::postData(target, h, data, [&](QByteArray result, QNetworkReply *) {
QApplication::clipboard()->setText(QString::fromUtf8(result));
});
}
else
{
ioutils::postJson(target, h, data, [&](QJsonDocument result, QNetworkReply *) {
if (result.isObject())
{
QApplication::clipboard()->setText(parsePathspec(result, returnPathspec));
}
});
}
break;
}
}