mirror of
https://github.com/QuasarApp/Heart.git
synced 2025-04-27 10:14:36 +00:00
create separate db class
This commit is contained in:
parent
836ffe241b
commit
1ae53fd8cc
554
Heart/DataBaseSpace/database.cpp
Normal file
554
Heart/DataBaseSpace/database.cpp
Normal file
@ -0,0 +1,554 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2021 QuasarApp.
|
||||
* Distributed under the lgplv3 software license, see the accompanying
|
||||
* Everyone is permitted to copy and distribute verbatim copies
|
||||
* of this license document, but changing it is not allowed.
|
||||
*/
|
||||
|
||||
#include "accesstoken.h"
|
||||
#include "database.h"
|
||||
#include "abstractnodeinfo.h"
|
||||
#include "sqldbcache.h"
|
||||
#include "sqldbwriter.h"
|
||||
#include "websocketcontroller.h"
|
||||
#include "asyncsqldbwriter.h"
|
||||
|
||||
#include <badrequest.h>
|
||||
#include <quasarapp.h>
|
||||
#include <websocket.h>
|
||||
#include <websocketsubscriptions.h>
|
||||
#include <websocketcontroller.h>
|
||||
#include <QCoreApplication>
|
||||
#include <ping.h>
|
||||
#include <keystorage.h>
|
||||
#include <basenodeinfo.h>
|
||||
#include <abstractnetworkmember.h>
|
||||
#include <memberpermisionobject.h>
|
||||
#include <networkmember.h>
|
||||
#include <deleteobject.h>
|
||||
#include "dberrorcodes.h"
|
||||
#include <QSet>
|
||||
#include <defaultpermision.h>
|
||||
#include <isubscribabledata.h>
|
||||
#include <itoken.h>
|
||||
#include <sqlitedbcache.h>
|
||||
#include <sqldb.h>
|
||||
#include <QCryptographicHash>
|
||||
#include "getsinglevalue.h"
|
||||
#include "setsinglevalue.h"
|
||||
|
||||
#define THIS_NODE "this_node_key"
|
||||
namespace QH {
|
||||
using namespace PKG;
|
||||
|
||||
DataBase::DataBase() {
|
||||
qRegisterMetaType<QSharedPointer<QH::PKG::DBObject>>();
|
||||
}
|
||||
|
||||
bool DataBase::initSqlDb(QString DBparamsFile,
|
||||
ISqlDBCache *cache,
|
||||
SqlDBWriter *writer) {
|
||||
|
||||
initDefaultDbObjects(cache, writer);
|
||||
|
||||
QVariantMap params;
|
||||
_db->setSQLSources(SQLSources());
|
||||
|
||||
if (DBparamsFile.isEmpty()) {
|
||||
params = defaultDbParams();
|
||||
|
||||
if (!_db->init(params)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (!_db->init(DBparamsFile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!upgradeDataBase()) {
|
||||
QuasarAppUtils::Params::log("Failed to upgrade database",
|
||||
QuasarAppUtils::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
QuasarAppUtils::Params::log(QString("Database loaded from: %0").arg(dbLocation()),
|
||||
QuasarAppUtils::Debug);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DataBase::isSqlInited() const {
|
||||
return _db;
|
||||
}
|
||||
|
||||
bool DataBase::run() {
|
||||
if (!isSqlInited() && !initSqlDb()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DataBase::run(const QString &localNodeName) {
|
||||
|
||||
if (localNodeName.isEmpty())
|
||||
return false;
|
||||
|
||||
setLocalNodeName(localNodeName);
|
||||
|
||||
if (!isSqlInited() && !initSqlDb()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DataBase::stop() {
|
||||
|
||||
if (db()) {
|
||||
auto writer = _db->writer();
|
||||
_db->softDelete();
|
||||
_db = nullptr;
|
||||
delete writer;
|
||||
}
|
||||
}
|
||||
|
||||
DataBase::~DataBase() {
|
||||
}
|
||||
|
||||
void DataBase::initDefaultDbObjects(ISqlDBCache *cache,
|
||||
SqlDBWriter *writer) {
|
||||
if (!writer) {
|
||||
writer = new AsyncSqlDBWriter();
|
||||
}
|
||||
|
||||
if (!cache) {
|
||||
cache = new SqlDB();
|
||||
}
|
||||
|
||||
cache->setWriter(writer);
|
||||
_db = cache;
|
||||
|
||||
connect(_db, &ISqlDBCache::sigItemChanged,
|
||||
this, &DataBase::handleObjectChanged,
|
||||
Qt::DirectConnection);
|
||||
|
||||
connect(_db, &ISqlDBCache::sigItemDeleted,
|
||||
this, &DataBase::handleObjectDeleted,
|
||||
Qt::DirectConnection);
|
||||
}
|
||||
|
||||
|
||||
bool DataBase::welcomeAddress(AbstractNodeInfo *) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DataBase::isBanned(const QVariant &node) const {
|
||||
NetworkMember member(node);
|
||||
auto objectFromDataBase = db()->getObject<AbstractNetworkMember>(member);
|
||||
|
||||
return objectFromDataBase->trust() <= 0;
|
||||
}
|
||||
|
||||
QStringList DataBase::SQLSources() const{
|
||||
return {
|
||||
DEFAULT_DB_INIT_FILE_PATH
|
||||
};
|
||||
}
|
||||
|
||||
QSet<QString> DataBase::systemTables() const {
|
||||
return {"NetworkMembers", "MemberPermisions"};
|
||||
}
|
||||
|
||||
bool DataBase::notifyObjectChanged(const QSharedPointer<PKG::ISubscribableData> &item) {
|
||||
|
||||
if (!item.dynamicCast<PKG::AbstractData>()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_webSocketWorker->handleItemChanged(item);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DataBase::objectRemoved(const DbAddress &) {
|
||||
|
||||
}
|
||||
|
||||
void DataBase::objectChanged(const QSharedPointer<DBObject> &) {
|
||||
|
||||
}
|
||||
|
||||
DBPatchMap DataBase::dbPatches() const {
|
||||
return {};
|
||||
}
|
||||
|
||||
void DataBase::handleObjectChanged(const QSharedPointer<DBObject> &item) {
|
||||
notifyObjectChanged(item.staticCast<PKG::ISubscribableData>());
|
||||
objectChanged(item);
|
||||
|
||||
}
|
||||
|
||||
void DataBase::handleObjectDeleted(const DbAddress &item) {
|
||||
objectRemoved(item);
|
||||
}
|
||||
|
||||
void DataBase::memberSubsribed(const QVariant &, unsigned int ) {
|
||||
return;
|
||||
}
|
||||
|
||||
void DataBase::memberUnsubsribed(const QVariant &, unsigned int ) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString DataBase::dbLocation() const {
|
||||
if (db() && db()->writer()) {
|
||||
return db()->writer()->databaseLocation();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
ISqlDBCache *DataBase::db() const {
|
||||
return _db;
|
||||
}
|
||||
|
||||
bool DataBase::isForbidenTable(const QString &table) {
|
||||
return systemTables().contains(table);
|
||||
}
|
||||
|
||||
bool DataBase::upgradeDataBase() {
|
||||
auto patches = dbPatches();
|
||||
int actyalyVersion = patches.size();
|
||||
int currentVersion = 0;
|
||||
|
||||
if (!db())
|
||||
return false;
|
||||
|
||||
bool fsupportUpgrade = db()->doQuery("SELECT COUNT(*) FROM DataBaseAttributes", true);
|
||||
|
||||
if (!fsupportUpgrade) {
|
||||
|
||||
QuasarAppUtils::Params::log("The data base of application do not support soft upgrade. "
|
||||
"Please remove database monyaly and restart application.",
|
||||
QuasarAppUtils::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
PKG::GetSingleValue request({"DataBaseAttributes", "version"}, "value", "name");
|
||||
|
||||
if (auto responce = _db->getObject(request)) {
|
||||
currentVersion = responce->value().toInt();
|
||||
}
|
||||
|
||||
bool fUpdated = false;
|
||||
while (currentVersion < actyalyVersion) {
|
||||
|
||||
auto patch = patches.value(currentVersion, {});
|
||||
|
||||
QString message;
|
||||
message = "Upgrade data base!. to %0 versions";
|
||||
message = message.arg(currentVersion);
|
||||
|
||||
QuasarAppUtils::Params::log(message,
|
||||
QuasarAppUtils::Info);
|
||||
|
||||
if (patch && !patch(db())) {
|
||||
QuasarAppUtils::Params::log("Failed to " + message,
|
||||
QuasarAppUtils::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
currentVersion++;
|
||||
fUpdated = true;
|
||||
}
|
||||
|
||||
if (fUpdated) {
|
||||
auto updateVersionRequest = QSharedPointer<PKG::SetSingleValue>::create(
|
||||
DbAddress{"DataBaseAttributes", "version"},
|
||||
"value", currentVersion, "name");
|
||||
|
||||
if (!_db->insertIfExistsUpdateObject(updateVersionRequest, true)) {
|
||||
QuasarAppUtils::Params::log("Failed to update version attribute",
|
||||
QuasarAppUtils::Error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const QString &DataBase::localNodeName() const {
|
||||
return _localNodeName;
|
||||
}
|
||||
|
||||
void DataBase::setLocalNodeName(const QString &newLocalNodeName) {
|
||||
_localNodeName = newLocalNodeName;
|
||||
}
|
||||
|
||||
QVariantMap DataBase::defaultDbParams() const {
|
||||
|
||||
return {
|
||||
{"DBDriver", "QSQLITE"},
|
||||
{"DBFilePath", DEFAULT_DB_PATH + "/" + localNodeName() + "/" + localNodeName() + "_" + DEFAULT_DB_NAME},
|
||||
};
|
||||
}
|
||||
|
||||
DBOperationResult
|
||||
QH::DataBase::getObject(const QVariant &requester,
|
||||
const QH::DBObject &templateObj,
|
||||
QSharedPointer<QH::PKG::DBObject> &result) const {
|
||||
|
||||
if (!_db && !result) {
|
||||
return DBOperationResult::Unknown;
|
||||
}
|
||||
|
||||
DBOperationResult permisionResult = checkPermission(requester, templateObj.dbAddress(),
|
||||
Permission::Read);
|
||||
if (permisionResult != DBOperationResult::Allowed) {
|
||||
return permisionResult;
|
||||
}
|
||||
|
||||
auto obj = _db->getObject(templateObj);
|
||||
if (!obj || (obj->dbAddress() != templateObj.dbAddress())) {
|
||||
return DBOperationResult::Unknown;
|
||||
}
|
||||
|
||||
result = obj;
|
||||
return DBOperationResult::Allowed;
|
||||
}
|
||||
|
||||
DBOperationResult
|
||||
DataBase::getObjects(const QVariant &requester,
|
||||
const DBObject &templateObj,
|
||||
QList<QSharedPointer<DBObject>> &result) const {
|
||||
if (!_db) {
|
||||
return DBOperationResult::Unknown;
|
||||
}
|
||||
|
||||
if (!_db->getAllObjects(templateObj, result)) {
|
||||
return DBOperationResult::Unknown;
|
||||
}
|
||||
|
||||
for (const auto& obj: qAsConst(result)) {
|
||||
if (!obj)
|
||||
return DBOperationResult::Unknown;
|
||||
|
||||
auto permisionResult = checkPermission(requester, obj->dbAddress(),
|
||||
Permission::Read);
|
||||
if (permisionResult != DBOperationResult::Allowed) {
|
||||
return permisionResult;
|
||||
}
|
||||
}
|
||||
|
||||
return DBOperationResult::Allowed;
|
||||
}
|
||||
|
||||
DBOperationResult
|
||||
DataBase::updateObject(const QVariant &requester,
|
||||
const QSharedPointer<DBObject> &saveObject) {
|
||||
|
||||
if (!_db) {
|
||||
return DBOperationResult::Unknown;
|
||||
}
|
||||
|
||||
auto permisionResult = checkPermission(requester,
|
||||
saveObject->dbAddress(),
|
||||
Permission::Write);
|
||||
if (permisionResult != DBOperationResult::Allowed) {
|
||||
return permisionResult;
|
||||
}
|
||||
|
||||
if (!_db->updateObject(saveObject)) {
|
||||
return DBOperationResult::Unknown;
|
||||
}
|
||||
|
||||
return DBOperationResult::Allowed;
|
||||
}
|
||||
|
||||
DBOperationResult
|
||||
DataBase::createObject(const QVariant &requester,
|
||||
const QSharedPointer<DBObject> &obj) {
|
||||
|
||||
if (!_db) {
|
||||
return DBOperationResult::Unknown;
|
||||
}
|
||||
|
||||
if (isForbidenTable(obj->tableName())) {
|
||||
return DBOperationResult::Forbidden;
|
||||
}
|
||||
|
||||
if (!_db->insertObject(obj)) {
|
||||
return DBOperationResult::Unknown;
|
||||
}
|
||||
|
||||
if (!addUpdatePermission(requester, obj->dbAddress(), Permission::Write)) {
|
||||
|
||||
_db->deleteObject(obj);
|
||||
|
||||
return DBOperationResult::Forbidden;
|
||||
}
|
||||
|
||||
return DBOperationResult::Allowed;
|
||||
|
||||
}
|
||||
|
||||
DBOperationResult
|
||||
DataBase::updateIfNotExistsCreateObject(const QVariant &requester,
|
||||
const QSharedPointer<DBObject> &obj) {
|
||||
|
||||
auto opResult = updateObject(requester, obj);
|
||||
if (opResult != QH::DBOperationResult::Unknown) {
|
||||
return opResult;
|
||||
}
|
||||
|
||||
return createObject(requester, obj);
|
||||
}
|
||||
|
||||
DBOperationResult
|
||||
DataBase::changeObjects(const QVariant &requester,
|
||||
const DBObject &templateObj,
|
||||
const std::function<bool (const QSharedPointer<DBObject> &)> &changeAction) {
|
||||
|
||||
DBOperationResult result = DBOperationResult::Unknown;
|
||||
|
||||
if (!_db) {
|
||||
return result;
|
||||
}
|
||||
|
||||
auto execWithCheck = [this, requester, &result, &changeAction]
|
||||
(const QSharedPointer<DBObject> & obj) {
|
||||
|
||||
result = checkPermission(requester, obj->dbAddress(), Permission::Update);
|
||||
if (result != DBOperationResult::Allowed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return changeAction(obj);
|
||||
};
|
||||
|
||||
if (!db()->changeObjects(templateObj, execWithCheck)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QVariant DataBase::getSender(const AbstractNodeInfo *connectInfo,
|
||||
const AbstractData *) const {
|
||||
|
||||
auto info = dynamic_cast<const BaseNodeInfo*>(connectInfo);
|
||||
if (!info)
|
||||
return {};
|
||||
|
||||
return info->id();
|
||||
}
|
||||
|
||||
DBOperationResult
|
||||
DataBase::checkPermission(const QVariant &requester,
|
||||
const DbAddress &objectAddress,
|
||||
const Permission& requarimentPermision) const {
|
||||
|
||||
if (!requester.isValid())
|
||||
return DBOperationResult::Unknown;
|
||||
|
||||
if (!_db) {
|
||||
return DBOperationResult::Unknown;
|
||||
}
|
||||
|
||||
auto member = _db->getObjectRaw(NetworkMember{requester});
|
||||
if (!member) {
|
||||
return DBOperationResult::Unknown;
|
||||
}
|
||||
|
||||
auto permision =
|
||||
_db->getObject(MemberPermisionObject({requester, objectAddress}));
|
||||
|
||||
if (!permision) {
|
||||
|
||||
permision = _db->getObject(DefaultPermision({requester, objectAddress}));
|
||||
if (!permision)
|
||||
return DBOperationResult::Unknown;
|
||||
}
|
||||
|
||||
if (permision->permisions() < requarimentPermision) {
|
||||
return DBOperationResult::Forbidden;
|
||||
}
|
||||
|
||||
return DBOperationResult::Allowed;
|
||||
}
|
||||
|
||||
bool DataBase::addUpdatePermission(const QVariant &member,
|
||||
const DbAddress &objectAddress,
|
||||
const Permission &permision,
|
||||
const Permission &defaultPermision) const {
|
||||
|
||||
if (!_db) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto object = QSharedPointer<MemberPermisionObject>::create();
|
||||
object->setKey(PermisionData(member, objectAddress));
|
||||
object->setPermisions(permision);
|
||||
|
||||
if (!_db->insertObject(object) && !_db->updateObject(object)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto defaultPermisionObject = QSharedPointer<DefaultPermision>::create();
|
||||
defaultPermisionObject->setKey(PermisionData({}, objectAddress));
|
||||
defaultPermisionObject->setPermisions(defaultPermision);
|
||||
|
||||
if (!_db->insertObject(defaultPermisionObject) &&
|
||||
!_db->updateObject(defaultPermisionObject)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DataBase::removePermission(const QVariant &member,
|
||||
const DbAddress &objectAddress) const {
|
||||
|
||||
if (!_db) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto object = QSharedPointer<MemberPermisionObject>::create();
|
||||
object->setKey(PermisionData(member, objectAddress));
|
||||
|
||||
if (!_db->deleteObject(object)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DBOperationResult
|
||||
DataBase::deleteObject(const QVariant &requester,
|
||||
const QSharedPointer<DBObject> &dbObject) {
|
||||
|
||||
if (!_db) {
|
||||
return DBOperationResult::Unknown;
|
||||
}
|
||||
|
||||
auto permisionResult = checkPermission(requester,
|
||||
dbObject->dbAddress(),
|
||||
Permission::Write);
|
||||
if (permisionResult != DBOperationResult::Allowed) {
|
||||
return permisionResult;
|
||||
}
|
||||
|
||||
auto address = dbObject->dbAddress();
|
||||
if (!_db->deleteObject(dbObject)) {
|
||||
return DBOperationResult::Unknown;
|
||||
}
|
||||
|
||||
return DBOperationResult::Allowed;
|
||||
}
|
||||
|
||||
}
|
||||
|
453
Heart/DataBaseSpace/database.h
Normal file
453
Heart/DataBaseSpace/database.h
Normal file
@ -0,0 +1,453 @@
|
||||
/*
|
||||
* Copyright (C) 2018-2021 QuasarApp.
|
||||
* Distributed under the lgplv3 software license, see the accompanying
|
||||
* Everyone is permitted to copy and distribute verbatim copies
|
||||
* of this license document, but changing it is not allowed.
|
||||
*/
|
||||
|
||||
#ifndef QH_DATABASE_H
|
||||
#define QH_DATABASE_H
|
||||
|
||||
#include "abstractnode.h"
|
||||
#include <dbobject.h>
|
||||
#include <hostaddress.h>
|
||||
#include <permission.h>
|
||||
|
||||
|
||||
namespace QH {
|
||||
|
||||
namespace PKG {
|
||||
class WebSocket;
|
||||
class ISubscribableData;
|
||||
|
||||
}
|
||||
|
||||
class ISqlDBCache;
|
||||
class SqlDBWriter;
|
||||
class WebSocketController;
|
||||
class DbAddress;
|
||||
class NodeId;
|
||||
class iObjectProvider;
|
||||
|
||||
|
||||
/**
|
||||
* @brief DBPatch This is function that should be upgrade database.
|
||||
* @see DBPatchMap
|
||||
* @see DataBaseNode::dbPatch
|
||||
*/
|
||||
typedef std::function<bool (const QH::iObjectProvider *)> DBPatch;
|
||||
/**
|
||||
* @brief DBPatchMap This is list when index of list is version of database and value if function that should be upgrade database.
|
||||
* @see DataBaseNode::dbPatch
|
||||
* @see DBPatchMap
|
||||
*/
|
||||
typedef QList<DBPatch> DBPatchMap;
|
||||
|
||||
/**
|
||||
* @brief The DataBase class is DataBase base implementation.
|
||||
* This implementation contains methods for work with database.
|
||||
* DataBaseNode is thread save class.
|
||||
* @see DBObject
|
||||
* @see DataBaseNode
|
||||
*/
|
||||
class HEARTSHARED_EXPORT DataBase
|
||||
{
|
||||
public:
|
||||
|
||||
DataBase();
|
||||
~DataBase();
|
||||
|
||||
/**
|
||||
* @brief intSqlDb This method initalize database of this node or server.
|
||||
* @param DBparamsFile This is path to json file with all params of database.
|
||||
* For more information of available parameters see the SqlDBWriter::defaultInitPararm method.
|
||||
* @param cache This is pointer to the custom child of SqlDBCache class.
|
||||
* IF you set nullptr value of this parameter then well be created a default SqlDBCache object.
|
||||
* @param writer This is pointer tot the custom child of SqlDBWriter class.
|
||||
* If you set nullptr value of this parameter then well be created a default AsyncSqlDbWriter object.
|
||||
* @return True if the database initialized successful.
|
||||
*/
|
||||
virtual bool initSqlDb( QString DBparamsFile = "",
|
||||
ISqlDBCache * cache = nullptr,
|
||||
SqlDBWriter* writer = nullptr);
|
||||
|
||||
/**
|
||||
* @brief isSqlInited This method return true if database initialized successful.
|
||||
* @return True if database initialized successful.
|
||||
*/
|
||||
bool isSqlInited() const;
|
||||
|
||||
/**
|
||||
* @brief run This method start and initialize the data base connection.
|
||||
* @return true if finished successful else false.
|
||||
*/
|
||||
bool run();
|
||||
|
||||
/**
|
||||
* @brief run This method is some as AbstractNode::run but set for node custom work folder.
|
||||
* This maybe use for multiple deployment nodes on one host.
|
||||
* @param localNodeName This is name of node and work folder of node.
|
||||
*/
|
||||
virtual bool run(const QString &localNodeName);
|
||||
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* @brief defaultDbParams This method return default database parameters for this node.
|
||||
* Override this method for set new default parameters. Or use json database parameters file in DataBaseNode::run.
|
||||
* @return Map with all database parameters.
|
||||
* For more information of available parameters see the SqlDBWriter::defaultInitPararm method.
|
||||
*/
|
||||
virtual QVariantMap defaultDbParams() const;
|
||||
|
||||
/**
|
||||
* @brief deleteObject This method delete object by database address.
|
||||
* @note If you want to delete any object use only this method because this method check permission of requester to execute this action.
|
||||
* @param requester This is pointer to network member that send this request.
|
||||
* @param dbObject This is pointer to object of database to remove.
|
||||
* @return result of operation (allow, forbidden, unknown).
|
||||
* For more information about results see the DBOperationResult enum.
|
||||
*/
|
||||
DBOperationResult deleteObject(const QVariant &requester,
|
||||
const QSharedPointer<PKG::DBObject> &dbObject);
|
||||
|
||||
/**
|
||||
* @brief getObject This method try get an object by database address.
|
||||
* @note If you want to get any object use only this method because this method check permission of requester to execute this action
|
||||
* @param requester This is pointer to network member that send this request.
|
||||
* @param templateObj This is pointer to object of database with data for generation the sql select request.
|
||||
* @param result This is a shared pointer for save result of request.
|
||||
* @return result of operation (allow, forbidden, unknown).
|
||||
* For more information about results see the DBOperationResult enum.
|
||||
*/
|
||||
DBOperationResult getObject(const QVariant &requester,
|
||||
const PKG::DBObject &templateObj,
|
||||
QSharedPointer<PKG::DBObject> &result) const;
|
||||
|
||||
/**
|
||||
* @brief getObjects This method try get objects by template object.
|
||||
* @note If you want to get any objects use only this method because this method check permission of requester to execute this action
|
||||
* @param requester This is pointer to network member that send this request.
|
||||
* @param templateObj This is pointer to object of database with data for generation the sql select request.
|
||||
* @param result This is reference to the list of result objects.
|
||||
* @return result of operation (allow, forbidden, unknown).
|
||||
* For more information about results see the DBOperationResult enum.
|
||||
*/
|
||||
DBOperationResult getObjects(const QVariant &requester,
|
||||
const PKG::DBObject &templateObj,
|
||||
QList<QSharedPointer<PKG::DBObject>> &result) const;
|
||||
|
||||
/**
|
||||
* @brief updateObject This method try save or update database object.
|
||||
* @note If you want to save or update any objects use only this method because this method check permission of requester to execute this action
|
||||
* @param requester This is network mebmer that send this request.
|
||||
* @param saveObject This is pointer to object of database for save or update.
|
||||
* @return result of operation (allow, forbidden, unknown).
|
||||
* For more information about results see the DBOperationResult enum.
|
||||
*/
|
||||
DBOperationResult updateObject(const QVariant &requester,
|
||||
const QSharedPointer<PKG::DBObject> &saveObject);
|
||||
|
||||
/**
|
||||
* @brief createObject This method create a new object in the database and add all permissions for the objects creator.
|
||||
* @note If you want to create any objects use only this method because this method check permission of requester to execute this action
|
||||
* @param requester This is network member that send this request.
|
||||
* @param obj This is pointer to object of database for save or update.
|
||||
* @return result of operation (allow, forbidden, unknown).
|
||||
* For more information about results see the DBOperationResult enum.
|
||||
*/
|
||||
DBOperationResult createObject(const QVariant &requester,
|
||||
const QSharedPointer<PKG::DBObject> &obj);
|
||||
|
||||
/**
|
||||
* @brief updateIfNotExistsCreateObject This is wraper of the updateObject and createObjects methods.
|
||||
* 1. Try update object
|
||||
* 2. If object not exists Try create new object.
|
||||
* 3. Return operation result
|
||||
* @param requester This is network member that send this request.
|
||||
* @param obj This is initializing object.
|
||||
* @return result of operation (allow, forbidden, unknown).
|
||||
* For more information about results see the DBOperationResult enum.
|
||||
*/
|
||||
DBOperationResult updateIfNotExistsCreateObject(const QVariant &requester,
|
||||
const QSharedPointer<PKG::DBObject> &obj);
|
||||
|
||||
/**
|
||||
* @brief changeObjects This is wrapper of the "ISqlDBCache::changeObjects" method.
|
||||
* Key difference between a base method is checking of the permision for needed action.
|
||||
* @note If you want to change any objects use only this method because this method check permission of requester to execute this action
|
||||
* @param requester This is network member that send this request.
|
||||
* @param templateObj This is pointer to object of database with data for generation the sql select request.
|
||||
* @param changeAction This is action function for change all selected objects.
|
||||
* @return result of operation (allow, forbidden, unknown).
|
||||
* For more information about results see the DBOperationResult enum.
|
||||
*/
|
||||
DBOperationResult changeObjects(const QVariant &requester,
|
||||
const PKG::DBObject &templateObj,
|
||||
const std::function<bool (const QSharedPointer<QH::PKG::DBObject>&)> &changeAction);
|
||||
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* @brief localNodeName This method return local node name.
|
||||
*
|
||||
* @return local node name
|
||||
*/
|
||||
const QString &localNodeName() const;
|
||||
|
||||
/**
|
||||
* @brief setLocalNodeName This method sets new local name of database file.
|
||||
* @note This method must be invoked before the DataBaseNode::initsqlDb and the DataBaseNode::run methods.
|
||||
* @param newLocalNodeName This is new name of node object and node databae file.
|
||||
*
|
||||
*/
|
||||
void setLocalNodeName(const QString &newLocalNodeName);
|
||||
|
||||
/**
|
||||
* @brief initDefaultDbObjects This method create a default cache and database writer objects if the input pointers is null
|
||||
* Override this method for create a custom database objects for your node class.
|
||||
* @note If you override this object then you no longer need to overload the run method to set your own controls.
|
||||
* This method invoked automatically when you call the DataBaseNode::run method.
|
||||
* @param cache This is Cache database object.
|
||||
* @param writer This is Database writerObject.
|
||||
*/
|
||||
virtual void initDefaultDbObjects(ISqlDBCache *cache, SqlDBWriter *writer);
|
||||
|
||||
/**
|
||||
* @brief changeTrust This implementation of change trust is change trust node or user by self id.
|
||||
* All changes of trust saving into local database.
|
||||
* @param id This is id of user of other network member object.
|
||||
* @param diff This is difference of trust.
|
||||
* @return true if trust of user changed successful.
|
||||
*/
|
||||
virtual bool changeTrust(const QVariant &id, int diff);
|
||||
|
||||
/**
|
||||
* @brief memberSubsribed This method invoked when client with @a clientId subscribed on object with @a subscribeId.
|
||||
* @param clientId This is id of the client member.
|
||||
* @param subscribeId This is id of the subscribeObject.
|
||||
*/
|
||||
virtual void memberSubsribed(const QVariant &clientId, unsigned int subscribeId);
|
||||
|
||||
/**
|
||||
* @brief memberUnSubsribed This method invoked when client with @a clientId unsubsribed on object with @a subscribeId
|
||||
* @param clientId This is id of the client member.
|
||||
* @param subscribeId This is id of the subscribeObject.
|
||||
*/
|
||||
virtual void memberUnsubsribed(const QVariant &clientId, unsigned int subscribeId);
|
||||
|
||||
/**
|
||||
* @brief db This node return pointer to database object.
|
||||
* @return The pointer to data base.
|
||||
*/
|
||||
ISqlDBCache* db() const;
|
||||
|
||||
/**
|
||||
* @brief getSender This method return id of requester.
|
||||
* By Default base implementation get id from BaseNdoeInfo.
|
||||
* override this method for correctly work of the DataBaseNode::ParsePacakge method.
|
||||
* @param connectInfo This is info about connection.
|
||||
* @param requestData This is data of request.
|
||||
* @return id of requester member.
|
||||
*/
|
||||
virtual QVariant getSender(const AbstractNodeInfo *connectInfo, const PKG::AbstractData *requestData) const;
|
||||
|
||||
/**
|
||||
* @brief checkPermision This method check a permision of requester, to database object with objectAddress.
|
||||
* Override this method if you have a custom database structure.
|
||||
* @param requester This is user, node or another object of network
|
||||
* @param objectAddress This is address to database object
|
||||
* @param requarimentPermision This is needed permission for requester
|
||||
* @return DBOperationResult::Alowed if permission granted.
|
||||
* For more information about result see the DBOperationResult enum.
|
||||
*/
|
||||
virtual DBOperationResult checkPermission(const QVariant &requester,
|
||||
const DbAddress& objectAddress,
|
||||
const Permission& requarimentPermision) const;
|
||||
|
||||
|
||||
/**
|
||||
* @brief addUpdatePermission This method added or update permission for member.
|
||||
* @warning This method do not have a validation. It is just change a NetworkMembers table, so use this carefully.
|
||||
* @param member This is member id (user of node).
|
||||
* @param objectAddress This is database object for which the permissions will be set.
|
||||
* @param permision This is permission level.
|
||||
* @param defaultPermision This is default permision for all of rest objects. By default This is Permission::Read
|
||||
* @return true if method finished successful.
|
||||
*/
|
||||
virtual bool addUpdatePermission(const QVariant &member,
|
||||
const DbAddress& objectAddress,
|
||||
const Permission& permision,
|
||||
const Permission& defaultPermision = Permission::Read) const;
|
||||
|
||||
/**
|
||||
* @brief removePermission This method use to removed permission for member.
|
||||
* @warning This method do not have a validation. It is just change a NetworkMembers table, so use this carefully.
|
||||
* @param member This is member id (user of node)
|
||||
* @param objectAddress This is database object for which the permissions will be removed
|
||||
* @return true if method finished successful.
|
||||
*/
|
||||
virtual bool removePermission(const QVariant &member,
|
||||
const DbAddress& objectAddress) const;
|
||||
|
||||
/**
|
||||
* @brief dbLocation This method return location of nodes or clients database.
|
||||
* @return path to the location of database.
|
||||
*/
|
||||
QString dbLocation() const;
|
||||
|
||||
/**
|
||||
* @brief welcomeAddress This method send to the node information about self.
|
||||
* Override this method if you want send custom data to incoming connection.
|
||||
* @param node This is info object of the peer node.
|
||||
* @return true if all information sender successful.
|
||||
*/
|
||||
virtual bool welcomeAddress(AbstractNodeInfo *node);
|
||||
|
||||
/**
|
||||
* @brief isBanned This method check trust of node, if node trust is lover of 0 return true.
|
||||
* @param member This is member of network (node, client or server).
|
||||
* @return true if node is banned.
|
||||
*/
|
||||
bool isBanned(const QVariant &member) const;
|
||||
|
||||
/**
|
||||
* @brief SQLSources This method contains list of sqldatabase sources.
|
||||
* This method will be invoked into initialize sql method and deploy sql database.
|
||||
*
|
||||
* All sql files will be deployed in QList order.
|
||||
*
|
||||
* By Default This method deploy next sql code:
|
||||
* \code{sql}
|
||||
* CREATE TABLE IF NOT EXISTS NetworkMembers (
|
||||
id VARCHAR(64) PRIMARY KEY NOT NULL,
|
||||
authenticationData BLOB default NULL,
|
||||
trust INTEGER default 0
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS MemberPermisions (
|
||||
memberId VARCHAR(64) NOT NULL,
|
||||
objectTable VARCHAR(100) NOT NULL,
|
||||
objectId VARCHAR(64) NOT NULL,
|
||||
lvl INTEGER NOT NULL,
|
||||
|
||||
FOREIGN KEY(memberId) REFERENCES NetworkMembers(id)
|
||||
ON UPDATE CASCADE
|
||||
ON DELETE CASCADE
|
||||
|
||||
);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS MemberPermisionsIndex ON MemberPermisions(memberId, objectTable, objectId);
|
||||
|
||||
* \endcode
|
||||
* For add own sql code just override this method, but do not forget invoke a base method of a parent class.
|
||||
*
|
||||
* Example:
|
||||
* \code{cpp}
|
||||
* return DataBaseNode::SQLSources() << "path/to/mySqlFile.sql";
|
||||
* \endcode
|
||||
*
|
||||
* @return the list to deploy sql files.
|
||||
*/
|
||||
virtual QStringList SQLSources() const;
|
||||
|
||||
/**
|
||||
* @brief systemTables This method return the set of tables that forbidden for users.
|
||||
* By default is NetworkMembers and MemberPermisions tables.
|
||||
* @return set of tables names.
|
||||
*/
|
||||
virtual QSet<QString> systemTables() const;
|
||||
|
||||
/**
|
||||
* @brief notifyObjectChanged This method send all subscriptions message with this object.
|
||||
* @param item changed object.
|
||||
* @return true if an item object sendible.
|
||||
*/
|
||||
bool notifyObjectChanged(const QSharedPointer<PKG::ISubscribableData> &item);
|
||||
|
||||
/**
|
||||
* @brief objectRemoved This method invoked when object with @a address removed from database.
|
||||
* Oberride this method for handle this event. Default implementation do nothing.
|
||||
* @param address This is address of the deteted object.
|
||||
*/
|
||||
virtual void objectRemoved(const DbAddress& address);
|
||||
|
||||
/**
|
||||
* @brief objectChanged This method invoked when object with @a address changed in database.
|
||||
* Override this method for handle this event. Default implementation do nothing.
|
||||
* @param obj This is address of the changed object.
|
||||
*/
|
||||
virtual void objectChanged(const QSharedPointer<PKG::DBObject>& obj);
|
||||
|
||||
/**
|
||||
* @brief dbPatches This method should be return map with functions that upgrade production data base.
|
||||
* Eeach function shoul be can upgrade databae from preview version to own version.
|
||||
* **Example**:
|
||||
*
|
||||
* We have 4 version of data base {0, 1, 2, 3} each version should be contains own function for upgrade data base.
|
||||
* Where the 0 version is first version of database. (genesis)
|
||||
*
|
||||
* @code{cpp}
|
||||
* QH::DBPatchMap dbPatches() const {
|
||||
QH::DBPatchMap result;
|
||||
|
||||
result += [](const QH::iObjectProvider* database) -> bool {
|
||||
// Some code for update from 0 to 1
|
||||
};
|
||||
|
||||
result += [](const QH::iObjectProvider* database) -> bool {
|
||||
// Some code for update from 1 to 2
|
||||
};
|
||||
|
||||
result += [](const QH::iObjectProvider* database) -> bool {
|
||||
// Some code for update from 2 to 3
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
* @endcode
|
||||
*
|
||||
* @return Map of database pactches.
|
||||
*
|
||||
* @see DBPatchMap
|
||||
* @see DBPatch
|
||||
*/
|
||||
virtual DBPatchMap dbPatches() const;
|
||||
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief workWithSubscribe This method work with subscribe commnads.
|
||||
* @param rec This is request data.
|
||||
* @param address This is sender address.
|
||||
* @return true if data parsed successful.
|
||||
*/
|
||||
bool workWithSubscribe(const PKG::WebSocket &rec,
|
||||
const QVariant &clientOrNodeid,
|
||||
const AbstractNodeInfo *sender);
|
||||
|
||||
|
||||
bool isForbidenTable(const QString& table);
|
||||
|
||||
/**
|
||||
* @brief upgradeDataBase This method upgrade data base to actyaly database version.
|
||||
* @note The last version of dbPatches is actyaly version.
|
||||
* @return true if operation finished successful
|
||||
*/
|
||||
bool upgradeDataBase();
|
||||
|
||||
ISqlDBCache *_db = nullptr;
|
||||
QString _localNodeName;
|
||||
WebSocketController *_webSocketWorker = nullptr;
|
||||
|
||||
|
||||
friend class WebSocketController;
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(QSharedPointer<QH::PKG::DBObject>)
|
||||
#endif // QH_DATABASE_H
|
@ -454,7 +454,7 @@ protected:
|
||||
|
||||
private slots:
|
||||
void handleObjectChanged(const QSharedPointer<PKG::DBObject> &item);
|
||||
void handleObjectDeleted(const DbAddress &item);
|
||||
void handleObjectDeleted(const QH::DbAddress &item);
|
||||
|
||||
|
||||
private:
|
||||
|
Loading…
x
Reference in New Issue
Block a user