Merge branch 'sync' into 'master'

Sync DB and Colnod

See merge request spaceti-app/integrations/acs/colnod-connector!8
This commit is contained in:
Ondřej Fischer 2019-11-07 08:16:06 +00:00
commit 14cdb47fd8
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/)
## 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
- 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 "datamanager.h"
#include "colnodapi.h"
#include "syncmanager.h"
#include <QCommandLineParser>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
ColnodAPI *api = new ColnodAPI();
api->downloadData(); // this will start downloading data
QObject::connect(api, &ColnodAPI::dataDownloaded, [=](){
qDebug() << "now I have all data";
api->syncDataToColnod();
QCoreApplication::quit();
QCoreApplication app(argc, argv);
QCoreApplication::setApplicationName("colnod-connector");
QCoreApplication::setApplicationVersion("1.0");
QCommandLineParser parser;
Logger *logger = Logger::getLogger();
parser.setApplicationDescription("Colnod sync");
QCommandLineOption dryModeOption("dryMode", "ColnodAPI", "Read-only mode, prints changes which would normally be made");
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();
});
return a.exec();
api.syncDataFromColnodToDB();
api.syncDataFromDBToColnod();
});
QObject::connect(&api, &SyncManager::error, [](){
qDebug() << "error";
QCoreApplication::exit();
});
return QCoreApplication::exec();
}

View File

