Merge branch 'sync' into 'master'

Sync DB and Colnod

See merge request spaceti-app/integrations/acs/colnod-connector!8
This commit is contained in:
Filip Bucek 2019-11-07 08:13:54 +00:00
commit a189b6fd65
28 changed files with 1506 additions and 980 deletions

View File

@ -2,6 +2,23 @@
Acces Management System of Colsys: [Product info](http://produkty.colsys.cz/colnod/) Acces Management System of Colsys: [Product info](http://produkty.colsys.cz/colnod/)
## TODO
- [ ] Debug Mode
- [ ] Logs
- Timestamp
- Id of record
- Destination
- Report
- Token `action` to `subject_id`
- Sbject `action`
- `action` - updated, deleted, added
- [ ] App output
- To Colnod
- Number of tokens added/deleted/updated
- To DB
- Number of subjects added/deleted/updated
- Number of tokens added/deleted/updated
## Requirements ## Requirements
- QPSQL driver must be installed (PostgreSQL) - QPSQL driver must be installed (PostgreSQL)

36
bugs/getTokensDeleted.sh Executable file
View File

@ -0,0 +1,36 @@
#!/bin/bash
# Saving login token
TOKEN=$(curl -k --user "spaceti:E7FEA07DBC82FB9BA34B2E453E2EFE89F0583E7187543507EF11E84726071FE428445372F2E46B455EB0C79747C51E362F403CE39473A2A8C2DFA0CE5C9826C0" -d '{"password":"E7FEA07DBC82FB9BA34B2E453E2EFE89F0583E7187543507EF11E84726071FE428445372F2E46B455EB0C79747C51E362F403CE39473A2A8C2DFA0CE5C9826C0","username":"spaceti"}' -H "Content-Type: application/json" https://192.168.1.3:8443/AaaManager/authSession 2>/dev/null | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["id"]')
# Saving current time and timestamp
DATE=`date +"%Y-%m-%d %H:%M:%S"`
TIMESTAMP=`date +%s%N | cut -b1-13`
echo
echo "I'm going to add and delete test token,"
echo "then ask for deleted tokens with time before deleting"
echo "and with time after deleting."
echo "It should return token deleted with time before,"
echo "but should NOT with time after."
echo "===================================================================="
echo "Current time: $DATE / timestamp: $TIMESTAMP"
echo "===================================================================="
echo "Creating test token with id = 235c4a3c-7e20-4f2a-8ed2-2fe36cc87907"
curl -k -u "$TOKEN:" -d '{"items":[{"id":"235c4a3c-7e20-4f2a-8ed2-2fe36cc87907","name":"bug test","description":"mobile","tokenType":"Token","tokenBits":32,"tokenData":"7B9D32","timeToLive":255,"authErrors":255,"flags":["Enabled","NoValidity"],"subjectId":"72b37f7e-5761-4e6c-8e87-20c0bed0d904"}]}' -H "Content-Type: application/json" -X POST https://192.168.1.3:8443/TokenManager/setTokens
echo
echo "Deleting test token..."
curl -k -u "$TOKEN:" -d '{"items":["235c4a3c-7e20-4f2a-8ed2-2fe36cc87907"]}' -H "Content-Type: application/json" -X POST https://192.168.1.3:8443/TokenManager/deleteTokens
echo
echo
echo "getTokensDeleted with time (before deleting): $DATE"
echo "Expect only one token which has been deleted"
curl -k -u "$TOKEN:" -d "{\"timestamp\":$TIMESTAMP}" -H "Content-Type: application/json" -X POST https://192.168.1.3:8443/TokenManager/getTokensDeleted
echo
echo "===================================================================="
echo "Waiting 5 secs, so we can ask again after deleting"
echo "===================================================================="
sleep 5
echo "getTokensDeleted with time (after deleting): $DATE + 2 sec"
echo "Expect no tokens returned, because token has been deleted before more than 5 secs"
((TIMESTAMP=TIMESTAMP+2000))
curl -k -u "$TOKEN:" -d "{\"timestamp\":$TIMESTAMP}" -H "Content-Type: application/json" -X POST https://192.168.1.3:8443/TokenManager/getTokensDeleted
echo
exit

66
bugs/getTokensDeleted_01.sh Executable file
View File

@ -0,0 +1,66 @@
#!/bin/bash
# Saving login token
TOKEN=$(curl -k --user "spaceti:E7FEA07DBC82FB9BA34B2E453E2EFE89F0583E7187543507EF11E84726071FE428445372F2E46B455EB0C79747C51E362F403CE39473A2A8C2DFA0CE5C9826C0" -d '{"password":"E7FEA07DBC82FB9BA34B2E453E2EFE89F0583E7187543507EF11E84726071FE428445372F2E46B455EB0C79747C51E362F403CE39473A2A8C2DFA0CE5C9826C0","username":"spaceti"}' -H "Content-Type: application/json" https://192.168.1.3:8443/AaaManager/authSession 2>/dev/null | python -c 'import json,sys;obj=json.load(sys.stdin);print obj["id"]')
# Saving current time and timestamp
# echo "=================================="
# echo "Saving current time ( saved_time ): $DATE / timestamp: $TIMESTAMP"
# echo "=================================="
echo "========================"
echo "Script to show uncorrect behavior when returing deleted tokens"
echo "1. create token"
echo "2. deletet token"
echo "3. request deleted token with time after last token was deleted"
echo "------------------------"
DATE=`date +"%Y-%m-%d %H:%M:%S"`
TIMESTAMP=`date +%s000 | cut -b1-13`
echo "------------------------"
echo "STEPS : Create TOKEN and then deletes it"
echo "EXPECT : Token is deleted and is returned when getting deleted token with saved_time ( time before was deleted )"
echo "------------------------"
#echo "Creating test token with id = 235c4a3c-7e20-4f2a-8ed2-2fe36cc87907"
RES=$(curl -k -u "$TOKEN:" -d '{"items":[{"id":"235c4a3c-7e20-4f2a-8ed2-2fe36cc87907","name":"bug test","description":"mobile","tokenType":"Token","tokenBits":32,"tokenData":"7B9D32","timeToLive":255,"authErrors":255,"flags":["Enabled","NoValidity"],"subjectId":"72b37f7e-5761-4e6c-8e87-20c0bed0d904"}]}' -H "Content-Type: application/json" -X POST https://192.168.1.3:8443/TokenManager/setTokens 2>/dev/null )
#echo
#echo "Deleting test token..."
RES=$(curl -k -u "$TOKEN:" -d '{"items":["235c4a3c-7e20-4f2a-8ed2-2fe36cc87907"]}' -H "Content-Type: application/json" -X POST https://192.168.1.3:8443/TokenManager/deleteTokens 2>/dev/null )
#echo "/getTokensDeleted with time: $DATE"
#echo "Expect only one token which has been deleted"
RES=$(curl -k -u "$TOKEN:" -d "{\"timestamp\":$TIMESTAMP}" -H "Content-Type: application/json" -X POST https://192.168.1.3:8443/TokenManager/getTokensDeleted 2>/dev/null )
echo "EXPECTED : {\"items\":[\"235c4a3c-7e20-4f2a-8ed2-2fe36cc87907\"]}"
echo "ACTUAL : $RES"
echo "------------------------"
echo "OK - expected token is returned"
echo "------------------------"
echo ""
echo "=================================="
echo "Now we wait 5 sec to ensure timestamp for deleted token is in past"
echo "=================================="
echo ""
sleep 5
echo "------------------------"
echo "STEPS : Getting deleted tokens before 2 sec"
echo "EXPECT : no tokens ( since we have deleted token before 5 sec )"
echo "------------------------"
((TIMESTAMP=TIMESTAMP+2000)) # adding 2000 ms to saved timestamp
RES=$(curl -k -u "$TOKEN:" -d "{\"timestamp\":$TIMESTAMP}" -H "Content-Type: application/json" -X POST https://192.168.1.3:8443/TokenManager/getTokensDeleted 2>/dev/null )
echo "EXPECTED : {"items":[]}"
echo "ACTUAL : $RES"
echo "------------------------"
echo "BUG: Token was deleted 5 seconds ago, but was returned even we requested tokens deleted 2 sec ago"
echo "------------------------"
echo ""
echo "Another bug: future date"
echo "------------------------"
echo "STEPS : Getting deleted tokens with future date"
echo "EXPECT : no tokens"
echo "------------------------"
((TIMESTAMP=TIMESTAMP+20000)) # adding 20s to saved timestamp
RES=$(curl -k -u "$TOKEN:" -d "{\"timestamp\":$TIMESTAMP}" -H "Content-Type: application/json" -X POST https://192.168.1.3:8443/TokenManager/getTokensDeleted 2>/dev/null )
echo "EXPECTED : {"items":[]}"
echo "ACTUAL : $RES"
echo "------------------------"
echo "BUG: Token was deleted 5 seconds ago, but was returned even we requested time in future"
echo "------------------------"

View File

@ -1,19 +1,34 @@
#include <QCoreApplication> #include <QCoreApplication>
#include "datamanager.h" #include "datamanager.h"
#include "colnodapi.h" #include "syncmanager.h"
#include <QCommandLineParser>
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
QCoreApplication a(argc, argv); QCoreApplication app(argc, argv);
ColnodAPI *api = new ColnodAPI(); QCoreApplication::setApplicationName("colnod-connector");
QCoreApplication::setApplicationVersion("1.0");
api->downloadData(); // this will start downloading data QCommandLineParser parser;
QObject::connect(api, &ColnodAPI::dataDownloaded, [=](){ Logger *logger = Logger::getLogger();
qDebug() << "now I have all data"; parser.setApplicationDescription("Colnod sync");
api->syncDataToColnod(); QCommandLineOption dryModeOption("dryMode", "ColnodAPI", "Read-only mode, prints changes which would normally be made");
QCoreApplication::quit(); parser.addOption(dryModeOption);
parser.process(app);
SyncManager api(parser.isSet(dryModeOption));
api.loadDataFromDB();
api.loadDataFromColnod();
QObject::connect(&api, &SyncManager::dataDownloaded, [&](){
QObject::connect(&api, &SyncManager::syncFinished, [](){
qDebug() << "Quit";
QCoreApplication::exit();
});
api.syncDataFromColnodToDB();
api.syncDataFromDBToColnod();
}); });
QObject::connect(&api, &SyncManager::error, [](){
return a.exec(); qDebug() << "error";
QCoreApplication::exit();
});
return QCoreApplication::exec();
} }

View File

@ -2,22 +2,24 @@ 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 \
$$PWD/logger.cpp \
$$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 \
$$PWD/logger.h \
$$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

@ -1,175 +0,0 @@
#include "colnodapi.h"
ColnodAPI::ColnodAPI()
{
reqMan = new RequestManager();
dataMan = new DataManager();
}
// PUBLIC FUNCTIONS
void ColnodAPI::downloadData()
{
Response* resp0 = reqMan->getSubjects();
connect(resp0, &Response::ready, [=](){
dataMan->localSaveSubjects(resp0->getJson());
areDataReady();
resp0->deleteLater();
});
Response* resp1 = reqMan->getTokens();
connect(resp1, &Response::ready, [=](){
dataMan->localSaveTokens(resp1->getJson());
areDataReady();
resp1->deleteLater();
});
/*
QNetworkReply* reply2 = reqMan->getTokens();
connect(reply2, &QNetworkReply::finished, [=](){
data->saveTokens(reply2->readAll());
});
*/
}
void ColnodAPI::downloadChangedDataFromColnod()
{
downloadUpdatedData();
downloadDeletedData();
}
void ColnodAPI::downloadUpdatedData()
{
uint64_t lastUpdate = dataMan->getLastUpdate();
qDebug() << lastUpdate;
Response* resp0 = reqMan->getSubjectsUpdated(lastUpdate);
connect(resp0, &Response::ready, [=](){
dataMan->localSaveSubjects(resp0->getJson());
areChangedDataReady();
resp0->deleteLater();
});
Response* resp1 = reqMan->getTokensUpdated(lastUpdate);
connect(resp1, &Response::ready, [=](){
dataMan->localSaveTokens(resp1->getJson());
areChangedDataReady();
resp1->deleteLater();
});
}
void ColnodAPI::downloadDeletedData()
{
uint64_t lastUpdate = dataMan->getLastUpdate();
Response* resp2 = reqMan->getSubjectsDeleted(lastUpdate);
connect(resp2, &Response::ready, [=](){
dataMan->localSaveSubjectsToDelete(resp2->getJson());
areChangedDataReady();
resp2->deleteLater();
});
Response* resp3 = reqMan->getTokensDeleted(lastUpdate);
connect(resp3, &Response::ready, [=](){
dataMan->localSaveTokensToDelete(resp3->getJson());
areChangedDataReady();
resp3->deleteLater();
});
}
void ColnodAPI::syncDataFromColnod()
{
dataMan->pushTokensToDB();
dataMan->pushSubjectsToDB();
dataMan->updateLastSync();
dataMan->clear();
}
void ColnodAPI::syncChangedDataFromColnod()
{
syncUpdatedDataFromColnod();
syncDeletedDataFromColnod();
dataMan->updateLastSync();
dataMan->clear();
}
void ColnodAPI::syncUpdatedDataFromColnod()
{
dataMan->pushSubjectsToDB();
dataMan->pushTokensToDB();
}
void ColnodAPI::syncDeletedDataFromColnod()
{
dataMan->deleteSubjectsFromDB();
dataMan->deleteTokensFromDB();
}
void ColnodAPI::syncDataToColnod()
{
// TODO
}
void ColnodAPI::syncChangedDataToColnod()
{
// TODO
dataMan->loadTokensToAdd();
dataMan->loadTokensToDelete();
processDataToColnod();
dataMan->clear();
}
void ColnodAPI::processDataToColnod()
{
QList<QString>* tokensToDelete = dataMan->getTokensToDelete();
if ((*tokensToDelete)[0] != "empty")
{
Response* resp0 = reqMan->deleteTokens(dataMan->getTokensToDelete());
connect(resp0, &Response::ready, [=](){
areProcessDataReady();
resp0->deleteLater();
});
}
QList<QPointer<Token>>* tokens = dataMan->getTokens();
if ((*tokens)[0]->getName() != "empty")
{
Response* resp1 = reqMan->setTokens(dataMan->getTokens());
connect(resp1, &Response::ready, [=](){
areProcessDataReady();
resp1->deleteLater();
});
}
connect(this, &ColnodAPI::dataLoaded, this, &ColnodAPI::syncChangedDataFromColnod);
}
void ColnodAPI::prepareDatabase()
{
dataMan->emptyDatabase();
}
// PRIVATE FUNCTIONS
void ColnodAPI::areDataReady()
{
if (dataMan->haveData())
emit dataDownloaded();
}
void ColnodAPI::areChangedDataReady()
{
if (dataMan->haveChangedData())
emit dataDownloaded();
}
void ColnodAPI::areProcessDataReady()
{
if (dataMan->haveProcessData())
{
emit dataLoaded();
}
}

View File

@ -1,62 +0,0 @@
#ifndef COLNODAPI_H
#define COLNODAPI_H
#include "requestmanager.h"
#include "datamanager.h"
class ColnodAPI : public QObject
{
Q_OBJECT
public:
ColnodAPI();
void downloadData();
void syncDataFromColnod();
void syncDataToColnod();
void syncChangedDataFromColnod();
void syncChangedDataToColnod();
void prepareDatabase();
public slots:
void downloadChangedDataFromColnod();
signals:
void dataDownloaded();
void dataLoaded();
private slots:
private:
void downloadUpdatedData();
void downloadDeletedData();
void syncUpdatedDataFromColnod();
void syncDeletedDataFromColnod();
void areDataReady();
void areChangedDataReady();
void areProcessDataReady();
void processDataToColnod();
RequestManager* reqMan = nullptr;
// Data* data = nullptr;
DataManager* dataMan = nullptr;
bool dataReady[2] = {false};
int index = 0;
const int numOfMembers = 2;
};
#endif // COLNODAPI_H

View File

@ -1,212 +1,302 @@
#include "databasemanager.h" #include "databasemanager.h"
DatabaseManager::DatabaseManager(QString host, QString dbName, QString user, QString password) DatabaseManager::DatabaseManager(const QString& host, const QString& dbName, const QString& user, const QString& password, const bool &dryMode)
:dryMode(dryMode)
{ {
db = QSqlDatabase::addDatabase("QPSQL"); db = QSqlDatabase::addDatabase("QPSQL");
db.setDatabaseName(dbName); db.setDatabaseName(dbName);
db.setHostName(host); db.setHostName(host);
db.setUserName(user); db.setUserName(user); // home-office stuff -->> db.setPort(80);
// home-office stuff
//db.setPort(80);
//
db.setPassword(password); db.setPassword(password);
opened = db.open(); if (!db.open())
if (!opened)
{ {
qDebug() << "Opening error" + db.lastError().text(); log("Opening error" + db.lastError().text());
emit error();
} }
query = QSqlQuery("query", db);
} }
void DatabaseManager::saveSubject(Subject* subject, QString table) // add or update subject to db
int DatabaseManager::saveSubject(const std::shared_ptr<Subject>& subject, const QString& table)
{ {
QSqlQuery query;
QString id = subject->idToStringWithoutBraces(); QString id = subject->idToStringWithoutBraces();
if (checkIfExists(id, table)) int rtn;
{ if (checkIfExists(id, table)){
query.prepare(QString("UPDATE %1 SET name = :name, last_update = :last_update " query.prepare(QString("UPDATE %1 SET id = :id, description = :description, last_update = :last_update, name = :name, pin = :pin, last_modified = :last_modified, deleted = :deleted "
"WHERE id = :id)").arg(table)); "WHERE id = :id").arg(table));
query.bindValue(":id", id); rtn = -1;
query.bindValue(":name", subject->getName()); }else{
query.bindValue(":last_update", QDateTime::fromMSecsSinceEpoch(subject->getLastUpdate()).toString("yyyy-MM-dd hh:mm:ss.zzz")); query.prepare(QString("INSERT INTO %1 (id, description, last_update, name, pin, last_modified, deleted) "
query.exec(); "VALUES (:id, :description, :last_update, :name, :pin, :last_modified, :deleted)").arg(table));
} rtn = 1;
else
{
query.prepare(QString("INSERT INTO %1 (id, name, last_update) "
"VALUES (:id, :name, :last_update)").arg(table));
query.bindValue(":id", id);
query.bindValue(":name", subject->getName());
query.bindValue(":last_update", QDateTime::fromMSecsSinceEpoch(subject->getLastUpdate()).toString("yyyy-MM-dd hh:mm:ss.zzz"));
query.exec();
} }
query.bindValue(":id", id);
query.bindValue(":description", subject->getDescription());
query.bindValue(":name", subject->getName());
query.bindValue(":last_update", QDateTime::fromMSecsSinceEpoch(subject->getLastUpdate()).toString("yyyy-MM-dd hh:mm:ss.zzz"));
query.bindValue(":pin", subject->getPin());
query.bindValue(":last_modified", QDateTime::fromMSecsSinceEpoch(subject->getLastUpdate()).toString("yyyy-MM-dd hh:mm:ss.zzz"));
query.bindValue(":deleted", subject->getDeleted());
executeQuery(query);
return rtn;
} }
void DatabaseManager::saveToken(Token* token, QString table) // add or update token to DB
int DatabaseManager::saveToken(const std::shared_ptr<Token>& token, const QString& table)
{ {
QSqlQuery query;
QString id = token->idToStringWithoutBraces(); QString id = token->idToStringWithoutBraces();
if (checkIfExists(id, table)) int rtn;
{ if (checkIfExists(id, table)){
query.prepare(QString("UPDATE %1 SET last_update = :last_update, token_data = :data, subject_id = :subject_id) " query.prepare(QString("UPDATE %1 SET id = :id, auth_errors = :auth_errors, description = :description, enabled = :enabled, last_update = :last_update, name = :name, no_validity = :no_validity, time_to_live = :time_to_live, token_bits = :token_bits, token_data = :token_data, token_type = :token_type, subject_id = :subject_id, last_modified = :last_modified, deleted = :deleted "
"WHERE id = :id").arg(table)); "WHERE id = :id").arg(table));
query.bindValue(":id", id); rtn = -1;
query.bindValue(":last_update", QDateTime::fromMSecsSinceEpoch(token->getLastUpdate()).toString("yyyy-MM-dd hh:mm:ss.zzz")); }else{
query.bindValue(":data", token->getTokenData()); query.prepare(QString("INSERT INTO %1 (id, auth_errors, description, enabled, last_update, name, no_validity, time_to_live, token_bits, token_data, token_type, subject_id, last_modified, deleted) "
query.bindValue(":subject_id", token->subjectIdToStringWithoutBraces()); "VALUES (:id, :auth_errors, :description, :enabled, :last_update, :name, :no_validity, :time_to_live, :token_bits, :token_data, :token_type, :subject_id, :last_modified, :deleted)").arg(table));
query.exec(); rtn = 1;
}
else
{
query.prepare(QString("INSERT INTO %1 (id, last_update, token_data, subject_id) "
"VALUES (:id, :last_update, :data, :subject_id)").arg(table));
query.bindValue(":id", id);
query.bindValue(":last_update", QDateTime::fromMSecsSinceEpoch(token->getLastUpdate()).toString("yyyy-MM-dd hh:mm:ss.zzz"));
query.bindValue(":data", token->getTokenData());
query.bindValue(":subject_id", token->subjectIdToStringWithoutBraces());
query.exec();
} }
query.bindValue(":id", id);
query.bindValue(":auth_errors", token->getAuthErrors());
query.bindValue(":description", token->getDescription());
query.bindValue(":enabled", token->getFlags().contains("Enabled"));
query.bindValue(":last_update", QDateTime::fromMSecsSinceEpoch(token->getLastUpdate()).toString("yyyy-MM-dd hh:mm:ss.zzz"));
query.bindValue(":name", token->getName());
query.bindValue(":no_validity", token->getFlags().contains("NoValidity"));
query.bindValue(":time_to_live", token->getTimeToLive());
query.bindValue(":token_bits", token->getTokenBits());
query.bindValue(":token_data", token->getTokenData());
query.bindValue(":token_type", token->getTokenType());
query.bindValue(":subject_id", token->subjectIdToStringWithoutBraces());
query.bindValue(":last_modified", QDateTime::fromMSecsSinceEpoch(token->getLastUpdate()).toString("yyyy-MM-dd hh:mm:ss.zzz"));
query.bindValue(":deleted", token->getDeleted());
executeQuery(query);
return rtn;
} }
void DatabaseManager::saveSubjectAttribute(Subject *subject, QString table) // add of update subject attributes
void DatabaseManager::saveSubjectAttributes(const std::shared_ptr<Subject>& subject, const QString& table)
{ {
QSqlQuery query;
auto attributes = subject->getAtr(); auto attributes = subject->getAtr();
for (auto attribute : attributes){ for (const auto& attribute : attributes){
QString id = subject->idToStringWithoutBraces() + " " + attribute.first; QString id = subject->idToStringWithoutBraces() + " " + attribute.first;
if (checkIfExists(id, table)) if (checkIfExists(id, table)){
{
query.prepare(QString("UPDATE %1 SET id = :id, attribute_key = :key, attribute_value = :value, subject_id = :subject_id) " query.prepare(QString("UPDATE %1 SET id = :id, attribute_key = :key, attribute_value = :value, subject_id = :subject_id) "
"WHERE id = :id").arg(table)); "WHERE id = :id").arg(table));
query.bindValue(":id", id); }else{
query.bindValue(":key", attribute.first);
query.bindValue(":value", attribute.second);
query.bindValue(":subject_id", subject->idToStringWithoutBraces());
query.exec();
}
else
{
query.prepare(QString("INSERT INTO %1 (id, attribute_key, attribute_value, subject_id)" query.prepare(QString("INSERT INTO %1 (id, attribute_key, attribute_value, subject_id)"
"VALUES (:id, :key, :value, :subject_id)").arg(table)); "VALUES (:id, :key, :value, :subject_id)").arg(table));
query.bindValue(":id", id);
query.bindValue(":key", attribute.first);
query.bindValue(":value", attribute.second);
query.bindValue(":subject_id", subject->idToStringWithoutBraces());
query.exec();
} }
query.bindValue(":id", id);
query.bindValue(":key", attribute.first);
query.bindValue(":value", attribute.second);
query.bindValue(":subject_id", subject->idToStringWithoutBraces());
executeQuery(query);
} }
} }
void DatabaseManager::deleteItem(QString id, QString table) // "delete" tokens from DB -> set deleted true
void DatabaseManager::setDeleted(const QString& id, const QString& table, quint64 time)
{ {
query.prepare(QString("DELETE FROM %1 WHERE id = :id").arg(table)); QSqlQuery query;
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.bindValue(":id", id); query.bindValue(":id", id);
query.exec(); query.bindValue(":now", nowString);
executeQuery(query);
} }
QString DatabaseManager::getTestMessage(int id) bool DatabaseManager::checkIfExists(const QString& id, const QString& table)
{
query.prepare("SELECT message FROM test WHERE id = :id");
query.bindValue(":id", id);
query.exec();
query.next();
return query.value(0).toString();
}
int DatabaseManager::createTestRecord(QString msg)
{
query.exec("SELECT MAX(id) FROM test");
query.next();
int id = query.value(0).toInt() + 1;
query.prepare("INSERT INTO test (id, message) VALUES (:id, :msg)");
query.bindValue(":id", id);
query.bindValue(":msg", msg);
query.exec();
qDebug() << "U inserted new row, id: " << id << "msg: " << getTestMessage(id);
return id;
}
bool DatabaseManager::checkIfExists(QString id, QString table)
{ {
QSqlQuery query;
query.prepare(QString("SELECT EXISTS(SELECT 1 FROM %1 WHERE id = :id)").arg(table)); query.prepare(QString("SELECT EXISTS(SELECT 1 FROM %1 WHERE id = :id)").arg(table));
query.bindValue(":id", id); query.bindValue(":id", id);
query.exec(); executeQuery(query);
query.first(); query.first();
return query.value(0).toBool(); return query.value(0).toBool();
} }
QString DatabaseManager::getLastQuery(const QSqlQuery& query) const
{
QString str = query.lastQuery();
QMapIterator<QString, QVariant> it(query.boundValues());
while (it.hasNext())
{
it.next();
str.replace(it.key(),it.value().toString());
}
return str;
}
bool DatabaseManager::executeQuery(QSqlQuery &query, const QString &statement)
{
if (statement.isEmpty()){
if (dryMode){
QString sqlStatement = getLastQuery(query);
qDebug() << sqlStatement;
}
if (!dryMode || getLastQuery(query).startsWith("SELECT")){
if (!query.exec()){
QString msg = QString("Source: Database Manager, Error: %1").arg(query.lastError().text());
log(QString(msg));
emit error();
}
}
return true;
}
if (dryMode){
qDebug() << statement;
}
if (!dryMode || statement.startsWith("SELECT")){
if (!query.exec(statement)){
QString msg = QString("Source: Database Manager, Error: %1").arg(query.lastError().text());
log(QString(msg));
emit error();
}
}
return true;
}
void DatabaseManager::dropTables() void DatabaseManager::dropTables()
{ {
query.exec("DROP TABLE IF EXISTS colnod_token, colnod_subject, colnod_subject_attribute"); QSqlQuery query;
executeQuery(query, "DROP TABLE IF EXISTS colnod_token, colnod_subject, colnod_subject_attribute");
} }
// create table after deleting, it is used for full sync
void DatabaseManager::createTables() void DatabaseManager::createTables()
{ {
query.exec("CREATE TABLE colnod_subject (" QSqlQuery query;
"id CHAR(36) primary key,"
"name VARCHAR(255),"
"last_update timestamp)");
query.exec("CREATE TABLE colnod_token (" executeQuery(query, "CREATE TABLE colnod_subject ("
"id CHAR(36) primary key," "id character(36) primary key NOT NULL,"
"token_data VARCHAR(255)," "description character varying(255),"
"subject_id CHAR(36)," "last_update timestamp NOT NULL,"
"last_update timestamp)"); "name character varying(255),"
query.exec("CREATE TABLE colnod_subject_attribute (" "pin character varying(255),"
"id VARCHAR(255) primary key," "last_modified timestamp,"
"attribute_key VARCHAR(255)," "deleted BOOLEAN)");
"attribute_value VARCHAR(255)," executeQuery(query, "CREATE TABLE colnod_token ("
"subject_id CHAR(36))"); "id CHAR(36) primary key NOT NULL,"
query.exec("CREATE TABLE users (" "auth_errors INTEGER NOT NULL,"
"id VARCHAR(255) primary key," "description VARCHAR(255),"
"email VARCHAR(255)," "enabled BOOLEAN NOT NULL,"
"token_data VARCHAR(255)," "last_update timestamp NOT NULL,"
"last_update timestamp)"); "name VARCHAR(255),"
"no_validity BOOLEAN NOT NULL,"
"time_to_live INTEGER NOT NULL,"
"token_bits INTEGER,"
"token_data VARCHAR(255),"
"token_type VARCHAR(255),"
"subject_id CHAR(36),"
"last_modified timestamp,"
"deleted BOOLEAN)");
executeQuery(query, "CREATE TABLE colnod_subject_attribute ("
"id VARCHAR(255) primary key,"
"attribute_key VARCHAR(255),"
"attribute_value VARCHAR(255),"
"subject_id CHAR(36))");
} }
uint64_t DatabaseManager::getLastUpdate() // return last_sync time
quint64 DatabaseManager::getLastSync()
{ {
query.exec("SELECT EXTRACT(EPOCH FROM (SELECT MIN(last_sync) FROM changes))*1000"); //MAX for using, MIN for testing QSqlQuery query;
executeQuery(query, "SELECT last_sync FROM config");
query.next();
quint64 temp = query.value(0).toULongLong();
return temp;
}
// on the very end of sync set new Last_sync time (begin of this sync)
void DatabaseManager::updateLastSync(quint64 lastSync)
{
QSqlQuery query;
query.prepare("UPDATE config SET last_sync = :last_sync");
query.bindValue(":last_sync", lastSync);
executeQuery(query);
}
// return set of tokens to update form DB
QSqlQuery DatabaseManager::getUpdatedTokens()
{
QSqlQuery query;
executeQuery(query, "SELECT id, auth_errors, description, enabled, last_update, name, no_validity, time_to_live, token_bits, token_data, token_type, subject_id, last_modified, deleted "
"FROM colnod_token WHERE EXTRACT(EPOCH FROM last_modified) * 1000 > EXTRACT(EPOCH FROM last_update) * 1000");
return query;
}
QSqlQuery DatabaseManager::getToken(const QString& id)
{
QSqlQuery query;
query.prepare("SELECT id, auth_errors, description, enabled, last_update, name, no_validity, time_to_live, token_bits, token_data, token_type, subject_id, last_modified, deleted "
"FROM colnod_token WHERE id = :id");
query.bindValue(":id", id);
executeQuery(query);
query.next();
return query;
}
quint64 DatabaseManager::getNow()
{
QSqlQuery query;
executeQuery(query, "SELECT EXTRACT(EPOCH FROM NOW())*1000");
query.next(); query.next();
return query.value(0).toULongLong(); return query.value(0).toULongLong();
} }
void DatabaseManager::makeTestingLast_sync() // sync last update back to DB from Colnod after changes made to Colnod
void DatabaseManager::setLastUpdate(const QString& id, quint64 lastUpdate)
{ {
query.prepare("INSERT INTO last_changes (last_sync) " QSqlQuery query;
"VALUES (:time)"); QString lsatUpdateString = QDateTime::fromMSecsSinceEpoch(lastUpdate).toString("yyyy-MM-dd hh:mm:ss.zzz");
query.bindValue(":time", QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz")); query.prepare("UPDATE colnod_token SET last_update = :last_update WHERE id = :id");
query.bindValue(":id", id);
query.bindValue(":last_update", lsatUpdateString);
executeQuery(query);
}
void DatabaseManager::log(const QString &msg)
{
QSqlQuery query;
query.prepare("INSERT INTO logs (log_time, msg) VALUES (NOW(), :msg)");
query.bindValue(":msg", msg);
query.exec(); query.exec();
} }
void DatabaseManager::updateLastSync() QString DatabaseManager::getSubjectNameByTokenId(const QString &tokenId)
{ {
query.prepare("INSERT INTO changes (last_sync) " QSqlQuery query;
"VALUES (:time)"); query.prepare("SELECT name FROM colnod_subject WHERE id = (SELECT subject_id FROM colnod_token WHERE id = :tokenId)");
query.bindValue(":time", QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz")); query.bindValue(":tokenId", tokenId);
query.exec(); executeQuery(query);
if (query.next())
return query.value(0).toString();
qWarning() << "Token:" << tokenId << "is not assigned to any subject";
return "(No subject)";
} }
QString DatabaseManager::getSubjectNameById(const QString &id)
QSqlQuery* DatabaseManager::getTokensToAdd()
{ {
QSqlQuery* qry = new QSqlQuery; QSqlQuery query;
qry->exec("SELECT name, token_data FROM changes WHERE status = 'toBeAdd'"); query.prepare("SELECT name FROM colnod_subject WHERE id = :id");
return qry; query.bindValue(":id", id);
executeQuery(query);
if (query.next())
return query.value(0).toString();
qWarning() << "Subject:" << id << "doesn't exists";
return "(No subject)";
} }
QSqlQuery* DatabaseManager::getTokensToDelete() bool DatabaseManager::checkDeletedToken(const QString &id)
{ {
QSqlQuery* qry = new QSqlQuery; QSqlQuery query;
qry->exec("SELECT id FROM changes WHERE status = 'toBeDeleted'"); query.prepare("SELECT deleted FROM colnod_token WHERE id = :id");
return qry; query.bindValue(":id", id);
} executeQuery(query);
QUuid DatabaseManager::getId(QString name)
{
query.prepare("SELECT id FROM colnod_subject WHERE name = :name");
query.bindValue(":name", name);
query.exec();
query.next(); query.next();
return query.value(0).toUuid(); return query.value(0).toBool();
} }

View File

@ -1,5 +1,5 @@
#ifndef DATABASEMANAGER_H #pragma once
#define DATABASEMANAGER_H
#include <QSql> #include <QSql>
#include <QSqlDatabase> #include <QSqlDatabase>
#include <QSqlQuery> #include <QSqlQuery>
@ -10,49 +10,47 @@
#include "subject.h" #include "subject.h"
#include "token.h" #include "token.h"
#include <QDateTime> #include <QDateTime>
//#include "logger.h"
class DatabaseManager : public QObject class DatabaseManager : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
DatabaseManager(QString host, QString dbName, QString user, QString password); DatabaseManager(const QString& host, const QString& dbName, const QString& user, const QString& password, const bool& dryMode = false);
void saveSubject(Subject* subject, QString table); int saveSubject(const std::shared_ptr<Subject>& subject, const QString& table);
void saveToken(Token* token, QString table); int saveToken(const std::shared_ptr<Token>& token, const QString& table);
void saveSubjectAttribute(Subject* subject, QString table); void saveSubjectAttributes(const std::shared_ptr<Subject>& subject, const QString& table);
void deleteItem(QString id, QString table); void setDeleted(const QString& id, const QString& table, quint64 time);
QString getTestMessage(int id);
int createTestRecord(QString msg);
//
void makeTestingLast_sync();
//
void dropTables(); void dropTables();
void createTables(); void createTables();
bool getOpened() {return opened;} quint64 getLastSync();
uint64_t getLastUpdate(); void updateLastSync(quint64 lastSync);
void updateLastSync(); quint64 getNow();
QSqlQuery* getTokensToAdd(); QSqlQuery getUpdatedTokens();
QSqlQuery* getTokensToDelete(); QSqlQuery getToken(const QString& id);
QUuid getId(QString name); void setLastUpdate(const QString& id, quint64 lastUpdate);
void log(const QString &msg);
QString getSubjectNameByTokenId(const QString &tokenId);
QString getSubjectNameById(const QString &id);
bool checkDeletedToken(const QString &id);
private: private:
bool checkIfExists(QString id, QString table); bool checkIfExists(const QString& id, const QString& table);
bool executeQuery(QSqlQuery &query, const QString &statement = QString());
QString getLastQuery(const QSqlQuery &query) const;
signals:
void error();
private: private:
QSqlDatabase db; QSqlDatabase db;
QSqlQuery query; bool dryMode = false;
bool opened;
}; };
#endif // DATABASEMANAGER_H

View File

@ -1,224 +1,342 @@
#include "datamanager.h" #include "datamanager.h"
DataManager::DataManager() DataManager::DataManager(const bool &dryMode)
:dryMode(dryMode)
{ {
db = new DatabaseManager("192.168.1.94", "deloitte", "postgres", "34rjkciea12"); 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);
nextLastSync = db->getNow();
lastSync = db->getLastSync();
connect(db.get(), &DatabaseManager::error, this, &DataManager::error);
} }
void DataManager::localSaveSubjects(QString response) // load all tokens from colnod to comparing with working set from DB
void DataManager::fillFullTokensColnod(const QString& response)
{ {
QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8()); QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8());
QJsonArray items = doc.object()["items"].toArray(); QJsonArray items = doc.object()["items"].toArray();
if (items.size() > 0) if (!items.empty())
{ {
for (QJsonValueRef item : items) for (QJsonValueRef item : items){
{ auto token = std::make_shared<Token>();
auto subject = new Subject();
subject->fromJSON(item.toObject());
subjects.append(subject);
}
}
else
{
Subject* subject = new Subject;
subject->setName("empty");
subjects.append(subject);
}
}
void DataManager::localSaveTokens(QString response)
{
QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8());
QJsonArray items = doc.object()["items"].toArray();
if (items.size() > 0)
{
for (QJsonValueRef item : items)
{
auto token = new Token();
token->fromJSON(item.toObject()); token->fromJSON(item.toObject());
tokens.append(token); allTokensFromColnodById.insert(token->idToStringWithoutBraces(), token);
allTokensFromColnodByName.insert(token->getName(), token);
} }
} }
else else{
{ qCritical() << "Colnod is Empty";
Token* token = new Token;
token->setName("empty");
tokens.append(token);
} }
} }
void DataManager::localSaveSubjectsToDelete(QString json) // load working set with updated tokens from Colnod
void DataManager::fillTokensToUpdateColnod(const QString& response)
{ {
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8()); QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8());
QJsonArray items = doc.object()["items"].toArray(); QJsonArray items = doc.object()["items"].toArray();
if (items.size() > 0) if (!items.empty())
{ {
for (QJsonValueRef item : items) for (QJsonValueRef item : items)
{ {
subjectsToDelete.append(item.toString()); auto token = std::make_shared<Token>();
token->fromJSON(item.toObject());
token->setDeleted(false);
tokensToUpdateFromColnodToDB.insert(token->idToStringWithoutBraces(), token);
} }
qInfo() << "Colnod:" << tokensToUpdateFromColnodToDB.size() << "tokens to update";
} }
else else
{ {
subjectsToDelete.append("empty"); qInfo() << "Colnod: 0 tokens to update";
} }
} }
void DataManager::localSaveTokensToDelete(QString json) // load working set with updated subjects from Colnod
void DataManager::fillSubjectsToUpdateColnod(const QString& response)
{ {
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8()); QJsonDocument doc = QJsonDocument::fromJson(response.toUtf8());
QJsonArray items = doc.object()["items"].toArray(); QJsonArray items = doc.object()["items"].toArray();
if (items.size() > 0) if (!items.empty())
{ {
for (QJsonValueRef item : items) for (QJsonValueRef item : items)
{ {
tokensToDelete.append(item.toString()); auto subject = std::make_shared<Subject>();
subject->fromJSON(item.toObject());
subject->setDeleted(false);
subjectsToUpdateFromColnodToDB.insert(subject->idToStringWithoutBraces(), subject);
} }
qInfo() << "Colnod:" << subjectsToUpdateFromColnodToDB.size() << "subjects to update";
} }
else else
{ {
tokensToDelete.append("empty"); qInfo() << "Colnod:" << "0 subjects to update";
} }
} }
// load working sets with updated/deleted tokens from DB
void DataManager::fillTokensToChangeDB()
{
QSqlQuery query = db->getUpdatedTokens();
while (query.next())
{
auto token = std::make_shared<Token>();
token->fromSQLRecord(query);
if (token->getDeleted()){ // sort to delete / to update
tokensFromDBToDeleteFromColnod.append(token->idToStringWithoutBraces());
}
else{
tokensToUpdateFromDBToColnod.insert(token->idToStringWithoutBraces(), token);
}
}
qDebug() << "DB:" << tokensToUpdateFromDBToColnod.size() << "tokens to update";
qDebug() << "DB:" << tokensFromDBToDeleteFromColnod.size() << "tokens to delete";
}
void DataManager::fillSubjectsToUpdateDB()
{
// Not needed yet
}
// load working set with subjest to delete from Colnod
void DataManager::fillSubjectsToDeleteColnod(const QString& json)
{
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8());
QJsonArray items = doc.object()["items"].toArray();
if (!items.empty())
{
for (QJsonValueRef item : items) {
subjectsFromColnodToDeleteFromDB.append(item.toString());
}
qInfo() << "Colnod:" << subjectsFromColnodToDeleteFromDB.size() << "subjects to delete";
}
else {
qInfo() << "Colnod: 0 subjects to delete";
}
}
// load working set with tokens to delete from DB
void DataManager::fillTokensToDeleteColnod(const QString& json)
{
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8());
QJsonArray items = doc.object()["items"].toArray();
if (!items.empty())
{
for (QJsonValueRef item : items) {
tokensFromColnodToDeleteFromDB.append(item.toString());
}
qInfo() << "Colnod:" << tokensFromColnodToDeleteFromDB.size() << "tokens to delete";
}
else {
qInfo() << "Colnod: 0 tokens to delete";
}
}
void DataManager::fillSubjectsToDeleteDB()
{
// Not needed yet
}
// update subjects from colnod to DB
void DataManager::pushSubjectsToDB() void DataManager::pushSubjectsToDB()
{ {
if (subjects.size() == 1 && subjects[0]->getName() == "empty") if (subjectsToUpdateFromColnodToDB.isEmpty()) {
{ qInfo() << "DB: 0 subjects added";
qDebug() << "All subjects are up to date"; qInfo() << "DB: 0 subjects updated";
return; return;
} }
//QSqlDatabase::database().transaction(); int updated = 0;
qDebug() << "Subjects in progress..."; int added = 0;
for (auto subject : subjects) for (const auto& subject : subjectsToUpdateFromColnodToDB)
{ {
db->saveSubject(subject, "colnod_subject"); if (db->saveSubject(subject, "colnod_subject") > 0){
db->saveSubjectAttribute(subject, "colnod_subject_attribute"); added++;
if (dryMode)
qInfo() << "Adding subject:" << subject->idToStringWithoutBraces() << "to DB";
else
Logger::logToDb(Logger::makeSubjectMsg( subject->idToStringWithoutBraces(),"added", "DB"));
}
else{
updated++;
if (dryMode)
qInfo() << "Updating subject:" << subject->idToStringWithoutBraces() << "to DB";
else
Logger::logToDb(Logger::makeSubjectMsg( subject->idToStringWithoutBraces(),"updated", "DB"));
}
db->saveSubjectAttributes(subject, "colnod_subject_attribute");
} }
//QSqlDatabase::database().commit(); qInfo() << "DB:" << added << "subjects added";
qDebug() << subjects.size() << " subjects has been updated"; qInfo() << "DB:" << updated << "subjects updated";
} }
// update tokens from colnod to DB
void DataManager::pushTokensToDB() void DataManager::pushTokensToDB()
{ {
if (tokens.size() == 1 && tokens[0]->getName() == "empty") if (tokensToUpdateFromColnodToDB.isEmpty()){
{ qInfo() << "DB: 0 tokens added";
qDebug() << "All tokens are up to date"; qInfo() << "DB: 0 tokens updated";
return; return;
} }
//QSqlDatabase::database().transaction(); filterTokensColnod();
qDebug() << "Tokens in progress..."; int updated = 0;
for (auto token : tokens) int added = 0;
for (const auto& token : tokensToUpdateFromColnodToDB)
{ {
db->saveToken(token, "colnod_token");
QString text;
// 1 = adding token
// -1 = updating token
if (db->saveToken(token, "colnod_token") == 1){
added++;
text = "Added";
}
else {
updated++;
text = "Updating";
}
if (dryMode)
qInfo() << text << "token:" << token->idToStringWithoutBraces() << "to DB";
else
Logger::logToDb(Logger::makeTokenMsg(token->idToStringWithoutBraces(), text, "DB"));
} }
//QSqlDatabase::database().commit(); qInfo() << "DB:" << added << "tokens added/edited";
qDebug() << tokens.size() << " tokens has been updated"; qInfo() << "DB:" << updated << "tokens updated";
} }
void DataManager::deleteSubjectsFromDB() void DataManager::deleteSubjectsFromDB()
{ {
if (subjectsToDelete.size() == 1 && subjectsToDelete[0] == "empty") if (subjectsFromColnodToDeleteFromDB.isEmpty())
{ {
qDebug() << "No subjects to be deleted"; qInfo() << "DB: 0 subjects deleted";
return; return;
} }
qDebug() << "Deleted subjects in progress..."; for (const auto& subjectId : subjectsFromColnodToDeleteFromDB)
//QSqlDatabase::database().transaction();
for (auto subjectId : subjectsToDelete)
{ {
db->deleteItem(subjectId, "colnod_subject"); db->setDeleted(subjectId, "colnod_subject", nextLastSync);
if (dryMode)
qInfo() << "Deleting subject:" << subjectId << "from DB";
else
Logger::logToDb(Logger::makeSubjectMsg(subjectId, "deleted", "DB"));
} }
//QSqlDatabase::database().commit(); qInfo() << "DB:" << subjectsFromColnodToDeleteFromDB.size() << " subject deleted";
qDebug() << subjectsToDelete.size() << "subject has beed deleted";
} }
void DataManager::deleteTokensFromDB() // "delete" (set deleted true) tokens in DB depends on Colnod
void DataManager::setDeletedToTokensFromDB()
{ {
if (tokensToDelete.size() == 1 && tokensToDelete[0] == "empty") if (tokensFromColnodToDeleteFromDB.isEmpty())
{ {
qDebug() << "No tokens to be deleted"; qDebug() << "DB: 0 tokens deleted";
return; return;
} }
// QSqlDatabase::database().transaction(); int alreadyDeleted = 0;
qDebug() << "Deleted tokens in progress..."; for (const auto& tokenId : tokensFromColnodToDeleteFromDB)
for (auto tokenId : tokensToDelete)
{ {
db->deleteItem(tokenId, "colnod_token"); if (!db->checkDeletedToken(tokenId)){
db->setDeleted(tokenId, "colnod_token", nextLastSync);
if (dryMode)
qInfo() << "Deleting token:" << tokenId << "from DB";
else
Logger::logToDb(Logger::makeTokenMsg(tokenId, "deleted", "DB"));
}
else
alreadyDeleted++;
} }
//QSqlDatabase::database().commit(); qDebug() << "DB:" << tokensFromColnodToDeleteFromDB.size() - alreadyDeleted << "tokens deleted";
qDebug() << tokensToDelete.size() << "tokens has beed deleted";
}
bool DataManager::haveData()
{
if ( !subjects.isEmpty() && !tokens.isEmpty() )
return true;
return false;
}
bool DataManager::haveChangedData()
{
if ( !subjects.isEmpty() && !tokens.isEmpty() && !subjectsToDelete.isEmpty() && !tokensToDelete.isEmpty() )
return true;
return false;
}
bool DataManager::haveProcessData()
{
if ( !tokens.isEmpty() && !tokensToDelete.isEmpty())
return true;
return false;
}
uint64_t DataManager::getLastUpdate()
{
return db->getLastUpdate();
} }
// recreate working tables
void DataManager::emptyDatabase() void DataManager::emptyDatabase()
{ {
db->dropTables(); db->dropTables();
db->createTables(); db->createTables();
} }
quint64 DataManager::getLastModifiedOfToken(const QString &id)
{
auto record = db->getToken(id);
auto token = std::make_shared<Token>();
token->fromSQLRecord(record);
return token->getLastModified();
}
//clear all structures
void DataManager::clear() void DataManager::clear()
{ {
subjects.clear(); subjectsToUpdateFromColnodToDB.clear();
subjectsToDelete.clear(); subjectsFromColnodToDeleteFromDB.clear();
tokens.clear(); tokensToUpdateFromColnodToDB.clear();
tokensToDelete.clear(); tokensFromColnodToDeleteFromDB.clear();
//subjectsDB.clear(); // not need yet
// subjectsToDeleteDB.clear(); // not need yet
tokensToUpdateFromDBToColnod.clear();
tokensFromDBToDeleteFromColnod.clear();
allTokensFromColnodById.clear();
} }
// on the very end of sync update last sync time to begin time of this sync
void DataManager::updateLastSync() void DataManager::updateLastSync()
{ {
db->updateLastSync(); db->updateLastSync(nextLastSync);
} }
void DataManager::loadTokensToAdd() // these to filter functions solve colision tokens -> remove when change on this token is earlier then change on the same token on the other side (Colnod/DB)
void DataManager::filterTokensDB()
{ {
QSqlQuery* query = db->getTokensToAdd(); QList<QString> idsToDelete;
while (query->next()) for (const auto& token : tokensToUpdateFromDBToColnod)
{ {
Token* token = new Token(query->value(0).toString(), query->value(1).toString()); QString id = token->idToStringWithoutBraces();
token->setSubjectId(db->getId(token->getName())); Q_ASSERT(token != allTokensFromColnodById.value(id)); // if working sets are loading correctly equels should never happend
tokens.append(token); if (allTokensFromColnodById.contains(id) && *token < *allTokensFromColnodById.value(id))
idsToDelete.append(id);
if (allTokensFromColnodById.contains(id) && token->getLastModified() == allTokensFromColnodById.value(id)->getLastUpdate()){
idsToDelete.append(id);
qWarning() << "Same token has been edited in colnod and db in same time. Change from Colnod has been used";
}
if (allTokensFromColnodByName.contains(token->getName())){
qWarning() << "Token:" << token->idToStringWithoutBraces() << "won't be added to Colnod, because token with the same name already exists, please change it manually";
if (!dryMode){
QString message = QString("Error: Token: %1 won't be added to Colnod, because token with the same name already exists, please change it manually").arg(token->idToStringWithoutBraces());
Logger::logToDb(Logger::makeErrorMsg("Db", message));
}
}
} }
if (tokens.isEmpty()) for (const auto &id : idsToDelete)
tokens.append(new Token("empty")); tokensToUpdateFromDBToColnod.remove(id);
} }
void DataManager::loadTokensToDelete() void DataManager::filterTokensColnod()
{ {
QSqlQuery* query = db->getTokensToDelete(); QList<QString> idsToDelete;
while (query->next()) for (const auto &token : tokensToUpdateFromColnodToDB)
{ {
tokensToDelete.append(query->value(0).toString()); QString id = token->idToStringWithoutBraces();
auto record = db->getToken(id);
if (!record.isValid())
continue;
auto tokenDB = std::make_shared<Token>();
tokenDB->fromSQLRecord(record);
if (*tokenDB == *token || *tokenDB > *token){
idsToDelete.append(id);
}
} }
if (tokensToDelete.isEmpty()) for (const auto &id : idsToDelete)
tokensToDelete.append("empty"); tokensToUpdateFromColnodToDB.remove(id);
}
// sync last update from colnod to DB
void DataManager::setLastUpdate()
{
if (!tokensToUpdateFromColnodToDB.isEmpty())
for (const auto &token : tokensToUpdateFromColnodToDB)
db->setLastUpdate(token->idToStringWithoutBraces(), token->getLastUpdate());
}
void DataManager::setLastUpdate(const QString &id)
{
db->setLastUpdate(id, nextLastSync);
} }

