diff --git a/sources/CMakeLists.txt b/sources/CMakeLists.txt index 32738c9..770d40b 100644 --- a/sources/CMakeLists.txt +++ b/sources/CMakeLists.txt @@ -32,6 +32,7 @@ message(STATUS "Build date: ${CURRENT_DATE}") option(BUILD_DEB_PACKAGE "Build deb package" OFF) option(BUILD_RPM_PACKAGE "Build rpm package" OFF) # build details +option(BUILD_DOCS "Build Doxygen documentation" OFF) option(BUILD_FUTURE "Build with the features which will be marked as stable later" OFF) option(BUILD_LOAD "Build with additional load" OFF) option(BUILD_TESTING "Build with additional test abilities" OFF) diff --git a/sources/queued/doxygen.conf.in b/sources/queued/doxygen.conf.in index 38be489..a767ceb 100644 --- a/sources/queued/doxygen.conf.in +++ b/sources/queued/doxygen.conf.in @@ -51,7 +51,7 @@ PROJECT_BRIEF = "Daemon to start jobs in queue" # pixels and the maximum width should not exceed 200 pixels. Doxygen will copy # the logo to the output directory. -PROJECT_LOGO = @CMAKE_CURRENT_SOURCE_DIR@/../resources/icon.png +PROJECT_LOGO = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is @@ -775,7 +775,7 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = @CMAKE_CURRENT_SOURCE_DIR@/include/quadro +INPUT = @CMAKE_CURRENT_SOURCE_DIR@/include/queued # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/sources/queued/include/queued/Queued.h b/sources/queued/include/queued/Queued.h index e374e71..8098e94 100644 --- a/sources/queued/include/queued/Queued.h +++ b/sources/queued/include/queued/Queued.h @@ -26,7 +26,9 @@ #include "QueuedDatabase.h" #include "QueuedDebug.h" +#include "QueuedEnums.h" #include "QueuedProcess.h" #include "QueuedProcessManager.h" +#include "QueuedUser.h" #endif /* QUEUED_H */ diff --git a/sources/queued/include/queued/QueuedDatabase.h b/sources/queued/include/queued/QueuedDatabase.h index 9ecebf5..676b2a1 100644 --- a/sources/queued/include/queued/QueuedDatabase.h +++ b/sources/queued/include/queued/QueuedDatabase.h @@ -50,10 +50,45 @@ public: * @brief QueuedDatabase class destructor */ virtual ~QueuedDatabase(); + /** + * @brief add record to database + * @param _table table name + * @param _value value to insert + * @return true on success + */ + bool add(const QString &_table, const QVariantHash &_value); /** * @brief check and create database */ void checkDatabase(); + /** + * @brief check and create queued administrator if missing + * @param _user administrator username + * @param _password administrator password SHA512 + */ + void createAdministrator(const QString &_user, const QString &_password); + /** + * @brief get all records from table + * @param _table table name + * @return list of records from table + */ + QList get(const QString &_table); + /** + * @brief get record from table with given id + * @param _table table name + * @param _id record id + * @return variant map from table + */ + QVariantHash get(const QString &_table, const long long _id); + /** + * @brief modify record in table + * @param _table table name + * @param _id id for search + * @param _value value to update + * @return true on successfully modification + */ + bool modify(const QString &_table, const long long _id, + const QVariantHash &_value); /** * @brief open database * @param _hostname hostname to connect, may be empty @@ -62,8 +97,8 @@ public: * @param _password password to connect, will be ignored if _username * is empty */ - void open(const QString _hostname, const int _port, const QString _username, - const QString _password); + void open(const QString &_hostname, const int _port, + const QString &_username, const QString &_password); /** * @brief path to database * @return path to used database @@ -83,12 +118,28 @@ private: * @brief create or update actual schema in table * @param _table table name */ - void createSchema(const QString _table); + void createSchema(const QString &_table); /** * @brief create given table * @param _table table name */ - void createTable(const QString _table); + void createTable(const QString &_table); + /** + * @brief additional function to get column numbers from table + * @param _columns columns mapping + * @param _record SQL record from query + * @return map of column names to their numbers + */ + QHash getColumnsInRecord(const QStringList &_columns, + const QSqlRecord &_record) const; + /** + * @brief additional function to get payload for query + * @param _table table name for search + * @param _value value to build payload + * @return list of keys and list of values + */ + QPair + getQueryPayload(const QString &_table, const QVariantHash &_value) const; }; #endif /* QUEUEDDATABASE_H */ diff --git a/sources/queued/include/queued/QueuedDatabaseSchema.h b/sources/queued/include/queued/QueuedDatabaseSchema.h index 2569ebc..111e07b 100644 --- a/sources/queued/include/queued/QueuedDatabaseSchema.h +++ b/sources/queued/include/queued/QueuedDatabaseSchema.h @@ -55,13 +55,14 @@ typedef QHash> QueuedDBSchema; */ namespace QueuedDB { +/** + * @brief database schema + */ const QueuedDBSchema DBSchema = { {"users", {{"_id", {"_id", "INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE", QVariant::LongLong}}, {"name", {"name", "TEXT NOT NULL DEFAULT '0'", QVariant::String}}, - {"uid", {"uid", "INT NOT NULL DEFAULT 0", QVariant::UInt}}, - {"gid", {"gid", "INT NOT NULL DEFAULT 0", QVariant::UInt}}, {"passwordSHA512", {"passwordSHA512", "TEXT", QVariant::String}}, {"email", {"email", "TEXT", QVariant::String}}, {"cpu", {"cpu", "INT", QVariant::LongLong}}, @@ -69,7 +70,7 @@ const QueuedDBSchema DBSchema = { {"memory", {"memory", "INT", QVariant::LongLong}}, {"gpumemory", {"gpumemory", "INT", QVariant::LongLong}}, {"storage", {"storage", "INT", QVariant::LongLong}}, - {"permissions", {"permissions", "INT", QVariant::LongLong}}}}, + {"permissions", {"permissions", "INT", QVariant::UInt}}}}, {"tasks", {{"_id", {"_id", "INTEGER PRIMARY KEY AUTOINCREMENT UNIQUE", QVariant::LongLong}}, @@ -77,7 +78,7 @@ const QueuedDBSchema DBSchema = { {"command", {"command", "TEXT", QVariant::String}}, {"arguments", {"arguments", "TEXT", QVariant::String}}, {"workDirectory", {"workDirectory", "TEXT", QVariant::String}}, - {"nice", {"nice", "INT", QVariant::Int}}, + {"nice", {"nice", "INT", QVariant::UInt}}, {"startTime", {"startTime", "INT", QVariant::LongLong}}, {"endTime", {"endTime", "INT", QVariant::LongLong}}}}}; }; diff --git a/sources/queued/include/queued/QueuedEnums.h b/sources/queued/include/queued/QueuedEnums.h new file mode 100644 index 0000000..ec83c72 --- /dev/null +++ b/sources/queued/include/queued/QueuedEnums.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2016 Evgeniy Alekseev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + */ +/** + * @file QueuedEnums.h + * Header of Queued library + * @author Evgeniy Alekseev + * @copyright MIT + * @bug https://github.com/arcan1s/queued/issues + */ + + +#ifndef QUEUEDENUMS_H +#define QUEUEDENUMS_H + + +/** + * @defgroup QueuedEnums + * @brief Queued enumerations + */ +namespace QueuedEnums +{ +/** + * @enum LimitType + * @brief available limit types + * @var LimitType::CPUThreads + * limit on CPU threads count + * @var LimitType::GPUThreads + * limit on GPU threads count + * @var LimitType::Memory + * limit on physical memory + * @var LimitType::GPUMemory + * limit on GPU memory + * @var LimitType::Storage + * limit on storage + */ +enum LimitType { + CPUThreads = 1 << 0, + GPUThreads = 1 << 1, + Memory = 1 << 2, + GPUMemory = 1 << 3, + Storage = 1 << 4 +}; +Q_DECLARE_FLAGS(LimitTypes, LimitType) +Q_DECLARE_OPERATORS_FOR_FLAGS(LimitTypes) + + +/** + * @enum Permissions + * @brief available user permissions + * @var Permissions::Admin + * administrative permissions + * @var Permissions::JobOwner + * owner job related permissions + * @var Permissions::JobGlobal + * other users job control + * @var Permissions::User + * user related permissions + * @var Permissions::Web + * web server access + * @var Permissions::Reports + * access to reports + */ +enum class Permission { + SuperAdmin = 1 << 0, + Admin = 1 << 1, + JobOwner = 1 << 2, + JobGlobal = 1 << 3, + User = 1 << 4, + Web = 1 << 5, + Reports = 1 << 6 +}; +Q_DECLARE_FLAGS(Permissions, Permission) +Q_DECLARE_OPERATORS_FOR_FLAGS(Permissions) +}; + + +#endif /* QUEUEDENUMS_H */ diff --git a/sources/queued/include/queued/QueuedProcess.h b/sources/queued/include/queued/QueuedProcess.h index 069b292..d139075 100644 --- a/sources/queued/include/queued/QueuedProcess.h +++ b/sources/queued/include/queued/QueuedProcess.h @@ -27,6 +27,8 @@ #include #include +#include "QueuedEnums.h" + /** * @struct QueuedProcessDefinition @@ -46,8 +48,8 @@ typedef struct { QString cmd; QStringList args; QString workingDirectory; - int uid; - int gid; + unsigned int uid; + unsigned int gid; } QueuedProcessDefinitions; @@ -61,28 +63,6 @@ class QueuedProcess : public QProcess Q_PROPERTY(QString name READ name) public: - /** - * @enum LimitType - * @brief available limit types - * @var LimitType::CPUThreads - * limit on CPU threads count - * @var LimitType::GPUThreads - * limit on GPU threads count - * @var LimitType::Memory - * limit on physical memory - * @var LimitType::GPUMemory - * limit on GPU memory - * @var LimitType::Storage - * limit on storage - */ - enum class LimitType { - CPUThreads = 1, - GPUThreads = 2, - Memory = 4, - GPUMemory = 8, - Storage = 16 - }; - /** * @brief QueuedProcess class constructor * @param parent pointer to parent item @@ -110,20 +90,20 @@ public: * @brief remove limit * @param _limitType limit type */ - virtual void removeLimit(const LimitType _limitType); + virtual void removeLimit(const QueuedEnums::LimitType _limitType); /** * @brief set limit * @param _limitType limit type * @param _value limit value */ - virtual void setLimit(const LimitType _limitType, - const QVariant _value = QVariant()); + virtual void setLimit(const QueuedEnums::LimitType _limitType, + const QVariant &_value = QVariant()); /** * @brief equal operator implementation * @param _other other object * @return true if objects are equal */ - bool operator==(const QueuedProcess _other); + bool operator==(const QueuedProcess &_other); protected: /** @@ -149,7 +129,7 @@ private: /** * @brief limits array */ - QMap m_limits; + QMap m_limits; /** * @brief convert QString memory value to integer * @param _value value to convert diff --git a/sources/queued/include/queued/QueuedProcessManager.h b/sources/queued/include/queued/QueuedProcessManager.h index caae4d7..7e8a2ee 100644 --- a/sources/queued/include/queued/QueuedProcessManager.h +++ b/sources/queued/include/queued/QueuedProcessManager.h @@ -28,7 +28,7 @@ #include #include -#include "queued/QueuedProcess.h" +#include "QueuedProcess.h" /** @@ -100,6 +100,11 @@ public: * @param _index task index */ void remove(const long long _index); + /** + * @brief force stop task + * @param _index task index + */ + void stop(const long long _index); signals: /** diff --git a/sources/queued/include/queued/QueuedUser.h b/sources/queued/include/queued/QueuedUser.h new file mode 100644 index 0000000..d4e3876 --- /dev/null +++ b/sources/queued/include/queued/QueuedUser.h @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2016 Evgeniy Alekseev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + */ +/** + * @file QueuedUser.h + * Header of Queued library + * @author Evgeniy Alekseev + * @copyright MIT + * @bug https://github.com/arcan1s/queued/issues + */ + + +#ifndef QUEUEDUSER_H +#define QUEUEDUSER_H + +#include +#include + +#include "QueuedEnums.h" + + +/** + * @struct QueuedUserDefinition + * @brief structure to define user + * @var name + * user name + * @var email + * user email + * @var passwordSHA512 + * password hash, may be empty + * @var permissions + * user permissions + * @var cpuLimit + * user limit by CPU + * @var gpuLimit + * user limit by GPU + * @var memoryLimit + * user limit by memory + * @var gpumemoryLimit + * user limit by GPU memory + * @var storageLimit + * user limit by storage + */ +typedef struct { + QString name; + QString email; + QString passwordSHA512; + unsigned int permissions; + long long cpuLimit; + long long gpuLimit; + long long memoryLimit; + long long gpumemoryLimit; + long long storageLimit; +} QueuedUserDefinitions; + + +/** + * @brief representation of user in queued + */ +class QueuedUser : public QObject +{ + Q_OBJECT + Q_PROPERTY(long long index READ index) + // generic properties + Q_PROPERTY(QString email READ email WRITE setEmail NOTIFY userUpdated) + Q_PROPERTY(QString name READ name WRITE setName NOTIFY userUpdated) + Q_PROPERTY( + QString password READ password WRITE setPassword NOTIFY userUpdated) + Q_PROPERTY(unsigned int permissions READ permissions WRITE setPermissions + NOTIFY userUpdated) + // limits + Q_PROPERTY( + long long cpuLimit READ cpuLimit WRITE setCpuLimit NOTIFY userUpdated) + Q_PROPERTY( + long long gpuLimit READ gpuLimit WRITE setGpuLimit NOTIFY userUpdated) + Q_PROPERTY(long long memoryLimit READ memoryLimit WRITE setMemoryLimit + NOTIFY userUpdated) + Q_PROPERTY(long long gpumemoryLimit READ gpumemoryLimit WRITE + setGpumemoryLimit NOTIFY userUpdated) + Q_PROPERTY(long long storageLimit READ storageLimit WRITE setStorageLimit + NOTIFY userUpdated) + +public: + /** + * @brief QueuedUser class constructor + * @param parent pointer to parent item + * @param definitions definitions of user + * @param index index of process + */ + explicit QueuedUser(QObject *parent, + const QueuedUserDefinitions &definitions, + const long long index); + /** + * @brief QueuedUser class destructor + */ + virtual ~QueuedUser(); + // methods + /** + * @brief add permissions to user + * @param _permissions new user permissions + * @return current user permissions + */ + QueuedEnums::Permissions + addPermissions(const QueuedEnums::Permissions _permissions); + /** + * @brief generates SHA512 hash from given password + * @param _password password as string + * @return SHA512 of password + */ + static QString hashFromPassword(const QString &_password); + /** + * @brief test user permissions + * @param _permission permission to test + * @return true if user has permission otherwise return false + */ + bool hasPermission(const QueuedEnums::Permission _permission); + /** + * @brief check if password is valid + * @param _password password as string + * @return true if password matches stored hash + */ + bool isPasswordValid(const QString &_password) const; + /** + * @brief remove permissions from user + * @param _permissions permissions to remove + * @return current user permissions + */ + QueuedEnums::Permissions + removePermissions(const QueuedEnums::Permissions _permissions); + // main properties + /** + * @brief user email + * @return assigned user email + */ + QString email() const; + /** + * @brief index of user + * @return assigned index of user + */ + long long index() const; + /** + * @brief username + * @return name of user associated with system one + */ + QString name() const; + /** + * @brief user password + * @return SHA512 of user password + */ + QString password() const; + /** + * @brief user permissions + * @return sum of user permissions from QueuedUser::Permissions + */ + unsigned int permissions() const; + // permissions + /** + * @brief cpu limit + * @return cpu limit in cores + */ + long long cpuLimit() const; + /** + * @brief gpu limit + * @return gpu limit in cores + */ + long long gpuLimit() const; + /** + * @brief memory limit + * @return memory limit in bytes + */ + long long memoryLimit() const; + /** + * @brief GPU memory limit + * @return GPU memory limit in bytes + */ + long long gpumemoryLimit() const; + /** + * @brief storage limit + * @return storage limit in bytes + */ + long long storageLimit() const; + // main properties + /** + * @brief set user email + * @param _email new user email + */ + void setEmail(const QString _email); + /** + * @brief set username + * @param _name new user name + */ + void setName(const QString _name); + /** + * @brief set user password + * @param _password new user password + */ + void setPassword(const QString _password); + /** + * @brief set user permissions + * @param _permissions new user permissions + */ + void setPermissions(const unsigned int _permissions); + // permissions + /** + * @brief set cpu limit + * @param _cpuLimit new cpu limit in cores + */ + void setCpuLimit(const long long _cpuLimit); + /** + * @brief set gpu limit + * @param _gpuLimit new gpu limit in cores + */ + void setGpuLimit(const long long _gpuLimit); + /** + * @brief set memory limit + * @param _memoryLimit new memory limit in bytes + */ + void setMemoryLimit(const long long _memoryLimit); + /** + * @brief set GPU memory limit + * @param _gpumemoryLimit new GPU memory limit in bytes + */ + void setGpumemoryLimit(const long long _gpumemoryLimit); + /** + * @brief set storage limit + * @param _storageLimit new storage limit in bytes + */ + void setStorageLimit(const long long _storageLimit); + /** + * @brief equal operator implementation + * @param _other other object + * @return true if objects are equal + */ + bool operator==(const QueuedUser &_other); + +signals: + /** + * @brief signal which emits on any property set action + */ + void userUpdated(); + +private: + /** + * @brief process definitions + */ + QueuedUserDefinitions m_definitions; + /** + * @brief index of user + */ + long long m_index = -1; +}; + +#endif /* QUEUEDUSER_H */ diff --git a/sources/queued/src/QueuedDatabase.cpp b/sources/queued/src/QueuedDatabase.cpp index 337a364..131a5b7 100644 --- a/sources/queued/src/QueuedDatabase.cpp +++ b/sources/queued/src/QueuedDatabase.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "queued/QueuedDatabaseSchema.h" @@ -55,24 +56,27 @@ QueuedDatabase::~QueuedDatabase() /** - * @fn open + * @fn add */ -void QueuedDatabase::open(const QString _hostname, const int _port, - const QString _username, const QString _password) +bool QueuedDatabase::add(const QString &_table, const QVariantHash &_value) { - qCDebug(LOG_LIB) << "Open database at" << _hostname << _port << "as user" - << _username; + qCDebug(LOG_LIB) << "Add record" << _value << "to table" << _table; - if (!_hostname.isEmpty()) - m_database.setHostName(_hostname); - if (_port > 0) - m_database.setPort(_port); - bool status = _username.isEmpty() ? m_database.open() - : m_database.open(_username, _password); + auto payload = getQueryPayload(_table, _value); + // build query + QSqlQuery query + = m_database.exec(QString("INSERT INTO %1 (%2) VALUES (%3)") + .arg(_table) + .arg(payload.first.join(QChar(','))) + .arg(payload.second.join(QChar(',')))); + QSqlError error = query.lastError(); + if (error.isValid()) { + qCCritical(LOG_LIB) << "Could not add record" << _value << "to table" + << _table << "message" << error.text(); + return false; + } - qCDebug(LOG_LIB) << "Open database status" << status; - if (status) - return checkDatabase(); + return true; } @@ -93,6 +97,151 @@ void QueuedDatabase::checkDatabase() } +/** + * @fn createAdministrator + */ +void QueuedDatabase::createAdministrator(const QString &_user, + const QString &_password) +{ + qCDebug(LOG_LIB) << "Check for user" << _user; + QString table("users"); + + QSqlQuery query = m_database.exec( + QString("SELECT * FROM '%1' WHERE name='%2'").arg(table).arg(_user)); + QSqlError error = query.lastError(); + if (error.isValid()) + qCWarning(LOG_LIB) << "Could not get record" << _user << "from" << table + << "message" << error.text(); + else if (query.size() > 0) + return; + + qCInfo(LOG_LIB) << "Create administrator user" << _user; + QVariantHash payload = { + {"name", _user}, + {"password", _password}, + {"permissions", static_cast(QueuedEnums::Permission::SuperAdmin)}}; + + if (!add(table, payload)) + qCCritical(LOG_LIB) << "Could not create administrator"; +} + + +/** + * @fn get + */ +QList QueuedDatabase::get(const QString &_table) +{ + qCDebug(LOG_LIB) << "Get records in table" << _table; + + QList output; + QSqlQuery query = m_database.exec( + QString("SELECT * FROM '%1' ORDER BY _id DESC").arg(_table)); + + QSqlError error = query.lastError(); + if (error.isValid()) { + qCWarning(LOG_LIB) << "Could not get records from" << _table + << "message" << error.text(); + return output; + } + QSqlRecord record = query.record(); + + QStringList columns = QueuedDB::DBSchema[_table].keys(); + auto dbColumns = getColumnsInRecord(columns, record); + while (query.next()) { + QVariantHash entry; + for (auto &column : columns) + entry[column] = query.value(dbColumns[column]); + output.append(entry); + } + + return output; +} + + +/** + * @fn get + */ +QVariantHash QueuedDatabase::get(const QString &_table, const long long _id) +{ + qCDebug(LOG_LIB) << "Get record" << _id << "in table" << _table; + + QVariantHash output; + QSqlQuery query = m_database.exec( + QString("SELECT * FROM '%1' WHERE _id=%2").arg(_table).arg(_id)); + + QSqlError error = query.lastError(); + if (error.isValid()) { + qCWarning(LOG_LIB) << "Could not get record" << _id << "from" << _table + << "message" << error.text(); + return output; + } + QSqlRecord record = query.record(); + + QStringList columns = QueuedDB::DBSchema[_table].keys(); + auto dbColumns = getColumnsInRecord(columns, record); + while (query.next()) { + output.clear(); + for (auto &column : columns) + output[column] = query.value(dbColumns[column]); + } + + return output; +} + + +/** + * @fn modify + */ +bool QueuedDatabase::modify(const QString &_table, const long long _id, + const QVariantHash &_value) +{ + qCDebug(LOG_LIB) << "Modify record" << _id << "in table" << _table + << "with value" << _value; + + auto payload = getQueryPayload(_table, _value); + QStringList stringPayload; + for (int i = 0; i < payload.first.count(); i++) + stringPayload.append(QString("%1='%2'") + .arg(payload.first.at(i)) + .arg(payload.second.at(i))); + // build query + QSqlQuery query = m_database.exec(QString("UPDATE %1 SET %2 WHERE _id=%3") + .arg(_table) + .arg(stringPayload.join(QChar(','))) + .arg(_id)); + QSqlError error = query.lastError(); + if (error.isValid()) { + qCCritical(LOG_LIB) << "Could not add record" << _value << "to table" + << _table << "message" << error.text(); + return false; + } + + return true; +} + + +/** + * @fn open + */ +void QueuedDatabase::open(const QString &_hostname, const int _port, + const QString &_username, const QString &_password) +{ + qCDebug(LOG_LIB) << "Open database at" << _hostname << _port << "as user" + << _username; + + if (!_hostname.isEmpty()) + m_database.setHostName(_hostname); + if (_port > 0) + m_database.setPort(_port); + bool status = _username.isEmpty() ? m_database.open() + : m_database.open(_username, _password); + + qCDebug(LOG_LIB) << "Open database status" << status; + if (status) + return checkDatabase(); +} + + /** * @fn path */ @@ -105,7 +254,7 @@ QString QueuedDatabase::path() const /** * @fn createSchema */ -void QueuedDatabase::createSchema(const QString _table) +void QueuedDatabase::createSchema(const QString &_table) { qCDebug(LOG_LIB) << "Create schema for" << _table; @@ -138,7 +287,7 @@ void QueuedDatabase::createSchema(const QString _table) /** * @fn createTable */ -void QueuedDatabase::createTable(const QString _table) +void QueuedDatabase::createTable(const QString &_table) { qCDebug(LOG_LIB) << "Create table" << _table; @@ -150,3 +299,47 @@ void QueuedDatabase::createTable(const QString _table) qCCritical(LOG_LIB) << "Could not create table" << _table << "error:" << error.text(); } + + +/** + * @fn getColumnsInRecord + */ +QHash +QueuedDatabase::getColumnsInRecord(const QStringList &_columns, + const QSqlRecord &_record) const +{ + qCDebug(LOG_LIB) << "Search for columns" << _columns; + + return std::accumulate( + _columns.begin(), _columns.end(), QHash(), + [&_record](QHash &map, const QString &column) { + map[column] = _record.indexOf(column); + return map; + }); +} + + +/** + * @fn getQueryPayload + */ +QPair +QueuedDatabase::getQueryPayload(const QString &_table, + const QVariantHash &_value) const +{ + qCDebug(LOG_LIB) << "Add record" << _value << "to table" << _table; + + QStringList keys; + QStringList values; + QStringList schemaColumns = QueuedDB::DBSchema[_table].keys(); + for (auto &key : _value.keys()) { + if (!schemaColumns.contains(key)) { + qCWarning(LOG_LIB) << "No key" << key << "found in schema of" + << _table; + continue; + } + keys.append(key); + values.append(QString("'%1'").arg(_value[key].toString())); + } + + return {keys, values}; +} diff --git a/sources/queued/src/QueuedProcess.cpp b/sources/queued/src/QueuedProcess.cpp index ef958e7..8a3d4f2 100644 --- a/sources/queued/src/QueuedProcess.cpp +++ b/sources/queued/src/QueuedProcess.cpp @@ -77,7 +77,7 @@ QString QueuedProcess::name() const /** * @fn removeLimit */ -void QueuedProcess::removeLimit(const LimitType _limitType) +void QueuedProcess::removeLimit(const QueuedEnums::LimitType _limitType) { qCDebug(LOG_LIB) << "Remove limit" << static_cast(_limitType); @@ -88,7 +88,8 @@ void QueuedProcess::removeLimit(const LimitType _limitType) /** * @fn setLimit */ -void QueuedProcess::setLimit(const LimitType _limitType, const QVariant _value) +void QueuedProcess::setLimit(const QueuedEnums::LimitType _limitType, + const QVariant &_value) { qCDebug(LOG_LIB) << "Set limit" << static_cast(_limitType) << "to" << _value; @@ -111,7 +112,7 @@ void QueuedProcess::setLimit(const LimitType _limitType, const QVariant _value) /** * @fn operator== */ -bool QueuedProcess::operator==(const QueuedProcess _other) +bool QueuedProcess::operator==(const QueuedProcess &_other) { return name() == _other.name(); } diff --git a/sources/queued/src/QueuedProcessManager.cpp b/sources/queued/src/QueuedProcessManager.cpp index bd61ccf..ba0de53 100644 --- a/sources/queued/src/QueuedProcessManager.cpp +++ b/sources/queued/src/QueuedProcessManager.cpp @@ -115,20 +115,44 @@ void QueuedProcessManager::remove(const long long _index) if (!m_processes.contains(_index)) return; - QueuedProcess *process = m_processes.take(_index); + QueuedProcess *pr = m_processes.take(_index); auto connection = m_connections.take(_index); disconnect(connection); switch (m_onExit) { case OnExitAction::Kill: - process->kill(); + pr->kill(); break; case OnExitAction::Terminate: - process->terminate(); + pr->terminate(); break; } - process->deleteLater(); + pr->deleteLater(); +} + + +/** + * @fn stop + */ +void QueuedProcessManager::stop(const long long _index) +{ + qCDebug(LOG_LIB) << "Stop task" << _index; + + auto pr = process(_index); + if (!pr) { + qCWarning(LOG_LIB) << "No task" << _index << "found"; + return; + } + + switch (m_onExit) { + case OnExitAction::Kill: + pr->kill(); + break; + case OnExitAction::Terminate: + pr->terminate(); + break; + } } diff --git a/sources/queued/src/QueuedUser.cpp b/sources/queued/src/QueuedUser.cpp new file mode 100644 index 0000000..c5a463b --- /dev/null +++ b/sources/queued/src/QueuedUser.cpp @@ -0,0 +1,315 @@ +/* + * Copyright (c) 2016 Evgeniy Alekseev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + */ +/** + * @file QueuedUser.cpp + * Source code of queued library + * @author Evgeniy Alekseev + * @copyright GPLv3 + * @bug https://github.com/arcan1s/queued/issues + */ + + +#include "queued/Queued.h" + +#include + + +/** + * @class QueuedUser + */ +/** + * @fn QueuedUser + */ +QueuedUser::QueuedUser(QObject *parent, const QueuedUserDefinitions &definitions, + const long long index) + : QObject(parent) + , m_definitions(definitions) + , m_index(index) +{ + qCDebug(LOG_LIB) << __PRETTY_FUNCTION__; +} + + +/** + * @fn ~QueuedUser + */ +QueuedUser::~QueuedUser() +{ + qCDebug(LOG_LIB) << __PRETTY_FUNCTION__; +} + + +/** + * @fn addPermissions + */ +QueuedEnums::Permissions +QueuedUser::addPermissions(const QueuedEnums::Permissions _permissions) +{ + qCDebug(LOG_LIB) << "Add user permission" << _permissions; + + setPermissions( + static_cast(m_definitions.permissions) + & _permissions); + + return static_cast(m_definitions.permissions); +} + + +/** + * @fn hashFromPassword + */ +QString QueuedUser::hashFromPassword(const QString &_password) +{ + return QCryptographicHash::hash(_password.toUtf8(), + QCryptographicHash::Sha512); +} + + +/** + * @fn hasPermission + */ +bool QueuedUser::hasPermission(const QueuedEnums::Permission _permission) +{ + qCDebug(LOG_LIB) << "Check permissions" << static_cast(_permission); + + if (static_cast(m_definitions.permissions) + .testFlag(QueuedEnums::Permission::SuperAdmin)) + return true; + else + return static_cast(m_definitions.permissions) + .testFlag(_permission); +} + + +/** + * @fn isPasswordValid + */ +bool QueuedUser::isPasswordValid(const QString &_password) const +{ + return (m_definitions.passwordSHA512.toUtf8() + == QCryptographicHash::hash(_password.toUtf8(), + QCryptographicHash::Sha512)); +} + + +QueuedEnums::Permissions +QueuedUser::removePermissions(const QueuedEnums::Permissions _permissions) +{ + qCDebug(LOG_LIB) << "Remove user permission" << _permissions; + + setPermissions( + static_cast(m_definitions.permissions) + & ~_permissions); + + return static_cast(m_definitions.permissions); +} + + +/** + * @fn email + */ +QString QueuedUser::email() const +{ + return m_definitions.email; +} + + +/** + * @fn index + */ +long long QueuedUser::index() const +{ + return m_index; +} + + +/** + * @fn name + */ +QString QueuedUser::name() const +{ + return m_definitions.name; +} + + +/** + * @fn password + */ +QString QueuedUser::password() const +{ + return m_definitions.passwordSHA512; +} + + +/** + * @fn permissions + */ +unsigned int QueuedUser::permissions() const +{ + return m_definitions.permissions; +} + + +/** + * @fn cpuLimit + */ +long long QueuedUser::cpuLimit() const +{ + return m_definitions.cpuLimit; +} + + +/** + * @fn gpuLimit + */ +long long QueuedUser::gpuLimit() const +{ + return m_definitions.gpuLimit; +} + + +/** + * @fn memoryLimit + */ +long long QueuedUser::memoryLimit() const +{ + return m_definitions.memoryLimit; +} + + +/** + * @fn gpumemoryLimit + */ +long long QueuedUser::gpumemoryLimit() const +{ + return m_definitions.gpumemoryLimit; +} + + +/** + * @fn storageLimit + */ +long long QueuedUser::storageLimit() const +{ + return m_definitions.storageLimit; +} + + +/** + * @fn setEmail + */ +void QueuedUser::setEmail(const QString _email) +{ + qCDebug(LOG_LIB) << "New user email" << _email; + + m_definitions.email = _email; +} + + +/** + * @fn setName + */ +void QueuedUser::setName(const QString _name) +{ + qCDebug(LOG_LIB) << "New user name" << _name; + + m_definitions.name = _name; +} + + +/** + * @fn setPassword + */ +void QueuedUser::setPassword(const QString _password) +{ + qCDebug(LOG_LIB) << "New user passoword SHA" << _password; + + m_definitions.passwordSHA512 = _password; +} + + +/** + * @fn setPermissions + */ +void QueuedUser::setPermissions(const unsigned int _permissions) +{ + qCDebug(LOG_LIB) << "New user permissions" << _permissions; + + m_definitions.permissions = _permissions; +} + + +/** + * @fn setCpuLimit + */ +void QueuedUser::setCpuLimit(const long long _cpuLimit) +{ + qCDebug(LOG_LIB) << "New user cpu limit" << _cpuLimit; + + m_definitions.cpuLimit = _cpuLimit; +} + + +/** + * @fn setGpuLimit + */ +void QueuedUser::setGpuLimit(const long long _gpuLimit) +{ + qCDebug(LOG_LIB) << "New user gpu limit" << _gpuLimit; + + m_definitions.gpuLimit = _gpuLimit; +} + + +/** + * @fn setMemoryLimit + */ +void QueuedUser::setMemoryLimit(const long long _memoryLimit) +{ + qCDebug(LOG_LIB) << "New user memory limit" << _memoryLimit; + + m_definitions.memoryLimit = _memoryLimit; +} + + +/** + * @fn setGpumemoryLimit + */ +void QueuedUser::setGpumemoryLimit(const long long _gpumemoryLimit) +{ + qCDebug(LOG_LIB) << "New user gpu memory limit" << _gpumemoryLimit; + + m_definitions.gpumemoryLimit = _gpumemoryLimit; +} + + +/** + * @fn setStorageLimit + */ +void QueuedUser::setStorageLimit(const long long _storageLimit) +{ + qCDebug(LOG_LIB) << "New user storage limit" << _storageLimit; + + m_definitions.storageLimit = _storageLimit; +} + + +/** + * @fn operator== + */ +bool QueuedUser::operator==(const QueuedUser &_other) +{ + return index() == _other.index(); +} diff --git a/sources/version.h.in b/sources/version.h.in index c0414b5..a73e4c0 100644 --- a/sources/version.h.in +++ b/sources/version.h.in @@ -14,6 +14,7 @@ const char SPECIAL_THANKS[] = ""; // configuration // use define here instead of normal const definition for moc +#cmakedefine BUILD_DOCS #cmakedefine BUILD_FUTURE #cmakedefine BUILD_LOAD #cmakedefine BUILD_TESTING @@ -53,6 +54,7 @@ const char COVERITY_EXECUTABLE[] = "@COVERITY_EXECUTABLE@"; const char COVERITY_URL[] = "@COVERITY_URL@"; const char CPPCHECK_EXECUTABLE[] = "@CPPCHECK_EXECUTABLE@"; // additional functions +const char PROP_DOCS[] = "@BUILD_DOCS@"; const char PROP_FUTURE[] = "@BUILD_FUTURE@"; const char PROP_LOAD[] = "@BUILD_LOAD@"; const char PROP_TEST[] = "@BUILD_TESTING@";