#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 */ 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(); auto errorHandler = [=](const std::shared_ptr& 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) { if (!data->updatedTokens.isEmpty() || !data->deletedTokens.isEmpty()) { qInfo(colnod) << dash; } 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 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("Updating", "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("Deleting", "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) { 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, const QByteArray &responseData) { data->loadTokensFromJson(responseData); } void ColnodAPI::saveDeletedTokens(const std::shared_ptr& 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, const QByteArray &responseData) { data->loadSubjectsFormJson(responseData); } void ColnodAPI::saveDeletedSubjects(const std::shared_ptr& 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"); }