View File

@ -1,5 +1,4 @@
#ifndef DATAMANAGER_H #pragma once
#define DATAMANAGER_H
#include "token.h" #include "token.h"
#include "subject.h" #include "subject.h"
@ -7,6 +6,7 @@
#include "databasemanager.h" #include "databasemanager.h"
#include <QJsonDocument> #include <QJsonDocument>
#include <qjsonarray.h> #include <qjsonarray.h>
#include <logger.h>
class DataManager : public QObject class DataManager : public QObject
@ -15,41 +15,67 @@ class DataManager : public QObject
Q_OBJECT Q_OBJECT
public: public:
DataManager(); DataManager(const bool& dryMode = false);
void localSaveSubjects(QString jsonResponse); void fillFullTokensColnod(const QString& jsonResponse);
void localSaveTokens(QString jsonResponse);
void localSaveSubjectsToDelete(QString jsonResponse); void fillTokensToUpdateColnod(const QString& jsonResponse);
void localSaveTokensToDelete(QString jsonResponse); void fillSubjectsToUpdateColnod(const QString& jsonResponse);
void fillSubjectsToDeleteColnod(const QString& jsonResponse);
void fillTokensToDeleteColnod(const QString& jsonResponse);
void fillTokensToChangeDB();
void fillSubjectsToUpdateDB();
void fillSubjectsToDeleteDB();
void filterTokensDB();
void filterTokensColnod();
void pushSubjectsToDB(); void pushSubjectsToDB();
void pushTokensToDB(); void pushTokensToDB();
void deleteSubjectsFromDB(); void deleteSubjectsFromDB();
void deleteTokensFromDB(); void setDeletedToTokensFromDB();
void updateLastSync(); void updateLastSync();
uint64_t getLastUpdate();
bool haveData();
bool haveChangedData();
bool haveProcessData();
void emptyDatabase(); void emptyDatabase();
quint64 getLastModifiedOfToken(const QString &id);
QHash<QString, std::shared_ptr<Token>> getTokensToUpdateFromColnod() {return tokensToUpdateFromColnodToDB;}
QList<QString> getTokensToDeleteColnod() {return tokensFromColnodToDeleteFromDB;}
QHash<QString, std::shared_ptr<Token>> getTokensToUpdateFromDB() {return tokensToUpdateFromDBToColnod;}
QList<QString> getTokensToDeleteDB() {return tokensFromDBToDeleteFromColnod;}
const quint64 &getLastSync() {return lastSync;}
const quint64 &getCurrentSync() {return nextLastSync;}
public slots:
void clear(); void clear();
void setLastUpdate();
void setLastUpdate(const QString &id);
void loadTokensToAdd(); signals:
void loadTokensToDelete(); void error();
QList<QPointer<Token>>* getTokens() {return &tokens;}
QList<QString>* getTokensToDelete() {return &tokensToDelete;}
private: private:
DatabaseManager *db = nullptr; std::shared_ptr<DatabaseManager> db;
QList<QPointer<Subject>> subjects;
QList<QPointer<Token>> tokens;
QList<QString> subjectsToDelete;
QList<QString> tokensToDelete;
};
#endif // DATAMANAGER_H quint64 lastSync; // time of last run
quint64 nextLastSync; // time of begin of this run
QHash<QString, std::shared_ptr<Token>> allTokensFromColnodById;
QHash<QString, std::shared_ptr<Token>> allTokensFromColnodByName;
QHash<QString, std::shared_ptr<Subject>> subjectsToUpdateFromColnodToDB;
QHash<QString, std::shared_ptr<Token>> tokensToUpdateFromColnodToDB;
QHash<QString, std::shared_ptr<Subject>> subjectsDB; // in future
QHash<QString, std::shared_ptr<Token>> tokensToUpdateFromDBToColnod;
QList<QString> subjectsFromColnodToDeleteFromDB;
QList<QString> tokensFromColnodToDeleteFromDB;
QList<QString> subjectsToDeleteDB;
QList<QString> tokensFromDBToDeleteFromColnod;
bool dryMode = false;
};

