colnod-connector/src/colnod/colnodapi.cpp
2019-12-06 15:33:28 +01:00

333 lines
11 KiB
C++

#include "colnodapi.h"
#include <utility>
Q_LOGGING_CATEGORY(colnod, "colnod.api");
ColnodAPI::ColnodAPI(serversdk::RequestManager* reqMan, const bool &dryMode, QString userName, QString password)
:mReqMan(reqMan), mUserName(std::move(userName)), mPassword(std::move(password)), mDryMode(dryMode)
{
// -----------------------------------
mReqMan->setIgnoreSsl(true);
// -----------------------------------
}
/**
* @brief Downloads new data from Colnod -> emits downloadDataFinished signal
* @param time
*
* @return signal with nullptr when something went wrong
* @return signal with data when valid data returned
*/
void ColnodAPI::downloadData(const qint64 &time)
{
// Have to get Login
auto login = requestLogin();
connect(login.get(), &serversdk::Request::finished, this, [=](){
// Get login token
if (login->status() != 200) {
emit downloadDataFinished(nullptr);
return;
}
AuthToken token;
if (checkResponse(login->responseData())) {
qCWarning(colnod) << "empty response data when logging in";
emit downloadDataFinished(nullptr);
return;
}
token.fromJson(login->responseData());
authToken = token.id();
if (authToken.isEmpty()) {
qCCritical(colnod) << "Token uuid is empty";
emit downloadDataFinished(nullptr);
return;
}
auto data = std::make_shared<Data>();
auto errorHandler = [=](const std::shared_ptr<serversdk::Request>& request){
if (!checkRequest(request)) {
qWarning(colnod) << "ERROR during calling" << request->url() << ", request unsuccessful";
mValid = false;
emit downloadDataFinished(nullptr);
}
else if (!checkResponse(request->responseData())) {
qWarning(colnod) << "Data from" << request->url() << "are invalid";
mValid = false;
emit downloadDataFinished(nullptr);
}
};
// if I have all data emit downloadDataFinished
connect(this, &ColnodAPI::partOfDataReady, this, &ColnodAPI::areDataReady);
Timestamp timestamp;
timestamp.setTimestamp(time);
auto tokensRequest = getTokensUpdated(timestamp);
connect(tokensRequest.get(), &serversdk::Request::finished, errorHandler);
connect(tokensRequest.get(), &serversdk::Request::finished, [=](){
saveUpdatedTokens(data, tokensRequest->responseData());
emit partOfDataReady(data);
});
auto deletedTokensRequest = getTokensDeleted(timestamp);
connect(deletedTokensRequest.get(), &serversdk::Request::finished, errorHandler);
connect(deletedTokensRequest.get(), &serversdk::Request::finished, [=](){
saveDeletedTokens(data, deletedTokensRequest->responseData());
emit partOfDataReady(data);
});
auto subjectsRequest = getSubjectsUpdated(timestamp);
connect(subjectsRequest.get(), &serversdk::Request::finished, errorHandler);
connect(subjectsRequest.get(), &serversdk::Request::finished, [=](){
saveUpdatedSubjects(data, subjectsRequest->responseData());
emit partOfDataReady(data);
});
auto deletedSubjectsRequest = getSubjectsDeleted(timestamp);
connect(deletedSubjectsRequest.get(), &serversdk::Request::finished, errorHandler);
connect(deletedSubjectsRequest.get(), &serversdk::Request::finished, [=](){
saveDeletedSubjects(data, deletedSubjectsRequest->responseData());
emit partOfDataReady(data);
});
});
}
void ColnodAPI::processData(const std::shared_ptr<Data> &data)
{
// OLD
// if (!data->updatedTokens.isEmpty() || !data->deletedTokens.isEmpty()) {
// qInfo(colnod) << dash;
// }
// NEW
qInfo(colnod) << "- push colnod: tokens [" << data->updatedTokens.size() << ":" << data->deletedTokens.size() <<
"] [ added/updated : deleted ]";
// OLD
// qInfo(colnod) << tab << "-> DATA PROCESSED TO COLNOD:";
// qInfo(colnod) << tab << tab << data->updatedTokens.size() << "TOKENS UPDATED";
// qInfo(colnod) << tab << tab << data->deletedTokens.size() << "TOKENS DELETED";
// qInfo(colnod) << dash;
connect(this, &ColnodAPI::partOfDataProcessFinished, this, &ColnodAPI::isDataProcessFinished);
if ( !data->updatedTokens.isEmpty() && !mDryMode) {
setTokens(data->updatedTokens);
} else {
emit partOfDataProcessFinished();
}
if ( !data->deletedTokens.isEmpty() && !mDryMode) {
deleteTokens(data->deletedTokens);
} else {
emit partOfDataProcessFinished();
}
}
std::shared_ptr<serversdk::Request> ColnodAPI::requestLogin()
{
Q_ASSERT(mReqMan);
LoginResp login;
login.setUsername(userName());
// password
QString encodedPassword = QCryptographicHash::hash(
password().toLocal8Bit(), // -> bytearray
QCryptographicHash::Sha512 // SHA 512
).toHex().toUpper();
login.setPassword(encodedPassword);
auto loginRequest = composeRequest("/AaaManager/authSession", login.jsonData());
loginRequest->setUserName(login.username());
loginRequest->setPassword(login.password());
mReqMan->processRequest(loginRequest);
return loginRequest;
}
std::shared_ptr<serversdk::Request> ColnodAPI::getTokensUpdated(const Timestamp &time)
{
auto request = composeRequest("/TokenManager/getTokensUpdated", time.jsonData());
request->setUserName(authToken);
mReqMan->processRequest(request);
return request;
}
std::shared_ptr<serversdk::Request> ColnodAPI::getTokensDeleted(const Timestamp &time)
{
auto request = composeRequest("/TokenManager/getTokensDeleted", time.jsonData());
request->setUserName(authToken);
mReqMan->processRequest(request);
return request;
}
std::shared_ptr<serversdk::Request> ColnodAPI::getSubjectsUpdated(const Timestamp &time)
{
auto request = composeRequest("/SubjectManager/getSubjectsUpdated", time.jsonData());
request->setUserName(authToken);
mReqMan->processRequest(request);
return request;
}
std::shared_ptr<serversdk::Request> ColnodAPI::getSubjectsDeleted(const Timestamp &time)
{
auto request = composeRequest("/SubjectManager/getSubjectsDeleted", time.jsonData());
request->setUserName(authToken);
mReqMan->processRequest(request);
return request;
}
std::shared_ptr<serversdk::Request> ColnodAPI::setTokens(const QHash<QString, std::shared_ptr<Token>> &tokens)
{
auto request = composeRequest("/TokenManager/setTokens", Token::tokensToColnodJson(tokens));
request->setUserName(authToken);
mReqMan->processRequest(request);
connect(request.get(), &serversdk::Request::finished, [=](){
if (!checkRequest(request)) {
qCritical(colnod) << "ERROR during calling /TokenManager/setTokens, request unsuccessful. EXIT";
}
if (checkResponse(request->responseData())) {
for (const auto &token : tokens) {
qInfo(colnod).noquote() << Message::massageTemplate("Updating", "token", "colnod", token->name());
}
emit partOfDataProcessFinished();
}
else {
qWarning(colnod) << "Tokens wasn't updated";
mValid = false;
emit partOfDataProcessFinished(false);
}
});
return request;
}
std::shared_ptr<serversdk::Request> ColnodAPI::deleteTokens(const QList<QString> &ids)
{
auto request = composeRequest("/TokenManager/deleteTokens", Token::idsToJSON(ids));
request->setUserName(authToken);
mReqMan->processRequest(request);
connect(request.get(), &serversdk::Request::finished, [=](){
if (!checkRequest(request)) {
qCritical(colnod) << "ERROR during calling /TokenManager/deleteTokens, request unsuccessful. EXIT";
}
if (checkResponse(request->responseData())) {
for (const auto &id : ids) {
qInfo(colnod).noquote() << Message::massageTemplate("Deleting", "token", "colnod", id);
}
emit partOfDataProcessFinished();
}
else {
qWarning(colnod) << "Tokens wasn't deleted";
mValid = false;
emit partOfDataProcessFinished(false);
}
});
return request;
}
std::shared_ptr<serversdk::Request> ColnodAPI::composeRequest(const QString &endpoint, const QByteArray &data)
{
QString url = mHost + endpoint;
return std::make_shared<serversdk::Request>("POST", url, data);
}
bool ColnodAPI::checkRequest(const std::shared_ptr<serversdk::Request> &request)
{
return request->status() == 200;
}
bool ColnodAPI::isValid()
{
return mValid;
}
QString ColnodAPI::password() const
{
return mPassword;
}
void ColnodAPI::setPassword(const QString &password)
{
mPassword = password;
}
QString ColnodAPI::userName() const
{
return mUserName;
}
void ColnodAPI::setUserName(const QString &userName)
{
mUserName = userName;
}
void ColnodAPI::areDataReady(const std::shared_ptr<Data> &data)
{
if (++amountData == 4) {
// new
qInfo(colnod) << "- src colnod: tokens [" << data->updatedTokens.size() << ":" << data->deletedTokens.size() <<
"] subjects [" << data->updatedSubjects.size() << ":" << data->deletedSubjects.size() << "] [ added/updated : deleted ]";
//OLD
// qInfo(colnod) << tab << "-> COLNOD DATA:";
// qInfo(colnod) << tab << tab << data->updatedTokens.size() << "TOKENS WERE ADDED/UPDATED";
// qInfo(colnod) << tab << tab << data->deletedTokens.size() << "TOKENS DELETED";
// qInfo(colnod) << tab << tab << data->updatedSubjects.size() << "SUBJECTS WERE ADDED/UPDATED";
// qInfo(colnod) << tab << tab << data->deletedSubjects.size() << "SUBJECTS DELETED";
// qInfo(colnod) << dash;
amountData = 0;
emit downloadDataFinished(data);
}
}
void ColnodAPI::isDataProcessFinished(bool success)
{
if (!success) {
mSuccess = false;
}
if (++amountProccessesFinished == 2) {
emit dataProcessFinished(mSuccess);
}
}
void ColnodAPI::saveUpdatedTokens(const std::shared_ptr<Data>& data, const QByteArray &responseData)
{
data->loadTokensFromJson(responseData);
}
void ColnodAPI::saveDeletedTokens(const std::shared_ptr<Data>& data, const QByteArray &responseData)
{
QJsonDocument doc = QJsonDocument::fromJson(responseData);
QJsonArray items = doc.object()["items"].toArray();
for (QJsonValueRef item : items) {
data->deletedTokens.append(item.toString());
}
}
void ColnodAPI::saveUpdatedSubjects(const std::shared_ptr<Data>& data, const QByteArray &responseData)
{
data->loadSubjectsFormJson(responseData);
}
void ColnodAPI::saveDeletedSubjects(const std::shared_ptr<Data>& data, const QByteArray &responseData)
{
QJsonDocument doc = QJsonDocument::fromJson(responseData);
QJsonArray items = doc.object()["items"].toArray();
for (QJsonValueRef item : items) {
data->deletedSubjects.append(item.toString());
}
}
bool ColnodAPI::checkResponse(const QByteArray &responseData)
{
QJsonDocument doc = QJsonDocument::fromJson(responseData);
return doc.object().contains("items");
}