Fix memory leaks and add error handling

This commit is contained in:
Ondřej Fischer 2019-11-04 11:07:11 +01:00
parent 8d6dc6714c
commit 8f16ac06a6
19 changed files with 176 additions and 143 deletions

View File

@ -1,7 +1,7 @@
#include <QCoreApplication> #include <QCoreApplication>
#include "datamanager.h" #include "datamanager.h"
#include "colnodapi.h" #include "syncmanager.h"
#include <QCommandLineParser> #include <QCommandLineParser>
int main(int argc, char *argv[]) int main(int argc, char *argv[])
@ -15,15 +15,19 @@ int main(int argc, char *argv[])
QCommandLineOption dryModeOption("dryMode", "ColnodAPI", "Read-only mode, prints changes which would normally be made"); QCommandLineOption dryModeOption("dryMode", "ColnodAPI", "Read-only mode, prints changes which would normally be made");
parser.addOption(dryModeOption); parser.addOption(dryModeOption);
parser.process(app); parser.process(app);
auto *api = new ColnodAPI(parser.isSet(dryModeOption)); SyncManager api(parser.isSet(dryModeOption));
api->loadDataFromDB(); api.loadDataFromDB();
api->loadDataFromColnod(); api.loadDataFromColnod();
QObject::connect(api, &ColnodAPI::dataDownloaded, [=](){ QObject::connect(&api, &SyncManager::dataDownloaded, [&](){
api->syncDataFromColnodToDB(); api.syncDataFromColnodToDB();
api->syncDataFromDBToColnod(); api.syncDataFromDBToColnod();
QObject::connect(api, &ColnodAPI::syncFinished, [=](){ QObject::connect(&api, &SyncManager::syncFinished, [](){
qDebug() << "Quit";
QCoreApplication::exit(); QCoreApplication::exit();
}); });
}); });
QObject::connect(&api, &SyncManager::error, [](){
QCoreApplication::exit(1);
});
return QCoreApplication::exec(); return QCoreApplication::exec();
} }

View File

@ -2,7 +2,6 @@ INCLUDEPATH += $$PWD
#SRC_DIR = $$PWD #SRC_DIR = $$PWD
message($$PWD) message($$PWD)
SOURCES += \ SOURCES += \
$$PWD/colnodapi.cpp \
$$PWD/databasemanager.cpp \ $$PWD/databasemanager.cpp \
$$PWD/datamanager.cpp \ $$PWD/datamanager.cpp \
$$PWD/entity.cpp \ $$PWD/entity.cpp \
@ -10,10 +9,10 @@ SOURCES += \
$$PWD/requestmanager.cpp \ $$PWD/requestmanager.cpp \
$$PWD/response.cpp \ $$PWD/response.cpp \
$$PWD/subject.cpp \ $$PWD/subject.cpp \
$$PWD/syncmanager.cpp \
$$PWD/token.cpp $$PWD/token.cpp
HEADERS += \ HEADERS += \
$$PWD/colnodapi.h \
$$PWD/databasemanager.h \ $$PWD/databasemanager.h \
$$PWD/datamanager.h \ $$PWD/datamanager.h \
$$PWD/entity.h \ $$PWD/entity.h \
@ -21,5 +20,6 @@ HEADERS += \
$$PWD/requestmanager.h \ $$PWD/requestmanager.h \
$$PWD/response.h \ $$PWD/response.h \
$$PWD/subject.h \ $$PWD/subject.h \
$$PWD/syncmanager.h \
$$PWD/token.h $$PWD/token.h
message($$SOURCES) message($$SOURCES)

View File