View File

@ -25,33 +25,52 @@ void Entity::setDescription(const QString &description) {
Entity::description = description; Entity::description = description;
} }
uint64_t Entity::getLastUpdate() const { quint64 Entity::getLastUpdate() const {
return lastUpdate; return lastUpdate;
} }
void Entity::setLastUpdate(uint64_t lastUpdate) { void Entity::setLastUpdate(quint64 lastUpdate) {
this->lastUpdate = lastUpdate; this->lastUpdate = lastUpdate;
} }
QString Entity::idToStringWithoutBraces() quint64 Entity::getLastModified() const {
return lastModified;
}
void Entity::setLastModified(const quint64 &lastModified) {
this->lastModified = lastModified;
}
bool Entity::getDeleted() const
{ {
return id.toString().mid(1,36); return deleted;
}
void Entity::setDeleted(const bool &deleted)
{
this->deleted = deleted;
}
QString Entity::idToStringWithoutBraces() const
{
const qint8 lengthOfUuid = 36;
return id.toString().mid(1, lengthOfUuid);
} }
void Entity::fromJSON(const QJsonObject &json) { void Entity::fromJSON(const QJsonObject &json) {
id = json.value("id").toString(); id = json["id"].toString();
name = json.value("name").toString(); name = json["name"].toString();
description = json.value("description").toString(); description = json["description"].toString();
lastUpdate = json.value("lastUpdate").toDouble(); lastUpdate = json["lastUpdate"].toDouble();
} }
QJsonObject Entity::toJSON() const { QJsonObject Entity::toJSON() const {
QJsonObject json; QJsonObject json;
json.value("id") = id.toString(); json["id"] = this->idToStringWithoutBraces();
json.value("name") = name; json["name"] = name;
json.value("description") = description; json["description"] = description;
json.value("lastUpdate") = lastUpdate; json["lastUpdate"] = lastUpdate;
return json; return json;
} }

