#include "databasemanager.h" DatabaseManager::DatabaseManager(const QString& host, const QString& dbName, const QString& user, const QString& password, const bool &dryMode) { 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); this->dryMode = dryMode; } // add or update subject to db int 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()); executeQuery(query); return -1; } 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()); executeQuery(query); return 1; } // add or update token to DB int 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()); executeQuery(query); return -1; } 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()); executeQuery(query); return 1; } // 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()); executeQuery(query); } 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()); executeQuery(query); } } } // "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); executeQuery(query); } 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); executeQuery(query); query.first(); return query.value(0).toBool(); } QString DatabaseManager::getLastQuery(const QSqlQuery& query) const { QString str = query.lastQuery(); QMapIterator it(query.boundValues()); while (it.hasNext()) { it.next(); str.replace(it.key(),it.value().toString()); } return str; } void DatabaseManager::executeNonPreperedQuery(const QString &statement, QSqlQuery &query) const { if (dryMode){ QString sqlStatement = getLastQuery(query); qDebug() << sqlStatement; if (statement.startsWith("SELECT")) query.exec(statement); } else{ query.exec(statement); } } bool DatabaseManager::executeQuery(QSqlQuery &query) const { if (dryMode){ QString sqlStatement = getLastQuery(query); qDebug() << sqlStatement; if (sqlStatement.startsWith("SELECT")) query.exec(); return true; } bool res = query.exec(); return res; } void DatabaseManager::dropTables() { executeNonPreperedQuery("DROP TABLE IF EXISTS colnod_token, colnod_subject, colnod_subject_attribute", query); } // create table after deleting, it is used for full sync void DatabaseManager::createTables() { executeNonPreperedQuery("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); executeNonPreperedQuery("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); executeNonPreperedQuery("CREATE TABLE colnod_subject_attribute (" "id VARCHAR(255) primary key," "attribute_key VARCHAR(255)," "attribute_value VARCHAR(255)," "subject_id CHAR(36))", query); } // return last_sync time quint64 DatabaseManager::getLastSync() { executeNonPreperedQuery("SELECT last_sync FROM config", query); 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); executeQuery(query); } // return set of tokens to update form DB QSqlQuery* DatabaseManager::getUpdatedTokens() { QSqlQuery* qry = new QSqlQuery; executeNonPreperedQuery("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", *qry); return qry; } QSqlQuery* DatabaseManager::getToken(const QString& id) { QSqlQuery* qry = new QSqlQuery; qry->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"); qry->bindValue(":id", id); executeQuery(*qry); if (qry->next()){ return qry; } return nullptr; } quint64 DatabaseManager::getNow() { executeNonPreperedQuery("SELECT EXTRACT(EPOCH FROM NOW())*1000", query); 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); executeQuery(query); } void DatabaseManager::log(const QString &msg) { query.prepare("INSERT INTO logs (log_time, msg) VALUES (NOW(), :msg)"); query.bindValue(":msg", msg); query.exec(); } QString DatabaseManager::getSubjectNameByTokenId(const QString &tokenId) { 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"; } QString DatabaseManager::getSubjectNameById(const QString &id) { 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"; } bool DatabaseManager::checkDeletedToken(const QString &id) { query.prepare("SELECT deleted FROM colnod_token WHERE id = :id"); query.bindValue(":id", id); executeQuery(query); query.next(); return query.value(0).toBool(); }