@ -9,14 +9,15 @@ DatabaseManager::DatabaseManager(const QString& host, const QString& dbName, con
db.setPassword(password); db.setPassword(password);
if (!db.open()) if (!db.open())
{ {
qDebug() << "Opening error" + db.lastError().text(); log("Opening error" + db.lastError().text());
emit error();
} }
query = QSqlQuery("query", db); query = QSqlQuery("query", db);
this->dryMode = dryMode; this->dryMode = dryMode;
} }
// add or update subject to db // add or update subject to db
int DatabaseManager::saveSubject(Subject* subject, const QString& table) int DatabaseManager::saveSubject(std::shared_ptr<Subject> subject, const QString& table)
{ {
QString id = subject->idToStringWithoutBraces(); QString id = subject->idToStringWithoutBraces();
if (checkIfExists(id, table)) if (checkIfExists(id, table))
@ -46,7 +47,7 @@ int DatabaseManager::saveSubject(Subject* subject, const QString& table)
} }
// add or update token to DB // add or update token to DB
int DatabaseManager::saveToken(Token* token, const QString& table) int DatabaseManager::saveToken(std::shared_ptr<Token> token, const QString& table)
{ {
QString id = token->idToStringWithoutBraces(); QString id = token->idToStringWithoutBraces();
if (checkIfExists(id, table)) if (checkIfExists(id, table))
@ -93,7 +94,7 @@ int DatabaseManager::saveToken(Token* token, const QString& table)
} }
// add of update subject attributes // add of update subject attributes
void DatabaseManager::saveSubjectAttributes(Subject *subject, const QString& table) void DatabaseManager::saveSubjectAttributes(std::shared_ptr<Subject> subject, const QString& table)
{ {
auto attributes = subject->getAtr(); auto attributes = subject->getAtr();
for (const auto& attribute : attributes){ for (const auto& attribute : attributes){
@ -123,10 +124,10 @@ void DatabaseManager::saveSubjectAttributes(Subject *subject, const QString& tab
void DatabaseManager::setDeleted(const QString& id, const QString& table, quint64 time) void DatabaseManager::setDeleted(const QString& id, const QString& table, quint64 time)
{ {
//quint64 now = getNow(); //quint64 now = getNow();
//QString nowString = QDateTime::fromMSecsSinceEpoch(now).toString("yyyy-MM-dd hh:mm:ss.zzz"); QString nowString = QDateTime::fromMSecsSinceEpoch(time).toString("yyyy-MM-dd hh:mm:ss.zzz");
query.prepare(QString("UPDATE %1 SET deleted = true, last_update = :now, last_modified = :now WHERE id = :id").arg(table)); query.prepare(QString("UPDATE %1 SET deleted = true, last_update = :now, last_modified = :now WHERE id = :id").arg(table));
query.bindValue(":id", id); query.bindValue(":id", id);
query.bindValue(":now", time); query.bindValue(":now", nowString);
executeQuery(query); executeQuery(query);
} }
@ -151,31 +152,37 @@ QString DatabaseManager::getLastQuery(const QSqlQuery& query) const
return str; return str;
} }
void DatabaseManager::executeNonPreperedQuery(const QString &statement, QSqlQuery &query) const void DatabaseManager::executeNonPreperedQuery(const QString &statement, QSqlQuery &query)
{ {
if (dryMode){ if (dryMode){
QString sqlStatement = getLastQuery(query); QString sqlStatement = getLastQuery(query);
qDebug() << sqlStatement; qDebug() << sqlStatement;
if (statement.startsWith("SELECT"))
query.exec(statement);
} }
else{ if (!dryMode || statement.startsWith("SELECT")){
query.exec(statement); if (!query.exec(statement)){
QString msg = QString("Source: Database Manager, Error: %1").arg(query.lastError().text());
log(QString(msg));
emit error();
}
} }
} }
bool DatabaseManager::executeQuery(QSqlQuery &query) const bool DatabaseManager::executeQuery(QSqlQuery &query)
{ {
if (dryMode){ if (dryMode){
QString sqlStatement = getLastQuery(query); QString sqlStatement = getLastQuery(query);
qDebug() << sqlStatement; qDebug() << sqlStatement;
if (sqlStatement.startsWith("SELECT"))
query.exec(); }
if (!dryMode || query.isSelect()){
if (!query.exec()){
QString msg = QString("Source: Database Manager, Error: %1").arg(query.lastError().text());
log(QString(msg));
emit error();
}
}
return true; return true;
}
bool res = query.exec();
return res;
} }
void DatabaseManager::dropTables() void DatabaseManager::dropTables()
@ -285,7 +292,7 @@ QString DatabaseManager::getSubjectNameByTokenId(const QString &tokenId)
if (query.next()) if (query.next())
return query.value(0).toString(); return query.value(0).toString();
qWarning() << "Token:" << tokenId << "is not assigned to any subject"; qWarning() << "Token:" << tokenId << "is not assigned to any subject";
return "No Subject"; return "(No subject)";
} }
QString DatabaseManager::getSubjectNameById(const QString &id) QString DatabaseManager::getSubjectNameById(const QString &id)
@ -296,7 +303,7 @@ QString DatabaseManager::getSubjectNameById(const QString &id)
if (query.next()) if (query.next())
return query.value(0).toString(); return query.value(0).toString();
qWarning() << "Subject:" << id << "doesn't exists"; qWarning() << "Subject:" << id << "doesn't exists";
return "No Subject"; return "(No subject)";
} }
bool DatabaseManager::checkDeletedToken(const QString &id) bool DatabaseManager::checkDeletedToken(const QString &id)

View File

@ -19,9 +19,9 @@ class DatabaseManager : public QObject
public: public:
DatabaseManager(const QString& host, const QString& dbName, const QString& user, const QString& password, const bool& dryMode = false); DatabaseManager(const QString& host, const QString& dbName, const QString& user, const QString& password, const bool& dryMode = false);
int saveSubject(Subject* subject, const QString& table); int saveSubject(std::shared_ptr<Subject> subject, const QString& table);
int saveToken(Token* token, const QString& table); int saveToken(std::shared_ptr<Token> token, const QString& table);
void saveSubjectAttributes(Subject* subject, const QString& table); void saveSubjectAttributes(std::shared_ptr<Subject> subject, const QString& table);
void setDeleted(const QString& id, const QString& table, quint64 time); void setDeleted(const QString& id, const QString& table, quint64 time);
void dropTables(); void dropTables();
@ -44,9 +44,12 @@ public:
private: private:
bool checkIfExists(const QString& id, const QString& table); bool checkIfExists(const QString& id, const QString& table);
bool executeQuery(QSqlQuery &query) const; bool executeQuery(QSqlQuery &query);
QString getLastQuery(const QSqlQuery &query) const; QString getLastQuery(const QSqlQuery &query) const;
void executeNonPreperedQuery(const QString &statement, QSqlQuery& query) const; void executeNonPreperedQuery(const QString &statement, QSqlQuery& query);
signals:
void error();
private: private:
QSqlDatabase db; QSqlDatabase db;

View File

