mirror of
https://gitlab.com/spaceti-app/integrations/acs/colnod-connector.git
synced 2026-07-12 16:20:39 +02:00
423 lines
14 KiB
C++
423 lines
14 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
|
|
*/
|
|
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 and check if is correct
|
|
if (!checkRequest(login)) {
|
|
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<Data>();
|
|
Timestamp timestamp;
|
|
timestamp.setTimestamp(time);
|
|
|
|
// emit signal when with all data when it is ready
|
|
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 (const auto &token : data->updatedTokens) {
|
|
qInfo(colnod) << Message::massageTemplate("Download updated", "token", "colnod", token->name());
|
|
}
|
|
for (const auto &id : data->deletedTokens) {
|
|
qInfo(colnod) << Message::massageTemplate("Download deleted", "token", "colnod", id);
|
|
}
|
|
for (const auto &subject : data->updatedSubjects) {
|
|
qInfo(colnod) << Message::massageTemplate("Download updated", "subject", "colnod", subject->name());
|
|
}
|
|
for (const 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 (!checkErrors(tokensRequest)) {
|
|
qCritical(colnod) << "Error during call getTokensUpdated endpoint";
|
|
emit downloadDataFinished(nullptr);
|
|
return;
|
|
}
|
|
if (!saveUpdatedTokens(data, tokensRequest->responseData())) {
|
|
qCritical(colnod) << "Error during saving getTokensUpdated";
|
|
emit downloadDataFinished(nullptr);
|
|
return;
|
|
}
|
|
checkData();
|
|
});
|
|
|
|
auto deletedTokensRequest = getTokensDeleted(timestamp);
|
|
connect(deletedTokensRequest.get(), &serversdk::Request::finished, [=](){
|
|
if (!checkErrors(deletedTokensRequest)) {
|
|
qCritical(colnod) << "Error during call getTokensDeleted endpoint";
|
|
emit downloadDataFinished(nullptr);
|
|
return;
|
|
}
|
|
if (!saveDeletedTokens(data, deletedTokensRequest->responseData())) {
|
|
qCritical(colnod) << "Error during saving getTokensDeleted";
|
|
emit downloadDataFinished(nullptr);
|
|
return;
|
|
}
|
|
checkData();
|
|
});
|
|
|
|
auto subjectsRequest = getSubjectsUpdated(timestamp);
|
|
connect(subjectsRequest.get(), &serversdk::Request::finished, [=](){
|
|
if (!checkErrors(subjectsRequest)) {
|
|
qCritical(colnod) << "Error during call getSubjectsUpdated endpoint";
|
|
emit downloadDataFinished(nullptr);
|
|
return;
|
|
}
|
|
if (!saveUpdatedSubjects(data, subjectsRequest->responseData())) {
|
|
qCritical(colnod) << "Error during saving getSubjectsUpdated";
|
|
emit downloadDataFinished(nullptr);
|
|
return;
|
|
}
|
|
checkData();
|
|
});
|
|
|
|
auto deletedSubjectsRequest = getSubjectsDeleted(timestamp);
|
|
connect(deletedSubjectsRequest.get(), &serversdk::Request::finished, [=](){
|
|
if (!checkErrors(deletedSubjectsRequest)) {
|
|
qCritical(colnod) << "Error during call getSubjectsDeleted endpoint";
|
|
emit downloadDataFinished(nullptr);
|
|
return;
|
|
}
|
|
if (!saveDeletedSubjects(data, deletedSubjectsRequest->responseData())) {
|
|
qCritical(colnod) << "Error during saving getSubjectsDeleted";
|
|
emit downloadDataFinished(nullptr);
|
|
return;
|
|
}
|
|
checkData();
|
|
});
|
|
return true;
|
|
|
|
});
|
|
return true;
|
|
}
|
|
|
|
void ColnodAPI::processData(const std::shared_ptr<PreparedData> &prepdata)
|
|
{
|
|
auto data = prepdata->databaseData;
|
|
// emit signal when finished
|
|
auto checkData = [=]() {
|
|
int dataCount = data->incrementCounter();
|
|
if ( dataCount > 3) {
|
|
qCCritical(colnod) << "check data cannnot be higher then 2";
|
|
}
|
|
Q_ASSERT(dataCount < 3);
|
|
if (dataCount == 2) {
|
|
qInfo(colnod) << tab << "- push col:" << tab << "tokens [" << data->updatedTokens.size() << ":" << data->deletedTokens.size() <<
|
|
"] [ added/updated : deleted ]";
|
|
|
|
if (!data->updatedTokens.isEmpty() || !data->deletedTokens.isEmpty() ||
|
|
!data->updatedSubjects.isEmpty() || !data->deletedSubjects.isEmpty()) {
|
|
qInfo(colnod) << dash;
|
|
}
|
|
|
|
for (const auto &token : data->updatedTokens) {
|
|
qInfo(colnod).noquote() << Message::massageTemplate("Updated", "token", "colnod", token->name());
|
|
}
|
|
|
|
for (const auto &id : data->deletedTokens) {
|
|
qInfo(colnod).noquote() << Message::massageTemplate("Deleted", "token", "colnod", id);
|
|
}
|
|
|
|
if (!data->updatedTokens.isEmpty() || !data->deletedTokens.isEmpty() ||
|
|
!data->updatedSubjects.isEmpty() || !data->deletedSubjects.isEmpty()) {
|
|
qInfo(colnod) << dash;
|
|
}
|
|
emit dataProcessFinished(mValid, prepdata);
|
|
}
|
|
};
|
|
|
|
if ( !data->updatedTokens.isEmpty() || !data->deletedTokens.isEmpty() ) {
|
|
qInfo(colnod) << dash;
|
|
}
|
|
if ( !data->updatedTokens.isEmpty() && !mDryMode ) {
|
|
auto setTokensRequest = setTokens(data->updatedTokens);
|
|
connect(setTokensRequest.get(), &serversdk::Request::finished, [=](){
|
|
if (!checkErrors(setTokensRequest)) {
|
|
data->updatedTokens.clear();
|
|
mValid = false;
|
|
return;
|
|
}
|
|
checkData();
|
|
});
|
|
} else {
|
|
checkData();
|
|
}
|
|
|
|
if ( !data->deletedTokens.isEmpty() && !mDryMode ) {
|
|
auto deletedTokensRequest = deleteTokens(data->deletedTokens);
|
|
connect(deletedTokensRequest.get(), &serversdk::Request::finished, [=](){
|
|
if (!checkErrors(deletedTokensRequest)) {
|
|
data->deletedTokens.clear();
|
|
mValid = false;
|
|
return;
|
|
}
|
|
checkData();
|
|
});
|
|
} else {
|
|
checkData();
|
|
}
|
|
}
|
|
|
|
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();
|
|
login.setPassword(encodedPassword);
|
|
|
|
auto loginRequest = composeRequest("/AaaManager/authSession", login.jsonData());
|
|
|
|
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);
|
|
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);
|
|
return request;
|
|
}
|
|
|
|
std::shared_ptr<serversdk::Request> ColnodAPI::composeRequest(const QString &endpoint, const QByteArray &data)
|
|
{
|
|
QString url = mHost + endpoint;
|
|
auto request = std::make_shared<serversdk::Request>("POST", url, data);
|
|
|
|
request->addHeader("client-id", mClientId);
|
|
request->addHeader("x-api-key", mApiKey);
|
|
|
|
return request;
|
|
}
|
|
|
|
bool ColnodAPI::checkRequest(const std::shared_ptr<serversdk::Request> &request)
|
|
{
|
|
return request->status() == 200;
|
|
}
|
|
|
|
bool ColnodAPI::checkErrors(const std::shared_ptr<serversdk::Request> &request)
|
|
{
|
|
if (!checkRequest(request)) {
|
|
qCWarning(colnod) << "Status is not 200";
|
|
return false;
|
|
}
|
|
if (!checkResponse(request->responseData())) {
|
|
qCWarning(colnod) << "Empty response data";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
bool ColnodAPI::saveUpdatedTokens(const std::shared_ptr<Data>& data, const QByteArray &responseData)
|
|
{
|
|
Q_ASSERT(data);
|
|
return data->loadTokensFromJson(responseData);
|
|
}
|
|
|
|
bool ColnodAPI::saveDeletedTokens(const std::shared_ptr<Data>& 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>& data, const QByteArray &responseData)
|
|
{
|
|
Q_ASSERT(data);
|
|
return data->loadSubjectsFormJson(responseData);
|
|
}
|
|
|
|
bool ColnodAPI::saveDeletedSubjects(const std::shared_ptr<Data>& 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");
|
|
}
|
|
|
|
bool ColnodAPI::updateAuthToken() {
|
|
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 and check if is correct
|
|
if (!checkRequest(login)) {
|
|
emit authTokenUpdated(false);
|
|
return;
|
|
}
|
|
AuthToken token;
|
|
|
|
if (checkResponse(login->responseData())) {
|
|
qCWarning(colnod) << "empty response data when logging in";
|
|
emit authTokenUpdated(false);
|
|
return;
|
|
}
|
|
|
|
token.fromJson(login->responseData());
|
|
authToken = token.id();
|
|
if (authToken.isEmpty()) {
|
|
qCCritical(colnod) << "Token uuid is empty";
|
|
emit authTokenUpdated(false);;
|
|
return ;
|
|
}
|
|
emit authTokenUpdated(true);
|
|
});
|
|
return true;
|
|
}
|