View File

@ -1,13 +1,14 @@
#ifndef COLNOD_CONNECTOR_ENTITY_H #pragma once
#define COLNOD_CONNECTOR_ENTITY_H
#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 {
Q_OBJECT Q_OBJECT
public: public:
using QObject::QObject; using QObject::QObject;
@ -20,20 +21,27 @@ public:
const QString &getDescription() const; const QString &getDescription() const;
void setDescription(const QString &description); void setDescription(const QString &description);
uint64_t getLastUpdate() const; quint64 getLastUpdate() const;
void setLastUpdate(uint64_t lastUpdate); void setLastUpdate(quint64 lastUpdate);
QString idToStringWithoutBraces(); quint64 getLastModified() const;
void setLastModified(const quint64 &lastModified);
bool getDeleted() const;
void setDeleted(const bool &deleted);
QString idToStringWithoutBraces() const;
virtual void fromJSON(const QJsonObject &json); virtual void fromJSON(const QJsonObject &json);
virtual QJsonObject toJSON() const; virtual QJsonObject toJSON() const;
protected:
private:
QUuid id; QUuid id;
QString name; QString name;
QString description; QString description;
qint64 lastUpdate; qint64 lastUpdate{};
quint64 lastModified{};
bool deleted{};
}; };
#endif //COLNOD_CONNECTOR_ENTITY_H

53
src/colnod/logger.cpp Normal file
View File

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

31
src/colnod/logger.h Normal file
View File

@ -0,0 +1,31 @@
#pragma once
#include <QString>
#include <QDebug>
#include <QSqlDatabase>
#include "databasemanager.h"
class Logger
{
static Logger *logger;
Logger();
static std::shared_ptr<DatabaseManager> dbMan;
public:
static Logger *getLogger();
static void log(const QString& msg);
static void logToDb(const QString& msg);
static void setDBMan(std::shared_ptr<DatabaseManager> dbMan);
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 makeErrorMsg(const QString& source, const QString& errMsg);
private:
};

View File

