add DATABASE_VERSION field for future migrations if any

This commit is contained in:
Evgenii Alekseev 2017-03-07 01:50:51 +03:00
parent bd62bc8777
commit 20578996b7
6 changed files with 365 additions and 122 deletions

View File

@ -85,6 +85,13 @@ const char LIB_INSTALL_DIR[] = "@LIB_INSTALL_DIR@";
*/
const char ROOT_INSTALL_DIR[] = "@CMAKE_INSTALL_PREFIX@";
// internal configuration
/**
* @ingroup QueuedConfig
* @brief version of internal storage
*/
const int DATABASE_VERSION = 1;
// plugin interfaces
/**
* @brief plugin interface name

View File

@ -48,6 +48,11 @@ public:
* @brief QueuedAdvancedSettings class destructor
*/
virtual ~QueuedAdvancedSettings();
/**
* @brief check database version
* @return true if no version update required, otherwise return false
*/
bool checkDatabaseVersion() const;
/**
* @brief get value
* @param _key
@ -76,6 +81,13 @@ public:
* @return ID in settings representation
*/
static QString internalId(const QString &_key);
/**
* @brief get internal ID by given string key
* @param _key
* string key
* @return ID in settings representation
*/
static QString internalId(const QueuedCfg::QueuedSettings _key);
/**
* @brief set value
* @param _key

View File

@ -28,6 +28,8 @@
#include <QString>
#include <QVariant>
#include "QueuedConfig.h"
/**
* @defgroup QueuedCfg
@ -91,6 +93,8 @@ typedef struct {
* on queued exit action enum
* @var Settings::TokenExpiration
* token expiration value in days
* @var Settings::DatabaseVersion
* internal field to control current database version
*/
enum class QueuedSettings {
Invalid = 1 << 0,
@ -100,6 +104,7 @@ enum class QueuedSettings {
KeepUsers = 1 << 4,
OnExitAction = 1 << 5,
TokenExpiration = 1 << 6,
DatabaseVersion = 1 << 7
};
/**
* @ingroup QueuedCfg
@ -133,7 +138,9 @@ const QueuedSettingsDefaultMap QueuedSettingsDefaults = {
{"KeepTasks", {QueuedSettings::KeepTasks, 0}},
{"KeepUsers", {QueuedSettings::KeepUsers, 0}},
{"OnExitAction", {QueuedSettings::OnExitAction, 2}},
{"TokenExpiration", {QueuedSettings::TokenExpiration, 39}}};
{"TokenExpiration", {QueuedSettings::TokenExpiration, 30}},
{"DatabaseVersion",
{QueuedSettings::DatabaseVersion, QueuedConfig::DATABASE_VERSION}}};
};
#endif /* QUEUEDCONFIGURATION_H */

View File

@ -317,6 +317,88 @@ private:
* @brief init users
*/
void initUsers();
// private interfaces
/**
* @brief add new task
* @param _command
* command line
* @param _arguments
* command arguments
* @param _workingDirectory
* working directory
* @param _nice
* nice level
* @param _userId
* task owner user ID
* @param _limits
* task defined limits
* @return true on successfully addition
*/
bool addTaskPrivate(const QString &_command, const QStringList &_arguments,
const QString &_workingDirectory, const uint _nice,
const long long _userId,
const QueuedLimits::Limits &_limits);
/**
* @brief add new user
* @param _name
* user name
* @param _email
* user email
* @param _password
* user password
* @param _permissions
* user permissions
* @param _limits
* user limits
* @return true on successfully addition
*/
bool addUserPrivate(const QString &_name, const QString &_email,
const QString &_password, const uint _permissions,
const QueuedLimits::Limits &_limits);
/**
* @brief edit advanced settings
* @param _key
* advanced settings key
* @param _value
* advanced settings value
* @return true on successful option edition
*/
bool editOptionPrivate(const QString &_key, const QVariant &_value);
/**
* @brief edit task
* @param _id
* task ID to edit
* @param _taskData
* task data to edit
* @remark _taskData should contain only fields defined in schema, any other
* fields will be ignored. No need to pass all properties here
* @return true on successful task edition
*/
bool editTaskPrivate(const long long _id, const QVariantHash &_taskData);
/**
* @brief edit user
* @param _id
* user ID to edit
* @param _userData
* user data to edit
* @remark _userData should contain only fields defined in schema, any other
* fields will be ignored. No need to pass all properties here
* @return true on successful user edition
*/
bool editUserPrivate(const long long _id, const QVariantHash &_userData);
/**
* @brief edit user permissions
* @param _id
* user ID to edit
* @param _permission
* permission to add or remove
* @param _add
* indicates whether it should be added or removed
* @return true on successful user permission edition
*/
bool editUserPermissionPrivate(const long long _id,
const QueuedEnums::Permission &_permission,
const bool _add);
};

