diff --git a/src/colnod/colnodapi.cpp b/src/colnod/colnodapi.cpp index 40f938d..531c639 100644 --- a/src/colnod/colnodapi.cpp +++ b/src/colnod/colnodapi.cpp @@ -8,6 +8,11 @@ ColnodAPI::ColnodAPI(serversdk::RequestManager* reqMan, qint64 lastSync, QString :mReqMan(reqMan), mUserName(userName), mPassword(password) { mLastSync.set_timestamp(lastSync); + data = std::make_shared(); + + // ----------------------------------- + mReqMan->setIgnoreSsl(true); + // ----------------------------------- } void ColnodAPI::downloadData() @@ -31,8 +36,16 @@ void ColnodAPI::downloadData() void ColnodAPI::processData(std::shared_ptr data) { - setTokens(data->updatedTokens); - deleteTokens(data->deletedTokens); + if ( !data->updatedTokens.isEmpty()) { + setTokens(data->updatedTokens); + } else { + emit partOfDataProcessFinished(); + } + if ( !data->deletedTokens.isEmpty()) { + deleteTokens(data->deletedTokens); + } else { + emit partOfDataProcessFinished(); + } } std::shared_ptr ColnodAPI::requestLogin() @@ -59,7 +72,7 @@ std::shared_ptr ColnodAPI::requestLogin() void ColnodAPI::getTokensUpdated(const Timestamp &time) { auto request = composeRequest("/TokenManager/getTokensUpdated", time.jsonData()); - request->setToken(authToken); + request->setUserName(authToken); mReqMan->processRequest(request); connect(request.get(), &serversdk::Request::finished, [=](){ saveUpdatedTokens(request->responseData()); @@ -70,7 +83,7 @@ void ColnodAPI::getTokensUpdated(const Timestamp &time) void ColnodAPI::getTokensDeleted(const Timestamp &time) { auto request = composeRequest("/TokenManager/getTokensDeleted", time.jsonData()); - request->setToken(authToken); + request->setUserName(authToken); mReqMan->processRequest(request); connect(request.get(), &serversdk::Request::finished, [=](){ saveDeletedTokens(request->responseData()); @@ -81,7 +94,7 @@ void ColnodAPI::getTokensDeleted(const Timestamp &time) void ColnodAPI::getSubjectsUpdated(const Timestamp &time) { auto request = composeRequest("/SubjectManager/getSubjectsUpdated", time.jsonData()); - request->setToken(authToken); + request->setUserName(authToken); mReqMan->processRequest(request); connect(request.get(), &serversdk::Request::finished, [=](){ saveUpdatedSubjects(request->responseData()); @@ -92,7 +105,7 @@ void ColnodAPI::getSubjectsUpdated(const Timestamp &time) void ColnodAPI::getSubjectsDeleted(const Timestamp &time) { auto request = composeRequest("/SubjectManager/getSubjectsDeleted", time.jsonData()); - request->setToken(authToken); + request->setUserName(authToken); mReqMan->processRequest(request); connect(request.get(), &serversdk::Request::finished, [=](){ saveDeletedSubjects(request->responseData()); @@ -102,8 +115,8 @@ void ColnodAPI::getSubjectsDeleted(const Timestamp &time) void ColnodAPI::setTokens(const QHash> &tokens) { - auto request = composeRequest("/TokenManager/setTokens", Token::tokensToJSON(tokens)); - request->setToken(authToken); + auto request = composeRequest("/TokenManager/setTokens", Token::tokensToColnodJson(tokens)); + request->setUserName(authToken); mReqMan->processRequest(request); connect(request.get(), &serversdk::Request::finished, [=](){ if (checkResponse(request->responseData())) { @@ -118,7 +131,7 @@ void ColnodAPI::setTokens(const QHash> &tokens) void ColnodAPI::deleteTokens(const QList &ids) { auto request = composeRequest("/TokenManager/deleteTokens", Token::idsToJSON(ids)); - request->setToken(authToken); + request->setUserName(authToken); mReqMan->processRequest(request); connect(request.get(), &serversdk::Request::finished, [=](){ if (checkResponse(request->responseData())) { diff --git a/src/colnod/data.cpp b/src/colnod/data.cpp index 5f15b8c..e8d9afa 100644 --- a/src/colnod/data.cpp +++ b/src/colnod/data.cpp @@ -19,8 +19,9 @@ void Data::loadTokensFromJson(const QByteArray &data) auto items = doc.object()["items"].toArray(); for (auto item : items) { auto token = std::make_shared(); - token->fromJson(item.toString().toUtf8()); - token->setDeleted(false); + doc.setObject(item.toObject()); + token->fromJson(doc.toJson()); + //token->setDeleted(false); updatedTokens.insert(token->id(), token); } } @@ -31,7 +32,8 @@ void Data::loadSubjectsFormJson(const QByteArray &data) auto items = doc.object()["items"].toArray(); for (auto item : items) { auto subject = std::make_shared(); - subject->fromJson(item.toString().toUtf8()); + doc.setObject(item.toObject()); + subject->fromJson(doc.toJson()); subject->setDeleted(false); updatedSubjects.insert(subject->id(), subject); } diff --git a/src/colnod/databaseapi.cpp b/src/colnod/databaseapi.cpp index 2bdc8c1..512afa4 100644 --- a/src/colnod/databaseapi.cpp +++ b/src/colnod/databaseapi.cpp @@ -19,9 +19,9 @@ bool DatabaseAPI::open() void DatabaseAPI::downloadData() { - QSqlQuery updatedQuery = mDbMan->execPlainSql("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 " + auto updatedQuery = mDbMan->execPlainSql("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 AND deleted = false"); - QSqlQuery deletedQuery = mDbMan->execPlainSql("SELECT id " + auto deletedQuery = mDbMan->execPlainSql("SELECT id " "FROM colnod_token WHERE EXTRACT(EPOCH FROM last_modified) * 1000 > EXTRACT(EPOCH FROM last_update) * 1000 AND deleted = true"); emit downloadDataFinished(composeData(updatedQuery, deletedQuery)); } @@ -65,7 +65,7 @@ qint64 DatabaseAPI::getLastSync() void DatabaseAPI::setLastSync(qint64 timestamp) { - QSqlQuery query("test", mDbMan->database()); + auto query = mDbMan->createQuery(); query.prepare("UPDATE config SET last_sync = :last_sync"); query.bindValue(":last_sync", timestamp); mDbMan->executeQuery(query); @@ -73,7 +73,7 @@ void DatabaseAPI::setLastSync(qint64 timestamp) void DatabaseAPI::setLastUpdate(QHash> tokens) { - QSqlQuery query("test", mDbMan->database()); + auto query = mDbMan->createQuery(); for (const auto &token : tokens){ query.prepare("UPDATE colnod_token SET last_update = :last_update WHERE id = :id"); query.bindValue(":last_update", token->lastUpdate()); @@ -84,14 +84,14 @@ void DatabaseAPI::setLastUpdate(QHash> tokens) qint64 DatabaseAPI::getNow() { - QSqlQuery query = mDbMan->execPlainSql("SELECT EXTRACT(EPOCH FROM NOW())*1000"); + auto query = mDbMan->execPlainSql("SELECT EXTRACT(EPOCH FROM NOW())*1000"); query.next(); return query.value(0).toLongLong(); } void DatabaseAPI::initNewTokens() { - QSqlQuery query = mDbMan->execPlainSql("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 " + auto query = mDbMan->execPlainSql("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 name IS NULL"); QHash> tokensToInit; while (query.next()){ @@ -108,7 +108,7 @@ void DatabaseAPI::initNewTokens() void DatabaseAPI::uploadTokens(QHash> tokens) { // TODO: - QSqlQuery query("test", mDbMan->database()); + auto query = mDbMan->createQuery(); for (const auto &token : tokens) { if (exists(token->id(), "colnod_token")) { query = utils->updateTable(token.get(), "colnod_token"); @@ -123,7 +123,7 @@ void DatabaseAPI::uploadTokens(QHash> tokens) void DatabaseAPI::uploadSubjects(QHash> subjects) { // TODO: - QSqlQuery query("test", mDbMan->database()); + auto query = mDbMan->createQuery(); for (const auto &subject : subjects) { if (exists(subject->id(), "colnod_subject")) { query = utils->updateTable(subject.get(), "colnod_subject"); @@ -138,7 +138,7 @@ void DatabaseAPI::uploadSubjects(QHash> subjec void DatabaseAPI::deleteItems(QList ids, const QString &tableName) { // TODO: - QSqlQuery query("test", mDbMan->database()); + auto query = mDbMan->createQuery(); QString nowString = QDateTime::fromMSecsSinceEpoch(getLastSync()).toString("yyyy-MM-dd hh:mm:ss.zzz"); for (const auto &id : ids) { query.prepare(QString("UPDATE %1 SET deleted = true, last_update = :now, last_modified = :now WHERE id = :id").arg(tableName)); @@ -148,10 +148,23 @@ void DatabaseAPI::deleteItems(QList ids, const QString &tableName) } } +QDateTime DatabaseAPI::getLastUpdate(const QString &id) +{ + auto query = mDbMan->createQuery(); + query.prepare("SELECT last_update FROM colnod_token WHERE id = :id"); + query.bindValue(":id", id); + mDbMan->executeQuery(query); + if (query.next()) { + return query.value(0).toDateTime(); + } + else { + return QDateTime(); + } +} + bool DatabaseAPI::exists(const QString &id, const QString &tableName) { - - QSqlQuery query("test", mDbMan->database()); + auto query = mDbMan->createQuery(); query.prepare(QString("SELECT 1 FROM %1 WHERE id = :id").arg(tableName)); query.bindValue(":id", id); query = mDbMan->executeQuery(query); @@ -165,7 +178,7 @@ bool DatabaseAPI::exists(const QString &id, const QString &tableName) qint16 DatabaseAPI::getNumOfTokensOfSubject(const QString &id) { - QSqlQuery query("test", mDbMan->database()); + auto query = mDbMan->createQuery(); query.prepare("SELECT 1 FROM colnod_token WHERE subject_id = :id AND deleted = false"); query.bindValue(":id", id); return static_cast(mDbMan->executeQuery(query).size()); @@ -173,7 +186,7 @@ qint16 DatabaseAPI::getNumOfTokensOfSubject(const QString &id) QString DatabaseAPI::getSubjectNameByTokenId(const QString &tokenId) { - QSqlQuery query("test", mDbMan->database()); + auto query = mDbMan->createQuery(); query.prepare("SELECT name FROM colnod_subject WHERE id = (SELECT subject_id FROM colnod_token WHERE id = :tokenId)"); query.bindValue(":tokenId", tokenId); if (mDbMan->executeQuery(query).next()) diff --git a/src/colnod/databaseapi.h b/src/colnod/databaseapi.h index 9ed1e6b..c2d9276 100644 --- a/src/colnod/databaseapi.h +++ b/src/colnod/databaseapi.h @@ -37,6 +37,8 @@ public: void uploadSubjects(QHash > subjects); void deleteItems(QList ids, const QString &tableName); + QDateTime getLastUpdate(const QString &id); + private: bool exists(const QString &id, const QString &tableName); diff --git a/src/colnod/subject.cpp b/src/colnod/subject.cpp index f155c50..c8af5a8 100644 --- a/src/colnod/subject.cpp +++ b/src/colnod/subject.cpp @@ -9,11 +9,6 @@ Subject::Subject(const QString &name) setName(name); } -QByteArray Subject::jsonData() const -{ - -} - bool Subject::fromJson(const QByteArray &data) { @@ -37,26 +32,26 @@ bool Subject::fromJson(const QByteArray &data) } -const QSet &Subject::getTokenFlags() const { - return tokenFlags; -} +//const QSet &Subject::getTokenFlags() const { +// return tokenFlags; +//} -void Subject::setTokenFlags(const QSet &tokenFlags) { - Subject::tokenFlags = tokenFlags; -} +//void Subject::setTokenFlags(const QSet &tokenFlags) { +// Subject::tokenFlags = tokenFlags; +//} -const QSet &Subject::getPinFlags() const { - return pinFlags; -} +//const QSet &Subject::getPinFlags() const { +// return pinFlags; +//} -void Subject::setPinFlags(const QSet &pinFlags) { - Subject::pinFlags = pinFlags; -} +//void Subject::setPinFlags(const QSet &pinFlags) { +// Subject::pinFlags = pinFlags; +//} -const QList> &Subject::getAtr() const { - return atr; -} +//const QList> &Subject::getAtr() const { +// return atr; +//} -void Subject::setAtr(const QList> &atr) { - this->atr = atr; -} +//void Subject::setAtr(const QList> &atr) { +// this->atr = atr; +//} diff --git a/src/colnod/subject.h b/src/colnod/subject.h index ee99f3d..9da9e88 100644 --- a/src/colnod/subject.h +++ b/src/colnod/subject.h @@ -34,23 +34,24 @@ public: Subject() = default; explicit Subject(const QString& name); - QByteArray jsonData() const override; bool fromJson(const QByteArray &data) override; - const QJsonObject &getAttributes() const; - void setAttributes(const QJsonObject &attributes); - const QSet &getTokenFlags() const; - void setTokenFlags(const QSet &tokenFlags); - const QString &getPin() const; - void setPin(const QString &pin); - const QSet &getPinFlags() const; - void setPinFlags(const QSet &pinFlags); +// const QJsonObject &getAttributes() const; +// void setAttributes(const QJsonObject &attributes); +// const QSet &getTokenFlags() const; +// void setTokenFlags(const QSet &tokenFlags); +// const QString &getPin() const; +// void setPin(const QString &pin); +// const QSet &getPinFlags() const; +// void setPinFlags(const QSet &pinFlags); - const QList> &getAtr() const; - void setAtr(const QList> &atr); +// const QList> &getAtr() const; +// void setAtr(const QList> &atr); private: QList> attributes; + + QSet tokenFlags; QSet pinFlags; QList> atr; diff --git a/src/colnod/syncmanager.cpp b/src/colnod/syncmanager.cpp index 36a1b21..ad2591d 100644 --- a/src/colnod/syncmanager.cpp +++ b/src/colnod/syncmanager.cpp @@ -37,12 +37,12 @@ void SyncManager::run() void SyncManager::downloadData() { - colnod->downloadData(); connect(colnod.get(), &ColnodAPI::downloadDataFinished, this, &SyncManager::saveColnodData); connect(colnod.get(), &ColnodAPI::downloadDataFinished, this, &SyncManager::areDataReady); - database->downloadData(); connect(database.get(), &DatabaseAPI::downloadDataFinished, this, &SyncManager::saveDatabaseData); connect(database.get(), &DatabaseAPI::downloadDataFinished, this, &SyncManager::areDataReady); + colnod->downloadData(); + database->downloadData(); } // finds conflicts -> changes on both sides (colnod and DB), apply newer change @@ -55,16 +55,22 @@ void SyncManager::prepareData() for (const auto &colnodToken : colnodDataToProcess->updatedTokens) { if (databaseDataToProcess->updatedTokens.contains(colnodToken->id())) { - // which change was later // if last_update in Colnod and DB equels -> already synced - if (databaseDataToProcess->updatedTokens.value(colnodToken->id()) > colnodToken || databaseDataToProcess->updatedTokens.value(colnodToken->id()) == colnodToken) + if (databaseDataToProcess->updatedTokens.value(colnodToken->id()) > colnodToken) { idsToDelete.append(colnodToken->id()); + } + continue; } + auto dbLastUpdate = database->getLastUpdate(colnodToken->id()); + if ( !dbLastUpdate.isNull() ) + if (dbLastUpdate == colnodToken->lastUpdate()) + idsToDelete.append(colnodToken->id()); } for (const auto &id : idsToDelete) colnodDataToProcess->updatedTokens.remove(id); + idsToDelete.clear(); - for (const auto &databaseToken : databaseDataToProcess->updatedTokens) { + for (const auto &databaseToken : databaseData->updatedTokens) { if (colnodDataToProcess->updatedTokens.contains(databaseToken->id())) { if (databaseToken > colnodDataToProcess->updatedTokens.value(databaseToken->id())) idsToDelete.append(databaseToken->id()); diff --git a/src/colnod/token.cpp b/src/colnod/token.cpp index 3239a22..b50bbae 100644 --- a/src/colnod/token.cpp +++ b/src/colnod/token.cpp @@ -22,13 +22,15 @@ Token::~Token() = default; -QByteArray Token::tokensToJSON(const QHash> &tokens) +QByteArray Token::tokensToColnodJson(const QHash> &tokens) { QJsonObject items; QJsonArray jsonTokens; for (const auto& token : tokens) { - //jsonTokens.push_back(token->toJSON()); + jsonTokens.push_back(QJsonValue(QJsonDocument::fromJson(token->jsonData()).object())); + //jsonTokens.append(QJsonValue::fromVariant(token->jsonData())); + //jsonTokens.push_back(QJsonValue::fromVariant(token->jsonData())); } items.insert("items", jsonTokens); QJsonDocument doc; @@ -36,13 +38,17 @@ QByteArray Token::tokensToJSON(const QHash> &tok return doc.toJson(); } -QByteArray Token::jsonData() const +QByteArray Token::jsonData(const QSet &filters) const { - auto variantMap = this->toVariantMap(); + auto variantMap = this->toVariantMap(filters); auto enabled = variantMap["enabled"].toBool(); auto noValidity = variantMap["noValidity"].toBool(); variantMap.remove("enabled"); variantMap.remove("noValidity"); + variantMap.remove("lastModified"); + variantMap.remove("deleted"); + variantMap.remove("lastUpdate"); + QVariantList flags; if ( enabled ) { flags << "Enabled"; @@ -70,7 +76,9 @@ bool Token::fromJson(const QByteArray &data) } } variant.remove("flags"); - + auto lastUpdate = variant["lastUpdate"].toLongLong(); + variant["lastUpdate"] = QDateTime::fromMSecsSinceEpoch(lastUpdate); + variant.insert("lastModified", QDateTime::fromMSecsSinceEpoch(lastUpdate)); // Populate this object data bool res = fromVariantMap(variant); return res; diff --git a/src/colnod/token.h b/src/colnod/token.h index 9da48fc..2f2fc45 100644 --- a/src/colnod/token.h +++ b/src/colnod/token.h @@ -10,6 +10,7 @@ #include + class Token : public serversdk::DatabaseTable { Q_OBJECT TABLE_PROPERTY(QString, id, setId, QString()) @@ -27,6 +28,8 @@ class Token : public serversdk::DatabaseTable { TABLE_PROPERTY(QDateTime, lastModified, setLastModified, QDateTime()) TABLE_PROPERTY(bool, deleted, setDeleted, false) + + public: /** * # Needed values to proper sync @@ -43,7 +46,7 @@ public: explicit Token(const QString& name); ~Token() override; - QByteArray jsonData() const override; + QByteArray jsonData(const QSet &filters = {}) const override; bool fromJson(const QByteArray &data) override; friend bool operator<(const Token &lToken, const Token &rToken){ @@ -52,6 +55,7 @@ public: friend bool operator>(const Token &lToken, const Token &rToken){ return lToken.lastModified() > rToken.lastUpdate(); } + friend bool operator==(const Token &lToken, const Token &rToken){ return lToken.id() == rToken.id() && lToken.name() == rToken.name() && @@ -78,7 +82,7 @@ public: void fromJSON(const QJsonObject &json); QJsonObject toJSON() const; - static QByteArray tokensToJSON(const QHash > &tokens); + static QByteArray tokensToColnodJson(const QHash > &tokens); static QByteArray idsToJSON(const QList &ids); private: diff --git a/test/unitTests/complextest.cpp b/test/unitTests/complextest.cpp index cb25a55..ef72769 100644 --- a/test/unitTests/complextest.cpp +++ b/test/unitTests/complextest.cpp @@ -18,6 +18,18 @@ void ComplexTest::initTestCase() } +//void DatabaseTableTest::enum_test2() +//{ +// auto test = R"({"id":"e2432439-41ed-4440-9c8e-40edb9989a15","name":"Pavel Kanka","description":"","lastUpdate":1565350519781,"attributes":{"items":{"Jmeno":"Pavel","Spolecnost":"Colsys","Prijmeni":"Kaňka"}},"tokenFlags":["NoPin"],"pin":"","pinFlags":["Access"]})"; +// Subject subject; +// subject.fromJson(test); + +// QCOMPARE(subject.name(), "Pavel Kanka"); +// qDebug() << subject.name() << subject.lastUpdate() << QDateTime::fromString("2019-08-09 11:35:19.000", "yyyy-MM-dd hh:mm:ss.zzz"); +// QCOMPARE(subject.lastUpdate(), QDateTime::fromString("2019-08-09 11:35:19", "yyyy-MM-dd hh:mm:ss.zzz")); +// qDebug() << subject.attrib.value(1)->toVariantMap(); +//} + void ComplexTest::cleanupTestCase() {