@ -2,58 +2,47 @@
RequestManager::RequestManager() RequestManager::RequestManager()
{ {
manager = new QNetworkAccessManager(); manager = std::make_unique<QNetworkAccessManager>();
token = ""; connect(manager.get(), &QNetworkAccessManager::sslErrors, this, &RequestManager::onSSLError);
loginStatus = false; //should be false, true for testing request header
/*
QFile configFile(QDir::current().filePath("config.json"));
if (!configFile.open(QIODevice::ReadOnly)) {
qCritical() << "Couldn't open config file config.json" << QDir::current().filePath("config.json");
QCoreApplication::exit(-1);
return;
}
this->config = QJsonDocument::fromJson(configFile.readAll());*/
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);
QJsonObject reqBody = { QJsonObject reqBody = {
{"password", hash}, {"password", hash},
{"username", this->user} {"username", this->user}
}; };
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;
} }
QNetworkReply* RequestManager::postRequest(QString endpoint, QByteArray json) QNetworkReply* RequestManager::postRequest(const QString& endpoint, const QByteArray& json)
{ {
QNetworkRequest request; QNetworkRequest request;
request.setUrl(host + endpoint); request.setUrl(host + endpoint);
@ -63,42 +52,37 @@ QNetworkReply* RequestManager::postRequest(QString endpoint, QByteArray json)
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();
}); });
return reply; return reply;
} }
// 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();
} }
return loginResponse; return loginResponse;
} }
Response* RequestManager::postRequestReturnLogic(QString endpoint, QByteArray data) Response* RequestManager::postRequestReturnLogic(const QString& endpoint, const QByteArray& data)
{ {
auto loginResponse = getLoginResponse(); auto loginResponse = getLoginResponse();
// This will ensure login is called only once
Q_ASSERT(loginResponse); Q_ASSERT(loginResponse);
Response* response = new Response; auto response = new Response;
if (!loginStatus){ if (!loginStatus){
connect(this, &RequestManager::successLogin, [=](){ connect(this, &RequestManager::successLogin, [=](){
response->setReply(postRequest(endpoint, data)); response->setReply(postRequest(endpoint, data));
connect(response->getReply(), &QNetworkReply::finished, response, &Response::ready); connect(response->getReply(), &QNetworkReply::finished, response, &Response::ready);
}); });
} }
else else
{ {
@ -108,9 +92,10 @@ Response* RequestManager::postRequestReturnLogic(QString endpoint, QByteArray da
return response; return response;
} }
QString RequestManager::getFromJson(QString json, const QString &member) // get value of member in json
QString RequestManager::getFromJson(const QString& json, const QString &member)
{ {
QJsonParseError err; QJsonParseError err{};
QJsonDocument document = QJsonDocument::fromJson(json.toUtf8(),&err); QJsonDocument document = QJsonDocument::fromJson(json.toUtf8(),&err);
if (err.error != 0) if (err.error != 0)
{ {
@ -119,12 +104,12 @@ QString RequestManager::getFromJson(QString json, const QString &member)
return document.object().value(member).toString(); return document.object().value(member).toString();
} }
QString RequestManager::encryptedPassword(QString password) QString RequestManager::encryptedPassword(const QString& password)
{ {
return QCryptographicHash::hash(password.toLocal8Bit(), QCryptographicHash::Sha512).toHex().toUpper(); return QCryptographicHash::hash(password.toLocal8Bit(), QCryptographicHash::Sha512).toHex().toUpper();
} }
QString RequestManager::getLoginHeader(QString username, QString hash) QString RequestManager::getLoginHeader(const QString& username, const QString& hash)
{ {
QString authValue = username + ":" + hash; QString authValue = username + ":" + hash;
return "Basic " + authValue.toLocal8Bit().toBase64(); return "Basic " + authValue.toLocal8Bit().toBase64();
@ -133,7 +118,7 @@ QString RequestManager::getLoginHeader(QString username, QString hash)
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();
} }
@ -150,7 +135,7 @@ void RequestManager::onSSLError(QNetworkReply *reply, const QList<QSslError> &er
} }
QByteArray RequestManager::makeTimeStampJson(uint64_t time) QByteArray RequestManager::makeTimestampJson(uint64_t time)
{ {
QJsonObject reqBody = {{"timestamp",QJsonValue(static_cast<qint64>(time)) }}; QJsonObject reqBody = {{"timestamp",QJsonValue(static_cast<qint64>(time)) }};
QJsonDocument doc; QJsonDocument doc;
@ -158,28 +143,13 @@ QByteArray RequestManager::makeTimeStampJson(uint64_t time)
return doc.toJson(); return doc.toJson();
} }
QByteArray RequestManager::makeTokensJson(QList<QPointer<Token>>* tokens) QByteArray RequestManager::makeTokensJson(const QHash<QString, std::shared_ptr<Token>> &tokens)
{ {
QJsonObject items; QJsonObject items;
QJsonArray jsonTokens; QJsonArray jsonTokens;
for (auto token : *tokens) for (const auto& token : tokens)
{ {
QJsonObject jsonToken; jsonTokens.push_back(token->toJSON());
jsonToken.insert("id",token->idToStringWithoutBraces());
jsonToken.insert("name",token->getName());
jsonToken.insert("description", token->getDescription());
jsonToken.insert("tokenType", token->getTokenType());
jsonToken.insert("tokenBits", token->getTokenBits());
jsonToken.insert("tokenData", token->getTokenData());
jsonToken.insert("timeToLive", token->getTimeToLive());
jsonToken.insert("authErrors", token->getAuthErrors());
QJsonArray flags;
auto flagStructure = token->getFlags();
for (auto flag : flagStructure)
flags.push_back(flag);
jsonToken.insert("flags", flags);
jsonToken.insert("subjectId", token->subjectIdToStringWithoutBraces());
jsonTokens.push_back(jsonToken);
} }
items.insert("items", jsonTokens); items.insert("items", jsonTokens);
QJsonDocument doc; QJsonDocument doc;
@ -187,10 +157,10 @@ QByteArray RequestManager::makeTokensJson(QList<QPointer<Token>>* tokens)
return doc.toJson(); return doc.toJson();
} }
QByteArray RequestManager::makeIdsJson(QList<QString>* ids) QByteArray RequestManager::makeIdsJson(const QList<QString> &ids)
{ {
QJsonArray jsonIds; QJsonArray jsonIds;
for (auto id : *ids) for (const auto& id : ids)
{ {
jsonIds.push_back(id); jsonIds.push_back(id);
} }
@ -218,22 +188,22 @@ Response* RequestManager::getTokenSubject()
Response* RequestManager::getSubjectsUpdated(uint64_t time) Response* RequestManager::getSubjectsUpdated(uint64_t time)
{ {
return postRequestReturnLogic("/SubjectManager/getSubjectsUpdated", makeTimeStampJson(time)); return postRequestReturnLogic("/SubjectManager/getSubjectsUpdated", makeTimestampJson(time));
} }
Response* RequestManager::getSubjectsDeleted(uint64_t time) Response* RequestManager::getSubjectsDeleted(uint64_t time)
{ {
return postRequestReturnLogic("/SubjectManager/getSubjectsDeleted", makeTimeStampJson(time)); return postRequestReturnLogic("/SubjectManager/getSubjectsDeleted", makeTimestampJson(time));
} }
Response* RequestManager::getTokensUpdated(uint64_t time) Response* RequestManager::getTokensUpdated(uint64_t time)
{ {
return postRequestReturnLogic("/TokenManager/getTokensUpdated", makeTimeStampJson(time)); return postRequestReturnLogic("/TokenManager/getTokensUpdated", makeTimestampJson(time));
} }
Response* RequestManager::getTokensDeleted(uint64_t time) Response* RequestManager::getTokensDeleted(uint64_t time)
{ {
return postRequestReturnLogic("/TokenManager/getTokensDeleted", makeTimeStampJson(time)); return postRequestReturnLogic("/TokenManager/getTokensDeleted", makeTimestampJson(time));
} }
Response* RequestManager::getAccessGroups() Response* RequestManager::getAccessGroups()
@ -243,12 +213,12 @@ Response* RequestManager::getAccessGroups()
Response* RequestManager::getAccessGroupsUpdated(uint64_t time) Response* RequestManager::getAccessGroupsUpdated(uint64_t time)
{ {
return postRequestReturnLogic("/AccessManager/getAccessGroupsUpdated", makeTimeStampJson(time)); return postRequestReturnLogic("/AccessManager/getAccessGroupsUpdated", makeTimestampJson(time));
} }
Response* RequestManager::getAccessGroupsDeleted(uint64_t time) Response* RequestManager::getAccessGroupsDeleted(uint64_t time)
{ {
return postRequestReturnLogic("/AccessManager/getAccessGroupsDeleted", makeTimeStampJson(time)); return postRequestReturnLogic("/AccessManager/getAccessGroupsDeleted", makeTimestampJson(time));
} }
Response* RequestManager::getAccessGroupMembership() Response* RequestManager::getAccessGroupMembership()
@ -258,20 +228,20 @@ Response* RequestManager::getAccessGroupMembership()
Response* RequestManager::getAccessGroupMembershipUpdated(uint64_t time) Response* RequestManager::getAccessGroupMembershipUpdated(uint64_t time)
{ {
return postRequestReturnLogic("/AccessManager/getAccessGroupMembershipUpdated", makeTimeStampJson(time)); return postRequestReturnLogic("/AccessManager/getAccessGroupMembershipUpdated", makeTimestampJson(time));
} }
Response* RequestManager::getAccessGroupMembershipDeleted(uint64_t time) Response* RequestManager::getAccessGroupMembershipDeleted(uint64_t time)
{ {
return postRequestReturnLogic("/AccessManager/getAccessGroupMembershipDeleted", makeTimeStampJson(time)); return postRequestReturnLogic("/AccessManager/getAccessGroupMembershipDeleted", makeTimestampJson(time));
} }
Response* RequestManager::setTokens(QList<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));
} }
Response* RequestManager::deleteTokens(QList<QString>* ids) Response* RequestManager::deleteTokens(const QList<QString> &ids)
{ {
return postRequestReturnLogic("/TokenManager/deleteTokens", makeIdsJson(ids)); return postRequestReturnLogic("/TokenManager/deleteTokens", makeIdsJson(ids));
} }

View File

@ -1,5 +1,4 @@
#ifndef REQUESTMANAGER_H #pragma once
#define REQUESTMANAGER_H
#include <QObject> #include <QObject>
#include <QNetworkReply> #include <QNetworkReply>
@ -25,13 +24,19 @@
#include "token.h" #include "token.h"
#include "response.h" #include "response.h"
#include "logger.h"
class RequestManager : public QObject 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,49 +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(QList<QPointer<Token>>* tokens); Response* setTokens(const QHash<QString, std::shared_ptr<Token>> &tokens);
Response* deleteTokens(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:
QNetworkReply* postRequest(QString endpoint, QByteArray json = QByteArray()); // should be public
Response* postRequestReturnLogic(QString endpoint, QByteArray data = QByteArray()); QNetworkReply* postRequest(const QString& endpoint, const QByteArray& json = QByteArray());
QString getFromJson(QString json, const QString &member); Response* postRequestReturnLogic(const QString& endpoint, const QByteArray& data = QByteArray());
QString encryptedPassword(QString password);
QString getLoginHeader(QString username, QString hash);
QByteArray makeTimeStampJson(uint64_t time); std::shared_ptr<Response> login();
QByteArray makeTokensJson(QList<QPointer<Token>>* tokens); std::shared_ptr<Response> getLoginResponse();
QByteArray makeIdsJson(QList<QString>* ids); QString getFromJson(const QString& json, const QString &member);
Response* getLoginResponse(); QString encryptedPassword(const QString& password);
QString getLoginHeader(const QString& username, const QString& hash);
// in colnod api as well
QByteArray makeTimestampJson(uint64_t time);
QByteArray makeTokensJson(const QHash<QString, std::shared_ptr<Token>> &tokens); // maybe better to be in Token class
QByteArray makeIdsJson(const QList<QString> &ids); // Entity class
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;
}; };
#endif // REQUESTMANAGER_H

View File

@ -1,5 +1,4 @@
#ifndef RESPONSE_H #pragma once
#define RESPONSE_H
#include <QObject> #include <QObject>
#include <qnetworkreply.h> #include <qnetworkreply.h>
@ -31,5 +30,3 @@ private:
QString json; QString json;
QNetworkReply *reply = nullptr; QNetworkReply *reply = nullptr;
}; };
#endif // RESPONSE_H

View File