@ -2,12 +2,13 @@
DataManager::DataManager(const bool &dryMode) DataManager::DataManager(const bool &dryMode)
{ {
db = new DatabaseManager("192.168.1.94", "deloitte", "postgres", "34rjkciea12", dryMode); db = std::make_shared<DatabaseManager>("192.168.1.94", "deloitte", "postgres", "34rjkciea12", dryMode);
//db = new DatabaseManager("localhost", "deloitte", "postgres", "34rjkciea12"); //db = std::make_shared<DatabaseManager>("localhost", "deloitte", "postgres", "34rjkciea12");
Logger::setDBMan(db); Logger::setDBMan(db);
nextLastSync = db->getNow(); nextLastSync = db->getNow();
lastSync = db->getLastSync(); lastSync = db->getLastSync();
this->dryMode = dryMode; this->dryMode = dryMode;
connect(db.get(), &DatabaseManager::error, this, &DataManager::error);
} }
// load all tokens from colnod to comparing with working set from DB // load all tokens from colnod to comparing with working set from DB
@ -18,14 +19,14 @@ void DataManager::fillFullTokensColnod(const QString& response)
if (!items.empty()) if (!items.empty())
{ {
for (QJsonValueRef item : items){ for (QJsonValueRef item : items){
auto token = new Token(); auto token = std::make_shared<Token>();
token->fromJSON(item.toObject()); token->fromJSON(item.toObject());
allTokensFromColnod.insert(token->idToStringWithoutBraces(), token); allTokensFromColnod.insert(token->idToStringWithoutBraces(), token);
} }
} }
else{ else{
qCritical() << "Colnod is Empty"; qCritical() << "Colnod is Empty";
auto token = new Token("empty"); auto token = std::make_shared<Token>("empty");
allTokensFromColnod.insert(token->idToStringWithoutBraces(), token); allTokensFromColnod.insert(token->idToStringWithoutBraces(), token);
} }
} }
@ -39,7 +40,7 @@ void DataManager::fillTokensToUpdateColnod(const QString& response)
{ {
for (QJsonValueRef item : items) for (QJsonValueRef item : items)
{ {
auto token = new Token(); auto token = std::make_shared<Token>();
token->fromJSON(item.toObject()); token->fromJSON(item.toObject());
token->setDeleted(false); token->setDeleted(false);
tokensToUpdateFromColnodToDB.insert(token->idToStringWithoutBraces(), token); tokensToUpdateFromColnodToDB.insert(token->idToStringWithoutBraces(), token);
@ -49,7 +50,7 @@ void DataManager::fillTokensToUpdateColnod(const QString& response)
else else
{ {
qInfo() << "Colnod: 0 tokens to update"; qInfo() << "Colnod: 0 tokens to update";
auto token = new Token("empty"); auto token = std::make_shared<Token>("empty");
tokensToUpdateFromColnodToDB.insert(token->getName(), token); tokensToUpdateFromColnodToDB.insert(token->getName(), token);
} }
} }
@ -63,7 +64,7 @@ void DataManager::fillSubjectsToUpdateColnod(const QString& response)
{ {
for (QJsonValueRef item : items) for (QJsonValueRef item : items)
{ {
auto subject = new Subject(); auto subject = std::make_shared<Subject>();
subject->fromJSON(item.toObject()); subject->fromJSON(item.toObject());
subjectsToUpdateFromColnodToDB.insert(subject->idToStringWithoutBraces(), subject); subjectsToUpdateFromColnodToDB.insert(subject->idToStringWithoutBraces(), subject);
} }
@ -72,7 +73,7 @@ void DataManager::fillSubjectsToUpdateColnod(const QString& response)
else else
{ {
qInfo() << "Colnod:" << "0 subjects to update"; qInfo() << "Colnod:" << "0 subjects to update";
Subject* subject = new Subject("empty"); auto subject = std::make_shared<Subject>("empty");
subjectsToUpdateFromColnodToDB.insert(subject->getName(), subject); subjectsToUpdateFromColnodToDB.insert(subject->getName(), subject);
} }
} }
@ -83,7 +84,7 @@ void DataManager::fillTokensToChangeDB()
QSqlQuery* query = db->getUpdatedTokens(); QSqlQuery* query = db->getUpdatedTokens();
while (query->next()) while (query->next())
{ {
auto token = new Token; auto token = std::make_shared<Token>();
token->fromSQLRecord(query); token->fromSQLRecord(query);
if (token->getDeleted()){ // sort to delete / to update if (token->getDeleted()){ // sort to delete / to update
tokensFromDBToDeleteFromColnod.append(token->idToStringWithoutBraces()); tokensFromDBToDeleteFromColnod.append(token->idToStringWithoutBraces());
@ -288,7 +289,7 @@ void DataManager::filterTokensColnod()
auto record = db->getToken(id); auto record = db->getToken(id);
if (!record) if (!record)
continue; continue;
auto tokenDB = new Token; auto tokenDB = std::shared_ptr<Token>();
tokenDB->fromSQLRecord(record); tokenDB->fromSQLRecord(record);
Q_ASSERT(tokenDB != token); Q_ASSERT(tokenDB != token);
if (*tokenDB > *token) if (*tokenDB > *token)

View File

@ -42,9 +42,9 @@ public:
void emptyDatabase(); void emptyDatabase();
QHash<QString, QPointer<Token>> getTokensToUpdateColnod() {return tokensToUpdateFromColnodToDB;} QHash<QString, std::shared_ptr<Token>> getTokensToUpdateColnod() {return tokensToUpdateFromColnodToDB;}
QList<QString> getTokensToDeleteColnod() {return tokensFromColnodToDeleteFromDB;} QList<QString> getTokensToDeleteColnod() {return tokensFromColnodToDeleteFromDB;}
QHash<QString, QPointer<Token>> getTokensToUpdateDB() {return tokensToUpdateFromDBToColnod;} QHash<QString, std::shared_ptr<Token>> getTokensToUpdateDB() {return tokensToUpdateFromDBToColnod;}
QList<QString> getTokensToDeleteDB() {return tokensFromDBToDeleteFromColnod;} QList<QString> getTokensToDeleteDB() {return tokensFromDBToDeleteFromColnod;}
const quint64 &getLastSync() {return lastSync;} const quint64 &getLastSync() {return lastSync;}
@ -55,17 +55,20 @@ public slots:
void setLastSync() {db->updateLastSync(nextLastSync);} void setLastSync() {db->updateLastSync(nextLastSync);}
void setLastUpdate(); void setLastUpdate();
signals:
void error();
private: private:
DatabaseManager *db = nullptr; std::shared_ptr<DatabaseManager> db;
quint64 lastSync; // time of last run quint64 lastSync; // time of last run
quint64 nextLastSync; // time of begin of this run quint64 nextLastSync; // time of begin of this run
QHash<QString, QPointer<Subject>> subjectsToUpdateFromColnodToDB; QHash<QString, std::shared_ptr<Subject>> subjectsToUpdateFromColnodToDB;
QHash<QString, QPointer<Token>> tokensToUpdateFromColnodToDB; QHash<QString, std::shared_ptr<Token>> tokensToUpdateFromColnodToDB;
QHash<QString, QPointer<Token>> allTokensFromColnod; QHash<QString, std::shared_ptr<Token>> allTokensFromColnod;
QHash<QString, QPointer<Subject>> subjectsDB; // in future QHash<QString, std::shared_ptr<Subject>> subjectsDB; // in future
QHash<QString, QPointer<Token>> tokensToUpdateFromDBToColnod; QHash<QString, std::shared_ptr<Token>> tokensToUpdateFromDBToColnod;
QList<QString> subjectsFromColnodToDeleteFromDB; QList<QString> subjectsFromColnodToDeleteFromDB;
QList<QString> tokensFromColnodToDeleteFromDB; QList<QString> tokensFromColnodToDeleteFromDB;

View File

@ -3,6 +3,8 @@
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QUuid> #include <QtCore/QUuid>
#include <QtCore/QJsonObject> #include <QtCore/QJsonObject>
#include <QDebug>
#include <memory>
class Entity : public QObject { class Entity : public QObject {

View File

@ -1,6 +1,6 @@
#include "logger.h" #include "logger.h"
DatabaseManager *Logger::dbMan = nullptr; std::shared_ptr<DatabaseManager> Logger::dbMan = nullptr;
Logger *Logger::logger = nullptr; Logger *Logger::logger = nullptr;
Logger::Logger() Logger::Logger()
@ -26,21 +26,24 @@ void Logger::logToDb(const QString &msg)
Logger::dbMan->log(msg); Logger::dbMan->log(msg);
} }
void Logger::setDBMan(DatabaseManager *dbMan) void Logger::setDBMan(std::shared_ptr<DatabaseManager> dbMan)
{ {
Logger::dbMan = dbMan; Logger::dbMan = dbMan;
} }
QString Logger::makeTokenMsg(const QString &tokenId, const QString &action, const QString &source) QString Logger::makeTokenMsg(const QString &tokenId, const QString &action, const QString &source)
{ {
QString msg = QString("Token: %1 of subject: %2 %3. Source: %4").arg(tokenId,dbMan->getSubjectNameByTokenId(tokenId), action, source); return QString("Token: %1 of subject: %2 %3. Source: %4").arg(tokenId,dbMan->getSubjectNameByTokenId(tokenId), action, source);
return msg;
} }
QString Logger::makeSubjectMsg(const QString &subjectId, const QString &action, const QString &source) QString Logger::makeSubjectMsg(const QString &subjectId, const QString &action, const QString &source)
{ {
QString msg = QString("Subject: %1 %2. Source: %3").arg(dbMan->getSubjectNameById(subjectId), action, source); return QString("Subject: %1 %2. Source: %3").arg(dbMan->getSubjectNameById(subjectId), action, source);
return msg; }
QString Logger::makeErrorMsg(const QString &source, const QString &errMsg)
{
return QString("Source: %1, Error: %2").arg(source, errMsg);
} }

View File

@ -13,16 +13,16 @@ class Logger
Logger(); Logger();
static DatabaseManager *dbMan; static std::shared_ptr<DatabaseManager> dbMan;
public: public:
static Logger *getLogger(); static Logger *getLogger();
static void log(const QString& msg); static void log(const QString& msg);
static void logToDb(const QString& msg); static void logToDb(const QString& msg);
static void setDBMan(DatabaseManager* dbMan); static void setDBMan(std::shared_ptr<DatabaseManager> dbMan);
static QString makeTokenMsg(const QString& tokenId, const QString& action, const QString& source); static QString makeTokenMsg(const QString& tokenId, const QString& action, const QString& source);
static QString makeSubjectMsg(const QString& subjectId, const QString& action, const QString& source); static QString makeSubjectMsg(const QString& subjectId, const QString& action, const QString& source);
static QString makeErrorMsg(const QString& source, const QString& errMsg);
private: private:

View File

@ -2,16 +2,14 @@
RequestManager::RequestManager() RequestManager::RequestManager()
{ {
manager = new QNetworkAccessManager(); manager = std::make_unique<QNetworkAccessManager>();
token = ""; connect(manager.get(), &QNetworkAccessManager::sslErrors, this, &RequestManager::onSSLError);
loginStatus = false;
QObject::connect(manager, &QNetworkAccessManager::sslErrors, this, &RequestManager::onSSLError);
} }
Response* RequestManager::login() std::shared_ptr<Response> RequestManager::login()
{ {
Q_ASSERT(!loginResponse); Q_ASSERT(!loginResponse);
loginResponse = new Response; loginResponse = std::make_shared<Response>();
QNetworkRequest request; QNetworkRequest request;
QString hash = encryptedPassword(this->password); QString hash = encryptedPassword(this->password);
authHeader = getLoginHeader(this->user, hash); authHeader = getLoginHeader(this->user, hash);
@ -22,25 +20,24 @@ Response* RequestManager::login()
request.setUrl(this->host + "/AaaManager/authSession"); request.setUrl(this->host + "/AaaManager/authSession");
request.setRawHeader("Authorization", authHeader.toLocal8Bit()); request.setRawHeader("Authorization", authHeader.toLocal8Bit());
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json; charset=UTF-8"); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json; charset=UTF-8");
QJsonDocument jsonDocument; QJsonDocument jsonDocument;
jsonDocument.setObject(reqBody); jsonDocument.setObject(reqBody);
QNetworkReply* reply = manager->post(request, jsonDocument.toJson()); QNetworkReply* reply = manager->post(request, jsonDocument.toJson());
loginResponse->setReply(reply); loginResponse->setReply(reply);
QObject::connect(reply, &QNetworkReply::finished, [=]() { connect(reply, &QNetworkReply::finished, [=]() {
if (reply->error()) if (reply->error())
{ {
qDebug() << "Login failed: "<< reply->errorString(); Logger::logToDb(Logger::makeErrorMsg("Request Manager", reply->errorString()));
loginStatus = false; loginStatus = false;
reply->deleteLater(); reply->deleteLater();
emit error();
return; return;
} }
//qDebug() << "Logged in successfully.";
loginStatus = true; loginStatus = true;
emit successLogin(); emit successLogin();
reply->deleteLater(); reply->deleteLater();
}); });
connect(this, &RequestManager::successLogin, loginResponse, &Response::ready); connect(this, &RequestManager::successLogin, loginResponse.get(), &Response::ready);
connect(this, &RequestManager::successLogin, this, &RequestManager::prepareAuthHeader); connect(this, &RequestManager::successLogin, this, &RequestManager::prepareAuthHeader);
return loginResponse; return loginResponse;
} }
@ -55,12 +52,12 @@ QNetworkReply* RequestManager::postRequest(const QString& endpoint, const QByteA
QObject::connect(reply, &QNetworkReply::finished, [=]() { QObject::connect(reply, &QNetworkReply::finished, [=]() {
if (reply->error()) if (reply->error())
{ {
qDebug() << "Authorization failed: " << reply->errorString(); Logger::logToDb(Logger::makeErrorMsg("Request Manager", reply->errorString()));
loginStatus = false; loginStatus = false;
reply->deleteLater(); reply->deleteLater();
emit error();
return; return;
} }
//qDebug() << "Authorized successfully, response ready.";
emit responseReady(); emit responseReady();
reply->deleteLater(); reply->deleteLater();
}); });
@ -68,7 +65,7 @@ QNetworkReply* RequestManager::postRequest(const QString& endpoint, const QByteA
} }
// This will ensure login is called only once // This will ensure login is called only once
Response* RequestManager::getLoginResponse() { std::shared_ptr<Response> RequestManager::getLoginResponse() {
if (!loginResponse){ if (!loginResponse){
loginResponse = login(); loginResponse = login();
} }
@ -79,7 +76,7 @@ Response* RequestManager::postRequestReturnLogic(const QString& endpoint, const
{ {
auto loginResponse = getLoginResponse(); auto loginResponse = getLoginResponse();
Q_ASSERT(loginResponse); Q_ASSERT(loginResponse);
auto* response = new Response; auto response = new Response;
if (!loginStatus){ if (!loginStatus){
connect(this, &RequestManager::successLogin, [=](){ connect(this, &RequestManager::successLogin, [=](){
@ -121,7 +118,7 @@ QString RequestManager::getLoginHeader(const QString& username, const QString& h
void RequestManager::prepareAuthHeader() void RequestManager::prepareAuthHeader()
{ {
jsonResponse = loginResponse->getJson(); jsonResponse = loginResponse->getJson();
token = getFromJson(jsonResponse, "id"); QString token = getFromJson(jsonResponse, "id");
QString authValue = token + ":"; QString authValue = token + ":";
authHeader = "Basic " + authValue.toLocal8Bit().toBase64(); authHeader = "Basic " + authValue.toLocal8Bit().toBase64();
} }
@ -146,7 +143,7 @@ QByteArray RequestManager::makeTimestampJson(uint64_t time)
return doc.toJson(); return doc.toJson();
} }
QByteArray RequestManager::makeTokensJson(const QHash<QString, QPointer<Token> > &tokens) QByteArray RequestManager::makeTokensJson(const QHash<QString, std::shared_ptr<Token>> &tokens)
{ {
QJsonObject items; QJsonObject items;
QJsonArray jsonTokens; QJsonArray jsonTokens;
@ -239,7 +236,7 @@ Response* RequestManager::getAccessGroupMembershipDeleted(uint64_t time)
return postRequestReturnLogic("/AccessManager/getAccessGroupMembershipDeleted", makeTimestampJson(time)); return postRequestReturnLogic("/AccessManager/getAccessGroupMembershipDeleted", makeTimestampJson(time));
} }
Response* RequestManager::setTokens(const QHash<QString, QPointer<Token> > &tokens) Response* RequestManager::setTokens(const QHash<QString, std::shared_ptr<Token>> &tokens)
{ {
return postRequestReturnLogic("/TokenManager/setTokens", makeTokensJson(tokens)); return postRequestReturnLogic("/TokenManager/setTokens", makeTokensJson(tokens));
} }

View File

@ -31,7 +31,12 @@ class RequestManager : public QObject
Q_OBJECT Q_OBJECT
public: public:
friend class UnitTest;
friend class ComplexTest;
RequestManager(); RequestManager();
// this should be in ColnodAPI class BEGIN
Response* getSubjects(); Response* getSubjects();
Response* getTokens(); Response* getTokens();
Response* getTokenSubject(); Response* getTokenSubject();
@ -49,47 +54,47 @@ public:
Response* getAccessGroupMembershipUpdated(uint64_t time); Response* getAccessGroupMembershipUpdated(uint64_t time);
Response* getAccessGroupMembershipDeleted(uint64_t time); Response* getAccessGroupMembershipDeleted(uint64_t time);
Response* setTokens(const QHash<QString, QPointer<Token>> &tokens); Response* setTokens(const QHash<QString, std::shared_ptr<Token>> &tokens);
Response* deleteTokens(const QList<QString> &ids); Response* deleteTokens(const QList<QString> &ids);
// END
Response* login(); //I want it private, but unittest???
const QJsonDocument &getConfig() const {return config;}
const QString &getResponse() const {return jsonResponse;}
private: private:
// should be public
QNetworkReply* postRequest(const QString& endpoint, const QByteArray& json = QByteArray()); QNetworkReply* postRequest(const QString& endpoint, const QByteArray& json = QByteArray());
Response* postRequestReturnLogic(const QString& endpoint, const QByteArray& data = QByteArray()); Response* postRequestReturnLogic(const QString& endpoint, const QByteArray& data = QByteArray());
std::shared_ptr<Response> login();
std::shared_ptr<Response> getLoginResponse();
QString getFromJson(const QString& json, const QString &member); QString getFromJson(const QString& json, const QString &member);
QString encryptedPassword(const QString& password); QString encryptedPassword(const QString& password);
QString getLoginHeader(const QString& username, const QString& hash); QString getLoginHeader(const QString& username, const QString& hash);
// in colnod api as well
QByteArray makeTimestampJson(uint64_t time); QByteArray makeTimestampJson(uint64_t time);
QByteArray makeTokensJson(const QHash<QString, QPointer<Token>> &tokens); QByteArray makeTokensJson(const QHash<QString, std::shared_ptr<Token>> &tokens); // maybe better to be in Token class
QByteArray makeIdsJson(const QList<QString> &ids); QByteArray makeIdsJson(const QList<QString> &ids); // Entity class
Response* getLoginResponse();
private slots: private slots:
void onSSLError(QNetworkReply *reply, const QList<QSslError> &errors); void onSSLError(QNetworkReply *reply, const QList<QSslError> &errors);
//void onReplyFinished(QNetworkReply *reply);
void prepareAuthHeader(); void prepareAuthHeader();
signals: signals:
void successLogin(); void successLogin();
void responseReady(); void responseReady();
void error();
private: private:
QNetworkAccessManager* manager = nullptr; std::unique_ptr<QNetworkAccessManager> manager;
Response* loginResponse = nullptr; std::shared_ptr<Response> loginResponse;
QJsonDocument config; QJsonDocument config;
QString authHeader; QString authHeader;
QString host = "https://192.168.1.3:8443"; const QString host = "https://192.168.1.3:8443";
//QString host = "https://localhost:8080"; //QString host = "https://localhost:8080";
QString password = "spaceti1"; const QString password = "spaceti1";
QString user = "spaceti"; const QString user = "spaceti";
QString token;
QString jsonResponse; QString jsonResponse;
bool loginStatus; bool loginStatus = false;
}; };

View File

@ -39,6 +39,6 @@ private:
QSet<QString> pinFlags; QSet<QString> pinFlags;
//QList<QPointer<Attribute>> atr; //QList<QPointer<Attribute>> atr;
QList<QPair<QString, QString>> atr; QList<QPair<QString, QString>> atr;
const std::array<QString, 6> attributeTypes = {"Jmeno", "Prijmeni", "ProfilParking", "Spolecnost", "Profil", "spz"}; const QList<QString> attributeTypes = {"Jmeno", "Prijmeni", "ProfilParking", "Spolecnost", "Profil", "spz"};
}; };

View File

@ -1,13 +1,16 @@
#include "colnodapi.h" #include "syncmanager.h"
ColnodAPI::ColnodAPI(bool dryMode) SyncManager::SyncManager(bool dryMode)
{ {
reqMan = new RequestManager(); reqMan = std::make_unique<RequestManager>();
dataMan = new DataManager(dryMode); dataMan = std::make_unique<DataManager>(dryMode);
this->dryMode = dryMode; this->dryMode = dryMode;
connect(reqMan.get(), &RequestManager::error, this, &SyncManager::error);
connect(dataMan.get(), &DataManager::error, this, &SyncManager::error);
} }
void ColnodAPI::loadDataFromColnod() void SyncManager::loadDataFromColnod()
{ {
loadTokensFromColnod(); loadTokensFromColnod();
loadUpdatedDataFromColnod(); loadUpdatedDataFromColnod();
@ -15,7 +18,7 @@ void ColnodAPI::loadDataFromColnod()
} }
// download all tokens form colnod for comparing with tokens to update from DB // download all tokens form colnod for comparing with tokens to update from DB
void ColnodAPI::loadTokensFromColnod() void SyncManager::loadTokensFromColnod()
{ {
Response* resp = reqMan->getTokens(); Response* resp = reqMan->getTokens();
connect(resp, &Response::ready, [=](){ connect(resp, &Response::ready, [=](){
@ -26,7 +29,7 @@ void ColnodAPI::loadTokensFromColnod()
} }
// fill tokens/subjects to update in data manager // fill tokens/subjects to update in data manager
void ColnodAPI::loadUpdatedDataFromColnod() void SyncManager::loadUpdatedDataFromColnod()
{ {
uint64_t lastUpdate = dataMan->getLastSync(); uint64_t lastUpdate = dataMan->getLastSync();
Response* resp0 = reqMan->getSubjectsUpdated(lastUpdate); Response* resp0 = reqMan->getSubjectsUpdated(lastUpdate);
@ -45,7 +48,7 @@ void ColnodAPI::loadUpdatedDataFromColnod()
} }
// fill tokens/subjects to delete in data manager // fill tokens/subjects to delete in data manager
void ColnodAPI::loadDeletedDataFromColnod() void SyncManager::loadDeletedDataFromColnod()
{ {
uint64_t lastUpdate = dataMan->getLastSync(); uint64_t lastUpdate = dataMan->getLastSync();
Response* resp2 = reqMan->getSubjectsDeleted(lastUpdate); Response* resp2 = reqMan->getSubjectsDeleted(lastUpdate);
@ -65,12 +68,12 @@ void ColnodAPI::loadDeletedDataFromColnod()
} }
// fill structures in data manager (tokens to updata/to delte) // fill structures in data manager (tokens to updata/to delte)
void ColnodAPI::loadDataFromDB() void SyncManager::loadDataFromDB()
{ {
dataMan->fillTokensToChangeDB(); dataMan->fillTokensToChangeDB();
} }
void ColnodAPI::syncDataFromColnodToDB() void SyncManager::syncDataFromColnodToDB()
{ {
syncUpdatedDataFromColnodToDB(); syncUpdatedDataFromColnodToDB();
if (dataMan->getLastSync() != 0) if (dataMan->getLastSync() != 0)
@ -78,21 +81,21 @@ void ColnodAPI::syncDataFromColnodToDB()
} }
// push data from colnod to DB // push data from colnod to DB
void ColnodAPI::syncUpdatedDataFromColnodToDB() void SyncManager::syncUpdatedDataFromColnodToDB()
{ {
dataMan->pushSubjectsToDB(); dataMan->pushSubjectsToDB();
dataMan->pushTokensToDB(); dataMan->pushTokensToDB();
} }
// set deleted tokens from Colnod, delete subject // set deleted tokens from Colnod, delete subject
void ColnodAPI::syncDeletedDataFromColnodToDB() void SyncManager::syncDeletedDataFromColnodToDB()
{ {
dataMan->deleteSubjectsFromDB(); dataMan->deleteSubjectsFromDB();
dataMan->setDeletedToTokensFromDB(); dataMan->setDeletedToTokensFromDB();
} }
// push changes form DB to Colnod // push changes form DB to Colnod
void ColnodAPI::syncDataFromDBToColnod() void SyncManager::syncDataFromDBToColnod()
{ {
if (!dataMan->getTokensToUpdateDB().contains("empty")){ if (!dataMan->getTokensToUpdateDB().contains("empty")){
@ -105,9 +108,9 @@ void ColnodAPI::syncDataFromDBToColnod()
} }
else else
updateFinished = true; updateFinished = true;
connect(this, &ColnodAPI::dataUpdatedToColnod, dataMan, &DataManager::clear); connect(this, &SyncManager::dataUpdatedToColnod, dataMan.get(), &DataManager::clear);
connect(this, &ColnodAPI::dataUpdatedToColnod, dataMan, &DataManager::setLastSync); connect(this, &SyncManager::dataUpdatedToColnod, dataMan.get(), &DataManager::setLastSync);
connect(this, &ColnodAPI::dataUpdatedToColnod, [=](){ connect(this, &SyncManager::dataUpdatedToColnod, [=](){
auto resp = reqMan->getTokensUpdated(dataMan->getCurrentSync()); auto resp = reqMan->getTokensUpdated(dataMan->getCurrentSync());
connect(resp, &Response::ready, [=](){ connect(resp, &Response::ready, [=](){
dataMan->fillTokensToUpdateColnod(resp->getJson()); dataMan->fillTokensToUpdateColnod(resp->getJson());
@ -121,7 +124,7 @@ void ColnodAPI::syncDataFromDBToColnod()
} }
// add or update tokens to Colnod // add or update tokens to Colnod
void ColnodAPI::syncUpdatedDataFromDBToColnod() void SyncManager::syncUpdatedDataFromDBToColnod()
{ {
auto tokensToUpdate = dataMan->getTokensToUpdateDB(); auto tokensToUpdate = dataMan->getTokensToUpdateDB();
if (dryMode){ if (dryMode){
@ -139,7 +142,7 @@ void ColnodAPI::syncUpdatedDataFromDBToColnod()
} }
// delete tokens in Colnod // delete tokens in Colnod
void ColnodAPI::syncDeletedDataFromDBToColnod() void SyncManager::syncDeletedDataFromDBToColnod()
{ {
dataMan->filterTokensDB(); dataMan->filterTokensDB();
auto tokensToDelete = dataMan->getTokensToDeleteDB(); auto tokensToDelete = dataMan->getTokensToDeleteDB();
@ -158,20 +161,20 @@ void ColnodAPI::syncDeletedDataFromDBToColnod()
} }
// For full sync // For full sync
void ColnodAPI::prepareDatabase() void SyncManager::prepareDatabase()
{ {
dataMan->emptyDatabase(); dataMan->emptyDatabase();
} }
// emit signal when all data is downloaded from Colnod // emit signal when all data is downloaded from Colnod
void ColnodAPI::areChangedDataReady() void SyncManager::areChangedDataReady()
{ {
if (dataMan->haveChangedData()) if (dataMan->haveChangedData())
emit dataDownloaded(); emit dataDownloaded();
} }
// emit signal when writing to Colnod is finised // emit signal when writing to Colnod is finised
void ColnodAPI::areDataUpdatedToColnod() void SyncManager::areDataUpdatedToColnod()
{ {
if (deleteFinished && updateFinished) if (deleteFinished && updateFinished)
{ {

View File

@ -4,13 +4,13 @@
#include "datamanager.h" #include "datamanager.h"
#include "logger.h" #include "logger.h"
class ColnodAPI : public QObject class SyncManager : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
ColnodAPI(bool dryMode = false); SyncManager(bool dryMode = false);
void syncDataFromColnodToDB(); void syncDataFromColnodToDB();
void syncDataFromDBToColnod(); void syncDataFromDBToColnod();
@ -25,6 +25,7 @@ signals:
void dataDownloaded(); void dataDownloaded();
void dataUpdatedToColnod(); void dataUpdatedToColnod();
void syncFinished(); void syncFinished();
void error();
private slots: private slots:
@ -46,8 +47,8 @@ private:
void areDataUpdatedToColnod(); void areDataUpdatedToColnod();
private: private:
RequestManager* reqMan = nullptr; std::unique_ptr<RequestManager> reqMan;
DataManager* dataMan = nullptr; std::unique_ptr<DataManager> dataMan;
bool dryMode = false; bool dryMode = false;
bool updateFinished = false; bool updateFinished = false;
bool deleteFinished = false; bool deleteFinished = false;

View File

@ -22,6 +22,10 @@ Token::Token(const QString &name)
this->setName(name); this->setName(name);
} }
Token::~Token()
{
}
void Token::fromJSON(const QJsonObject &json) { void Token::fromJSON(const QJsonObject &json) {
Entity::fromJSON(json); Entity::fromJSON(json);

View File

@ -14,6 +14,7 @@ public:
Token() = default; Token() = default;
Token(const QString& name, QString tokenData, const QString& decription = "mobile"); Token(const QString& name, QString tokenData, const QString& decription = "mobile");
Token(const QString& name); Token(const QString& name);
~Token() override;
friend bool operator<(const Token &lToken, const Token &rToken){ friend bool operator<(const Token &lToken, const Token &rToken){
return lToken.getLastModified() < rToken.getLastUpdate(); return lToken.getLastModified() < rToken.getLastUpdate();

View File

@ -14,7 +14,7 @@ void UnitTest::loginSuccessfully()
spy.wait(timeout); spy.wait(timeout);
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
QString json = testAccess->getResponse(); QString json = testAccess->jsonResponse;
qDebug() << json; qDebug() << json;
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8()); QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8());
QVERIFY2(doc.object().value("id").isString(), "No parameter 'id' in response"); QVERIFY2(doc.object().value("id").isString(), "No parameter 'id' in response");
@ -211,15 +211,14 @@ void UnitTest::setTokens()
QJsonObject obj = doc.object(); QJsonObject obj = doc.object();
QJsonArray arr = obj["items"].toArray(); QJsonArray arr = obj["items"].toArray();
qDebug() << arr; qDebug() << arr;
QHash<QString, QPointer<Token>> tokens; QHash<QString, std::shared_ptr<Token>> tokens;
for (auto object : arr) for (auto object : arr)
{ {
auto token = new Token; auto token = std::shared_ptr<Token>();
token->fromJSON(object.toObject()); token->fromJSON(object.toObject());
qDebug() << token;
tokens.insert(token->idToStringWithoutBraces(), token); tokens.insert(token->idToStringWithoutBraces(), token);
} }
auto* testAccess = new RequestManager(); auto testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady())); QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->setTokens(tokens); Response* response = testAccess->setTokens(tokens);
QCOMPARE(spy.count(), 0); QCOMPARE(spy.count(), 0);

View File

@ -13,7 +13,7 @@ void ComplexTest::initTestCase()
// QTest::qWait(2500); // QTest::qWait(2500);
// Logger *logger = Logger::getLogger(); // Logger *logger = Logger::getLogger();
start = QDateTime::currentMSecsSinceEpoch()-2000; start = QDateTime::currentMSecsSinceEpoch()-2000;
api = new ColnodAPI(); api = new SyncManager();
qDebug() << start; qDebug() << start;
} }
@ -37,8 +37,8 @@ void ComplexTest::complexTest()
// LOGIN_BEGIN // LOGIN_BEGIN
reqMan = new RequestManager; reqMan = new RequestManager;
QSignalSpy loginSpy(reqMan, &RequestManager::successLogin); QSignalSpy loginSpy(reqMan, &RequestManager::successLogin);
Response* loginResp = reqMan->login(); auto loginResp = reqMan->login();
QSignalSpy loginRespSpy(loginResp, &Response::ready); QSignalSpy loginRespSpy(loginResp.get(), &Response::ready);
QCOMPARE(loginSpy.count(), 0); QCOMPARE(loginSpy.count(), 0);
QCOMPARE(loginRespSpy.count(), 0); QCOMPARE(loginRespSpy.count(), 0);
loginSpy.wait(timeout); loginSpy.wait(timeout);
@ -58,7 +58,7 @@ void ComplexTest::complexTest()
// ADD_TOKENS_CHECK_BEGIN // ADD_TOKENS_CHECK_BEGIN
QHash<QString, QPointer<Token>> tokens; QHash<QString, std::shared_ptr<Token>> tokens;
auto token = getTestToken(); auto token = getTestToken();
tokens.insert(token->idToStringWithoutBraces(), token); tokens.insert(token->idToStringWithoutBraces(), token);
Response* setTokensResp = reqMan->setTokens(tokens); Response* setTokensResp = reqMan->setTokens(tokens);
@ -117,14 +117,14 @@ void ComplexTest::fullSync()
{ {
api->prepareDatabase(); api->prepareDatabase();
api->loadDataFromColnod(); api->loadDataFromColnod();
QSignalSpy spy(api, &ColnodAPI::dataDownloaded); QSignalSpy spy(api, &SyncManager::dataDownloaded);
spy.wait(timeout); spy.wait(timeout);
api->loadDataFromDB(); api->loadDataFromDB();
api->syncDataFromColnodToDB(); api->syncDataFromColnodToDB();
api->syncDataFromDBToColnod(); api->syncDataFromDBToColnod();
QSignalSpy processSpy(api, &ColnodAPI::dataUpdatedToColnod); QSignalSpy processSpy(api, &SyncManager::dataUpdatedToColnod);
processSpy.wait(timeout); processSpy.wait(timeout);
QSignalSpy finish(api, &ColnodAPI::syncFinished); QSignalSpy finish(api, &SyncManager::syncFinished);
finish.wait(timeout); finish.wait(timeout);
} }
@ -132,14 +132,14 @@ void ComplexTest::syncLastUpdated()
{ {
Logger::log("ahoj"); Logger::log("ahoj");
api->loadDataFromColnod(); api->loadDataFromColnod();
QSignalSpy spy(api, &ColnodAPI::dataDownloaded); QSignalSpy spy(api, &SyncManager::dataDownloaded);
spy.wait(timeout); spy.wait(timeout);
api->loadDataFromDB(); api->loadDataFromDB();
api->syncDataFromColnodToDB(); api->syncDataFromColnodToDB();
api->syncDataFromDBToColnod(); api->syncDataFromDBToColnod();
QSignalSpy processSpy(api, &ColnodAPI::dataUpdatedToColnod); QSignalSpy processSpy(api, &SyncManager::dataUpdatedToColnod);
processSpy.wait(timeout); processSpy.wait(timeout);
QSignalSpy finish(api, &ColnodAPI::syncFinished); QSignalSpy finish(api, &SyncManager::syncFinished);
finish.wait(timeout); finish.wait(timeout);
qDebug() << "All right, at least should be."; qDebug() << "All right, at least should be.";
} }
@ -175,7 +175,7 @@ QJsonDocument ComplexTest::getJsonDoc(const QString &json)
return QJsonDocument::fromJson(json.toUtf8()); return QJsonDocument::fromJson(json.toUtf8());
} }
QPointer<Token> ComplexTest::getTestToken() std::shared_ptr<Token> ComplexTest::getTestToken()
{ {
QJsonObject jsonToken; QJsonObject jsonToken;
jsonToken.insert("id", "062c93f6-ba3e-46af-a3a6-7a2988d1f0e9"); jsonToken.insert("id", "062c93f6-ba3e-46af-a3a6-7a2988d1f0e9");
@ -191,7 +191,7 @@ QPointer<Token> ComplexTest::getTestToken()
flags.push_back("NoValidity"); flags.push_back("NoValidity");
jsonToken.insert("flags", flags); jsonToken.insert("flags", flags);
jsonToken.insert("subjectId", "72b37f7e-5761-4e6c-8e87-20c0bed0d904"); jsonToken.insert("subjectId", "72b37f7e-5761-4e6c-8e87-20c0bed0d904");
QPointer<Token> token = new Token; auto token = std::shared_ptr<Token>();
token->fromJSON(jsonToken); token->fromJSON(jsonToken);
return token; return token;
} }

View File

@ -5,7 +5,7 @@
#include <QtTest/QtTest> #include <QtTest/QtTest>
#include "response.h" #include "response.h"
#include "requestmanager.h" #include "requestmanager.h"
#include "colnodapi.h" #include "syncmanager.h"
#include "logger.h" #include "logger.h"
class ComplexTest : public QObject class ComplexTest : public QObject
@ -25,7 +25,7 @@ private:
int getNumOfSubjects(); int getNumOfSubjects();
int getNumOfTokens(); int getNumOfTokens();
QJsonDocument getJsonDoc(const QString &json); QJsonDocument getJsonDoc(const QString &json);
QPointer<Token> getTestToken(); std::shared_ptr<Token> getTestToken();
// VARIABLES // VARIABLES
@ -34,7 +34,7 @@ private:
QString password = "spaceti1"; QString password = "spaceti1";
RequestManager* reqMan = nullptr; RequestManager* reqMan = nullptr;
uint64_t start = 0; uint64_t start = 0;
ColnodAPI* api = nullptr; SyncManager* api = nullptr;
static constexpr qint16 timeout = 10000; static constexpr qint16 timeout = 10000;
}; };