#include "databasemanager.h" DatabaseManager::DatabaseManager(const QString& host, const QString& dbName, const QString& user, const QString& password) { db = QSqlDatabase::addDatabase("QPSQL"); db.setDatabaseName(dbName); db.setHostName(host); db.setUserName(user); // home-office stuff //db.setPort(80); // db.setPassword(password); if (!db.open()) { qDebug() << "Opening error" + db.lastError().text(); } query = QSqlQuery("query", db); } // add or update subject to db void DatabaseManager::saveSubject(Subject* subject, const QString& table) { QString id = subject->idToStringWithoutBraces(); if (checkIfExists(id, table)) { query.prepare(QString("UPDATE %1 SET id = :id, description = :description, last_update = last_update:, name = :name, pin = :pin" "WHERE id = :id)").arg(table)); query.bindValue(":id", id); query.bindValue(":description", subject->getDescription()); query.bindValue(":name", subject->getName()); query.bindValue(":last_update", QDateTime::fromMSecsSinceEpoch(subject->getLastUpdate()).toString("yyyy-MM-dd hh:mm:ss.zzz")); query.bindValue(":pin", subject->getPin()); query.exec(); } else { query.prepare(QString("INSERT INTO %1 (id, description, last_update, name, pin) " "VALUES (:id, :description, :last_update, :name, :pin)").arg(table)); query.bindValue(":id", id); query.bindValue(":description", subject->getDescription()); query.bindValue(":last_update", QDateTime::fromMSecsSinceEpoch(subject->getLastUpdate()).toString("yyyy-MM-dd hh:mm:ss.zzz")); query.bindValue(":name", subject->getName()); query.bindValue(":pin", subject->getPin()); query.exec(); } } // add or update token to DB void DatabaseManager::saveToken(Token* token, const QString& table) { QString id = token->idToStringWithoutBraces(); if (checkIfExists(id, table)) { query.prepare(QString("UPDATE %1 SET id = :id, auth_errors = :auth_errors, description = :description, enabled = :enabled, 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)); query.bindValue(":id", id); query.bindValue(":auth_errors", token->getAuthErrors()); query.bindValue(":description", token->getDescription()); query.bindValue(":enabled", token->getFlags().contains("Enabled")); 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()); query.exec(); } 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)); 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()); query.exec(); } } // add of update subject attributes void DatabaseManager::saveSubjectAttributes(Subject *subject, const QString& table) { auto attributes = subject->getAtr(); for (const auto& attribute : attributes){ QString id = subject->idToStringWithoutBraces() + " " + attribute.first; 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{ 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(); } } } // "delete" tokens from DB -> set deleted true void DatabaseManager::setDeleted(const QString& id, const QString& table) { quint64 now = getNow(); QString nowString = QDateTime::fromMSecsSinceEpoch(now).toString("yyyy-MM-dd hh:mm:ss.zzz"); query.prepare(QString("UPDATE %1 SET deleted = true, last_update = :now, last_modified = :now WHERE id = :id").arg(table)); query.bindValue(":id", id); query.bindValue(":now", nowString); query.exec(); } bool DatabaseManager::checkIfExists(const QString& id, const QString& table) { query.prepare(QString("SELECT EXISTS(SELECT 1 FROM %1 WHERE id = :id)").arg(table)); query.bindValue(":id", id); query.exec(); query.first(); return query.value(0).toBool(); } bool DatabaseManager::executeQuery(QSqlQuery &query) const { bool res = query.exec(); return res; } void DatabaseManager::dropTables() { query.exec("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 character(36) primary key NOT NULL," "description character varying(255)," "last_update timestamp NOT NULL," "name character varying(255)," "pin character varying(255))"); query.exec("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_modified timestamp," "deleted BOOLEAN)"); query.exec("CREATE TABLE colnod_subject_attribute (" "id VARCHAR(255) primary key," "attribute_key VARCHAR(255)," "attribute_value VARCHAR(255)," "subject_id CHAR(36))"); } // return last_sync time uint64_t DatabaseManager::getLastSync() { query.exec("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) { query.prepare("UPDATE config SET last_sync = :last_sync"); query.bindValue(":last_sync", lastSync); query.exec(); } // return set of tokens to update form DB QSqlQuery* DatabaseManager::getUpdatedTokens() { QSqlQuery* qry = new QSqlQuery; qry->exec("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 qry; } QSqlQuery* DatabaseManager::getToken(const QString& id) { QSqlQuery* qry = new QSqlQuery; qry->prepare("SELECT 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"); qry->bindValue(":id", id); qry->exec(); if (qry->next()){ return qry; } return nullptr; } quint64 DatabaseManager::getNow() { query.exec("SELECT EXTRACT(EPOCH FROM NOW())*1000"); query.next(); return query.value(0).toULongLong(); } // sync last update back to DB from Colnod after changes made to Colnod void DatabaseManager::setLastUpdate(const QString& id, quint64 lastUpdate) { query.prepare("UPDATE colnod_token SET last_update = :lastUpdate WHERE id = :id"); query.bindValue(":id", id); query.bindValue(":lastUpdate", lastUpdate); query.exec(); }