@ -4,6 +4,11 @@
#include <QJsonArray> #include <QJsonArray>
Subject::Subject(const QString &name)
{
setName(name);
}
QString Subject::getEmail() const { QString Subject::getEmail() const {
return attributes["email"].toString(); return attributes["email"].toString();
} }
@ -11,21 +16,21 @@ QString Subject::getEmail() const {
void Subject::fromJSON(const QJsonObject &json) { void Subject::fromJSON(const QJsonObject &json) {
Entity::fromJSON(json); Entity::fromJSON(json);
attributes = json.value("attributes").toObject().value("items").toObject(); attributes = json["attributes"].toObject()["items"].toObject();
for (int i = 0; i < attributeTypes->length(); i++) for (const auto & attributeType : attributeTypes)
{ {
if (!attributes[attributeTypes[i]].toString().isEmpty()){ if (!attributes[attributeType].toString().isEmpty()){
atr.append(qMakePair(attributeTypes[i], attributes[attributeTypes[i]].toString())); atr.append(qMakePair(attributeType, attributes[attributeType].toString()));
} }
} }
const auto &tokenFlagsArray = json.value("tokenFlags").toArray(); const auto &tokenFlagsArray = json["tokenFlags"].toArray();
for(const auto &flag : tokenFlagsArray){ for(const auto &flag : tokenFlagsArray){
tokenFlags.insert(flag.toString()); tokenFlags.insert(flag.toString());
} }
pin = json.value("pin").toString(); pin = json["pin"].toString();
const auto &pinFlagsArray = json.value("pinFlags").toArray(); const auto &pinFlagsArray = json["pinFlags"].toArray();
for(const auto &flag : pinFlagsArray){ for(const auto &flag : pinFlagsArray){
pinFlags.insert(flag.toString()); pinFlags.insert(flag.toString());
} }
@ -36,10 +41,10 @@ QJsonObject Subject::toJSON() const {
QJsonObject json = Entity::toJSON(); QJsonObject json = Entity::toJSON();
QJsonObject items({{"items", attributes}}); QJsonObject items({{"items", attributes}});
json.value("atributes") = items; json["atributes"] = items;
json.value("tokenFlags") = QJsonArray::fromStringList(tokenFlags.toList()); json["tokenFlags"] = QJsonArray::fromStringList(tokenFlags.toList());
json.value("pin") = pin; json["pin"] = pin;
json.value("pinFlags") = QJsonArray::fromStringList(pinFlags.toList()); json["pinFlags"] = QJsonArray::fromStringList(pinFlags.toList());
return json; return json;
} }

View File

@ -1,5 +1,4 @@
#ifndef COLNOD_CONNECTOR_SUBJECT_H #pragma once
#define COLNOD_CONNECTOR_SUBJECT_H
#include <QSet> #include <QSet>
@ -12,6 +11,8 @@ class Subject : public Entity {
public: public:
using Entity::Entity; using Entity::Entity;
Subject() = default;
Subject(const QString& name);
QString getEmail() const; QString getEmail() const;
@ -23,24 +24,18 @@ public:
void setPin(const QString &pin); void setPin(const QString &pin);
const QSet<QString> &getPinFlags() const; const QSet<QString> &getPinFlags() const;
void setPinFlags(const QSet<QString> &pinFlags); void setPinFlags(const QSet<QString> &pinFlags);
// const QList<QPointer<Attribute>> &getAtr() const;
// void setAtr(const QList<QPointer<Attribute>> &atr);
const QList<QPair<QString, QString>> &getAtr() const; const QList<QPair<QString, QString>> &getAtr() const;
void setAtr(const QList<QPair<QString, QString>> &atr); void setAtr(const QList<QPair<QString, QString>> &atr);
void fromJSON(const QJsonObject &json) override; void fromJSON(const QJsonObject &json) override;
QJsonObject toJSON() const override; QJsonObject toJSON() const override;
protected: private:
QJsonObject attributes; QJsonObject attributes;
QSet<QString> tokenFlags; QSet<QString> tokenFlags;
QString pin; QString pin;
QSet<QString> pinFlags; QSet<QString> pinFlags;
//QList<QPointer<Attribute>> atr;
QList<QPair<QString, QString>> atr; QList<QPair<QString, QString>> atr;
const QString attributeTypes[6] = {"Jmeno", "Prijmeni", "ProfilParking", "Spolecnost", "Profil", "spz"}; const QList<QString> attributeTypes = {"Jmeno", "Prijmeni", "ProfilParking", "Spolecnost", "Profil", "spz"};
}; };
#endif //COLNOD_CONNECTOR_SUBJECT_H

202
src/colnod/syncmanager.cpp Normal file
View File

@ -0,0 +1,202 @@
#include "syncmanager.h"
SyncManager::SyncManager(bool dryMode)
{
reqMan = std::make_unique<RequestManager>();
dataMan = std::make_unique<DataManager>(dryMode);
this->dryMode = dryMode;
connect(reqMan.get(), &RequestManager::error, this, &SyncManager::error);
connect(dataMan.get(), &DataManager::error, this, &SyncManager::error);
}
void SyncManager::loadDataFromColnod()
{
loadTokensFromColnod();
loadUpdatedDataFromColnod();
loadDeletedDataFromColnod();
}
// download all tokens form colnod for comparing with tokens to update from DB
void SyncManager::loadTokensFromColnod()
{
Response* resp = reqMan->getTokens();
connect(resp, &Response::ready, [=](){
dataMan->fillFullTokensColnod(resp->getJson());
areChangedDataReady();
resp->deleteLater();
});
}
// fill tokens/subjects to update in data manager
void SyncManager::loadUpdatedDataFromColnod()
{
uint64_t lastUpdate = dataMan->getLastSync();
Response* resp0 = reqMan->getSubjectsUpdated(lastUpdate);
connect(resp0, &Response::ready, [=](){
dataMan->fillSubjectsToUpdateColnod(resp0->getJson());
areChangedDataReady();
resp0->deleteLater();
});
Response* resp1 = reqMan->getTokensUpdated(lastUpdate);
connect(resp1, &Response::ready, [=](){
dataMan->fillTokensToUpdateColnod(resp1->getJson());
areChangedDataReady();
resp1->deleteLater();
});
}
// fill tokens/subjects to delete in data manager
void SyncManager::loadDeletedDataFromColnod()
{
uint64_t lastUpdate = dataMan->getLastSync();
Response* resp2 = reqMan->getSubjectsDeleted(lastUpdate);
connect(resp2, &Response::ready, [=](){
dataMan->fillSubjectsToDeleteColnod(resp2->getJson());
areChangedDataReady();
resp2->deleteLater();
});
Response* resp3 = reqMan->getTokensDeleted(lastUpdate);
connect(resp3, &Response::ready, [=](){
dataMan->fillTokensToDeleteColnod(resp3->getJson());
areChangedDataReady();
resp3->deleteLater();
});
}
// fill structures in data manager (tokens to updata/to delte)
void SyncManager::loadDataFromDB()
{
dataMan->fillTokensToChangeDB();
}
void SyncManager::syncDataFromColnodToDB()
{
syncUpdatedDataFromColnodToDB();
if (dataMan->getLastSync() != 0)
syncDeletedDataFromColnodToDB();
}
// push data from colnod to DB
void SyncManager::syncUpdatedDataFromColnodToDB()
{
dataMan->pushSubjectsToDB();
dataMan->pushTokensToDB();
}
// set deleted tokens from Colnod, delete subject
void SyncManager::syncDeletedDataFromColnodToDB()
{
dataMan->deleteSubjectsFromDB();
dataMan->setDeletedToTokensFromDB();
}
// push changes form DB to Colnod
void SyncManager::syncDataFromDBToColnod()
{
connect(this, &SyncManager::dataUpdatedToColnod, dataMan.get(), &DataManager::clear);
//connect(this, &SyncManager::dataUpdatedToColnod, dataMan.get(), &DataManager::setLastSync);
if (!dryMode)
connect(this, &SyncManager::dataUpdatedToColnod, [=](){
auto resp = reqMan->getTokensUpdated(dataMan->getCurrentSync());
connect(resp, &Response::ready, [=](){
dataMan->fillTokensToUpdateColnod(resp->getJson());
dataMan->setLastUpdate();
dataMan->clear();
dataMan->updateLastSync();
emit syncFinished();
resp->deleteLater();
});
});
else
connect(this, &SyncManager::dataUpdatedToColnod, [=](){
dataMan->updateLastSync();
emit syncFinished();
});
if (!dataMan->getTokensToUpdateFromDB().contains("empty")){
syncUpdatedDataFromDBToColnod();
}
else
updateFinished = true;
if (!dataMan->getTokensToDeleteDB().contains("empty")){
syncDeletedDataFromDBToColnod();
}
else
deleteFinished = true;
}
// add or update tokens to Colnod
void SyncManager::syncUpdatedDataFromDBToColnod()
{
dataMan->filterTokensDB();
auto tokensToUpdate = dataMan->getTokensToUpdateFromDB();
if (dryMode){
for (const auto &token : tokensToUpdate)
qInfo() << "Updating token:" << token->idToStringWithoutBraces() << "to Colnod";
updateFinished = true;
areDataUpdatedToColnod();
}
else {
Response* resp0 = reqMan->setTokens(tokensToUpdate);
connect(resp0, &Response::ready, [=](){
qInfo() << "Colnod:" << tokensToUpdate.size() << "tokens updated";
for(const auto &token : tokensToUpdate)
Logger::logToDb(Logger::makeTokenMsg(token->idToStringWithoutBraces(), "updated", "Colnod"));
updateFinished = true;
areDataUpdatedToColnod();
resp0->deleteLater();
});
}
}
// delete tokens in Colnod
void SyncManager::syncDeletedDataFromDBToColnod()
{
auto tokensToDelete = dataMan->getTokensToDeleteDB();
if (dryMode){
for (const auto &token : tokensToDelete)
qInfo() << "Deleting token:" << token << "from Colnod";
deleteFinished = true;
areDataUpdatedToColnod();
}
else {
Response* resp1 = reqMan->deleteTokens(tokensToDelete);
connect(resp1, &Response::ready, [=](){
qInfo() << "Colnod:" << tokensToDelete.size() << "tokens deleted";
for (const auto &id : tokensToDelete){
dataMan->setLastUpdate(id);
Logger::logToDb(Logger::makeTokenMsg(id, "deleted", "Colnod"));
}
deleteFinished = true;
areDataUpdatedToColnod();
resp1->deleteLater();
});
}
}
// For full sync
void SyncManager::prepareDatabase()
{
dataMan->emptyDatabase();
}
// emit signal when all data is downloaded from Colnod
void SyncManager::areChangedDataReady()
{
if (++dataCounter == 5)
emit dataDownloaded();
}
// emit signal when writing to Colnod is finised
void SyncManager::areDataUpdatedToColnod()
{
if (deleteFinished && updateFinished)
{
emit dataUpdatedToColnod();
}
}

57
src/colnod/syncmanager.h Normal file
View File

@ -0,0 +1,57 @@
#pragma once
#include "requestmanager.h"
#include "datamanager.h"
#include "logger.h"
class SyncManager : public QObject
{
Q_OBJECT
public:
SyncManager(bool dryMode = false);
void syncDataFromColnodToDB();
void syncDataFromDBToColnod();
void prepareDatabase();
public slots:
void loadDataFromColnod();
void loadDataFromDB();
signals:
void dataDownloaded();
void dataUpdatedToColnod();
void syncFinished();
void error();
private slots:
private:
void loadTokensFromColnod();
void loadUpdatedDataFromColnod();
void loadDeletedDataFromColnod();
void loadUpdatedDataFromDB();
void loadDeletedDataFromDB();
void syncUpdatedDataFromColnodToDB();
void syncDeletedDataFromColnodToDB();
void syncUpdatedDataFromDBToColnod();
void syncDeletedDataFromDBToColnod();
void areChangedDataReady();
void areDataUpdatedToColnod();
private:
std::unique_ptr<RequestManager> reqMan;
std::unique_ptr<DataManager> dataMan;
bool dryMode = false;
bool updateFinished = false;
bool deleteFinished = false;
int dataCounter = 0;
};

View File

@ -1,13 +1,14 @@
#include "token.h" #include "token.h"
#include <QJsonArray> #include <QJsonArray>
#include <utility>
Token::Token(QString namee, QString tokenData, QString decription) Token::Token(const QString& name, QString tokenData, const QString& decription)
{ {
this->name = namee; this->setName(name);
this->tokenData = tokenData; this->tokenData = std::move(tokenData);
this->description = decription; this->setDescription(decription);
this->id = QUuid::createUuid(); this->setId(QUuid::createUuid());
this->tokenType = "Token"; this->tokenType = "Token";
this->tokenBits = 32; this->tokenBits = 32;
this->timeToLive = 255; this->timeToLive = 255;
@ -16,44 +17,69 @@ Token::Token(QString namee, QString tokenData, QString decription)
} }
Token::Token(QString namee) Token::Token(const QString &name)
{ {
this->name = namee; this->setName(name);
} }
Token::~Token()
= default;
void Token::fromJSON(const QJsonObject &json) { void Token::fromJSON(const QJsonObject &json) {
Entity::fromJSON(json); Entity::fromJSON(json);
tokenType = json.value("tokenType").toString(); tokenType = json["tokenType"].toString();
tokenBits = json.value("tokenBits").toInt(); tokenBits = json["tokenBits"].toInt();
tokenData = json.value("tokenData").toString(); tokenData = json["tokenData"].toString();
validFrom = json.value("validFrom").toDouble(); timeToLive = json["timeToLive"].toInt();
validTo = json.value("validTo").toDouble();
timeToLive = json.value("timeToLive").toInt();
authErrors = json["authErrors"].toInt(); authErrors = json["authErrors"].toInt();
const auto &flagsArray = json["flags"].toArray(); const auto &flagsArray = json["flags"].toArray();
for(const auto &flag : flagsArray){ for(const auto &flag : flagsArray){
flags.insert(flag.toString()); flags.insert(flag.toString());
} }
subjectId = json.value("subjectId").toString(); subjectId = json["subjectId"].toString();
} }
QJsonObject Token::toJSON() const { QJsonObject Token::toJSON() const {
QJsonObject json = Entity::toJSON(); QJsonObject json = Entity::toJSON();
json.insert("tokenType", tokenType);
json.value("tokenType") = tokenType; json["tokenBits"] = tokenBits;
json.value("tokenBits") = tokenBits; json["tokenType"] = tokenType;
json.value("tokenData") = tokenData; json["tokenBits"] = tokenBits;
json.value("validFrom") = validFrom; json["tokenData"] = tokenData;
json.value("validTo") = validTo; json["timeToLive"] = timeToLive;
json.value("timeToLive") = timeToLive; json["authErrors"] = authErrors;
json.value("authErrors") = authErrors; json["flags"] = QJsonArray::fromStringList(flags.toList());
json.value("flags") = QJsonArray::fromStringList(flags.toList()); json["subjectId"] = subjectId.toString().mid(1,36);
json.value("subjectId") = subjectId.toString();
return json; return json;
} }
void Token::fromSQLRecord(const QSqlQuery& query)
{
setId(query.value(0).toUuid());
authErrors = query.value(1).toInt();
setDescription(query.value(2).toString());
QSet<QString> flags;
if (query.value(6).toBool())
flags.insert("NoValidity");
if (query.value(3).toBool())
flags.insert("Enabled");
this->flags = flags;
QDateTime date = query.value(4).toDateTime();
setLastUpdate(date.toMSecsSinceEpoch());
setName(query.value(5).toString());
timeToLive = query.value(7).toInt();
tokenBits = query.value(8).toInt();
tokenData = query.value(9).toString();
tokenType = query.value(10).toString();
subjectId = query.value(11).toUuid();
date = query.value(12).toDateTime();
setLastModified(date.toMSecsSinceEpoch());
setDeleted(query.value(13).toBool());
}
const QString &Token::getTokenType() const { const QString &Token::getTokenType() const {
return tokenType; return tokenType;
} }
@ -78,22 +104,6 @@ void Token::setTokenData(const QString &tokenData) {
Token::tokenData = tokenData; Token::tokenData = tokenData;
} }
qint64 Token::getValidFrom() const {
return validFrom;
}
void Token::setValidFrom(qint64 validFrom) {
Token::validFrom = validFrom;
}
qint64 Token::getValidTo() const {
return validTo;
}
void Token::setValidTo(qint64 validTo) {
Token::validTo = validTo;
}
int Token::getTimeToLive() const { int Token::getTimeToLive() const {
return timeToLive; return timeToLive;
} }
@ -127,5 +137,5 @@ void Token::setSubjectId(const QUuid &subjectId) {
} }
QString Token::subjectIdToStringWithoutBraces(){ QString Token::subjectIdToStringWithoutBraces(){
return subjectId.toString().mid(1,36); return subjectId.toString().mid(1,36);
} }

View File

@ -1,28 +1,48 @@
#ifndef COLNOD_CONNECTOR_TOKEN_H #pragma once
#define COLNOD_CONNECTOR_TOKEN_H
#include "entity.h" #include "entity.h"
#include <QSet> #include <QSet>
#include <qsqlquery.h>
#include <QVariant>
#include <QDebug>
#include <QDateTime>
class Token : public Entity { class Token : public Entity {
public: public:
// using Entity::Entity; // using Entity::Entity;
Token() = default; Token() = default;
Token(QString name, QString tokenData, QString decription = "mobile"); Token(const QString& name, QString tokenData, const QString& decription = "mobile");
Token(QString name); Token(const QString& name);
~Token() override;
friend bool operator<(const Token &lToken, const Token &rToken){
return lToken.getLastModified() < rToken.getLastUpdate();
}
friend bool operator>(const Token &lToken, const Token &rToken){
return lToken.getLastModified() > rToken.getLastUpdate();
}
friend bool operator==(const Token &lToken, const Token &rToken){
return lToken.getId() == rToken.getId() &&
lToken.getName() == rToken.getName() &&
lToken.getDescription() == rToken.getDescription() &&
lToken.getLastUpdate() == rToken.getLastUpdate() &&
lToken.tokenType == rToken.tokenType &&
lToken.tokenBits == rToken.tokenBits &&
lToken.tokenData == rToken.tokenData &&
lToken.timeToLive == rToken.timeToLive &&
lToken.authErrors == rToken.authErrors &&
lToken.flags == rToken.flags &&
lToken.subjectId == rToken.subjectId;
}
const QString &getTokenType() const; const QString &getTokenType() const;
void setTokenType(const QString &tokenType); void setTokenType(const QString &tokenType);
int getTokenBits() const; int getTokenBits() const;
void setTokenBits(int tokenBits); void setTokenBits(int tokenBits);
const QString &getTokenData() const; const QString &getTokenData() const;
void setTokenData(const QString &tokenData); void setTokenData(const QString &tokenData);
qint64 getValidFrom() const;
void setValidFrom(qint64 validFrom);
qint64 getValidTo() const;
void setValidTo(qint64 validTo);
int getTimeToLive() const; int getTimeToLive() const;
void setTimeToLive(int timeToLive); void setTimeToLive(int timeToLive);
int getAuthErrors() const; int getAuthErrors() const;
@ -32,22 +52,19 @@ public:
const QUuid &getSubjectId() const; const QUuid &getSubjectId() const;
void setSubjectId(const QUuid &subjectId); void setSubjectId(const QUuid &subjectId);
QString subjectIdToStringWithoutBraces(); QString subjectIdToStringWithoutBraces();
void fromSQLRecord(const QSqlQuery& query);
void fromJSON(const QJsonObject &json) override; void fromJSON(const QJsonObject &json) override;
QJsonObject toJSON() const override; QJsonObject toJSON() const override;
protected:
private:
QString tokenType; QString tokenType;
int tokenBits; int tokenBits{};
QString tokenData; QString tokenData;
qint64 validFrom; int timeToLive{};
qint64 validTo; int authErrors{};
int timeToLive;
int authErrors;
QSet<QString> flags; QSet<QString> flags;
QUuid subjectId; QUuid subjectId;
}; };
#endif //COLNOD_CONNECTOR_TOKEN_H

View File

