From 1bd913aea5e6f1c8c0395ded46251bb76528b865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 26 Nov 2015 18:36:14 +0100 Subject: [PATCH] fixed #244 --- libguh/devicemanager.cpp | 163 +++++++++++++++++----------------- libguh/devicemanager.h | 7 +- libguh/plugin/deviceclass.cpp | 33 +++++++ libguh/plugin/deviceclass.h | 3 + server/jsonrpc/jsontypes.cpp | 14 +-- server/ruleengine.cpp | 42 +++++---- 6 files changed, 155 insertions(+), 107 deletions(-) diff --git a/libguh/devicemanager.cpp b/libguh/devicemanager.cpp index 07cec888..acf5f606 100644 --- a/libguh/devicemanager.cpp +++ b/libguh/devicemanager.cpp @@ -765,6 +765,87 @@ DeviceClass DeviceManager::findDeviceClass(const DeviceClassId &deviceClassId) c return DeviceClass(); } +DeviceManager::DeviceError DeviceManager::verifyParams(const QList paramTypes, ParamList ¶ms, bool requireAll) +{ + foreach (const Param ¶m, params) { + DeviceManager::DeviceError result = verifyParam(paramTypes, param); + if (result != DeviceErrorNoError) { + return result; + } + } + if (!requireAll) { + return DeviceErrorNoError; + } + foreach (const ParamType ¶mType, paramTypes) { + bool found = false; + foreach (const Param ¶m, params) { + if (paramType.name() == param.name()) { + found = true; + } + } + + // This paramType has a default value... lets fill in that one. + if (!paramType.defaultValue().isNull() && !found) { + found = true; + params.append(Param(paramType.name(), paramType.defaultValue())); + } + + if (!found) { + qCWarning(dcDeviceManager) << "Missing parameter:" << paramType.name(); + return DeviceErrorMissingParameter; + } + } + return DeviceErrorNoError; +} + +DeviceManager::DeviceError DeviceManager::verifyParam(const QList paramTypes, const Param ¶m) +{ + foreach (const ParamType ¶mType, paramTypes) { + if (paramType.name() == param.name()) { + return verifyParam(paramType, param); + } + } + qCWarning(dcDeviceManager) << "Invalid parameter" << param.name() << "in parameter list"; + return DeviceErrorInvalidParameter; +} + +DeviceManager::DeviceError DeviceManager::verifyParam(const ParamType ¶mType, const Param ¶m) +{ + if (paramType.name() == param.name()) { + + if (!param.value().canConvert(paramType.type())) { + qCWarning(dcDeviceManager) << "Wrong parameter type for param" << param.name() << " Got:" << param.value() << " Expected:" << QVariant::typeToName(paramType.type()); + return DeviceErrorInvalidParameter; + } + + if (!param.value().convert(paramType.type())) { + qCWarning(dcDeviceManager) << "Could not convert value of param" << param.name() << " to:" << QVariant::typeToName(paramType.type()) << " Got:" << param.value(); + return DeviceErrorInvalidParameter; + } + + if (paramType.maxValue().isValid() && param.value() > paramType.maxValue()) { + qCWarning(dcDeviceManager) << "Value out of range for param" << param.name() << " Got:" << param.value() << " Max:" << paramType.maxValue(); + return DeviceErrorInvalidParameter; + } + if (paramType.minValue().isValid() && param.value() < paramType.minValue()) { + qCWarning(dcDeviceManager) << "Value out of range for param" << param.name() << " Got:" << param.value() << " Min:" << paramType.minValue(); + return DeviceErrorInvalidParameter; + } + if (!paramType.allowedValues().isEmpty() && !paramType.allowedValues().contains(param.value())) { + QStringList allowedValues; + foreach (const QVariant &value, paramType.allowedValues()) { + allowedValues.append(value.toString()); + } + + qCWarning(dcDeviceManager) << "Value not in allowed values for param" << param.name() << " Got:" << param.value() << " Allowed:" << allowedValues.join(","); + return DeviceErrorInvalidParameter; + } + return DeviceErrorNoError; + } + qCWarning(dcDeviceManager) << "Parameter name" << param.name() << "does not match with ParamType name" << paramType.name(); + return DeviceErrorInvalidParameter; +} + /*! Execute the given \l{Action}. * This will find the \l{Device} \a action refers to the \l{Action}{deviceId()} and * its \l{DevicePlugin}. Then will dispatch the execution to the \l{DevicePlugin}.*/ @@ -786,7 +867,6 @@ DeviceManager::DeviceError DeviceManager::executeAction(const Action &action) return paramCheck; } finalAction.setParams(finalParams); - found = true; continue; } @@ -1294,84 +1374,3 @@ void DeviceManager::postSetupDevice(Device *device) plugin->postSetupDevice(device); } -DeviceManager::DeviceError DeviceManager::verifyParams(const QList paramTypes, ParamList ¶ms, bool requireAll) -{ - foreach (const Param ¶m, params) { - DeviceManager::DeviceError result = verifyParam(paramTypes, param); - if (result != DeviceErrorNoError) { - return result; - } - } - if (!requireAll) { - return DeviceErrorNoError; - } - foreach (const ParamType ¶mType, paramTypes) { - bool found = false; - foreach (const Param ¶m, params) { - if (paramType.name() == param.name()) { - found = true; - } - } - - // This paramType has a default value... lets fill in that one. - if (!paramType.defaultValue().isNull() && !found) { - found = true; - params.append(Param(paramType.name(), paramType.defaultValue())); - } - - if (!found) { - qCWarning(dcDeviceManager) << "Missing parameter:" << paramType.name(); - return DeviceErrorMissingParameter; - } - } - return DeviceErrorNoError; -} - -DeviceManager::DeviceError DeviceManager::verifyParam(const QList paramTypes, const Param ¶m) -{ - foreach (const ParamType ¶mType, paramTypes) { - if (paramType.name() == param.name()) { - return verifyParam(paramType, param); - } - } - qCWarning(dcDeviceManager) << "Invalid parameter" << param.name() << "in parameter list"; - return DeviceErrorInvalidParameter; -} - -DeviceManager::DeviceError DeviceManager::verifyParam(const ParamType ¶mType, const Param ¶m) -{ - if (paramType.name() == param.name()) { - - if (!param.value().canConvert(paramType.type())) { - qCWarning(dcDeviceManager) << "Wrong parameter type for param" << param.name() << " Got:" << param.value() << " Expected:" << QVariant::typeToName(paramType.type()); - return DeviceErrorInvalidParameter; - } - - if (!param.value().convert(paramType.type())) { - qCWarning(dcDeviceManager) << "Could not convert value of param" << param.name() << " to:" << QVariant::typeToName(paramType.type()) << " Got:" << param.value(); - return DeviceErrorInvalidParameter; - } - - if (paramType.maxValue().isValid() && param.value() > paramType.maxValue()) { - qCWarning(dcDeviceManager) << "Value out of range for param" << param.name() << " Got:" << param.value() << " Max:" << paramType.maxValue(); - return DeviceErrorInvalidParameter; - } - if (paramType.minValue().isValid() && param.value() < paramType.minValue()) { - qCWarning(dcDeviceManager) << "Value out of range for param" << param.name() << " Got:" << param.value() << " Min:" << paramType.minValue(); - return DeviceErrorInvalidParameter; - } - if (!paramType.allowedValues().isEmpty() && !paramType.allowedValues().contains(param.value())) { - QStringList allowedValues; - foreach (const QVariant &value, paramType.allowedValues()) { - allowedValues.append(value.toString()); - } - - qCWarning(dcDeviceManager) << "Value not in allowed values for param" << param.name() << " Got:" << param.value() << " Allowed:" << allowedValues.join(","); - return DeviceErrorInvalidParameter; - } - return DeviceErrorNoError; - } - qCWarning(dcDeviceManager) << "Parameter name" << param.name() << "does not match with ParamType name" << paramType.name(); - return DeviceErrorInvalidParameter; -} - diff --git a/libguh/devicemanager.h b/libguh/devicemanager.h index 7057358f..4bcd78b0 100644 --- a/libguh/devicemanager.h +++ b/libguh/devicemanager.h @@ -125,6 +125,10 @@ public: QList findChildDevices(Device *device) const; DeviceClass findDeviceClass(const DeviceClassId &deviceClassId) const; + DeviceError verifyParams(const QList paramTypes, ParamList ¶ms, bool requireAll = true); + DeviceError verifyParam(const QList paramTypes, const Param ¶m); + DeviceError verifyParam(const ParamType ¶mType, const Param ¶m); + signals: void loaded(); void eventTriggered(const Event &event); @@ -171,9 +175,6 @@ private: DeviceError addConfiguredDeviceInternal(const DeviceClassId &deviceClassId, const ParamList ¶ms, const DeviceId id = DeviceId::createDeviceId()); DeviceSetupStatus setupDevice(Device *device); void postSetupDevice(Device *device); - DeviceError verifyParams(const QList paramTypes, ParamList ¶ms, bool requireAll = true); - DeviceError verifyParam(const QList paramTypes, const Param ¶m); - DeviceError verifyParam(const ParamType ¶mType, const Param ¶m); private: QHash m_supportedVendors; diff --git a/libguh/plugin/deviceclass.cpp b/libguh/plugin/deviceclass.cpp index 7d65e3b6..a24428f4 100644 --- a/libguh/plugin/deviceclass.cpp +++ b/libguh/plugin/deviceclass.cpp @@ -134,6 +134,17 @@ void DeviceClass::setStateTypes(const QList &stateTypes) } } +/*! Returns true if this DeviceClass has a \l{StateType} with the given \a stateTypeId. */ +bool DeviceClass::hasStateType(const StateTypeId &stateTypeId) +{ + foreach (const StateType &stateType, m_stateTypes) { + if (stateType.id() == stateTypeId) { + return true; + } + } + return false; +} + /*! Returns the eventTypes of this DeviceClass. \{Device}{Devices} created from this \l{DeviceClass} must have their events matching to this template. */ QList DeviceClass::eventTypes() const @@ -157,6 +168,17 @@ void DeviceClass::setEventTypes(const QList &eventTypes) } } +/*! Returns true if this DeviceClass has a \l{EventType} with the given \a eventTypeId. */ +bool DeviceClass::hasEventType(const EventTypeId &eventTypeId) +{ + foreach (const EventType &eventType, m_eventTypes) { + if (eventType.id() == eventTypeId) { + return true; + } + } + return false; +} + /*! Returns the actionTypes of this DeviceClass. \{Device}{Devices} created from this \l{DeviceClass} must have their actions matching to this template. */ QList DeviceClass::actionTypes() const @@ -171,6 +193,17 @@ void DeviceClass::setActionTypes(const QList &actionTypes) m_actionTypes = actionTypes; } +/*! Returns true if this DeviceClass has a \l{ActionType} with the given \a actionTypeId. */ +bool DeviceClass::hasActionType(const ActionTypeId &actionTypeId) +{ + foreach (const ActionType &actionType, m_actionTypes) { + if (actionType.id() == actionTypeId) { + return true; + } + } + return false; +} + /*! Returns the params description of this DeviceClass. \{Device}{Devices} created from this \l{DeviceClass} must have their params matching to this template. */ QList DeviceClass::paramTypes() const diff --git a/libguh/plugin/deviceclass.h b/libguh/plugin/deviceclass.h index 4d349bee..88f66ef2 100644 --- a/libguh/plugin/deviceclass.h +++ b/libguh/plugin/deviceclass.h @@ -64,12 +64,15 @@ public: QList stateTypes() const; void setStateTypes(const QList &stateTypes); + bool hasStateType(const StateTypeId &stateTypeId); QList eventTypes() const; void setEventTypes(const QList &eventTypes); + bool hasEventType(const EventTypeId &eventTypeId); QList actionTypes() const; void setActionTypes(const QList &actionTypes); + bool hasActionType(const ActionTypeId &actionTypeId); QList paramTypes() const; void setParamTypes(const QList ¶mTypes); diff --git a/server/jsonrpc/jsontypes.cpp b/server/jsonrpc/jsontypes.cpp index a9b3c715..1e8691c1 100644 --- a/server/jsonrpc/jsontypes.cpp +++ b/server/jsonrpc/jsontypes.cpp @@ -1305,25 +1305,25 @@ QPair JsonTypes::validateVariant(const QVariant &templateVariant, QPair JsonTypes::validateBasicType(const QVariant &variant) { - if (variant.canConvert(QVariant::Uuid)) { + if (variant.canConvert(QVariant::Uuid) && QVariant(variant).convert(QVariant::Uuid)) { return report(true, ""); } - if (variant.canConvert(QVariant::String)) { + if (variant.canConvert(QVariant::String) && QVariant(variant).convert(QVariant::String)) { return report(true, ""); } - if (variant.canConvert(QVariant::Int)) { + if (variant.canConvert(QVariant::Int) && QVariant(variant).convert(QVariant::Int)) { return report(true, ""); } - if (variant.canConvert(QVariant::UInt)){ + if (variant.canConvert(QVariant::UInt) && QVariant(variant).convert(QVariant::UInt)){ return report(true, ""); } - if (variant.canConvert(QVariant::Double)) { + if (variant.canConvert(QVariant::Double) && QVariant(variant).convert(QVariant::Double)) { return report(true, ""); } - if (variant.canConvert(QVariant::Bool)) { + if (variant.canConvert(QVariant::Bool && QVariant(variant).convert(QVariant::Bool))) { return report(true, ""); } - if (variant.canConvert(QVariant::Color)) { + if (variant.canConvert(QVariant::Color) && QVariant(variant).convert(QVariant::Color)) { return report(true, ""); } return report(false, QString("Error validating basic type %1.").arg(variant.toString())); diff --git a/server/ruleengine.cpp b/server/ruleengine.cpp index d0418872..2ec374b6 100644 --- a/server/ruleengine.cpp +++ b/server/ruleengine.cpp @@ -297,6 +297,7 @@ RuleEngine::RuleError RuleEngine::addRule(const RuleId &ruleId, const QString &n } } + foreach (const RuleAction &action, actions) { Device *device = GuhCore::instance()->findConfiguredDevice(action.deviceId()); if (!device) { @@ -304,17 +305,24 @@ RuleEngine::RuleError RuleEngine::addRule(const RuleId &ruleId, const QString &n return RuleErrorDeviceNotFound; } DeviceClass deviceClass = GuhCore::instance()->findDeviceClass(device->deviceClassId()); - - bool actionTypeFound = false; - foreach (const ActionType &actionType, deviceClass.actionTypes()) { - if (actionType.id() == action.actionTypeId()) { - actionTypeFound = true; - } - } - if (!actionTypeFound) { + if (!deviceClass.hasActionType(action.actionTypeId())) { qCWarning(dcRuleEngine) << "Cannot create rule. Device " + device->name() + " has no action type:" << action.actionTypeId(); return RuleErrorActionTypeNotFound; } + + // if the action is eventbased, it is already checked + if (!action.isEventBased()) { + // verify action params + foreach (const ActionType &actionType, deviceClass.actionTypes()) { + if (actionType.id() == action.actionTypeId()) { + ParamList finalParams = action.toAction().params(); + DeviceManager::DeviceError paramCheck = GuhCore::instance()->deviceManager()->verifyParams(actionType.paramTypes(), finalParams); + if (paramCheck != DeviceManager::DeviceErrorNoError) + return RuleErrorInvalidRuleActionParameter; + } + } + } + } if (actions.count() > 0) { qCDebug(dcRuleEngine) << "actions" << actions.last().actionTypeId() << actions.last().ruleActionParams(); @@ -328,16 +336,20 @@ RuleEngine::RuleError RuleEngine::addRule(const RuleId &ruleId, const QString &n } DeviceClass deviceClass = GuhCore::instance()->findDeviceClass(device->deviceClassId()); - bool actionTypeFound = false; - foreach (const ActionType &actionType, deviceClass.actionTypes()) { - if (actionType.id() == action.actionTypeId()) { - actionTypeFound = true; - } - } - if (!actionTypeFound) { + if (!deviceClass.hasActionType(action.actionTypeId())) { qCWarning(dcRuleEngine) << "Cannot create rule. Device " + device->name() + " has no action type:" << action.actionTypeId(); return RuleErrorActionTypeNotFound; } + + // verify action params + foreach (const ActionType &actionType, deviceClass.actionTypes()) { + if (actionType.id() == action.actionTypeId()) { + ParamList finalParams = action.toAction().params(); + DeviceManager::DeviceError paramCheck = GuhCore::instance()->deviceManager()->verifyParams(actionType.paramTypes(), finalParams); + if (paramCheck != DeviceManager::DeviceErrorNoError) + return RuleErrorInvalidRuleActionParameter; + } + } } if (exitActions.count() > 0) { qCDebug(dcRuleEngine) << "exit actions" << exitActions.last().actionTypeId() << exitActions.last().ruleActionParams();