View File

@ -47,6 +47,20 @@ QueuedAdvancedSettings::~QueuedAdvancedSettings()
}
/**
* @fn checkDatabase
*/
bool QueuedAdvancedSettings::checkDatabaseVersion() const
{
QString key = internalId(QueuedCfg::QueuedSettings::DatabaseVersion);
if (m_values.contains(key.toLower()))
return get(key).toInt() == QueuedConfig::DATABASE_VERSION;
else
return false;
}
/**
* @fn get
*/
@ -108,6 +122,23 @@ QString QueuedAdvancedSettings::internalId(const QString &_key)
}
/**
* @fn internalId
*/
QString QueuedAdvancedSettings::internalId(const QueuedCfg::QueuedSettings _key)
{
qCDebug(LOG_LIB) << "Looking for key" << static_cast<int>(_key);
for (auto &internal : QueuedCfg::QueuedSettingsDefaults.keys()) {
if (QueuedCfg::QueuedSettingsDefaults[internal].id != _key)
continue;
return internal;
}
return QString();
}
/**
* @fn set
*/

View File

@ -92,35 +92,8 @@ bool QueuedCore::addTask(
}
}
// add to database
auto ids = m_users->ids(_userId);
auto user = m_users->user(_userId);
if (!user) {
qCWarning(LOG_LIB) << "Could not find task user" << _userId;
return false;
}
auto taskLimits = QueuedLimits::minimalLimits(
_limits, user->nativeLimits(),
QueuedLimits::Limits(
m_advancedSettings->get(QueuedCfg::QueuedSettings::DefaultLimits)
.toString()));
QVariantHash properties = {{"user", _userId},
{"command", _command},
{"commandArguments", _arguments},
{"workDirectory", _workingDirectory},
{"nice", _nice},
{"uid", ids.first},
{"gid", ids.second},
{"limits", taskLimits.toString()}};
auto id = m_database->add(QueuedDB::TASKS_TABLE, properties);
if (id == -1) {
qCWarning(LOG_LIB) << "Could not add task" << _command;
return false;
}
// add to child object
m_processes->add(properties, id);
return true;
return addTaskPrivate(_command, _arguments, _workingDirectory, _nice,
_userId, _limits);
}
@ -149,25 +122,13 @@ bool QueuedCore::addUser(
return false;
}
// add to dababase
QVariantHash properties
= {{"name", _name},
{"password", QueuedUser::hashFromPassword(_password)},
{"email", _email},
{"permissions", _permissions},
{"limits", _limits.toString()}};
auto id = m_database->add(QueuedDB::USERS_TABLE, properties);
if (id == -1) {
qCWarning(LOG_LIB) << "Could not add user" << _name;
return false;
}
// add to child object
m_users->add(properties, id);
return true;
return addUserPrivate(_name, _email, _password, _permissions, _limits);
}
/**
* @fn authorization
*/
QueuedUserManager::QueuedUserAuthorization
QueuedCore::authorization(const QString &_name, const QString &_password)
{
@ -206,25 +167,7 @@ bool QueuedCore::editOption(
return false;
}
// add to database
long long id = m_advancedSettings->id(_key);
QVariantHash payload = {{"key", _key}, {"value", _value}};
bool status = false;
if (id == -1) {
id = m_database->add(QueuedDB::SETTINGS_TABLE, payload);
qCInfo(LOG_LIB) << "Added new key with ID" << id;
status = (id != -1);
} else {
status = m_database->modify(QueuedDB::SETTINGS_TABLE, id, payload);
qCInfo(LOG_LIB) << "Value for" << _key
<< "has been modified with status" << status;
}
// add to child objectm
if (status)
m_advancedSettings->set(_key, _value);
return status;
return editOptionPrivate(_key, _value);
}
@ -281,20 +224,7 @@ bool QueuedCore::editTask(
= isAdmin ? _taskData
: dropAdminFields(QueuedDB::TASKS_TABLE, _taskData);
// modify record in database first
bool status = m_database->modify(QueuedDB::TASKS_TABLE, _id, payload);
if (!status) {
qCWarning(LOG_LIB) << "Could not modify task record" << _id
<< "in database, do not edit it in memory";
return false;
}
// modify values stored in memory
for (auto &property : payload.keys())
task->setProperty(property.toLocal8Bit().constData(),
payload[property]);
return true;
return editTaskPrivate(_id, payload);
}
@ -334,20 +264,7 @@ bool QueuedCore::editUser(
= isAdmin ? _userData
: dropAdminFields(QueuedDB::USERS_TABLE, _userData);
// modify record in database first
bool status = m_database->modify(QueuedDB::USERS_TABLE, _id, payload);
if (!status) {
qCWarning(LOG_LIB) << "Could not modify user record" << _id
<< "in database, do not edit it in memory";
return false;
}
// modify values stored in memory
for (auto &property : payload.keys())
user->setProperty(property.toLocal8Bit().constData(),
payload[property]);
return true;
return editUserPrivate(_id, payload);
}
@ -361,12 +278,6 @@ bool QueuedCore::editUserPermission(
qCDebug(LOG_LIB) << "Edit permissions" << static_cast<int>(_permission)
<< "for user" << _id << "add" << _add;
auto user = m_users->user(_id);
if (!user) {
qCWarning(LOG_LIB) << "Could not find user with ID" << _id;
return false;
}
// check permissions
auto authUser = m_users->user(_auth.user);
if (!authUser) {
@ -383,29 +294,7 @@ bool QueuedCore::editUserPermission(
}
}
// edit runtime permissions to get value
if (_add)
user->addPermissions(_permission);
else
user->removePermissions(_permission);
uint permissions = user->permissions();
qCInfo(LOG_LIB) << "New user permissions";
// modify in database now
QVariantHash payload = {{"permissions", permissions}};
bool status = m_database->modify(QueuedDB::USERS_TABLE, _id, payload);
if (!status) {
qCWarning(LOG_LIB) << "Could not modify user record" << _id
<< "in database, do not edit it in memory";
// rollback in-memory values
if (_add)
user->removePermissions(_permission);
else
user->addPermissions(_permission);
return false;
}
return true;
return editUserPermissionPrivate(_id, _permission, _add);
}
@ -597,6 +486,8 @@ void QueuedCore::updateSettings(const QueuedCfg::QueuedSettings _key,
case QueuedCfg::QueuedSettings::DatabaseInterval:
m_databaseManager->setInterval(_value.toLongLong());
break;
case QueuedCfg::QueuedSettings::DatabaseVersion:
break;
case QueuedCfg::QueuedSettings::DefaultLimits:
break;
case QueuedCfg::QueuedSettings::KeepTasks:
@ -762,6 +653,13 @@ void QueuedCore::initSettings(const QString &_configuration)
// and load advanced settings
m_advancedSettings = new QueuedAdvancedSettings(this);
m_advancedSettings->set(m_database->get(QueuedDB::SETTINGS_TABLE));
if (!m_advancedSettings->checkDatabaseVersion()) {
qCInfo(LOG_LIB) << "Bump database version to"
<< QueuedConfig::DATABASE_VERSION;
editOptionPrivate(m_advancedSettings->internalId(
QueuedCfg::QueuedSettings::DatabaseVersion),
QueuedConfig::DATABASE_VERSION);
}
// report manager
m_reports = new QueuedReportManager(this, m_database);
@ -794,3 +692,209 @@ void QueuedCore::initUsers()
m_users, SIGNAL(userLoggedIn(const long long, const QDateTime &)), this,
SLOT(updateUserLoginTime(const long long, const QDateTime &)));
}
/**
* @addTaskPrivate
*/
bool QueuedCore::addTaskPrivate(const QString &_command,
const QStringList &_arguments,
const QString &_workingDirectory,
const uint _nice, const long long _userId,
const QueuedLimits::Limits &_limits)
{
qCDebug(LOG_LIB) << "Add task" << _command << "with arguments" << _arguments
<< "from user" << _userId;
// add to database
auto ids = m_users->ids(_userId);
auto user = m_users->user(_userId);
if (!user) {
qCWarning(LOG_LIB) << "Could not find task user" << _userId;
return false;
}
auto taskLimits = QueuedLimits::minimalLimits(
_limits, user->nativeLimits(),
QueuedLimits::Limits(
m_advancedSettings->get(QueuedCfg::QueuedSettings::DefaultLimits)
.toString()));
QVariantHash properties = {{"user", _userId},
{"command", _command},
{"commandArguments", _arguments},
{"workDirectory", _workingDirectory},
{"nice", _nice},
{"uid", ids.first},
{"gid", ids.second},
{"limits", taskLimits.toString()}};
auto id = m_database->add(QueuedDB::TASKS_TABLE, properties);
if (id == -1) {
qCWarning(LOG_LIB) << "Could not add task" << _command;
return false;
}
// add to child object
m_processes->add(properties, id);
return true;
}
/**
* @fn addUserPrivate
*/
bool QueuedCore::addUserPrivate(const QString &_name, const QString &_email,
const QString &_password,
const uint _permissions,
const QueuedLimits::Limits &_limits)
{
qCDebug(LOG_LIB) << "Add user" << _name << "with email" << _email
<< "and permissions" << _permissions;
// add to database
QVariantHash properties
= {{"name", _name},
{"password", QueuedUser::hashFromPassword(_password)},
{"email", _email},
{"permissions", _permissions},
{"limits", _limits.toString()}};
auto id = m_database->add(QueuedDB::USERS_TABLE, properties);
if (id == -1) {
qCWarning(LOG_LIB) << "Could not add user" << _name;
return false;
}
// add to child object
m_users->add(properties, id);
return true;
}
/**
* @fn editOptionPrivate
*/
bool QueuedCore::editOptionPrivate(const QString &_key, const QVariant &_value)
{
qCDebug(LOG_LIB) << "Set key" << _key << "to" << _value;
// add to database
long long id = m_advancedSettings->id(_key);
QVariantHash payload = {{"key", _key}, {"value", _value}};
bool status = false;
if (id == -1) {
id = m_database->add(QueuedDB::SETTINGS_TABLE, payload);
qCInfo(LOG_LIB) << "Added new key with ID" << id;
status = (id != -1);
} else {
status = m_database->modify(QueuedDB::SETTINGS_TABLE, id, payload);
qCInfo(LOG_LIB) << "Value for" << _key
<< "has been modified with status" << status;
}
// add to child object
if (status)
m_advancedSettings->set(_key, _value);
return status;
}
/**
* @fn editTaskPrivate
*/
bool QueuedCore::editTaskPrivate(const long long _id,
const QVariantHash &_taskData)
{
qCDebug(LOG_LIB) << "Edit task with ID" << _id;
auto task = m_processes->process(_id);
if (!task) {
qCWarning(LOG_LIB) << "Could not find task with ID" << _id;
return false;
}
// modify record in database first
bool status = m_database->modify(QueuedDB::TASKS_TABLE, _id, _taskData);
if (!status) {
qCWarning(LOG_LIB) << "Could not modify task record" << _id
<< "in database, do not edit it in memory";
return false;
}
// modify values stored in memory
for (auto &property : _taskData.keys())
task->setProperty(property.toLocal8Bit().constData(),
_taskData[property]);
return true;
}
/**
* @fn editUserPrivate
*/
bool QueuedCore::editUserPrivate(const long long _id,
const QVariantHash &_userData)
{
qCDebug(LOG_LIB) << "Edit user with ID" << _id;
auto user = m_users->user(_id);
if (!user) {
qCWarning(LOG_LIB) << "Could not find user with ID" << _id;
return false;
};
// modify record in database first
bool status = m_database->modify(QueuedDB::USERS_TABLE, _id, _userData);
if (!status) {
qCWarning(LOG_LIB) << "Could not modify user record" << _id
<< "in database, do not edit it in memory";
return false;
}
// modify values stored in memory
for (auto &property : _userData.keys())
user->setProperty(property.toLocal8Bit().constData(),
_userData[property]);
return true;
}
/**
* @fn editUserPermissionPrivate
*/
bool QueuedCore::editUserPermissionPrivate(
const long long _id, const QueuedEnums::Permission &_permission,
const bool _add)
{
qCDebug(LOG_LIB) << "Edit permissions" << static_cast<int>(_permission)
<< "for user" << _id << "add" << _add;
auto user = m_users->user(_id);
if (!user) {
qCWarning(LOG_LIB) << "Could not find user with ID" << _id;
return false;
}
// edit runtime permissions to get value
if (_add)
user->addPermissions(_permission);
else
user->removePermissions(_permission);
uint permissions = user->permissions();
qCInfo(LOG_LIB) << "New user permissions";
// modify in database now
QVariantHash payload = {{"permissions", permissions}};
bool status = m_database->modify(QueuedDB::USERS_TABLE, _id, payload);
if (!status) {
qCWarning(LOG_LIB) << "Could not modify user record" << _id
<< "in database, do not edit it in memory";
// rollback in-memory values
if (_add)
user->removePermissions(_permission);
else
user->addPermissions(_permission);
return false;
}
return true;
}