@ -7,15 +7,14 @@ void UnitTest::initTestCase()
void UnitTest::loginSuccessfully() void UnitTest::loginSuccessfully()
{ {
RequestManager* testAccess = new RequestManager(); auto testAccess = new RequestManager();
QJsonDocument config = testAccess->getConfig();
QSignalSpy spy(testAccess, SIGNAL(successLogin())); QSignalSpy spy(testAccess, SIGNAL(successLogin()));
QVERIFY(spy.isValid()); QVERIFY(spy.isValid());
testAccess->login(); testAccess->login();
spy.wait(15000); 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");
@ -24,13 +23,13 @@ void UnitTest::loginSuccessfully()
//POST request w/o datas //POST request w/o datas
void UnitTest::getSubjects() void UnitTest::getSubjects()
{ {
RequestManager* testAccess = new RequestManager(); auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady())); QSignalSpy spy(testAccess, SIGNAL(responseReady()));
QVERIFY(spy.isValid()); QVERIFY(spy.isValid());
Response* response = testAccess->getSubjects(); Response* response = testAccess->getSubjects();
QSignalSpy spy1(response, &Response::ready); QSignalSpy spy1(response, &Response::ready);
spy.wait(15000); spy.wait(timeout);
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
QCOMPARE(spy1.count(), 1); QCOMPARE(spy1.count(), 1);
@ -45,11 +44,11 @@ void UnitTest::getSubjects()
void UnitTest::getTokens() void UnitTest::getTokens()
{ {
RequestManager* testAccess = new RequestManager(); auto* testAccess = new RequestManager();
Response* response = testAccess->getTokens(); Response* response = testAccess->getTokens();
QSignalSpy spy(response, &Response::ready); QSignalSpy spy(response, &Response::ready);
QCOMPARE(spy.count(), 0); QCOMPARE(spy.count(), 0);
spy.wait(15000); spy.wait(timeout);
QVERIFY(spy.isValid()); QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
QString json = response->getJson(); QString json = response->getJson();
@ -62,11 +61,11 @@ void UnitTest::getTokens()
void UnitTest::getTokenSubject() void UnitTest::getTokenSubject()
{ {
RequestManager* testAccess = new RequestManager(); auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady())); QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getTokenSubject(); Response* response = testAccess->getTokenSubject();
QCOMPARE(spy.count(), 0); QCOMPARE(spy.count(), 0);
spy.wait(15000); spy.wait(timeout);
QVERIFY(spy.isValid()); QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
QString json = response->getJson(); QString json = response->getJson();
@ -75,11 +74,11 @@ void UnitTest::getTokenSubject()
void UnitTest::getSubjectsUpdated() void UnitTest::getSubjectsUpdated()
{ {
RequestManager* testAccess = new RequestManager(); auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady())); QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getSubjectsUpdated(1568646217767); Response* response = testAccess->getSubjectsUpdated(epochMS);
QCOMPARE(spy.count(), 0); QCOMPARE(spy.count(), 0);
spy.wait(15000); spy.wait(timeout);
QVERIFY(spy.isValid()); QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
QString json = response->getJson(); QString json = response->getJson();
@ -88,11 +87,11 @@ void UnitTest::getSubjectsUpdated()
void UnitTest::getSubjectsDeleted() void UnitTest::getSubjectsDeleted()
{ {
RequestManager* testAccess = new RequestManager(); auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady())); QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getSubjectsDeleted(1568646217767); Response* response = testAccess->getSubjectsDeleted(epochMS);
QCOMPARE(spy.count(), 0); QCOMPARE(spy.count(), 0);
spy.wait(15000); spy.wait(timeout);
QVERIFY(spy.isValid()); QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
QString json = response->getJson(); QString json = response->getJson();
@ -101,11 +100,11 @@ void UnitTest::getSubjectsDeleted()
void UnitTest::getTokensUpdated() void UnitTest::getTokensUpdated()
{ {
RequestManager* testAccess = new RequestManager(); auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady())); QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getTokensUpdated(1570109859681); Response* response = testAccess->getTokensUpdated(epochMS);
QCOMPARE(spy.count(), 0); QCOMPARE(spy.count(), 0);
spy.wait(15000); spy.wait(timeout);
QVERIFY(spy.isValid()); QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
QString json = response->getJson(); QString json = response->getJson();
@ -114,11 +113,11 @@ void UnitTest::getTokensUpdated()
void UnitTest::getTokensDeleted() void UnitTest::getTokensDeleted()
{ {
RequestManager* testAccess = new RequestManager(); auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady())); QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getTokensDeleted(1570109859681); Response* response = testAccess->getTokensDeleted(epochMS);
QCOMPARE(spy.count(), 0); QCOMPARE(spy.count(), 0);
spy.wait(15000); spy.wait(timeout);
QVERIFY(spy.isValid()); QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
QString json = response->getJson(); QString json = response->getJson();
@ -127,11 +126,11 @@ void UnitTest::getTokensDeleted()
void UnitTest::getAccessGroups() void UnitTest::getAccessGroups()
{ {
RequestManager* testAccess = new RequestManager(); auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady())); QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getAccessGroups(); Response* response = testAccess->getAccessGroups();
QCOMPARE(spy.count(), 0); QCOMPARE(spy.count(), 0);
spy.wait(15000); spy.wait(timeout);
QVERIFY(spy.isValid()); QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
QString json = response->getJson(); QString json = response->getJson();
@ -140,11 +139,11 @@ void UnitTest::getAccessGroups()
void UnitTest::getAccessGroupsUpdated() void UnitTest::getAccessGroupsUpdated()
{ {
RequestManager* testAccess = new RequestManager(); auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady())); QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getAccessGroupsUpdated(1568646217767); Response* response = testAccess->getAccessGroupsUpdated(epochMS);
QCOMPARE(spy.count(), 0); QCOMPARE(spy.count(), 0);
spy.wait(15000); spy.wait(timeout);
QVERIFY(spy.isValid()); QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
QString json = response->getJson(); QString json = response->getJson();
@ -153,11 +152,11 @@ void UnitTest::getAccessGroupsUpdated()
void UnitTest::getAccessGroupsDeleted() void UnitTest::getAccessGroupsDeleted()
{ {
RequestManager* testAccess = new RequestManager(); auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady())); QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getAccessGroupsDeleted(1568646217767); Response* response = testAccess->getAccessGroupsDeleted(epochMS);
QCOMPARE(spy.count(), 0); QCOMPARE(spy.count(), 0);
spy.wait(15000); spy.wait(timeout);
QVERIFY(spy.isValid()); QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
QString json = response->getJson(); QString json = response->getJson();
@ -166,11 +165,11 @@ void UnitTest::getAccessGroupsDeleted()
void UnitTest::getAccessGroupMembership() void UnitTest::getAccessGroupMembership()
{ {
RequestManager* testAccess = new RequestManager(); auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady())); QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getAccessGroupMembership(); Response* response = testAccess->getAccessGroupMembership();
QCOMPARE(spy.count(), 0); QCOMPARE(spy.count(), 0);
spy.wait(15000); spy.wait(timeout);
QVERIFY(spy.isValid()); QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
QString json = response->getJson(); QString json = response->getJson();
@ -179,11 +178,11 @@ void UnitTest::getAccessGroupMembership()
void UnitTest::getAccessGroupMembershipUpdated() void UnitTest::getAccessGroupMembershipUpdated()
{ {
RequestManager* testAccess = new RequestManager(); auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady())); QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getAccessGroupMembershipUpdated(1568646217767); Response* response = testAccess->getAccessGroupMembershipUpdated(epochMS);
QCOMPARE(spy.count(), 0); QCOMPARE(spy.count(), 0);
spy.wait(15000); spy.wait(timeout);
QVERIFY(spy.isValid()); QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
QString json = response->getJson(); QString json = response->getJson();
@ -192,11 +191,11 @@ void UnitTest::getAccessGroupMembershipUpdated()
void UnitTest::getAccessGroupMembershipDeleted() void UnitTest::getAccessGroupMembershipDeleted()
{ {
RequestManager* testAccess = new RequestManager(); auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady())); QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getAccessGroupMembershipDeleted(1568646217767); Response* response = testAccess->getAccessGroupMembershipDeleted(epochMS);
QCOMPARE(spy.count(), 0); QCOMPARE(spy.count(), 0);
spy.wait(15000); spy.wait(timeout);
QVERIFY(spy.isValid()); QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
QString json = response->getJson(); QString json = response->getJson();
@ -205,26 +204,15 @@ void UnitTest::getAccessGroupMembershipDeleted()
void UnitTest::setTokens() void UnitTest::setTokens()
{ {
QFile jsonData(QDir::current().filePath("tokens.json"));
QVERIFY2(jsonData.open(QIODevice::ReadOnly), "Couldn't open config file tokens.json"); QHash<QString, std::shared_ptr<Token>> tokens;
QJsonDocument doc = QJsonDocument::fromJson(jsonData.readAll()); auto token = getTestToken();
QJsonObject obj = doc.object(); tokens.insert(token->idToStringWithoutBraces(), token);
QJsonArray arr = obj["items"].toArray(); auto testAccess = new RequestManager();
qDebug() << arr;
QList<QPointer<Token>> tokens;
for (auto object : arr)
{
auto token = new Token;
token->fromJSON(object.toObject());
qDebug() << token;
tokens.append(token);
}
RequestManager* 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);
spy.wait(15000); spy.wait(timeout);
QVERIFY(spy.isValid()); QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
QString json = response->getJson(); QString json = response->getJson();
@ -233,14 +221,14 @@ void UnitTest::setTokens()
void UnitTest::deleteTokens() void UnitTest::deleteTokens()
{ {
RequestManager* testAccess = new RequestManager(); auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady())); QSignalSpy spy(testAccess, SIGNAL(responseReady()));
QList<QString> ids; QList<QString> ids;
ids.append("582c982d-6fd7-4856-8548-7ce542791c7a"); ids.append("582c982d-6fd7-4856-8548-7ce542791c7a");
ids.append("3ff23b41-3da3-4b33-82ce-d8e2d8c9a546"); ids.append("3ff23b41-3da3-4b33-82ce-d8e2d8c9a546");
Response* response = testAccess->deleteTokens(&ids); Response* response = testAccess->deleteTokens(ids);
QCOMPARE(spy.count(), 0); QCOMPARE(spy.count(), 0);
spy.wait(15000); spy.wait(timeout);
QVERIFY(spy.isValid()); QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1); QCOMPARE(spy.count(), 1);
QString json = response->getJson(); QString json = response->getJson();
@ -262,10 +250,10 @@ void UnitTest::subjectJSONParser()
QJsonObject obj = doc.object(); QJsonObject obj = doc.object();
QJsonArray arr = obj["items"].toArray(); QJsonArray arr = obj["items"].toArray();
*/ */
RequestManager* testAccess = new RequestManager(); auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady())); QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getSubjects(); Response* response = testAccess->getSubjects();
spy.wait(15000); spy.wait(timeout);
QString json = response->getJson(); QString json = response->getJson();
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8()); QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8());
QJsonArray arr = doc.object()["items"].toArray(); QJsonArray arr = doc.object()["items"].toArray();
@ -277,10 +265,10 @@ void UnitTest::subjectJSONParser()
void UnitTest::tokenJSONParser() void UnitTest::tokenJSONParser()
{ {
RequestManager* testAccess = new RequestManager(); auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady())); QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getTokens(); Response* response = testAccess->getTokens();
spy.wait(15000); spy.wait(timeout);
QString json = response->getJson(); QString json = response->getJson();
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8()); QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8());
QJsonArray arr = doc.object()["items"].toArray(); QJsonArray arr = doc.object()["items"].toArray();
@ -290,15 +278,15 @@ void UnitTest::tokenJSONParser()
QVERIFY(!testToken->getName().isEmpty()); QVERIFY(!testToken->getName().isEmpty());
} }
void UnitTest::connectToDB() //void UnitTest::connectToDB()
{ //{
DatabaseManager *db = new DatabaseManager("192.168.1.94", "deloitte", "postgres", "34rjkciea12"); // DatabaseManager *db = new DatabaseManager("192.168.1.94", "deloitte", "postgres", "34rjkciea12");
QVERIFY(db->getOpened()); // QVERIFY(db->getOpened());
qDebug() << db->getTestMessage(1); // qDebug() << db->getTestMessage(1);
QVERIFY(true); // QVERIFY(true);
QCOMPARE(db->getTestMessage(1), QStringLiteral("Hello world")); // QCOMPARE(db->getTestMessage(1), QStringLiteral("Hello world"));
QCOMPARE(db->getTestMessage(db->createTestRecord("Now it's diffrent")), QStringLiteral("Now it's diffrent")); // QCOMPARE(db->getTestMessage(db->createTestRecord("Now it's diffrent")), QStringLiteral("Now it's diffrent"));
} //}
/* /*
void UnitTest::debugConnection() void UnitTest::debugConnection()
@ -344,7 +332,7 @@ void UnitTest::debugConnection()
void UnitTest::saveDataToDB() void UnitTest::saveDataToDB()
{ {
// dataMan->localSaveTokens(); // dataMan->localSaveTokens();
QVERIFY(true); QVERIFY(true);
} }
@ -355,6 +343,25 @@ void UnitTest::getUuid()
QCOMPARE(1,1); QCOMPARE(1,1);
} }
std::shared_ptr<Token> UnitTest::getTestToken()
{
QJsonObject jsonToken;
jsonToken.insert("id", "062c93f6-ba3e-46af-a3a6-7a2988d1f0e9");
jsonToken.insert("name", "test");
jsonToken.insert("description", "mobile");
jsonToken.insert("tokenType", "Token");
jsonToken.insert("tokenBits", 32);
jsonToken.insert("tokenData", "7B9D32");
jsonToken.insert("timeToLive", 255);
jsonToken.insert("authErrors", 255);
QJsonArray flags;
flags.push_back("Enabled");
flags.push_back("NoValidity");
jsonToken.insert("flags", flags);
jsonToken.insert("subjectId", "72b37f7e-5761-4e6c-8e87-20c0bed0d904");
auto token = std::make_shared<Token>();
token->fromJSON(jsonToken);
return token;
}
QTEST_MAIN(UnitTest)
//QTEST_MAIN(UnitTest)

View File

@ -2,135 +2,147 @@
void ComplexTest::initTestCase() void ComplexTest::initTestCase()
{ {
auto reqMan1 = new RequestManager; // auto reqMan1 = new RequestManager;
QList<QString> ids; // QList<QString> ids;
ids.append("582c982d-6fd7-4856-8548-7ce542791c7a"); // ids.append("582c982d-6fd7-4856-8548-7ce542791c7a");
ids.append("3ff23b41-3da3-4b33-82ce-d8e2d8c9a546"); // ids.append("3ff23b41-3da3-4b33-82ce-d8e2d8c9a546");
Response* deleteTokensResp = reqMan1->deleteTokens(&ids); // Response* deleteTokensResp = reqMan1->deleteTokens(ids);
QSignalSpy deleteTokensRespSpy(deleteTokensResp, &Response::ready); // QSignalSpy deleteTokensRespSpy(deleteTokensResp, &Response::ready);
QCOMPARE(deleteTokensRespSpy.count(), 0); // QCOMPARE(deleteTokensRespSpy.count(), 0);
deleteTokensRespSpy.wait(10000); // deleteTokensRespSpy.wait(timeout);
QTest::qWait(2500); // QTest::qWait(2500);
// Logger *logger = Logger::getLogger();
start = QDateTime::currentMSecsSinceEpoch()-2000; start = QDateTime::currentMSecsSinceEpoch()-2000;
api = new ColnodAPI; api = new SyncManager();
qDebug() << start; qDebug() << start;
} }
void ComplexTest::cleanupTestCase() void ComplexTest::cleanupTestCase()
{ {
QList<QString> ids;
ids.append("582c982d-6fd7-4856-8548-7ce542791c7a"); // QList<QString> ids;
ids.append("3ff23b41-3da3-4b33-82ce-d8e2d8c9a546"); // ids.append("582c982d-6fd7-4856-8548-7ce542791c7a");
auto reqMan = new RequestManager; // ids.append("3ff23b41-3da3-4b33-82ce-d8e2d8c9a546");
Response* deleteTokensResp = reqMan->deleteTokens(&ids); // auto reqMan = new RequestManager;
QSignalSpy deleteTokensRespSpy(deleteTokensResp, &Response::ready); // Response* deleteTokensResp = reqMan->deleteTokens(ids);
QCOMPARE(deleteTokensRespSpy.count(), 0); // QSignalSpy deleteTokensRespSpy(deleteTokensResp, &Response::ready);
deleteTokensRespSpy.wait(10000); // QCOMPARE(deleteTokensRespSpy.count(), 0);
QCOMPARE(deleteTokensRespSpy.count(), 1); // deleteTokensRespSpy.wait(timeout);
// QCOMPARE(deleteTokensRespSpy.count(), 1);
} }
void ComplexTest::complexTest() void ComplexTest::complexTest()
{ {
// LOGIN_BEGIN // // LOGIN_BEGIN
reqMan = new RequestManager; // reqMan = new RequestManager;
QSignalSpy loginSpy(reqMan, &RequestManager::successLogin); // QSignalSpy loginSpy(reqMan, &RequestManager::successLogin);
QVERIFY(reqMan); // auto loginResp = reqMan->login();
Response* loginResp = reqMan->login(); // QSignalSpy loginRespSpy(loginResp.get(), &Response::ready);
QSignalSpy loginRespSpy(loginResp, &Response::ready); // QCOMPARE(loginSpy.count(), 0);
QCOMPARE(loginSpy.count(), 0); // QCOMPARE(loginRespSpy.count(), 0);
QCOMPARE(loginRespSpy.count(), 0); // loginSpy.wait(timeout);
loginSpy.wait(10000); // QCOMPARE(loginResp->getStatusCode(), 200); // HTTP status code check
QCOMPARE(loginResp->getStatusCode(), 200); // HTTP status code check // QCOMPARE(loginSpy.count(), 1); // Checking multiple calls
QCOMPARE(loginSpy.count(), 1); // Checking multiple calls // QCOMPARE(loginRespSpy.count(), 1);
QCOMPARE(loginRespSpy.count(), 1); // auto doc0 = getJsonDoc(loginResp->getJson());
auto doc0 = getJsonDoc(loginResp->getJson()); // QVERIFY(doc0.object()["id"].isString());
QVERIFY(doc0.object()["id"].isString()); // // LOGIN_END
// LOGIN_END
// NUMBER_OF_SUBJECTS_AND_TOKENS_BEGIN // // NUMBER_OF_SUBJECTS_AND_TOKENS_BEGIN
int numOfSubjects = getNumOfSubjects(); // int numOfSubjects = getNumOfSubjects();
QCOMPARE(numOfSubjects, 2893); // should be still the same, if false db has been changed // QCOMPARE(numOfSubjects, 2893); // should be still the same, if false db has been changed
int numOfTokens = getNumOfTokens(); // int numOfTokens = getNumOfTokens();
QCOMPARE(numOfTokens, 2881); // should be still the same, if false db has been changed, or deleteTokens didnt work in previous test // QCOMPARE(numOfTokens, 2881); // should be still the same, if false db has been changed, or deleteTokens didnt work in previous test
// NUMBER_OF_SUBJECTS_AND_TOKENS_END // // NUMBER_OF_SUBJECTS_AND_TOKENS_END
// ADD_TOKENS_CHECK_BEGIN // // ADD_TOKENS_CHECK_BEGIN
QList<QPointer<Token>> tokens; // QHash<QString, std::shared_ptr<Token>> tokens;
tokens.append(getTestToken()); // auto token = getTestToken();
Response* setTokensResp = reqMan->setTokens(&tokens); // tokens.insert(token->idToStringWithoutBraces(), token);
QSignalSpy setTokensRespSpy(setTokensResp, &Response::ready); // Response* setTokensResp = reqMan->setTokens(tokens);
QCOMPARE(setTokensRespSpy.count(), 0); // QSignalSpy setTokensRespSpy(setTokensResp, &Response::ready);
setTokensRespSpy.wait(10000); // QCOMPARE(setTokensRespSpy.count(), 0);
QCOMPARE(setTokensRespSpy.count(), 1); // setTokensRespSpy.wait(timeout);
QCOMPARE(setTokensResp->getStatusCode(), 200); // QCOMPARE(setTokensRespSpy.count(), 1);
QCOMPARE(getNumOfTokens(), numOfTokens + 1); // QCOMPARE(setTokensResp->getStatusCode(), 200);
// ADD_TOKENS_CHEK_END // QCOMPARE(getNumOfTokens(), numOfTokens + 1);
// // ADD_TOKENS_CHEK_END
// CHECK_UPDATED_TOKENS_BEGIN // // CHECK_UPDATED_TOKENS_BEGIN
Response* getTokensUpdatedResp = reqMan->getTokensUpdated(start); // Response* getTokensUpdatedResp = reqMan->getTokensUpdated(start);
//start = QDateTime::currentMSecsSinceEpoch(); // //start = QDateTime::currentMSecsSinceEpoch();
QSignalSpy getTokensUpdatedRespSpy(getTokensUpdatedResp, &Response::ready); // QSignalSpy getTokensUpdatedRespSpy(getTokensUpdatedResp, &Response::ready);
QCOMPARE(getTokensUpdatedRespSpy.count(), 0); // QCOMPARE(getTokensUpdatedRespSpy.count(), 0);
getTokensUpdatedRespSpy.wait(10000); // getTokensUpdatedRespSpy.wait(timeout);
QCOMPARE(getTokensUpdatedResp->getStatusCode(), 200); // QCOMPARE(getTokensUpdatedResp->getStatusCode(), 200);
QCOMPARE(getTokensUpdatedRespSpy.count(), 1); // QCOMPARE(getTokensUpdatedRespSpy.count(), 1);
auto doc1 = getJsonDoc(getTokensUpdatedResp->getJson()); // auto doc1 = getJsonDoc(getTokensUpdatedResp->getJson());
QCOMPARE(doc1.object()["items"].toArray().size(), 1); // QCOMPARE(doc1.object()["items"].toArray().size(), 1);
// CHECK_UPDATED_TOKENS_END // // CHECK_UPDATED_TOKENS_END
// DELETE_TOKENS_CHECK_BEGIN // // DELETE_TOKENS_CHECK_BEGIN
QList<QString> ids; // QList<QString> ids;
ids.append("582c982d-6fd7-4856-8548-7ce542791c7a"); // ids.append("062c93f6-ba3e-46af-a3a6-7a2988d1f0e9");
Response* deleteTokensResp = reqMan->deleteTokens(&ids); // Response* deleteTokensResp = reqMan->deleteTokens(ids);
QSignalSpy deleteTokensRespSpy(deleteTokensResp, &Response::ready); // QSignalSpy deleteTokensRespSpy(deleteTokensResp, &Response::ready);
QCOMPARE(deleteTokensRespSpy.count(), 0); // QCOMPARE(deleteTokensRespSpy.count(), 0);
deleteTokensRespSpy.wait(10000); // deleteTokensRespSpy.wait(timeout);
QCOMPARE(deleteTokensRespSpy.count(), 1); // QCOMPARE(deleteTokensRespSpy.count(), 1);
QCOMPARE(deleteTokensResp->getStatusCode(), 200); // QCOMPARE(deleteTokensResp->getStatusCode(), 200);
// DELETE_TOKENS_CHECK_END // // DELETE_TOKENS_CHECK_END
// CHECK_DELETED_TOKENS_BEGIN // // CHECK_DELETED_TOKENS_BEGIN
Response* getTokensDeletedResp = reqMan->getTokensDeleted(start); // Response* getTokensDeletedResp = reqMan->getTokensDeleted(start);
start = QDateTime::currentMSecsSinceEpoch(); // start = QDateTime::currentMSecsSinceEpoch();
QSignalSpy getTokensDeletedRespSpy(getTokensDeletedResp, &Response::ready); // QSignalSpy getTokensDeletedRespSpy(getTokensDeletedResp, &Response::ready);
QCOMPARE(getTokensDeletedRespSpy.count(), 0); // QCOMPARE(getTokensDeletedRespSpy.count(), 0);
getTokensDeletedRespSpy.wait(10000); // getTokensDeletedRespSpy.wait(timeout);
QCOMPARE(getTokensDeletedResp->getStatusCode(), 200); // QCOMPARE(getTokensDeletedResp->getStatusCode(), 200);
QCOMPARE(getTokensDeletedRespSpy.count(), 1); // QCOMPARE(getTokensDeletedRespSpy.count(), 1);
auto doc2 = getJsonDoc(getTokensDeletedResp->getJson()); // auto doc2 = getJsonDoc(getTokensDeletedResp->getJson());
QCOMPARE(doc2.object()["items"].toArray().size(), 1); // QCOMPARE(doc2.object()["items"].toArray().size(), 1);
QVERIFY(doc2.object()["items"].toArray().contains("582c982d-6fd7-4856-8548-7ce542791c7a")); // QVERIFY(doc2.object()["items"].toArray().contains("062c93f6-ba3e-46af-a3a6-7a2988d1f0e9"));
// CHECK_DELETED_TOKENS_END // // CHECK_DELETED_TOKENS_END
// // LAST_TESTS (for sure)
// QCOMPARE(loginSpy.count(), 1); // Checking multiple calls
// LAST_TESTS (for sure) // QCOMPARE(loginRespSpy.count(), 1);
QCOMPARE(loginSpy.count(), 1); // Checking multiple calls // QCOMPARE(getNumOfSubjects(), numOfSubjects);
QCOMPARE(loginRespSpy.count(), 1); // QCOMPARE(getNumOfTokens(), numOfTokens);
QCOMPARE(getNumOfSubjects(), numOfSubjects);
QCOMPARE(getNumOfTokens(), numOfTokens);
} }
void ComplexTest::fullSync() void ComplexTest::fullSync()
{ {
api->prepareDatabase(); /* api->prepareDatabase();
api->downloadData(); api->loadDataFromColnod();
QSignalSpy spy(api, &ColnodAPI::dataDownloaded); QSignalSpy spy(api, &SyncManager::dataDownloaded);
spy.wait(10000); spy.wait(timeout);
api->syncDataFromColnod(); api->loadDataFromDB();
// api->syncDataToColnod(); api->syncDataFromColnodToDB();
api->syncDataFromDBToColnod();
QSignalSpy processSpy(api, &SyncManager::dataUpdatedToColnod);
processSpy.wait(timeout);
QSignalSpy finish(api, &SyncManager::syncFinished);
finish.wait(timeout); */
} }
void ComplexTest::syncLastUpdated() void ComplexTest::syncLastUpdated()
{ {
api->downloadChangedDataFromColnod(); // Logger::log("ahoj");
QSignalSpy spy(api, &ColnodAPI::dataDownloaded); // api->loadDataFromColnod();
spy.wait(10000); // QSignalSpy spy(api, &SyncManager::dataDownloaded);
api->syncChangedDataFromColnod(); // spy.wait(timeout);
// api->syncChangedDataToColnod(); // api->loadDataFromDB();
// api->syncDataFromColnodToDB();
// api->syncDataFromDBToColnod();
// QSignalSpy processSpy(api, &SyncManager::dataUpdatedToColnod);
// processSpy.wait(timeout);
// QSignalSpy finish(api, &SyncManager::syncFinished);
// finish.wait(timeout);
// qDebug() << "All right, at least should be.";
} }
void ComplexTest::testingStuff() void ComplexTest::testingStuff()
@ -143,31 +155,33 @@ void ComplexTest::testingStuff()
// HELPFUL_FUNCTIONS // HELPFUL_FUNCTIONS
int ComplexTest::getNumOfSubjects() int ComplexTest::getNumOfSubjects()
{ {
auto reqMan = new RequestManager;
Response* subjectsResp = reqMan->getSubjects(); Response* subjectsResp = reqMan->getSubjects();
QSignalSpy subjectsRespSpy(subjectsResp, &Response::ready); QSignalSpy subjectsRespSpy(subjectsResp, &Response::ready);
subjectsRespSpy.wait(10000); subjectsRespSpy.wait(timeout);
auto doc = getJsonDoc(subjectsResp->getJson()); auto doc = getJsonDoc(subjectsResp->getJson());
return doc.object()["items"].toArray().size(); return doc.object()["items"].toArray().size();
} }
int ComplexTest::getNumOfTokens() int ComplexTest::getNumOfTokens()
{ {
auto reqMan = new RequestManager;
Response* tokensResp = reqMan->getTokens(); Response* tokensResp = reqMan->getTokens();
QSignalSpy tokensRespSpy(tokensResp, &Response::ready); QSignalSpy tokensRespSpy(tokensResp, &Response::ready);
tokensRespSpy.wait(10000); tokensRespSpy.wait(timeout);
auto doc = getJsonDoc(tokensResp->getJson()); auto doc = getJsonDoc(tokensResp->getJson());
return doc.object()["items"].toArray().size(); return doc.object()["items"].toArray().size();
} }
QJsonDocument ComplexTest::getJsonDoc(QString json) QJsonDocument ComplexTest::getJsonDoc(const QString &json)
{ {
return QJsonDocument::fromJson(json.toUtf8()); return QJsonDocument::fromJson(json.toUtf8());
} }
Token* ComplexTest::getTestToken() std::shared_ptr<Token> ComplexTest::getTestToken()
{ {
QJsonObject jsonToken; QJsonObject jsonToken;
jsonToken.insert("id", "582c982d-6fd7-4856-8548-7ce542791c7a"); jsonToken.insert("id", "062c93f6-ba3e-46af-a3a6-7a2988d1f0e9");
jsonToken.insert("name", "test"); jsonToken.insert("name", "test");
jsonToken.insert("description", "mobile"); jsonToken.insert("description", "mobile");
jsonToken.insert("tokenType", "Token"); jsonToken.insert("tokenType", "Token");
@ -180,9 +194,9 @@ 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");
Token* token = new Token; auto token = std::shared_ptr<Token>();
token->fromJSON(jsonToken); token->fromJSON(jsonToken);
return token; return token;
} }
QTEST_MAIN(ComplexTest) //QTEST_MAIN(ComplexTest)