@ -2,22 +2,24 @@ INCLUDEPATH += $$PWD
#SRC_DIR = $$PWD
message($$PWD)
SOURCES += \
$$PWD/colnodapi.cpp \
$$PWD/databasemanager.cpp \
$$PWD/datamanager.cpp \
$$PWD/entity.cpp \
$$PWD/logger.cpp \
$$PWD/requestmanager.cpp \
$$PWD/response.cpp \
$$PWD/subject.cpp \
$$PWD/syncmanager.cpp \
$$PWD/token.cpp
HEADERS += \
$$PWD/colnodapi.h \
$$PWD/databasemanager.h \
$$PWD/datamanager.h \
$$PWD/entity.h \
$$PWD/logger.h \
$$PWD/requestmanager.h \
$$PWD/response.h \
$$PWD/subject.h \
$$PWD/syncmanager.h \
$$PWD/token.h
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"
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.setDatabaseName(dbName);
db.setHostName(host);
db.setUserName(user);
// home-office stuff
//db.setPort(80);
//
db.setUserName(user); // home-office stuff -->> db.setPort(80);
db.setPassword(password);
opened = db.open();
if (!opened)
if (!db.open())
{
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();
if (checkIfExists(id, table))
{
query.prepare(QString("UPDATE %1 SET name = :name, last_update = :last_update "
"WHERE id = :id)").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();
}
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();
}
}
void DatabaseManager::saveToken(Token* token, QString table)
{
QString id = token->idToStringWithoutBraces();
if (checkIfExists(id, table))
{
query.prepare(QString("UPDATE %1 SET last_update = :last_update, token_data = :data, subject_id = :subject_id) "
int rtn;
if (checkIfExists(id, table)){
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));
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();
rtn = -1;
}else{
query.prepare(QString("INSERT INTO %1 (id, description, last_update, name, pin, last_modified, deleted) "
"VALUES (:id, :description, :last_update, :name, :pin, :last_modified, :deleted)").arg(table));
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(":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::saveSubjectAttribute(Subject *subject, 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();
int rtn;
if (checkIfExists(id, table)){
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));
rtn = -1;
}else{
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) "
"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));
rtn = 1;
}
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;
}
// add of update subject attributes
void DatabaseManager::saveSubjectAttributes(const std::shared_ptr<Subject>& subject, const QString& table)
{
QSqlQuery query;
auto attributes = subject->getAtr();
for (auto attribute : attributes){
for (const auto& attribute : attributes){
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) "
"WHERE id = :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();
}
else
{
}else{
query.prepare(QString("INSERT INTO %1 (id, attribute_key, attribute_value, subject_id)"
"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();
}
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.exec();
query.bindValue(":now", nowString);
executeQuery(query);
}
QString DatabaseManager::getTestMessage(int id)
{
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)
bool DatabaseManager::checkIfExists(const QString& id, const QString& table)
{
QSqlQuery query;
query.prepare(QString("SELECT EXISTS(SELECT 1 FROM %1 WHERE id = :id)").arg(table));
query.bindValue(":id", id);
query.exec();
executeQuery(query);
query.first();
return query.value(0).toBool();
}
void DatabaseManager::dropTables()
QString DatabaseManager::getLastQuery(const QSqlQuery& query) const
{
query.exec("DROP TABLE IF EXISTS colnod_token, colnod_subject, colnod_subject_attribute");
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()
{
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()
{
query.exec("CREATE TABLE colnod_subject ("
"id CHAR(36) primary key,"
"name VARCHAR(255),"
"last_update timestamp)");
QSqlQuery query;
query.exec("CREATE TABLE colnod_token ("
"id CHAR(36) primary key,"
executeQuery(query, "CREATE TABLE colnod_subject ("
"id character(36) primary key NOT NULL,"
"description character varying(255),"
"last_update timestamp NOT NULL,"
"name character varying(255),"
"pin character varying(255),"
"last_modified timestamp,"
"deleted BOOLEAN)");
executeQuery(query, "CREATE TABLE colnod_token ("
"id CHAR(36) primary key NOT NULL,"
"auth_errors INTEGER NOT NULL,"
"description VARCHAR(255),"
"enabled BOOLEAN NOT NULL,"
"last_update timestamp NOT NULL,"
"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_update timestamp)");
query.exec("CREATE TABLE colnod_subject_attribute ("
"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))");
query.exec("CREATE TABLE users ("
"id VARCHAR(255) primary key,"
"email VARCHAR(255),"
"token_data VARCHAR(255),"
"last_update timestamp)");
}
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();
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) "
"VALUES (:time)");
query.bindValue(":time", QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz"));
QSqlQuery query;
QString lsatUpdateString = QDateTime::fromMSecsSinceEpoch(lastUpdate).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();
}
void DatabaseManager::updateLastSync()
QString DatabaseManager::getSubjectNameByTokenId(const QString &tokenId)
{
query.prepare("INSERT INTO changes (last_sync) "
"VALUES (:time)");
query.bindValue(":time", QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz"));
query.exec();
QSqlQuery query;
query.prepare("SELECT name FROM colnod_subject WHERE id = (SELECT subject_id FROM colnod_token WHERE id = :tokenId)");
query.bindValue(":tokenId", tokenId);
executeQuery(query);
if (query.next())
return query.value(0).toString();
qWarning() << "Token:" << tokenId << "is not assigned to any subject";
return "(No subject)";
}
QSqlQuery* DatabaseManager::getTokensToAdd()
QString DatabaseManager::getSubjectNameById(const QString &id)
{
QSqlQuery* qry = new QSqlQuery;
qry->exec("SELECT name, token_data FROM changes WHERE status = 'toBeAdd'");
return qry;
QSqlQuery query;
query.prepare("SELECT name FROM colnod_subject WHERE id = :id");
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;
qry->exec("SELECT id FROM changes WHERE status = 'toBeDeleted'");
return qry;
}
QUuid DatabaseManager::getId(QString name)
{
query.prepare("SELECT id FROM colnod_subject WHERE name = :name");
query.bindValue(":name", name);
query.exec();
QSqlQuery query;
query.prepare("SELECT deleted FROM colnod_token WHERE id = :id");
query.bindValue(":id", id);
executeQuery(query);
query.next();
return query.value(0).toUuid();
return query.value(0).toBool();
}

View File

@ -1,5 +1,5 @@
#ifndef DATABASEMANAGER_H
#define DATABASEMANAGER_H
#pragma once
#include <QSql>
#include <QSqlDatabase>
#include <QSqlQuery>
@ -10,49 +10,47 @@
#include "subject.h"
#include "token.h"
#include <QDateTime>
//#include "logger.h"
class DatabaseManager : public QObject
{
Q_OBJECT
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);
void saveToken(Token* token, QString table);
void saveSubjectAttribute(Subject* subject, QString table);
void deleteItem(QString id, QString table);
QString getTestMessage(int id);
int createTestRecord(QString msg);
//
void makeTestingLast_sync();
//
int saveSubject(const std::shared_ptr<Subject>& subject, const QString& table);
int saveToken(const std::shared_ptr<Token>& token, const QString& table);
void saveSubjectAttributes(const std::shared_ptr<Subject>& subject, const QString& table);
void setDeleted(const QString& id, const QString& table, quint64 time);
void dropTables();
void createTables();
bool getOpened() {return opened;}
uint64_t getLastUpdate();
void updateLastSync();
quint64 getLastSync();
void updateLastSync(quint64 lastSync);
quint64 getNow();
QSqlQuery* getTokensToAdd();
QSqlQuery* getTokensToDelete();
QSqlQuery getUpdatedTokens();
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:
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:
QSqlDatabase db;
QSqlQuery query;
bool opened;
bool dryMode = false;
};
#endif // DATABASEMANAGER_H

View File

@ -1,224 +1,342 @@
#include "datamanager.h"
DataManager::DataManager()
DataManager::DataManager(const bool &dryMode)
:dryMode(dryMode)
{
db = new DatabaseManager("192.168.1.94", "deloitte", "postgres", "34rjkciea12");
//db = new DatabaseManager("localhost", "deloitte", "postgres", "34rjkciea12");
db = std::make_shared<DatabaseManager>("192.168.1.94", "deloitte", "postgres", "34rjkciea12", dryMode);
//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());
QJsonArray items = doc.object()["items"].toArray();
if (items.size() > 0)
if (!items.empty())
{
for (QJsonValueRef item : items)
{
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();
for (QJsonValueRef item : items){
auto token = std::make_shared<Token>();
token->fromJSON(item.toObject());
tokens.append(token);
allTokensFromColnodById.insert(token->idToStringWithoutBraces(), token);
allTokensFromColnodByName.insert(token->getName(), token);
}
}
else
{
Token* token = new Token;
token->setName("empty");
tokens.append(token);
else{
qCritical() << "Colnod is Empty";
}
}
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();
if (items.size() > 0)
if (!items.empty())
{
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
{
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();
if (items.size() > 0)
if (!items.empty())
{
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
{
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()
{
if (subjects.size() == 1 && subjects[0]->getName() == "empty")
{
qDebug() << "All subjects are up to date";
if (subjectsToUpdateFromColnodToDB.isEmpty()) {
qInfo() << "DB: 0 subjects added";
qInfo() << "DB: 0 subjects updated";
return;
}
//QSqlDatabase::database().transaction();
qDebug() << "Subjects in progress...";
for (auto subject : subjects)
int updated = 0;
int added = 0;
for (const auto& subject : subjectsToUpdateFromColnodToDB)
{
db->saveSubject(subject, "colnod_subject");
db->saveSubjectAttribute(subject, "colnod_subject_attribute");
if (db->saveSubject(subject, "colnod_subject") > 0){
added++;
if (dryMode)
qInfo() << "Adding subject:" << subject->idToStringWithoutBraces() << "to DB";
else
Logger::logToDb(Logger::makeSubjectMsg( subject->idToStringWithoutBraces(),"added", "DB"));
}
//QSqlDatabase::database().commit();
qDebug() << subjects.size() << " subjects has been updated";
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");
}
qInfo() << "DB:" << added << "subjects added";
qInfo() << "DB:" << updated << "subjects updated";
}
// update tokens from colnod to DB
void DataManager::pushTokensToDB()
{
if (tokens.size() == 1 && tokens[0]->getName() == "empty")
{
qDebug() << "All tokens are up to date";
if (tokensToUpdateFromColnodToDB.isEmpty()){
qInfo() << "DB: 0 tokens added";
qInfo() << "DB: 0 tokens updated";
return;
}
//QSqlDatabase::database().transaction();
qDebug() << "Tokens in progress...";
for (auto token : tokens)
filterTokensColnod();
int updated = 0;
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";
}
//QSqlDatabase::database().commit();
qDebug() << tokens.size() << " tokens has been updated";
else {
updated++;
text = "Updating";
}
if (dryMode)
qInfo() << text << "token:" << token->idToStringWithoutBraces() << "to DB";
else
Logger::logToDb(Logger::makeTokenMsg(token->idToStringWithoutBraces(), text, "DB"));
}
qInfo() << "DB:" << added << "tokens added/edited";
qInfo() << "DB:" << updated << "tokens updated";
}
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;
}
qDebug() << "Deleted subjects in progress...";
//QSqlDatabase::database().transaction();
for (auto subjectId : subjectsToDelete)
for (const auto& subjectId : subjectsFromColnodToDeleteFromDB)
{
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();
qDebug() << subjectsToDelete.size() << "subject has beed deleted";
qInfo() << "DB:" << subjectsFromColnodToDeleteFromDB.size() << " subject 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;
}
// QSqlDatabase::database().transaction();
qDebug() << "Deleted tokens in progress...";
for (auto tokenId : tokensToDelete)
int alreadyDeleted = 0;
for (const auto& tokenId : tokensFromColnodToDeleteFromDB)
{
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"));
}
//QSqlDatabase::database().commit();
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();
else
alreadyDeleted++;
}
qDebug() << "DB:" << tokensFromColnodToDeleteFromDB.size() - alreadyDeleted << "tokens deleted";
}
// recreate working tables
void DataManager::emptyDatabase()
{
db->dropTables();
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()
{
subjects.clear();
subjectsToDelete.clear();
tokens.clear();
tokensToDelete.clear();
subjectsToUpdateFromColnodToDB.clear();
subjectsFromColnodToDeleteFromDB.clear();
tokensToUpdateFromColnodToDB.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()
{
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();
while (query->next())
QList<QString> idsToDelete;
for (const auto& token : tokensToUpdateFromDBToColnod)
{
Token* token = new Token(query->value(0).toString(), query->value(1).toString());
token->setSubjectId(db->getId(token->getName()));
tokens.append(token);
QString id = token->idToStringWithoutBraces();
Q_ASSERT(token != allTokensFromColnodById.value(id)); // if working sets are loading correctly equels should never happend
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 (tokens.isEmpty())
tokens.append(new Token("empty"));
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));
}
}
}
for (const auto &id : idsToDelete)
tokensToUpdateFromDBToColnod.remove(id);
}
void DataManager::loadTokensToDelete()
void DataManager::filterTokensColnod()
{
QSqlQuery* query = db->getTokensToDelete();
while (query->next())
QList<QString> idsToDelete;
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())
tokensToDelete.append("empty");
}
for (const auto &id : idsToDelete)
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
#define DATAMANAGER_H
#pragma once
#include "token.h"
#include "subject.h"
@ -7,6 +6,7 @@
#include "databasemanager.h"
#include <QJsonDocument>
#include <qjsonarray.h>
#include <logger.h>
class DataManager : public QObject
@ -15,41 +15,67 @@ class DataManager : public QObject
Q_OBJECT
public:
DataManager();
DataManager(const bool& dryMode = false);
void localSaveSubjects(QString jsonResponse);
void localSaveTokens(QString jsonResponse);
void localSaveSubjectsToDelete(QString jsonResponse);
void localSaveTokensToDelete(QString jsonResponse);
void fillFullTokensColnod(const QString& jsonResponse);
void fillTokensToUpdateColnod(const 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 pushTokensToDB();
void deleteSubjectsFromDB();
void deleteTokensFromDB();
void setDeletedToTokensFromDB();
void updateLastSync();
uint64_t getLastUpdate();
bool haveData();
bool haveChangedData();
bool haveProcessData();
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 setLastUpdate();
void setLastUpdate(const QString &id);
void loadTokensToAdd();
void loadTokensToDelete();
QList<QPointer<Token>>* getTokens() {return &tokens;}
QList<QString>* getTokensToDelete() {return &tokensToDelete;}
signals:
void error();
private:
DatabaseManager *db = nullptr;
QList<QPointer<Subject>> subjects;
QList<QPointer<Token>> tokens;
QList<QString> subjectsToDelete;
QList<QString> tokensToDelete;
};
std::shared_ptr<DatabaseManager> db;
#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;
}
uint64_t Entity::getLastUpdate() const {
quint64 Entity::getLastUpdate() const {
return lastUpdate;
}
void Entity::setLastUpdate(uint64_t lastUpdate) {
void Entity::setLastUpdate(quint64 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) {
id = json.value("id").toString();
name = json.value("name").toString();
description = json.value("description").toString();
lastUpdate = json.value("lastUpdate").toDouble();
id = json["id"].toString();
name = json["name"].toString();
description = json["description"].toString();
lastUpdate = json["lastUpdate"].toDouble();
}
QJsonObject Entity::toJSON() const {
QJsonObject json;
json.value("id") = id.toString();
json.value("name") = name;
json.value("description") = description;
json.value("lastUpdate") = lastUpdate;
json["id"] = this->idToStringWithoutBraces();
json["name"] = name;
json["description"] = description;
json["lastUpdate"] = lastUpdate;
return json;
}

View File

@ -1,9 +1,10 @@
#ifndef COLNOD_CONNECTOR_ENTITY_H
#define COLNOD_CONNECTOR_ENTITY_H
#pragma once
#include <QtCore/QObject>
#include <QtCore/QUuid>
#include <QtCore/QJsonObject>
#include <QDebug>
#include <memory>
class Entity : public QObject {
@ -20,20 +21,27 @@ public:
const QString &getDescription() const;
void setDescription(const QString &description);
uint64_t getLastUpdate() const;
void setLastUpdate(uint64_t lastUpdate);
quint64 getLastUpdate() const;
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 QJsonObject toJSON() const;
protected:
private:
QUuid id;
QString name;
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,24 +2,14 @@
RequestManager::RequestManager()
{
manager = new QNetworkAccessManager();
token = "";
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);
manager = std::make_unique<QNetworkAccessManager>();
connect(manager.get(), &QNetworkAccessManager::sslErrors, this, &RequestManager::onSSLError);
}
Response* RequestManager::login()
std::shared_ptr<Response> RequestManager::login()
{
Q_ASSERT(!loginResponse);
loginResponse = new Response;
loginResponse = std::make_shared<Response>();
QNetworkRequest request;
QString hash = encryptedPassword(this->password);
authHeader = getLoginHeader(this->user, hash);
@ -30,30 +20,29 @@ Response* RequestManager::login()
request.setUrl(this->host + "/AaaManager/authSession");
request.setRawHeader("Authorization", authHeader.toLocal8Bit());
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json; charset=UTF-8");
QJsonDocument jsonDocument;
jsonDocument.setObject(reqBody);
QNetworkReply* reply = manager->post(request, jsonDocument.toJson());
loginResponse->setReply(reply);
QObject::connect(reply, &QNetworkReply::finished, [=]() {
connect(reply, &QNetworkReply::finished, [=]() {
if (reply->error())
{
qDebug() << "Login failed: "<< reply->errorString();
Logger::logToDb(Logger::makeErrorMsg("Request Manager", reply->errorString()));
loginStatus = false;
reply->deleteLater();
emit error();
return;
}
qDebug() << "Logged in successfully.";
loginStatus = true;
emit successLogin();
reply->deleteLater();
});
connect(this, &RequestManager::successLogin, loginResponse, &Response::ready);
connect(this, &RequestManager::successLogin, loginResponse.get(), &Response::ready);
connect(this, &RequestManager::successLogin, this, &RequestManager::prepareAuthHeader);
return loginResponse;
}
QNetworkReply* RequestManager::postRequest(QString endpoint, QByteArray json)
QNetworkReply* RequestManager::postRequest(const QString& endpoint, const QByteArray& json)
{
QNetworkRequest request;
request.setUrl(host + endpoint);
@ -63,38 +52,33 @@ QNetworkReply* RequestManager::postRequest(QString endpoint, QByteArray json)
QObject::connect(reply, &QNetworkReply::finished, [=]() {
if (reply->error())
{
qDebug() << "Authorization failed: " << reply->errorString();
Logger::logToDb(Logger::makeErrorMsg("Request Manager", reply->errorString()));
loginStatus = false;
reply->deleteLater();
emit error();
return;
}
qDebug() << "Authorized successfully, response ready.";
emit responseReady();
reply->deleteLater();
});
return reply;
}
Response* RequestManager::getLoginResponse() {
// This will ensure login is called only once
std::shared_ptr<Response> RequestManager::getLoginResponse() {
if (!loginResponse){
loginResponse = login();
}
return loginResponse;
}
Response* RequestManager::postRequestReturnLogic(QString endpoint, QByteArray data)
Response* RequestManager::postRequestReturnLogic(const QString& endpoint, const QByteArray& data)
{
auto loginResponse = getLoginResponse();
// This will ensure login is called only once
Q_ASSERT(loginResponse);
Response* response = new Response;
auto response = new Response;
if (!loginStatus){
connect(this, &RequestManager::successLogin, [=](){
response->setReply(postRequest(endpoint, data));
connect(response->getReply(), &QNetworkReply::finished, response, &Response::ready);
@ -108,9 +92,10 @@ Response* RequestManager::postRequestReturnLogic(QString endpoint, QByteArray da
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);
if (err.error != 0)
{
@ -119,12 +104,12 @@ QString RequestManager::getFromJson(QString json, const QString &member)
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();
}
QString RequestManager::getLoginHeader(QString username, QString hash)
QString RequestManager::getLoginHeader(const QString& username, const QString& hash)
{
QString authValue = username + ":" + hash;
return "Basic " + authValue.toLocal8Bit().toBase64();
@ -133,7 +118,7 @@ QString RequestManager::getLoginHeader(QString username, QString hash)
void RequestManager::prepareAuthHeader()
{
jsonResponse = loginResponse->getJson();
token = getFromJson(jsonResponse, "id");
QString token = getFromJson(jsonResponse, "id");
QString authValue = token + ":";
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)) }};
QJsonDocument doc;
@ -158,28 +143,13 @@ QByteArray RequestManager::makeTimeStampJson(uint64_t time)
return doc.toJson();
}
QByteArray RequestManager::makeTokensJson(QList<QPointer<Token>>* tokens)
QByteArray RequestManager::makeTokensJson(const QHash<QString, std::shared_ptr<Token>> &tokens)
{
QJsonObject items;
QJsonArray jsonTokens;
for (auto token : *tokens)
for (const auto& token : tokens)
{
QJsonObject jsonToken;
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);
jsonTokens.push_back(token->toJSON());
}
items.insert("items", jsonTokens);
QJsonDocument doc;
@ -187,10 +157,10 @@ QByteArray RequestManager::makeTokensJson(QList<QPointer<Token>>* tokens)
return doc.toJson();
}
QByteArray RequestManager::makeIdsJson(QList<QString>* ids)
QByteArray RequestManager::makeIdsJson(const QList<QString> &ids)
{
QJsonArray jsonIds;
for (auto id : *ids)
for (const auto& id : ids)
{
jsonIds.push_back(id);
}
@ -218,22 +188,22 @@ Response* RequestManager::getTokenSubject()
Response* RequestManager::getSubjectsUpdated(uint64_t time)
{
return postRequestReturnLogic("/SubjectManager/getSubjectsUpdated", makeTimeStampJson(time));
return postRequestReturnLogic("/SubjectManager/getSubjectsUpdated", makeTimestampJson(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)
{
return postRequestReturnLogic("/TokenManager/getTokensUpdated", makeTimeStampJson(time));
return postRequestReturnLogic("/TokenManager/getTokensUpdated", makeTimestampJson(time));
}
Response* RequestManager::getTokensDeleted(uint64_t time)
{
return postRequestReturnLogic("/TokenManager/getTokensDeleted", makeTimeStampJson(time));
return postRequestReturnLogic("/TokenManager/getTokensDeleted", makeTimestampJson(time));
}
Response* RequestManager::getAccessGroups()
@ -243,12 +213,12 @@ Response* RequestManager::getAccessGroups()
Response* RequestManager::getAccessGroupsUpdated(uint64_t time)
{
return postRequestReturnLogic("/AccessManager/getAccessGroupsUpdated", makeTimeStampJson(time));
return postRequestReturnLogic("/AccessManager/getAccessGroupsUpdated", makeTimestampJson(time));
}
Response* RequestManager::getAccessGroupsDeleted(uint64_t time)
{
return postRequestReturnLogic("/AccessManager/getAccessGroupsDeleted", makeTimeStampJson(time));
return postRequestReturnLogic("/AccessManager/getAccessGroupsDeleted", makeTimestampJson(time));
}
Response* RequestManager::getAccessGroupMembership()
@ -258,20 +228,20 @@ Response* RequestManager::getAccessGroupMembership()
Response* RequestManager::getAccessGroupMembershipUpdated(uint64_t time)
{
return postRequestReturnLogic("/AccessManager/getAccessGroupMembershipUpdated", makeTimeStampJson(time));
return postRequestReturnLogic("/AccessManager/getAccessGroupMembershipUpdated", makeTimestampJson(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));
}
Response* RequestManager::deleteTokens(QList<QString>* ids)
Response* RequestManager::deleteTokens(const QList<QString> &ids)
{
return postRequestReturnLogic("/TokenManager/deleteTokens", makeIdsJson(ids));
}

View File

@ -1,5 +1,4 @@
#ifndef REQUESTMANAGER_H
#define REQUESTMANAGER_H
#pragma once
#include <QObject>
#include <QNetworkReply>
@ -25,13 +24,19 @@
#include "token.h"
#include "response.h"
#include "logger.h"
class RequestManager : public QObject
{
Q_OBJECT
public:
friend class UnitTest;
friend class ComplexTest;
RequestManager();
// this should be in ColnodAPI class BEGIN
Response* getSubjects();
Response* getTokens();
Response* getTokenSubject();
@ -49,49 +54,47 @@ public:
Response* getAccessGroupMembershipUpdated(uint64_t time);
Response* getAccessGroupMembershipDeleted(uint64_t time);
Response* setTokens(QList<QPointer<Token>>* tokens);
Response* deleteTokens(QList<QString>* ids);
Response* login(); //I want it private, but unittest???
const QJsonDocument &getConfig() const {return config;}
const QString &getResponse() const {return jsonResponse;}
Response* setTokens(const QHash<QString, std::shared_ptr<Token>> &tokens);
Response* deleteTokens(const QList<QString> &ids);
// END
private:
QNetworkReply* postRequest(QString endpoint, QByteArray json = QByteArray());
Response* postRequestReturnLogic(QString endpoint, QByteArray data = QByteArray());
QString getFromJson(QString json, const QString &member);
QString encryptedPassword(QString password);
QString getLoginHeader(QString username, QString hash);
// should be public
QNetworkReply* postRequest(const QString& endpoint, const QByteArray& json = QByteArray());
Response* postRequestReturnLogic(const QString& endpoint, const QByteArray& data = QByteArray());
QByteArray makeTimeStampJson(uint64_t time);
QByteArray makeTokensJson(QList<QPointer<Token>>* tokens);
QByteArray makeIdsJson(QList<QString>* ids);
Response* getLoginResponse();
std::shared_ptr<Response> login();
std::shared_ptr<Response> getLoginResponse();
QString getFromJson(const QString& json, const QString &member);
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:
void onSSLError(QNetworkReply *reply, const QList<QSslError> &errors);
//void onReplyFinished(QNetworkReply *reply);
void prepareAuthHeader();
signals:
void successLogin();
void responseReady();
void error();
private:
QNetworkAccessManager* manager = nullptr;
Response* loginResponse = nullptr;
std::unique_ptr<QNetworkAccessManager> manager;
std::shared_ptr<Response> loginResponse;
QJsonDocument config;
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 password = "spaceti1";
QString user = "spaceti";
QString token;
const QString password = "spaceti1";
const QString user = "spaceti";
QString jsonResponse;
bool loginStatus;
bool loginStatus = false;
};
#endif // REQUESTMANAGER_H

View File

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

View File

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

View File

@ -1,5 +1,4 @@
#ifndef COLNOD_CONNECTOR_SUBJECT_H
#define COLNOD_CONNECTOR_SUBJECT_H
#pragma once
#include <QSet>
@ -12,6 +11,8 @@ class Subject : public Entity {
public:
using Entity::Entity;
Subject() = default;
Subject(const QString& name);
QString getEmail() const;
@ -23,24 +24,18 @@ public:
void setPin(const QString &pin);
const QSet<QString> &getPinFlags() const;
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;
void setAtr(const QList<QPair<QString, QString>> &atr);
void fromJSON(const QJsonObject &json) override;
QJsonObject toJSON() const override;
protected:
private:
QJsonObject attributes;
QSet<QString> tokenFlags;
QString pin;
QSet<QString> pinFlags;
//QList<QPointer<Attribute>> 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 <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->tokenData = tokenData;
this->description = decription;
this->id = QUuid::createUuid();
this->setName(name);
this->tokenData = std::move(tokenData);
this->setDescription(decription);
this->setId(QUuid::createUuid());
this->tokenType = "Token";
this->tokenBits = 32;
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) {
Entity::fromJSON(json);
tokenType = json.value("tokenType").toString();
tokenBits = json.value("tokenBits").toInt();
tokenData = json.value("tokenData").toString();
validFrom = json.value("validFrom").toDouble();
validTo = json.value("validTo").toDouble();
timeToLive = json.value("timeToLive").toInt();
tokenType = json["tokenType"].toString();
tokenBits = json["tokenBits"].toInt();
tokenData = json["tokenData"].toString();
timeToLive = json["timeToLive"].toInt();
authErrors = json["authErrors"].toInt();
const auto &flagsArray = json["flags"].toArray();
for(const auto &flag : flagsArray){
flags.insert(flag.toString());
}
subjectId = json.value("subjectId").toString();
subjectId = json["subjectId"].toString();
}
QJsonObject Token::toJSON() const {
QJsonObject json = Entity::toJSON();
json.value("tokenType") = tokenType;
json.value("tokenBits") = tokenBits;
json.value("tokenData") = tokenData;
json.value("validFrom") = validFrom;
json.value("validTo") = validTo;
json.value("timeToLive") = timeToLive;
json.value("authErrors") = authErrors;
json.value("flags") = QJsonArray::fromStringList(flags.toList());
json.value("subjectId") = subjectId.toString();
json.insert("tokenType", tokenType);
json["tokenBits"] = tokenBits;
json["tokenType"] = tokenType;
json["tokenBits"] = tokenBits;
json["tokenData"] = tokenData;
json["timeToLive"] = timeToLive;
json["authErrors"] = authErrors;
json["flags"] = QJsonArray::fromStringList(flags.toList());
json["subjectId"] = subjectId.toString().mid(1,36);
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 {
return tokenType;
}
@ -78,22 +104,6 @@ void Token::setTokenData(const QString &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 {
return timeToLive;
}

View File

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

View File

@ -7,15 +7,14 @@ void UnitTest::initTestCase()
void UnitTest::loginSuccessfully()
{
RequestManager* testAccess = new RequestManager();
QJsonDocument config = testAccess->getConfig();
auto testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(successLogin()));
QVERIFY(spy.isValid());
testAccess->login();
spy.wait(15000);
spy.wait(timeout);
QCOMPARE(spy.count(), 1);
QString json = testAccess->getResponse();
QString json = testAccess->jsonResponse;
qDebug() << json;
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8());
QVERIFY2(doc.object().value("id").isString(), "No parameter 'id' in response");
@ -24,13 +23,13 @@ void UnitTest::loginSuccessfully()
//POST request w/o datas
void UnitTest::getSubjects()
{
RequestManager* testAccess = new RequestManager();
auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady()));
QVERIFY(spy.isValid());
Response* response = testAccess->getSubjects();
QSignalSpy spy1(response, &Response::ready);
spy.wait(15000);
spy.wait(timeout);
QCOMPARE(spy.count(), 1);
QCOMPARE(spy1.count(), 1);
@ -45,11 +44,11 @@ void UnitTest::getSubjects()
void UnitTest::getTokens()
{
RequestManager* testAccess = new RequestManager();
auto* testAccess = new RequestManager();
Response* response = testAccess->getTokens();
QSignalSpy spy(response, &Response::ready);
QCOMPARE(spy.count(), 0);
spy.wait(15000);
spy.wait(timeout);
QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1);
QString json = response->getJson();
@ -62,11 +61,11 @@ void UnitTest::getTokens()
void UnitTest::getTokenSubject()
{
RequestManager* testAccess = new RequestManager();
auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getTokenSubject();
QCOMPARE(spy.count(), 0);
spy.wait(15000);
spy.wait(timeout);
QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1);
QString json = response->getJson();
@ -75,11 +74,11 @@ void UnitTest::getTokenSubject()
void UnitTest::getSubjectsUpdated()
{
RequestManager* testAccess = new RequestManager();
auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getSubjectsUpdated(1568646217767);
Response* response = testAccess->getSubjectsUpdated(epochMS);
QCOMPARE(spy.count(), 0);
spy.wait(15000);
spy.wait(timeout);
QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1);
QString json = response->getJson();
@ -88,11 +87,11 @@ void UnitTest::getSubjectsUpdated()
void UnitTest::getSubjectsDeleted()
{
RequestManager* testAccess = new RequestManager();
auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getSubjectsDeleted(1568646217767);
Response* response = testAccess->getSubjectsDeleted(epochMS);
QCOMPARE(spy.count(), 0);
spy.wait(15000);
spy.wait(timeout);
QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1);
QString json = response->getJson();
@ -101,11 +100,11 @@ void UnitTest::getSubjectsDeleted()
void UnitTest::getTokensUpdated()
{
RequestManager* testAccess = new RequestManager();
auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getTokensUpdated(1570109859681);
Response* response = testAccess->getTokensUpdated(epochMS);
QCOMPARE(spy.count(), 0);
spy.wait(15000);
spy.wait(timeout);
QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1);
QString json = response->getJson();
@ -114,11 +113,11 @@ void UnitTest::getTokensUpdated()
void UnitTest::getTokensDeleted()
{
RequestManager* testAccess = new RequestManager();
auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getTokensDeleted(1570109859681);
Response* response = testAccess->getTokensDeleted(epochMS);
QCOMPARE(spy.count(), 0);
spy.wait(15000);
spy.wait(timeout);
QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1);
QString json = response->getJson();
@ -127,11 +126,11 @@ void UnitTest::getTokensDeleted()
void UnitTest::getAccessGroups()
{
RequestManager* testAccess = new RequestManager();
auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getAccessGroups();
QCOMPARE(spy.count(), 0);
spy.wait(15000);
spy.wait(timeout);
QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1);
QString json = response->getJson();
@ -140,11 +139,11 @@ void UnitTest::getAccessGroups()
void UnitTest::getAccessGroupsUpdated()
{
RequestManager* testAccess = new RequestManager();
auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getAccessGroupsUpdated(1568646217767);
Response* response = testAccess->getAccessGroupsUpdated(epochMS);
QCOMPARE(spy.count(), 0);
spy.wait(15000);
spy.wait(timeout);
QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1);
QString json = response->getJson();
@ -153,11 +152,11 @@ void UnitTest::getAccessGroupsUpdated()
void UnitTest::getAccessGroupsDeleted()
{
RequestManager* testAccess = new RequestManager();
auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getAccessGroupsDeleted(1568646217767);
Response* response = testAccess->getAccessGroupsDeleted(epochMS);
QCOMPARE(spy.count(), 0);
spy.wait(15000);
spy.wait(timeout);
QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1);
QString json = response->getJson();
@ -166,11 +165,11 @@ void UnitTest::getAccessGroupsDeleted()
void UnitTest::getAccessGroupMembership()
{
RequestManager* testAccess = new RequestManager();
auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getAccessGroupMembership();
QCOMPARE(spy.count(), 0);
spy.wait(15000);
spy.wait(timeout);
QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1);
QString json = response->getJson();
@ -179,11 +178,11 @@ void UnitTest::getAccessGroupMembership()
void UnitTest::getAccessGroupMembershipUpdated()
{
RequestManager* testAccess = new RequestManager();
auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getAccessGroupMembershipUpdated(1568646217767);
Response* response = testAccess->getAccessGroupMembershipUpdated(epochMS);
QCOMPARE(spy.count(), 0);
spy.wait(15000);
spy.wait(timeout);
QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1);
QString json = response->getJson();
@ -192,11 +191,11 @@ void UnitTest::getAccessGroupMembershipUpdated()
void UnitTest::getAccessGroupMembershipDeleted()
{
RequestManager* testAccess = new RequestManager();
auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getAccessGroupMembershipDeleted(1568646217767);
Response* response = testAccess->getAccessGroupMembershipDeleted(epochMS);
QCOMPARE(spy.count(), 0);
spy.wait(15000);
spy.wait(timeout);
QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1);
QString json = response->getJson();
@ -205,26 +204,15 @@ void UnitTest::getAccessGroupMembershipDeleted()
void UnitTest::setTokens()
{
QFile jsonData(QDir::current().filePath("tokens.json"));
QVERIFY2(jsonData.open(QIODevice::ReadOnly), "Couldn't open config file tokens.json");
QJsonDocument doc = QJsonDocument::fromJson(jsonData.readAll());
QJsonObject obj = doc.object();
QJsonArray arr = obj["items"].toArray();
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();
QHash<QString, std::shared_ptr<Token>> tokens;
auto token = getTestToken();
tokens.insert(token->idToStringWithoutBraces(), token);
auto testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->setTokens(&tokens);
Response* response = testAccess->setTokens(tokens);
QCOMPARE(spy.count(), 0);
spy.wait(15000);
spy.wait(timeout);
QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1);
QString json = response->getJson();
@ -233,14 +221,14 @@ void UnitTest::setTokens()
void UnitTest::deleteTokens()
{
RequestManager* testAccess = new RequestManager();
auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady()));
QList<QString> ids;
ids.append("582c982d-6fd7-4856-8548-7ce542791c7a");
ids.append("3ff23b41-3da3-4b33-82ce-d8e2d8c9a546");
Response* response = testAccess->deleteTokens(&ids);
Response* response = testAccess->deleteTokens(ids);
QCOMPARE(spy.count(), 0);
spy.wait(15000);
spy.wait(timeout);
QVERIFY(spy.isValid());
QCOMPARE(spy.count(), 1);
QString json = response->getJson();
@ -262,10 +250,10 @@ void UnitTest::subjectJSONParser()
QJsonObject obj = doc.object();
QJsonArray arr = obj["items"].toArray();
*/
RequestManager* testAccess = new RequestManager();
auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getSubjects();
spy.wait(15000);
spy.wait(timeout);
QString json = response->getJson();
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8());
QJsonArray arr = doc.object()["items"].toArray();
@ -277,10 +265,10 @@ void UnitTest::subjectJSONParser()
void UnitTest::tokenJSONParser()
{
RequestManager* testAccess = new RequestManager();
auto* testAccess = new RequestManager();
QSignalSpy spy(testAccess, SIGNAL(responseReady()));
Response* response = testAccess->getTokens();
spy.wait(15000);
spy.wait(timeout);
QString json = response->getJson();
QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8());
QJsonArray arr = doc.object()["items"].toArray();
@ -290,15 +278,15 @@ void UnitTest::tokenJSONParser()
QVERIFY(!testToken->getName().isEmpty());
}
void UnitTest::connectToDB()
{
DatabaseManager *db = new DatabaseManager("192.168.1.94", "deloitte", "postgres", "34rjkciea12");
QVERIFY(db->getOpened());
qDebug() << db->getTestMessage(1);
QVERIFY(true);
QCOMPARE(db->getTestMessage(1), QStringLiteral("Hello world"));
QCOMPARE(db->getTestMessage(db->createTestRecord("Now it's diffrent")), QStringLiteral("Now it's diffrent"));
}
//void UnitTest::connectToDB()
//{
// DatabaseManager *db = new DatabaseManager("192.168.1.94", "deloitte", "postgres", "34rjkciea12");
// QVERIFY(db->getOpened());
// qDebug() << db->getTestMessage(1);
// QVERIFY(true);
// QCOMPARE(db->getTestMessage(1), QStringLiteral("Hello world"));
// QCOMPARE(db->getTestMessage(db->createTestRecord("Now it's diffrent")), QStringLiteral("Now it's diffrent"));
//}
/*
void UnitTest::debugConnection()
@ -355,6 +343,25 @@ void UnitTest::getUuid()
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()
{
auto reqMan1 = new RequestManager;
QList<QString> ids;
ids.append("582c982d-6fd7-4856-8548-7ce542791c7a");
ids.append("3ff23b41-3da3-4b33-82ce-d8e2d8c9a546");
Response* deleteTokensResp = reqMan1->deleteTokens(&ids);
QSignalSpy deleteTokensRespSpy(deleteTokensResp, &Response::ready);
QCOMPARE(deleteTokensRespSpy.count(), 0);
deleteTokensRespSpy.wait(10000);
QTest::qWait(2500);
// auto reqMan1 = new RequestManager;
// QList<QString> ids;
// ids.append("582c982d-6fd7-4856-8548-7ce542791c7a");
// ids.append("3ff23b41-3da3-4b33-82ce-d8e2d8c9a546");
// Response* deleteTokensResp = reqMan1->deleteTokens(ids);
// QSignalSpy deleteTokensRespSpy(deleteTokensResp, &Response::ready);
// QCOMPARE(deleteTokensRespSpy.count(), 0);
// deleteTokensRespSpy.wait(timeout);
// QTest::qWait(2500);
// Logger *logger = Logger::getLogger();
start = QDateTime::currentMSecsSinceEpoch()-2000;
api = new ColnodAPI;
api = new SyncManager();
qDebug() << start;
}
void ComplexTest::cleanupTestCase()
{
QList<QString> ids;
ids.append("582c982d-6fd7-4856-8548-7ce542791c7a");
ids.append("3ff23b41-3da3-4b33-82ce-d8e2d8c9a546");
auto reqMan = new RequestManager;
Response* deleteTokensResp = reqMan->deleteTokens(&ids);
QSignalSpy deleteTokensRespSpy(deleteTokensResp, &Response::ready);
QCOMPARE(deleteTokensRespSpy.count(), 0);
deleteTokensRespSpy.wait(10000);
QCOMPARE(deleteTokensRespSpy.count(), 1);
// QList<QString> ids;
// ids.append("582c982d-6fd7-4856-8548-7ce542791c7a");
// ids.append("3ff23b41-3da3-4b33-82ce-d8e2d8c9a546");
// auto reqMan = new RequestManager;
// Response* deleteTokensResp = reqMan->deleteTokens(ids);
// QSignalSpy deleteTokensRespSpy(deleteTokensResp, &Response::ready);
// QCOMPARE(deleteTokensRespSpy.count(), 0);
// deleteTokensRespSpy.wait(timeout);
// QCOMPARE(deleteTokensRespSpy.count(), 1);
}
void ComplexTest::complexTest()
{
// LOGIN_BEGIN
reqMan = new RequestManager;
QSignalSpy loginSpy(reqMan, &RequestManager::successLogin);
QVERIFY(reqMan);
Response* loginResp = reqMan->login();
QSignalSpy loginRespSpy(loginResp, &Response::ready);
QCOMPARE(loginSpy.count(), 0);
QCOMPARE(loginRespSpy.count(), 0);
loginSpy.wait(10000);
QCOMPARE(loginResp->getStatusCode(), 200); // HTTP status code check
QCOMPARE(loginSpy.count(), 1); // Checking multiple calls
QCOMPARE(loginRespSpy.count(), 1);
auto doc0 = getJsonDoc(loginResp->getJson());
QVERIFY(doc0.object()["id"].isString());
// LOGIN_END
// // LOGIN_BEGIN
// reqMan = new RequestManager;
// QSignalSpy loginSpy(reqMan, &RequestManager::successLogin);
// auto loginResp = reqMan->login();
// QSignalSpy loginRespSpy(loginResp.get(), &Response::ready);
// QCOMPARE(loginSpy.count(), 0);
// QCOMPARE(loginRespSpy.count(), 0);
// loginSpy.wait(timeout);
// QCOMPARE(loginResp->getStatusCode(), 200); // HTTP status code check
// QCOMPARE(loginSpy.count(), 1); // Checking multiple calls
// QCOMPARE(loginRespSpy.count(), 1);
// auto doc0 = getJsonDoc(loginResp->getJson());
// QVERIFY(doc0.object()["id"].isString());
// // LOGIN_END
// NUMBER_OF_SUBJECTS_AND_TOKENS_BEGIN
int numOfSubjects = getNumOfSubjects();
QCOMPARE(numOfSubjects, 2893); // should be still the same, if false db has been changed
int numOfTokens = getNumOfTokens();
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_BEGIN
// int numOfSubjects = getNumOfSubjects();
// QCOMPARE(numOfSubjects, 2893); // should be still the same, if false db has been changed
// int numOfTokens = getNumOfTokens();
// 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
// ADD_TOKENS_CHECK_BEGIN
QList<QPointer<Token>> tokens;
tokens.append(getTestToken());
Response* setTokensResp = reqMan->setTokens(&tokens);
QSignalSpy setTokensRespSpy(setTokensResp, &Response::ready);
QCOMPARE(setTokensRespSpy.count(), 0);
setTokensRespSpy.wait(10000);
QCOMPARE(setTokensRespSpy.count(), 1);
QCOMPARE(setTokensResp->getStatusCode(), 200);
QCOMPARE(getNumOfTokens(), numOfTokens + 1);
// ADD_TOKENS_CHEK_END
// // ADD_TOKENS_CHECK_BEGIN
// QHash<QString, std::shared_ptr<Token>> tokens;
// auto token = getTestToken();
// tokens.insert(token->idToStringWithoutBraces(), token);
// Response* setTokensResp = reqMan->setTokens(tokens);
// QSignalSpy setTokensRespSpy(setTokensResp, &Response::ready);
// QCOMPARE(setTokensRespSpy.count(), 0);
// setTokensRespSpy.wait(timeout);
// QCOMPARE(setTokensRespSpy.count(), 1);
// QCOMPARE(setTokensResp->getStatusCode(), 200);
// QCOMPARE(getNumOfTokens(), numOfTokens + 1);
// // ADD_TOKENS_CHEK_END
// CHECK_UPDATED_TOKENS_BEGIN
Response* getTokensUpdatedResp = reqMan->getTokensUpdated(start);
// // CHECK_UPDATED_TOKENS_BEGIN
// Response* getTokensUpdatedResp = reqMan->getTokensUpdated(start);
// //start = QDateTime::currentMSecsSinceEpoch();
// QSignalSpy getTokensUpdatedRespSpy(getTokensUpdatedResp, &Response::ready);
// QCOMPARE(getTokensUpdatedRespSpy.count(), 0);
// getTokensUpdatedRespSpy.wait(timeout);
// QCOMPARE(getTokensUpdatedResp->getStatusCode(), 200);
// QCOMPARE(getTokensUpdatedRespSpy.count(), 1);
// auto doc1 = getJsonDoc(getTokensUpdatedResp->getJson());
// QCOMPARE(doc1.object()["items"].toArray().size(), 1);
// // CHECK_UPDATED_TOKENS_END
// // DELETE_TOKENS_CHECK_BEGIN
// QList<QString> ids;
// ids.append("062c93f6-ba3e-46af-a3a6-7a2988d1f0e9");
// Response* deleteTokensResp = reqMan->deleteTokens(ids);
// QSignalSpy deleteTokensRespSpy(deleteTokensResp, &Response::ready);
// QCOMPARE(deleteTokensRespSpy.count(), 0);
// deleteTokensRespSpy.wait(timeout);
// QCOMPARE(deleteTokensRespSpy.count(), 1);
// QCOMPARE(deleteTokensResp->getStatusCode(), 200);
// // DELETE_TOKENS_CHECK_END
// // CHECK_DELETED_TOKENS_BEGIN
// Response* getTokensDeletedResp = reqMan->getTokensDeleted(start);
// start = QDateTime::currentMSecsSinceEpoch();
QSignalSpy getTokensUpdatedRespSpy(getTokensUpdatedResp, &Response::ready);
QCOMPARE(getTokensUpdatedRespSpy.count(), 0);
getTokensUpdatedRespSpy.wait(10000);
QCOMPARE(getTokensUpdatedResp->getStatusCode(), 200);
QCOMPARE(getTokensUpdatedRespSpy.count(), 1);
auto doc1 = getJsonDoc(getTokensUpdatedResp->getJson());
QCOMPARE(doc1.object()["items"].toArray().size(), 1);
// CHECK_UPDATED_TOKENS_END
// QSignalSpy getTokensDeletedRespSpy(getTokensDeletedResp, &Response::ready);
// QCOMPARE(getTokensDeletedRespSpy.count(), 0);
// getTokensDeletedRespSpy.wait(timeout);
// QCOMPARE(getTokensDeletedResp->getStatusCode(), 200);
// QCOMPARE(getTokensDeletedRespSpy.count(), 1);
// auto doc2 = getJsonDoc(getTokensDeletedResp->getJson());
// QCOMPARE(doc2.object()["items"].toArray().size(), 1);
// QVERIFY(doc2.object()["items"].toArray().contains("062c93f6-ba3e-46af-a3a6-7a2988d1f0e9"));
// // CHECK_DELETED_TOKENS_END
// DELETE_TOKENS_CHECK_BEGIN
QList<QString> ids;
ids.append("582c982d-6fd7-4856-8548-7ce542791c7a");
Response* deleteTokensResp = reqMan->deleteTokens(&ids);
QSignalSpy deleteTokensRespSpy(deleteTokensResp, &Response::ready);
QCOMPARE(deleteTokensRespSpy.count(), 0);
deleteTokensRespSpy.wait(10000);
QCOMPARE(deleteTokensRespSpy.count(), 1);
QCOMPARE(deleteTokensResp->getStatusCode(), 200);
// DELETE_TOKENS_CHECK_END
// CHECK_DELETED_TOKENS_BEGIN
Response* getTokensDeletedResp = reqMan->getTokensDeleted(start);
start = QDateTime::currentMSecsSinceEpoch();
QSignalSpy getTokensDeletedRespSpy(getTokensDeletedResp, &Response::ready);
QCOMPARE(getTokensDeletedRespSpy.count(), 0);
getTokensDeletedRespSpy.wait(10000);
QCOMPARE(getTokensDeletedResp->getStatusCode(), 200);
QCOMPARE(getTokensDeletedRespSpy.count(), 1);
auto doc2 = getJsonDoc(getTokensDeletedResp->getJson());
QCOMPARE(doc2.object()["items"].toArray().size(), 1);
QVERIFY(doc2.object()["items"].toArray().contains("582c982d-6fd7-4856-8548-7ce542791c7a"));
// CHECK_DELETED_TOKENS_END
// LAST_TESTS (for sure)
QCOMPARE(loginSpy.count(), 1); // Checking multiple calls
QCOMPARE(loginRespSpy.count(), 1);
QCOMPARE(getNumOfSubjects(), numOfSubjects);
QCOMPARE(getNumOfTokens(), numOfTokens);
// // LAST_TESTS (for sure)
// QCOMPARE(loginSpy.count(), 1); // Checking multiple calls
// QCOMPARE(loginRespSpy.count(), 1);
// QCOMPARE(getNumOfSubjects(), numOfSubjects);
// QCOMPARE(getNumOfTokens(), numOfTokens);
}
void ComplexTest::fullSync()
{
api->prepareDatabase();
api->downloadData();
QSignalSpy spy(api, &ColnodAPI::dataDownloaded);
spy.wait(10000);
api->syncDataFromColnod();
// api->syncDataToColnod();
/* api->prepareDatabase();
api->loadDataFromColnod();
QSignalSpy spy(api, &SyncManager::dataDownloaded);
spy.wait(timeout);
api->loadDataFromDB();
api->syncDataFromColnodToDB();
api->syncDataFromDBToColnod();
QSignalSpy processSpy(api, &SyncManager::dataUpdatedToColnod);
processSpy.wait(timeout);
QSignalSpy finish(api, &SyncManager::syncFinished);
finish.wait(timeout); */
}
void ComplexTest::syncLastUpdated()
{
api->downloadChangedDataFromColnod();
QSignalSpy spy(api, &ColnodAPI::dataDownloaded);
spy.wait(10000);
api->syncChangedDataFromColnod();
// api->syncChangedDataToColnod();
// Logger::log("ahoj");
// api->loadDataFromColnod();
// QSignalSpy spy(api, &SyncManager::dataDownloaded);
// spy.wait(timeout);
// 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()
@ -143,31 +155,33 @@ void ComplexTest::testingStuff()
// HELPFUL_FUNCTIONS
int ComplexTest::getNumOfSubjects()
{
auto reqMan = new RequestManager;
Response* subjectsResp = reqMan->getSubjects();
QSignalSpy subjectsRespSpy(subjectsResp, &Response::ready);
subjectsRespSpy.wait(10000);
subjectsRespSpy.wait(timeout);
auto doc = getJsonDoc(subjectsResp->getJson());
return doc.object()["items"].toArray().size();
}
int ComplexTest::getNumOfTokens()
{
auto reqMan = new RequestManager;
Response* tokensResp = reqMan->getTokens();
QSignalSpy tokensRespSpy(tokensResp, &Response::ready);
tokensRespSpy.wait(10000);
tokensRespSpy.wait(timeout);
auto doc = getJsonDoc(tokensResp->getJson());
return doc.object()["items"].toArray().size();
}
QJsonDocument ComplexTest::getJsonDoc(QString json)
QJsonDocument ComplexTest::getJsonDoc(const QString &json)
{
return QJsonDocument::fromJson(json.toUtf8());
}
Token* ComplexTest::getTestToken()
std::shared_ptr<Token> ComplexTest::getTestToken()
{
QJsonObject jsonToken;
jsonToken.insert("id", "582c982d-6fd7-4856-8548-7ce542791c7a");
jsonToken.insert("id", "062c93f6-ba3e-46af-a3a6-7a2988d1f0e9");
jsonToken.insert("name", "test");
jsonToken.insert("description", "mobile");
jsonToken.insert("tokenType", "Token");
@ -180,9 +194,9 @@ Token* ComplexTest::getTestToken()
flags.push_back("NoValidity");
jsonToken.insert("flags", flags);
jsonToken.insert("subjectId", "72b37f7e-5761-4e6c-8e87-20c0bed0d904");
Token* token = new Token;
auto token = std::shared_ptr<Token>();
token->fromJSON(jsonToken);
return token;
}
QTEST_MAIN(ComplexTest)
//QTEST_MAIN(ComplexTest)

View File

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

View File

@ -37,15 +37,20 @@ private slots:
void deleteTokens();
void subjectJSONParser();
void tokenJSONParser();
void connectToDB();
//void connectToDB();
//void debugConnection();
void saveDataToDB();
void getUuid();
private:
std::shared_ptr<Token> getTestToken();
//QString host = "http://localhost:8080"; //colnod server (ssh -L 8080:192.168.254.11:8443 penta-master)
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;
};