#include "colnodapi.h" #include 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 */ bool ColnodAPI::downloadData(const qint64 &time) { // Have to get Login auto login = requestLogin(); Q_ASSERT(login); if (login->networkReply() == nullptr) { qCCritical(colnod) << "Not possible to create login request"; return false; } connect(login.get(), &serversdk::Request::finished, this, [=](){ // Get login token if (login->status() != 200) { emit downloadDataFinished(nullptr); return false; } AuthToken token; if (checkResponse(login->responseData())) { qCWarning(colnod) << "empty response data when logging in"; emit downloadDataFinished(nullptr); return false; } token.fromJson(login->responseData()); authToken = token.id(); if (authToken.isEmpty()) { qCCritical(colnod) << "Token uuid is empty"; emit downloadDataFinished(nullptr); return false; } auto data = std::make_shared(); Timestamp timestamp; timestamp.setTimestamp(time); auto checkData = [=]() { int dataCount = data->incrementCounter(); if ( dataCount > 5) { qCCritical(colnod) << "check data cannnot be higher then 4"; } Q_ASSERT(dataCount < 5); if (dataCount == 4) { qInfo(colnod) << tab << "- src col:" << tab << "tokens [" << data->updatedTokens.size() << ":" << data->deletedTokens.size() << "] subjects [" << data->updatedSubjects.size() << ":" << data->deletedSubjects.size() << "] [ added/updated : deleted ]"; if (!data->updatedTokens.isEmpty() || !data->deletedTokens.isEmpty() || !data->updatedSubjects.isEmpty() || !data->deletedSubjects.isEmpty()) { qInfo(colnod) << dash; } for (auto token : data->updatedTokens) { qInfo(colnod) << Message::massageTemplate("Download updated", "token", "colnod", token->name()); } for (auto id : data->deletedTokens) { qInfo(colnod) << Message::massageTemplate("Download deleted", "token", "colnod", id); } for (auto subject : data->updatedSubjects) { qInfo(colnod) << Message::massageTemplate("Download updated", "subject", "colnod", subject->name()); } for (auto id : data->deletedSubjects) { qInfo(colnod) << Message::massageTemplate("Download deleted", "token", "colnod", id); } if (!data->updatedTokens.isEmpty() || !data->deletedTokens.isEmpty() || !data->updatedSubjects.isEmpty() || !data->deletedSubjects.isEmpty()) { qInfo(colnod) << dash; } emit downloadDataFinished(data); } }; auto tokensRequest = getTokensUpdated(timestamp); connect(tokensRequest.get(), &serversdk::Request::finished, [=](){ if (!saveUpdatedTokens(data, tokensRequest->responseData())) { emit downloadDataFinished(nullptr); return; } checkData(); }); auto deletedTokensRequest = getTokensDeleted(timestamp); connect(deletedTokensRequest.get(), &serversdk::Request::finished, [=](){ if (!saveDeletedTokens(data, deletedTokensRequest->responseData())) { emit downloadDataFinished(nullptr); return; } checkData(); }); auto subjectsRequest = getSubjectsUpdated(timestamp); connect(subjectsRequest.get(), &serversdk::Request::finished, [=](){ if (!saveUpdatedSubjects(data, subjectsRequest->responseData())) { emit downloadDataFinished(nullptr); return; } checkData(); }); auto deletedSubjectsRequest = getSubjectsDeleted(timestamp); connect(deletedSubjectsRequest.get(), &serversdk::Request::finished, [=](){ if (!saveDeletedSubjects(data, deletedSubjectsRequest->responseData())) { emit downloadDataFinished(nullptr); return; } checkData(); }); return true; }); return true; } void ColnodAPI::processData(const std::shared_ptr &data) { qInfo(colnod) << tab << "- push col:" << tab << "tokens [" << data->updatedTokens.size() << ":" << data->deletedTokens.size() << "] [ added/updated : deleted ]"; connect(this, &ColnodAPI::partOfDataProcessFinished, this, &ColnodAPI::isDataProcessFinished); if (!data->updatedTokens.isEmpty() || !data->deletedTokens.isEmpty()) { qInfo(colnod) << dash; } if ( !data->updatedTokens.isEmpty() && !mDryMode) { setTokens(data->updatedTokens); } else { emit partOfDataProcessFinished(); } if ( !data->deletedTokens.isEmpty() && !mDryMode) { deleteTokens(data->deletedTokens); } else { emit partOfDataProcessFinished(); } if (!data->updatedTokens.isEmpty() || !data->deletedTokens.isEmpty()) { qInfo(colnod) << dash; } } std::shared_ptr 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 ColnodAPI::getTokensUpdated(const Timestamp &time) { auto request = composeRequest("/TokenManager/getTokensUpdated", time.jsonData()); request->setUserName(authToken); mReqMan->processRequest(request); return request; } std::shared_ptr ColnodAPI::getTokensDeleted(const Timestamp &time) { auto request = composeRequest("/TokenManager/getTokensDeleted", time.jsonData()); request->setUserName(authToken); mReqMan->processRequest(request); return request; } std::shared_ptr ColnodAPI::getSubjectsUpdated(const Timestamp &time) { auto request = composeRequest("/SubjectManager/getSubjectsUpdated", time.jsonData()); request->setUserName(authToken); mReqMan->processRequest(request); return request; } std::shared_ptr ColnodAPI::getSubjectsDeleted(const Timestamp &time) { auto request = composeRequest("/SubjectManager/getSubjectsDeleted", time.jsonData()); request->setUserName(authToken); mReqMan->processRequest(request); return request; } std::shared_ptr ColnodAPI::setTokens(const QHash> &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("Updated", "token", "colnod", token->name()); } emit partOfDataProcessFinished(); } else { qWarning(colnod) << "Tokens wasn't updated"; mValid = false; emit partOfDataProcessFinished(false); } }); return request; } std::shared_ptr ColnodAPI::deleteTokens(const QList &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("Deleted", "token", "colnod", id); } emit partOfDataProcessFinished(); } else { qWarning(colnod) << "Tokens wasn't deleted"; mValid = false; emit partOfDataProcessFinished(false); } }); return request; } std::shared_ptr ColnodAPI::composeRequest(const QString &endpoint, const QByteArray &data) { QString url = mHost + endpoint; return std::make_shared("POST", url, data); } bool ColnodAPI::checkRequest(const std::shared_ptr &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) { 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); } } bool ColnodAPI::saveUpdatedTokens(const std::shared_ptr& data, const QByteArray &responseData) { Q_ASSERT(data); return data->loadTokensFromJson(responseData); } bool ColnodAPI::saveDeletedTokens(const std::shared_ptr& data, const QByteArray &responseData) { Q_ASSERT(data); if (responseData.isEmpty()) return false; QJsonDocument doc = QJsonDocument::fromJson(responseData); QJsonArray items = doc.object()["items"].toArray(); for (QJsonValueRef item : items) { data->deletedTokens.append(item.toString()); } return true; } bool ColnodAPI::saveUpdatedSubjects(const std::shared_ptr& data, const QByteArray &responseData) { Q_ASSERT(data); return data->loadSubjectsFormJson(responseData); } bool ColnodAPI::saveDeletedSubjects(const std::shared_ptr& data, const QByteArray &responseData) { Q_ASSERT(data); if (responseData.isEmpty()) return false; QJsonDocument doc = QJsonDocument::fromJson(responseData); QJsonArray items = doc.object()["items"].toArray(); for (QJsonValueRef item : items) { data->deletedSubjects.append(item.toString()); } return true; } bool ColnodAPI::checkResponse(const QByteArray &responseData) { QJsonDocument doc = QJsonDocument::fromJson(responseData); return doc.object().contains("items"); }