View File

@ -5,7 +5,8 @@
#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"
class ComplexTest : public QObject class ComplexTest : public QObject
{ {
@ -23,8 +24,8 @@ private:
// FUNCTIONS // FUNCTIONS
int getNumOfSubjects(); int getNumOfSubjects();
int getNumOfTokens(); int getNumOfTokens();
QJsonDocument getJsonDoc(QString json); QJsonDocument getJsonDoc(const QString &json);
Token* getTestToken(); std::shared_ptr<Token> getTestToken();
// VARIABLES // VARIABLES
@ -32,7 +33,8 @@ private:
QString user = "spaceti"; QString user = "spaceti";
QString password = "spaceti1"; QString password = "spaceti1";
uint64_t start = 0; uint64_t start = 0;
RequestManager* reqMan = nullptr; SyncManager* api = nullptr;
ColnodAPI* api = nullptr;
static constexpr qint16 timeout = 10000;
}; };

View File

@ -37,15 +37,20 @@ private slots:
void deleteTokens(); void deleteTokens();
void subjectJSONParser(); void subjectJSONParser();
void tokenJSONParser(); void tokenJSONParser();
void connectToDB(); //void connectToDB();
//void debugConnection(); //void debugConnection();
void saveDataToDB(); void saveDataToDB();
void getUuid(); void getUuid();
private: private:
//QString host = "http://localhost:8080"; //colnod server (ssh -L 8080:192.168.254.11:8443 penta-master) std::shared_ptr<Token> getTestToken();
QString host = "https://192.168.1.3:8443"; //local testing server
QString password = "spaceti1"; //QString host = "http://localhost:8080"; //colnod server (ssh -L 8080:192.168.254.11:8443 penta-master)
QString email = "spaceti"; QString host = "https://192.168.1.3:8443"; //local testing server
QString password = "spaceti1";
QString email = "spaceti";
static constexpr int timeout = 10000;
static constexpr qint64 epochMS = 1568646217767;
}; };