Implement a tagging system
This commit is contained in:
parent
4e0091fdff
commit
a6f4ddf188
@ -220,6 +220,14 @@ QVariantMap JsonHandler::statusToReply(NetworkManager::NetworkManagerError statu
|
||||
return returns;
|
||||
}
|
||||
|
||||
/*! Returns the formated error map for the given \a status. */
|
||||
QVariantMap JsonHandler::statusToReply(TagsStorage::TagError status) const
|
||||
{
|
||||
QVariantMap returns;
|
||||
returns.insert("tagError", JsonTypes::tagErrorToString(status));
|
||||
return returns;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\class nymeaserver::JsonReply
|
||||
|
||||
@ -113,6 +113,7 @@ protected:
|
||||
QVariantMap statusToReply(Logging::LoggingError status) const;
|
||||
QVariantMap statusToReply(NymeaConfiguration::ConfigurationError status) const;
|
||||
QVariantMap statusToReply(NetworkManager::NetworkManagerError status) const;
|
||||
QVariantMap statusToReply(TagsStorage::TagError status) const;
|
||||
|
||||
private:
|
||||
QHash<QString, QString> m_descriptions;
|
||||
|
||||
@ -57,6 +57,7 @@
|
||||
#include "websocketserver.h"
|
||||
#include "configurationhandler.h"
|
||||
#include "networkmanagerhandler.h"
|
||||
#include "tagshandler.h"
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QStringList>
|
||||
@ -453,6 +454,7 @@ void JsonRPCServer::setup()
|
||||
registerHandler(new StateHandler(this));
|
||||
registerHandler(new ConfigurationHandler(this));
|
||||
registerHandler(new NetworkManagerHandler(this));
|
||||
registerHandler(new TagsHandler(this));
|
||||
|
||||
connect(NymeaCore::instance()->cloudManager(), &CloudManager::pairingReply, this, &JsonRPCServer::pairingFinished);
|
||||
connect(NymeaCore::instance()->cloudManager(), &CloudManager::connectedChanged, this, &JsonRPCServer::onCloudConnectedChanged);
|
||||
|
||||
@ -89,6 +89,7 @@ QVariantList JsonTypes::s_networkManagerError;
|
||||
QVariantList JsonTypes::s_networkManagerState;
|
||||
QVariantList JsonTypes::s_networkDeviceState;
|
||||
QVariantList JsonTypes::s_userError;
|
||||
QVariantList JsonTypes::s_tagError;
|
||||
|
||||
QVariantMap JsonTypes::s_paramType;
|
||||
QVariantMap JsonTypes::s_param;
|
||||
@ -122,6 +123,7 @@ QVariantMap JsonTypes::s_wirelessNetworkDevice;
|
||||
QVariantMap JsonTypes::s_tokenInfo;
|
||||
QVariantMap JsonTypes::s_serverConfiguration;
|
||||
QVariantMap JsonTypes::s_webServerConfiguration;
|
||||
QVariantMap JsonTypes::s_tag;
|
||||
|
||||
void JsonTypes::init()
|
||||
{
|
||||
@ -148,6 +150,7 @@ void JsonTypes::init()
|
||||
s_networkManagerState = enumToStrings(NetworkManager::staticMetaObject, "NetworkManagerState");
|
||||
s_networkDeviceState = enumToStrings(NetworkDevice::staticMetaObject, "NetworkDeviceState");
|
||||
s_userError = enumToStrings(UserManager::staticMetaObject, "UserError");
|
||||
s_tagError = enumToStrings(TagsStorage::staticMetaObject, "TagError");
|
||||
|
||||
// ParamType
|
||||
s_paramType.insert("id", basicTypeToString(Uuid));
|
||||
@ -387,6 +390,13 @@ void JsonTypes::init()
|
||||
s_webServerConfiguration = s_serverConfiguration;
|
||||
s_webServerConfiguration.insert("publicFolder", basicTypeToString(QVariant::String));
|
||||
|
||||
// Tag
|
||||
s_tag.insert("o:deviceId", basicTypeToString(QVariant::Uuid));
|
||||
s_tag.insert("o:ruleId", basicTypeToString(QVariant::Uuid));
|
||||
s_tag.insert("appId", basicTypeToString(QVariant::String));
|
||||
s_tag.insert("tagId", basicTypeToString(QVariant::String));
|
||||
s_tag.insert("o:value", basicTypeToString(QVariant::String));
|
||||
|
||||
s_initialized = true;
|
||||
}
|
||||
|
||||
@ -435,6 +445,7 @@ QVariantMap JsonTypes::allTypes()
|
||||
allTypes.insert("NetworkManagerState", networkManagerState());
|
||||
allTypes.insert("NetworkDeviceState", networkDeviceState());
|
||||
allTypes.insert("UserError", userError());
|
||||
allTypes.insert("TagError", tagErrorRef());
|
||||
|
||||
allTypes.insert("StateType", stateTypeDescription());
|
||||
allTypes.insert("StateDescriptor", stateDescriptorDescription());
|
||||
@ -467,6 +478,7 @@ QVariantMap JsonTypes::allTypes()
|
||||
allTypes.insert("TokenInfo", tokenInfoDescription());
|
||||
allTypes.insert("ServerConfiguration", serverConfigurationDescription());
|
||||
allTypes.insert("WebServerConfiguration", serverConfigurationDescription());
|
||||
allTypes.insert("Tag", tagDescription());
|
||||
|
||||
return allTypes;
|
||||
}
|
||||
@ -946,6 +958,21 @@ QVariantMap JsonTypes::packLogEntry(const LogEntry &logEntry)
|
||||
return logEntryMap;
|
||||
}
|
||||
|
||||
/*! Returns a variant map of the given \a tag. */
|
||||
QVariantMap JsonTypes::packTag(const Tag &tag)
|
||||
{
|
||||
QVariantMap ret;
|
||||
if (!tag.deviceId().isNull()){
|
||||
ret.insert("deviceId", tag.deviceId());
|
||||
} else {
|
||||
ret.insert("ruleId", tag.ruleId());
|
||||
}
|
||||
ret.insert("appId", tag.appId());
|
||||
ret.insert("tagId", tag.tagId());
|
||||
ret.insert("value", tag.value());
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*! Returns a variant list of the given \a createMethods. */
|
||||
QVariantList JsonTypes::packCreateMethods(DeviceClass::CreateMethods createMethods)
|
||||
{
|
||||
@ -1609,6 +1636,20 @@ TimeDescriptor JsonTypes::unpackTimeDescriptor(const QVariantMap &timeDescriptor
|
||||
return timeDescriptor;
|
||||
}
|
||||
|
||||
/*! Returns a \l{Tag} created from the given \a tagMap. */
|
||||
Tag JsonTypes::unpackTag(const QVariantMap &tagMap)
|
||||
{
|
||||
DeviceId deviceId = DeviceId(tagMap.value("deviceId").toString());
|
||||
RuleId ruleId = RuleId(tagMap.value("ruleId").toString());
|
||||
QString appId = tagMap.value("appId").toString();
|
||||
QString tagId = tagMap.value("tagId").toString();
|
||||
QString value = tagMap.value("value").toString();
|
||||
if (!deviceId.isNull()) {
|
||||
return Tag(deviceId, appId, tagId, value);
|
||||
}
|
||||
return Tag(ruleId, appId, tagId, value);
|
||||
}
|
||||
|
||||
ServerConfiguration JsonTypes::unpackServerConfiguration(const QVariantMap &serverConfigurationMap)
|
||||
{
|
||||
ServerConfiguration serverConfiguration;
|
||||
@ -1939,6 +1980,12 @@ QPair<bool, QString> JsonTypes::validateVariant(const QVariant &templateVariant,
|
||||
qCWarning(dcJsonRpc) << "WebServerConfiguration not matching";
|
||||
return result;
|
||||
}
|
||||
} else if (refName == tagRef()) {
|
||||
QPair<bool, QString> result = validateMap(tagDescription(), variant.toMap());
|
||||
if (!result.first) {
|
||||
qCWarning(dcJsonRpc) << "Tag not matching";
|
||||
return result;
|
||||
}
|
||||
} else if (refName == basicTypeRef()) {
|
||||
QPair<bool, QString> result = validateBasicType(variant);
|
||||
if (!result.first) {
|
||||
@ -2071,11 +2118,16 @@ QPair<bool, QString> JsonTypes::validateVariant(const QVariant &templateVariant,
|
||||
qCWarning(dcJsonRpc) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(userErrorRef());
|
||||
return result;
|
||||
}
|
||||
} else if (refName == tagErrorRef()) {
|
||||
QPair<bool, QString> result = validateEnum(s_tagError, variant);
|
||||
if (!result.first) {
|
||||
qCWarning(dcJsonRpc()) << QString("Value %1 not allowed in %2").arg(variant.toString()).arg(logEntryRef());
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
Q_ASSERT_X(false, "JsonTypes", QString("Unhandled ref: %1").arg(refName).toLatin1().data());
|
||||
return report(false, QString("Unhandled ref %1. Server implementation incomplete.").arg(refName));
|
||||
}
|
||||
|
||||
} else {
|
||||
QPair<bool, QString> result = JsonTypes::validateProperty(templateVariant, variant);
|
||||
if (!result.first) {
|
||||
|
||||
@ -42,6 +42,9 @@
|
||||
#include "logging/logentry.h"
|
||||
#include "logging/logfilter.h"
|
||||
|
||||
#include "tagging/tagsstorage.h"
|
||||
#include "tagging/tag.h"
|
||||
|
||||
#include "time/calendaritem.h"
|
||||
#include "time/repeatingoption.h"
|
||||
#include "time/timedescriptor.h"
|
||||
@ -135,6 +138,7 @@ public:
|
||||
DECLARE_TYPE(networkManagerState, "NetworkManagerState", NetworkManager, NetworkManagerState)
|
||||
DECLARE_TYPE(networkDeviceState, "NetworkDeviceState", NetworkDevice, NetworkDeviceState)
|
||||
DECLARE_TYPE(userError, "UserError", UserManager, UserError)
|
||||
DECLARE_TYPE(tagError, "TagError", TagsStorage, TagError)
|
||||
|
||||
DECLARE_OBJECT(paramType, "ParamType")
|
||||
DECLARE_OBJECT(param, "Param")
|
||||
@ -168,6 +172,7 @@ public:
|
||||
DECLARE_OBJECT(tokenInfo, "TokenInfo")
|
||||
DECLARE_OBJECT(serverConfiguration, "ServerConfiguration")
|
||||
DECLARE_OBJECT(webServerConfiguration, "WebServerConfiguration")
|
||||
DECLARE_OBJECT(tag, "Tag")
|
||||
|
||||
// pack types
|
||||
static QVariantMap packEventType(const EventType &eventType);
|
||||
@ -192,6 +197,7 @@ public:
|
||||
static QVariantMap packRule(const Rule &rule);
|
||||
static QVariantMap packRuleDescription(const Rule &rule);
|
||||
static QVariantMap packLogEntry(const LogEntry &logEntry);
|
||||
static QVariantMap packTag(const Tag &tag);
|
||||
static QVariantMap packRepeatingOption(const RepeatingOption &option);
|
||||
static QVariantMap packCalendarItem(const CalendarItem &calendarItem);
|
||||
static QVariantMap packTimeEventItem(const TimeEventItem &timeEventItem);
|
||||
@ -241,6 +247,7 @@ public:
|
||||
static CalendarItem unpackCalendarItem(const QVariantMap &calendarItemMap);
|
||||
static TimeEventItem unpackTimeEventItem(const QVariantMap &timeEventItemMap);
|
||||
static TimeDescriptor unpackTimeDescriptor(const QVariantMap &timeDescriptorMap);
|
||||
static Tag unpackTag(const QVariantMap &tagMap);
|
||||
|
||||
static ServerConfiguration unpackServerConfiguration(const QVariantMap &serverConfigurationMap);
|
||||
static WebServerConfiguration unpackWebServerConfiguration(const QVariantMap &webServerConfigurationMap);
|
||||
|
||||
143
libnymea-core/jsonrpc/tagshandler.cpp
Normal file
143
libnymea-core/jsonrpc/tagshandler.cpp
Normal file
@ -0,0 +1,143 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2018 Michael Zanetti <michael.zanetti@guh.io> *
|
||||
* *
|
||||
* This file is part of nymea. *
|
||||
* *
|
||||
* nymea is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* nymea is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with nymea. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "tagshandler.h"
|
||||
|
||||
#include "nymeacore.h"
|
||||
#include "tagging/tagsstorage.h"
|
||||
|
||||
TagsHandler::TagsHandler(QObject *parent) : JsonHandler(parent)
|
||||
{
|
||||
QVariantMap params;
|
||||
QVariantMap returns;
|
||||
|
||||
params.clear(); returns.clear();
|
||||
setDescription("GetTags", "Get the Tags matching the given filter. Tags can be filtered by a deviceID, a ruleId, an appId, a tagId or a combination of any (however, combining deviceId and ruleId will return an empty result set).");
|
||||
params.insert("o:deviceId", JsonTypes::basicTypeToString(JsonTypes::Uuid));
|
||||
params.insert("o:ruleId", JsonTypes::basicTypeToString(JsonTypes::Uuid));
|
||||
params.insert("o:appId", JsonTypes::basicTypeToString(JsonTypes::String));
|
||||
params.insert("o:tagId", JsonTypes::basicTypeToString(JsonTypes::String));
|
||||
setParams("GetTags", params);
|
||||
returns.insert("tagError", JsonTypes::tagErrorRef());
|
||||
returns.insert("o:tags", QVariantList() << JsonTypes::tagRef());
|
||||
setReturns("GetTags", returns);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
setDescription("AddTag", "Add a Tag. A Tag must have a deviceId OR a ruleId (call this method twice if you want to attach the same tag to a device and a rule), an appId (Use the appId of your app), a tagId (e.g. \"favorites\") and a value. Upon success, a TagAdded notification will be emitted. Calling this method twice for the same ids (device/rule, appId and tagId) but with a different value will update the tag's value and the TagValueChanged notification will be emitted.");
|
||||
params.insert("tag", JsonTypes::tagRef());
|
||||
setParams("AddTag", params);
|
||||
returns.insert("tagError", JsonTypes::tagErrorRef());
|
||||
setReturns("AddTag", returns);
|
||||
|
||||
params.clear(); returns.clear();
|
||||
setDescription("RemoveTag", "Remove a Tag. Tag value is optional and will be disregarded. If the ids match, the tag will be deleted and a TagRemoved notification will be emitted.");
|
||||
params.insert("tag", JsonTypes::tagRef());
|
||||
setParams("RemoveTag", params);
|
||||
returns.insert("tagError", JsonTypes::tagErrorRef());
|
||||
setReturns("RemoveTag", returns);
|
||||
|
||||
// Notifications
|
||||
params.clear();
|
||||
setDescription("TagAdded", "Emitted whenever a tag is added to the system. ");
|
||||
params.insert("tag", JsonTypes::tagRef());
|
||||
setParams("TagAdded", params);
|
||||
connect(NymeaCore::instance()->tagsStorage(), &TagsStorage::tagAdded, this, &TagsHandler::onTagAdded);
|
||||
|
||||
params.clear();
|
||||
setDescription("TagRemoved", "Emitted whenever a tag is removed from the system. ");
|
||||
params.insert("tag", JsonTypes::tagRef());
|
||||
setParams("TagRemoved", params);
|
||||
connect(NymeaCore::instance()->tagsStorage(), &TagsStorage::tagRemoved, this, &TagsHandler::onTagRemoved);
|
||||
|
||||
params.clear();
|
||||
setDescription("TagValueChanged", "Emitted whenever a tag's value is changed in the system. ");
|
||||
params.insert("tag", JsonTypes::tagRef());
|
||||
setParams("TagValueChanged", params);
|
||||
connect(NymeaCore::instance()->tagsStorage(), &TagsStorage::tagValueChanged, this, &TagsHandler::onTagValueChanged);
|
||||
}
|
||||
|
||||
QString TagsHandler::name() const
|
||||
{
|
||||
return "Tags";
|
||||
}
|
||||
|
||||
JsonReply *TagsHandler::GetTags(const QVariantMap ¶ms) const
|
||||
{
|
||||
QVariantList ret;
|
||||
foreach (const Tag &tag, NymeaCore::instance()->tagsStorage()->tags()) {
|
||||
if (params.contains("deviceId") && params.value("deviceId").toString() != tag.deviceId().toString()) {
|
||||
continue;
|
||||
}
|
||||
if (params.contains("ruleId") && params.value("ruleId").toString() != tag.ruleId().toString()) {
|
||||
continue;
|
||||
}
|
||||
if (params.contains("appId") && params.value("appId").toString() != tag.appId()) {
|
||||
continue;
|
||||
}
|
||||
if (params.contains("tagId") && params.value("tagId").toString() != tag.tagId()) {
|
||||
continue;
|
||||
}
|
||||
ret.append(JsonTypes::packTag(tag));
|
||||
}
|
||||
QVariantMap returns = statusToReply(TagsStorage::TagErrorNoError);
|
||||
returns.insert("tags", ret);
|
||||
return createReply(returns);
|
||||
|
||||
}
|
||||
|
||||
JsonReply *TagsHandler::AddTag(const QVariantMap ¶ms) const
|
||||
{
|
||||
Tag tag = JsonTypes::unpackTag(params.value("tag").toMap());
|
||||
TagsStorage::TagError error = NymeaCore::instance()->tagsStorage()->addTag(tag);
|
||||
QVariantMap returns = statusToReply(error);
|
||||
return createReply(returns);
|
||||
}
|
||||
|
||||
JsonReply *TagsHandler::RemoveTag(const QVariantMap ¶ms) const
|
||||
{
|
||||
Tag tag = JsonTypes::unpackTag(params.value("tag").toMap());
|
||||
TagsStorage::TagError error = NymeaCore::instance()->tagsStorage()->removeTag(tag);
|
||||
QVariantMap returns = statusToReply(error);
|
||||
return createReply(returns);
|
||||
}
|
||||
|
||||
void TagsHandler::onTagAdded(const Tag &tag)
|
||||
{
|
||||
qCDebug(dcJsonRpc) << "Notify \"Tags.TagAdded\"";
|
||||
QVariantMap params;
|
||||
params.insert("tag", JsonTypes::packTag(tag));
|
||||
emit TagAdded(params);
|
||||
}
|
||||
|
||||
void TagsHandler::onTagRemoved(const Tag &tag)
|
||||
{
|
||||
qCDebug(dcJsonRpc) << "Notify \"Tags.TagRemoved\"";
|
||||
QVariantMap params;
|
||||
params.insert("tag", JsonTypes::packTag(tag));
|
||||
emit TagRemoved(params);
|
||||
}
|
||||
|
||||
void TagsHandler::onTagValueChanged(const Tag &tag)
|
||||
{
|
||||
qCDebug(dcJsonRpc) << "Notify \"Tags.TagValueChanged\"";
|
||||
QVariantMap params;
|
||||
params.insert("tag", JsonTypes::packTag(tag));
|
||||
emit TagValueChanged(params);
|
||||
}
|
||||
54
libnymea-core/jsonrpc/tagshandler.h
Normal file
54
libnymea-core/jsonrpc/tagshandler.h
Normal file
@ -0,0 +1,54 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2018 Michael Zanetti <michael.zanetti@guh.io> *
|
||||
* *
|
||||
* This file is part of nymea. *
|
||||
* *
|
||||
* nymea is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* nymea is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with nymea. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef TAGSHANDLER_H
|
||||
#define TAGSHANDLER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "jsonhandler.h"
|
||||
|
||||
namespace nymeaserver {
|
||||
|
||||
class TagsHandler : public JsonHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TagsHandler(QObject *parent = nullptr);
|
||||
QString name() const override;
|
||||
|
||||
Q_INVOKABLE JsonReply *GetTags(const QVariantMap ¶ms) const;
|
||||
Q_INVOKABLE JsonReply *AddTag(const QVariantMap ¶ms) const;
|
||||
Q_INVOKABLE JsonReply *RemoveTag(const QVariantMap ¶ms) const;
|
||||
|
||||
signals:
|
||||
void TagAdded(const QVariantMap ¶ms);
|
||||
void TagRemoved(const QVariantMap ¶ms);
|
||||
void TagValueChanged(const QVariantMap ¶ms);
|
||||
|
||||
private slots:
|
||||
void onTagAdded(const Tag &tag);
|
||||
void onTagRemoved(const Tag &tag);
|
||||
void onTagValueChanged(const Tag &tag);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // TAGSHANDLER_H
|
||||
@ -93,7 +93,10 @@ HEADERS += nymeacore.h \
|
||||
hardware/network/avahi/qtavahiservice_p.h \
|
||||
hardware/network/avahi/qtavahiservicebrowserimplementation.h \
|
||||
hardware/network/avahi/qtavahiservicebrowserimplementation_p.h \
|
||||
debugserverhandler.h
|
||||
debugserverhandler.h \
|
||||
tagging/tagsstorage.h \
|
||||
tagging/tag.h \
|
||||
jsonrpc/tagshandler.h
|
||||
|
||||
SOURCES += nymeacore.cpp \
|
||||
tcpserver.cpp \
|
||||
@ -171,4 +174,7 @@ SOURCES += nymeacore.cpp \
|
||||
hardware/network/avahi/qtavahiservice_p.cpp \
|
||||
hardware/network/avahi/qtavahiservicebrowserimplementation.cpp \
|
||||
hardware/network/avahi/qtavahiservicebrowserimplementation_p.cpp \
|
||||
debugserverhandler.cpp
|
||||
debugserverhandler.cpp \
|
||||
tagging/tagsstorage.cpp \
|
||||
tagging/tag.cpp \
|
||||
jsonrpc/tagshandler.cpp
|
||||
|
||||
@ -101,6 +101,7 @@
|
||||
#include "ruleengine.h"
|
||||
#include "networkmanager/networkmanager.h"
|
||||
#include "nymeasettings.h"
|
||||
#include "tagging/tagsstorage.h"
|
||||
|
||||
#include "devicemanager.h"
|
||||
#include "plugin/device.h"
|
||||
@ -485,6 +486,12 @@ DebugServerHandler *NymeaCore::debugServerHandler() const
|
||||
return m_debugServerHandler;
|
||||
}
|
||||
|
||||
/*! Returns a pointer to the \l{TagsStorage} instance owned by NymeaCore. */
|
||||
TagsStorage *NymeaCore::tagsStorage() const
|
||||
{
|
||||
return m_tagsStorage;
|
||||
}
|
||||
|
||||
|
||||
/*! Constructs NymeaCore with the given \a parent. This is private.
|
||||
Use \l{NymeaCore::instance()} to access the single instance.*/
|
||||
@ -516,6 +523,9 @@ void NymeaCore::init() {
|
||||
qCDebug(dcApplication()) << "Creating User Manager";
|
||||
m_userManager = new UserManager(NymeaSettings::settingsPath() + "/user-db.sqlite", this);
|
||||
|
||||
qCDebug(dcApplication()) << "Creating Tags Storage";
|
||||
m_tagsStorage = new TagsStorage(m_deviceManager, m_ruleEngine, this);
|
||||
|
||||
qCDebug(dcApplication) << "Creating Server Manager";
|
||||
m_serverManager = new ServerManager(m_configuration, this);
|
||||
|
||||
|
||||
@ -49,6 +49,7 @@ class JsonRPCServer;
|
||||
class LogEngine;
|
||||
class NetworkManager;
|
||||
class NymeaConfiguration;
|
||||
class TagsStorage;
|
||||
|
||||
class NymeaCore : public QObject
|
||||
{
|
||||
@ -84,6 +85,7 @@ public:
|
||||
UserManager *userManager() const;
|
||||
CloudManager *cloudManager() const;
|
||||
DebugServerHandler *debugServerHandler() const;
|
||||
TagsStorage *tagsStorage() const;
|
||||
|
||||
static QStringList getAvailableLanguages();
|
||||
|
||||
@ -121,6 +123,7 @@ private:
|
||||
CloudManager *m_cloudManager;
|
||||
HardwareManagerImplementation *m_hardwareManager;
|
||||
DebugServerHandler *m_debugServerHandler;
|
||||
TagsStorage *m_tagsStorage;
|
||||
|
||||
NetworkManager *m_networkManager;
|
||||
UserManager *m_userManager;
|
||||
|
||||
95
libnymea-core/tagging/tag.cpp
Normal file
95
libnymea-core/tagging/tag.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2018 Michael Zanetti <michael.zanetti@guh.io> *
|
||||
* *
|
||||
* This file is part of nymea. *
|
||||
* *
|
||||
* nymea is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* nymea is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with nymea. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "tag.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace nymeaserver {
|
||||
|
||||
Tag::Tag(const DeviceId &deviceId, const QString &appId, const QString &tagId, const QString &value):
|
||||
m_deviceId(deviceId),
|
||||
m_appId(appId),
|
||||
m_tagId(tagId),
|
||||
m_value(value)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
Tag::Tag(const RuleId &ruleId, const QString &appId, const QString &tagId, const QString &value):
|
||||
m_ruleId(ruleId),
|
||||
m_appId(appId),
|
||||
m_tagId(tagId),
|
||||
m_value(value)
|
||||
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DeviceId Tag::deviceId() const
|
||||
{
|
||||
return m_deviceId;
|
||||
}
|
||||
|
||||
RuleId Tag::ruleId() const
|
||||
{
|
||||
return m_ruleId;
|
||||
}
|
||||
|
||||
QString Tag::appId() const
|
||||
{
|
||||
return m_appId;
|
||||
}
|
||||
|
||||
QString Tag::tagId() const
|
||||
{
|
||||
return m_tagId;
|
||||
}
|
||||
|
||||
QString Tag::value() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
void Tag::setValue(const QString &value)
|
||||
{
|
||||
m_value = value;
|
||||
}
|
||||
|
||||
bool Tag::operator==(const Tag &other) const
|
||||
{
|
||||
return m_deviceId == other.deviceId() &&
|
||||
m_ruleId == other.ruleId() &&
|
||||
m_appId == other.appId() &&
|
||||
m_tagId == other.tagId();
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug dbg, const Tag &tag)
|
||||
{
|
||||
if (!tag.deviceId().isNull()) {
|
||||
dbg.nospace() << "Tag (DeviceId:" << tag.deviceId();
|
||||
} else {
|
||||
dbg.nospace() << "Tag (RuleId:" << tag.ruleId();
|
||||
}
|
||||
dbg.nospace() << ", AppId:" << tag.appId() << ", TagId:" << tag.tagId() << ", Value:" << tag.value() << ")" << endl;
|
||||
return dbg;
|
||||
}
|
||||
|
||||
}
|
||||
57
libnymea-core/tagging/tag.h
Normal file
57
libnymea-core/tagging/tag.h
Normal file
@ -0,0 +1,57 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2018 Michael Zanetti <michael.zanetti@guh.io> *
|
||||
* *
|
||||
* This file is part of nymea. *
|
||||
* *
|
||||
* nymea is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* nymea is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with nymea. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef TAG_H
|
||||
#define TAG_H
|
||||
|
||||
#include "typeutils.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
namespace nymeaserver {
|
||||
|
||||
class Tag
|
||||
{
|
||||
public:
|
||||
Tag(const DeviceId &deviceId, const QString &appId, const QString &tagId, const QString &value);
|
||||
Tag(const RuleId &ruleId, const QString &appId, const QString &tagId, const QString &value);
|
||||
|
||||
DeviceId deviceId() const;
|
||||
RuleId ruleId() const;
|
||||
QString appId() const;
|
||||
QString tagId() const;
|
||||
|
||||
QString value() const;
|
||||
void setValue(const QString &value);
|
||||
|
||||
bool operator==(const Tag &other) const;
|
||||
|
||||
private:
|
||||
DeviceId m_deviceId;
|
||||
RuleId m_ruleId;
|
||||
QString m_appId;
|
||||
QString m_tagId;
|
||||
QString m_value;
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug dbg, const Tag &tag);
|
||||
}
|
||||
|
||||
#endif // TAG_H
|
||||
185
libnymea-core/tagging/tagsstorage.cpp
Normal file
185
libnymea-core/tagging/tagsstorage.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2018 Michael Zanetti <michael.zanetti@guh.io> *
|
||||
* *
|
||||
* This file is part of nymea. *
|
||||
* *
|
||||
* nymea is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* nymea is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with nymea. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "tagsstorage.h"
|
||||
#include "devicemanager.h"
|
||||
#include "ruleengine.h"
|
||||
#include "nymeasettings.h"
|
||||
|
||||
namespace nymeaserver {
|
||||
|
||||
TagsStorage::TagsStorage(DeviceManager *deviceManager, RuleEngine *ruleEngine, QObject *parent):
|
||||
QObject(parent),
|
||||
m_deviceManager(deviceManager),
|
||||
m_ruleEngine(ruleEngine)
|
||||
{
|
||||
connect(deviceManager, &DeviceManager::deviceRemoved, this, &TagsStorage::deviceRemoved);
|
||||
|
||||
NymeaSettings settings(NymeaSettings::SettingsRoleTags);
|
||||
|
||||
settings.beginGroup("Devices");
|
||||
foreach (const QString &deviceId, settings.childGroups()) {
|
||||
settings.beginGroup(deviceId);
|
||||
foreach (const QString &appId, settings.childGroups()) {
|
||||
settings.beginGroup(appId);
|
||||
foreach (const QString &tagId, settings.childKeys()) {
|
||||
Tag tag(DeviceId(deviceId), appId, tagId, settings.value(tagId).toString());
|
||||
m_tags.append(tag);
|
||||
}
|
||||
settings.endGroup();
|
||||
}
|
||||
settings.endGroup();
|
||||
}
|
||||
settings.endGroup();
|
||||
settings.beginGroup("Rules");
|
||||
foreach (const QString &ruleId, settings.childGroups()) {
|
||||
settings.beginGroup(ruleId);
|
||||
foreach (const QString &appId, settings.childGroups()) {
|
||||
settings.beginGroup(appId);
|
||||
foreach (const QString &tagId, settings.childKeys()) {
|
||||
Tag tag(RuleId(ruleId), appId, tagId, settings.value(tagId).toString());
|
||||
m_tags.append(tag);
|
||||
}
|
||||
settings.endGroup();
|
||||
}
|
||||
settings.endGroup();
|
||||
}
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
QList<Tag> TagsStorage::tags() const
|
||||
{
|
||||
return m_tags;
|
||||
}
|
||||
|
||||
QList<Tag> TagsStorage::tags(const DeviceId &deviceId) const
|
||||
{
|
||||
QList<Tag> ret;
|
||||
foreach (const Tag &tag, m_tags) {
|
||||
if (tag.deviceId() == deviceId) {
|
||||
ret.append(tag);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QList<Tag> TagsStorage::tags(const RuleId &ruleId) const
|
||||
{
|
||||
QList<Tag> ret;
|
||||
foreach (const Tag &tag, m_tags) {
|
||||
if (tag.ruleId() == ruleId) {
|
||||
ret.append(tag);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
TagsStorage::TagError TagsStorage::addTag(const Tag &tag)
|
||||
{
|
||||
if (!tag.deviceId().isNull()) {
|
||||
if (!m_deviceManager->findConfiguredDevice(tag.deviceId())) {
|
||||
return TagsStorage::TagErrorDeviceNotFound;
|
||||
}
|
||||
} else if (!tag.ruleId().isNull()) {
|
||||
if (!m_ruleEngine->findRule(tag.ruleId()).isValid()) {
|
||||
return TagsStorage::TagErrorRuleNotFound;
|
||||
}
|
||||
}
|
||||
|
||||
int index = m_tags.indexOf(tag);
|
||||
if (index >= 0) {
|
||||
m_tags.replace(index, tag);
|
||||
emit tagValueChanged(tag);
|
||||
} else {
|
||||
m_tags.append(tag);
|
||||
emit tagAdded(tag);
|
||||
}
|
||||
saveTag(tag);
|
||||
return TagsStorage::TagErrorNoError;
|
||||
}
|
||||
|
||||
TagsStorage::TagError TagsStorage::removeTag(const Tag &tag)
|
||||
{
|
||||
if (!m_tags.contains(tag)) {
|
||||
return TagErrorTagNotFound;
|
||||
}
|
||||
m_tags.removeAll(tag);
|
||||
unsaveTag(tag);
|
||||
emit tagRemoved(tag);
|
||||
return TagErrorNoError;
|
||||
}
|
||||
|
||||
void TagsStorage::deviceRemoved(const DeviceId &deviceId)
|
||||
{
|
||||
QList<Tag> tagsToRemove;
|
||||
foreach (const Tag &tag, m_tags) {
|
||||
if (tag.deviceId() == deviceId) {
|
||||
tagsToRemove.append(tag);
|
||||
}
|
||||
}
|
||||
while (!tagsToRemove.isEmpty()) {
|
||||
removeTag(tagsToRemove.takeFirst());
|
||||
}
|
||||
}
|
||||
|
||||
void TagsStorage::ruleRemoved(const RuleId &ruleId)
|
||||
{
|
||||
QList<Tag> tagsToRemove;
|
||||
foreach (const Tag &tag, m_tags) {
|
||||
if (tag.ruleId() == ruleId) {
|
||||
tagsToRemove.append(tag);
|
||||
}
|
||||
}
|
||||
while (!tagsToRemove.isEmpty()) {
|
||||
removeTag(tagsToRemove.takeFirst());
|
||||
}
|
||||
}
|
||||
|
||||
void TagsStorage::saveTag(const Tag &tag)
|
||||
{
|
||||
NymeaSettings settings(NymeaSettings::SettingsRoleTags);
|
||||
|
||||
if (!tag.deviceId().isNull()) {
|
||||
settings.beginGroup("Devices");
|
||||
settings.beginGroup(tag.deviceId().toString());
|
||||
} else {
|
||||
settings.beginGroup("Rules");
|
||||
settings.beginGroup(tag.ruleId().toString());
|
||||
}
|
||||
settings.beginGroup(tag.appId());
|
||||
settings.setValue(tag.tagId(), tag.value());
|
||||
}
|
||||
|
||||
void TagsStorage::unsaveTag(const Tag &tag)
|
||||
{
|
||||
NymeaSettings settings(NymeaSettings::SettingsRoleTags);
|
||||
|
||||
if (!tag.deviceId().isNull()) {
|
||||
settings.beginGroup("Devices");
|
||||
settings.beginGroup(tag.deviceId().toString());
|
||||
} else {
|
||||
settings.beginGroup("Rules");
|
||||
settings.beginGroup(tag.deviceId().toString());
|
||||
}
|
||||
settings.beginGroup(tag.appId());
|
||||
settings.remove(tag.tagId());
|
||||
}
|
||||
|
||||
}
|
||||
78
libnymea-core/tagging/tagsstorage.h
Normal file
78
libnymea-core/tagging/tagsstorage.h
Normal file
@ -0,0 +1,78 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2018 Michael Zanetti <michael.zanetti@guh.io> *
|
||||
* *
|
||||
* This file is part of nymea. *
|
||||
* *
|
||||
* nymea is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
* nymea is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with nymea. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef TAGSSTORAGE_H
|
||||
#define TAGSSTORAGE_H
|
||||
|
||||
#include "tag.h"
|
||||
#include "typeutils.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
|
||||
class DeviceManager;
|
||||
|
||||
namespace nymeaserver {
|
||||
|
||||
class RuleEngine;
|
||||
|
||||
class TagsStorage : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum TagError {
|
||||
TagErrorNoError,
|
||||
TagErrorDeviceNotFound,
|
||||
TagErrorRuleNotFound,
|
||||
TagErrorTagNotFound
|
||||
};
|
||||
Q_ENUM(TagError)
|
||||
|
||||
explicit TagsStorage(DeviceManager* deviceManager, RuleEngine* ruleEngine, QObject *parent = nullptr);
|
||||
|
||||
TagError addTag(const Tag &tag);
|
||||
TagError removeTag(const Tag &tag);
|
||||
|
||||
QList<Tag> tags() const;
|
||||
QList<Tag> tags(const DeviceId &deviceId) const;
|
||||
QList<Tag> tags(const RuleId &ruleId) const;
|
||||
|
||||
signals:
|
||||
void tagAdded(const Tag &tag);
|
||||
void tagRemoved(const Tag &tag);
|
||||
void tagValueChanged(const Tag &tag);
|
||||
|
||||
private slots:
|
||||
void deviceRemoved(const DeviceId &deviceId);
|
||||
void ruleRemoved(const RuleId &ruleId);
|
||||
|
||||
private:
|
||||
void saveTag(const Tag &tag);
|
||||
void unsaveTag(const Tag &tag);
|
||||
|
||||
private:
|
||||
DeviceManager *m_deviceManager;
|
||||
RuleEngine *m_ruleEngine;
|
||||
QList<Tag> m_tags;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // TAGSSTORAGE_H
|
||||
@ -99,6 +99,9 @@ NymeaSettings::NymeaSettings(const SettingsRole &role, QObject *parent):
|
||||
case SettingsRoleDeviceStates:
|
||||
fileName = "devicestates.conf";
|
||||
break;
|
||||
case SettingsRoleTags:
|
||||
fileName = "tags.conf";
|
||||
break;
|
||||
}
|
||||
m_settings = new QSettings(basePath + settingsPrefix + fileName, QSettings::IniFormat, this);
|
||||
}
|
||||
|
||||
@ -40,7 +40,8 @@ public:
|
||||
SettingsRoleRules,
|
||||
SettingsRolePlugins,
|
||||
SettingsRoleGlobal,
|
||||
SettingsRoleDeviceStates
|
||||
SettingsRoleDeviceStates,
|
||||
SettingsRoleTags
|
||||
};
|
||||
|
||||
explicit NymeaSettings(const SettingsRole &role = SettingsRoleNone, QObject *parent = nullptr);
|
||||
|
||||
@ -6,7 +6,7 @@ NYMEA_PLUGINS_PATH=/usr/lib/$$system('dpkg-architecture -q DEB_HOST_MULTIARCH')/
|
||||
|
||||
# define protocol versions
|
||||
JSON_PROTOCOL_VERSION_MAJOR=1
|
||||
JSON_PROTOCOL_VERSION_MINOR=5
|
||||
JSON_PROTOCOL_VERSION_MINOR=6
|
||||
REST_API_VERSION=1
|
||||
|
||||
DEFINES += NYMEA_VERSION_STRING=\\\"$${NYMEA_VERSION_STRING}\\\" \
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
1.5
|
||||
1.6
|
||||
{
|
||||
"methods": {
|
||||
"Actions.ExecuteAction": {
|
||||
@ -789,6 +789,39 @@
|
||||
"deviceError": "$ref:DeviceError",
|
||||
"o:stateType": "$ref:StateType"
|
||||
}
|
||||
},
|
||||
"Tags.AddTag": {
|
||||
"description": "Add a Tag. A Tag must have a deviceId OR a ruleId (call this method twice if you want to attach the same tag to a device and a rule), an appId (Use the appId of your app), a tagId (e.g. \"favorites\") and a value. Upon success, a TagAdded notification will be emitted. Calling this method twice for the same ids (device/rule, appId and tagId) but with a different value will update the tag's value and the TagValueChanged notification will be emitted.",
|
||||
"params": {
|
||||
"tag": "$ref:Tag"
|
||||
},
|
||||
"returns": {
|
||||
"tagError": "$ref:TagError"
|
||||
}
|
||||
},
|
||||
"Tags.GetTags": {
|
||||
"description": "Get the Tags matching the given filter. Tags can be filtered by a deviceID, a ruleId, an appId, a tagId or a combination of any (however, combining deviceId and ruleId will return an empty result set).",
|
||||
"params": {
|
||||
"o:appId": "String",
|
||||
"o:deviceId": "Uuid",
|
||||
"o:ruleId": "Uuid",
|
||||
"o:tagId": "String"
|
||||
},
|
||||
"returns": {
|
||||
"o:tags": [
|
||||
"$ref:Tag"
|
||||
],
|
||||
"tagError": "$ref:TagError"
|
||||
}
|
||||
},
|
||||
"Tags.RemoveTag": {
|
||||
"description": "Remove a Tag. Tag value is optional and will be disregarded. If the ids match, the tag will be deleted and a TagRemoved notification will be emitted.",
|
||||
"params": {
|
||||
"tag": "$ref:Tag"
|
||||
},
|
||||
"returns": {
|
||||
"tagError": "$ref:TagError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"notifications": {
|
||||
@ -962,6 +995,24 @@
|
||||
"params": {
|
||||
"ruleId": "Uuid"
|
||||
}
|
||||
},
|
||||
"Tags.TagAdded": {
|
||||
"description": "Emitted whenever a tag is added to the system. ",
|
||||
"params": {
|
||||
"tag": "$ref:Tag"
|
||||
}
|
||||
},
|
||||
"Tags.TagRemoved": {
|
||||
"description": "Emitted whenever a tag is removed from the system. ",
|
||||
"params": {
|
||||
"tag": "$ref:Tag"
|
||||
}
|
||||
},
|
||||
"Tags.TagValueChanged": {
|
||||
"description": "Emitted whenever a tag's value is changed in the system. ",
|
||||
"params": {
|
||||
"tag": "$ref:Tag"
|
||||
}
|
||||
}
|
||||
},
|
||||
"types": {
|
||||
@ -1437,6 +1488,14 @@
|
||||
"o:unit": "$ref:Unit",
|
||||
"type": "$ref:BasicType"
|
||||
},
|
||||
"Tag": {
|
||||
"appId": "String",
|
||||
"o:deviceId": "Uuid",
|
||||
"o:ruleId": "Uuid",
|
||||
"o:value": "String",
|
||||
"tagId": "String"
|
||||
},
|
||||
"TagError": "$ref:TagError",
|
||||
"TimeDescriptor": {
|
||||
"o:calendarItems": [
|
||||
"$ref:CalendarItem"
|
||||
|
||||
@ -22,3 +22,4 @@ SUBDIRS = versioning \
|
||||
configurations \
|
||||
timemanager \
|
||||
userloading \
|
||||
tags \
|
||||
|
||||
@ -503,7 +503,7 @@ void TestJSONRPC::introspect()
|
||||
foreach (const QString &ref, extractRefs(item)) {
|
||||
QString typeId = ref;
|
||||
typeId.remove("$ref:");
|
||||
QVERIFY2(types.contains(typeId), QString("Undefined ref: %1").arg(ref).toLatin1().data());
|
||||
QVERIFY2(types.contains(typeId), QString("Undefined ref: %1. Did you forget to add it to JsonTypes::allTypes()?").arg(ref).toLatin1().data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,6 +154,10 @@ protected:
|
||||
verifyError(response, "configurationError", JsonTypes::configurationErrorToString(error));
|
||||
}
|
||||
|
||||
inline void verifyTagError(const QVariant &response, TagsStorage::TagError error = TagsStorage::TagErrorNoError) {
|
||||
verifyError(response, "tagError", JsonTypes::tagErrorToString(error));
|
||||
}
|
||||
|
||||
inline void verifyParams(const QVariantList &requestList, const QVariantList &responseList, bool allRequired = true)
|
||||
{
|
||||
if (allRequired)
|
||||
|
||||
5
tests/auto/tags/tags.pro
Normal file
5
tests/auto/tags/tags.pro
Normal file
@ -0,0 +1,5 @@
|
||||
include(../../../nymea.pri)
|
||||
include(../autotests.pri)
|
||||
|
||||
TARGET = testtags
|
||||
SOURCES += testtags.cpp
|
||||
248
tests/auto/tags/testtags.cpp
Normal file
248
tests/auto/tags/testtags.cpp
Normal file
@ -0,0 +1,248 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* *
|
||||
* Copyright (C) 2018 Michael Zanetti <michael.zanetti@guh.io> *
|
||||
* *
|
||||
* This file is part of nymea. *
|
||||
* *
|
||||
* nymea is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, version 2 of the License. *
|
||||
* *
|
||||
**
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with nymea. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "nymeatestbase.h"
|
||||
#include "nymeacore.h"
|
||||
#include "devicemanager.h"
|
||||
#include "mocktcpserver.h"
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
#include <QCoreApplication>
|
||||
#include <QTcpSocket>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
#include <QCoreApplication>
|
||||
|
||||
using namespace nymeaserver;
|
||||
|
||||
class TestTags: public NymeaTestBase
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void addTag_data();
|
||||
void addTag();
|
||||
|
||||
void updateTagValue();
|
||||
|
||||
void removeTag();
|
||||
|
||||
private:
|
||||
QVariantMap createDeviceTag(const QString &deviceId, const QString &appId, const QString &tagId, const QString &value);
|
||||
bool compareDeviceTag(const QVariantMap &tag, const QString &deviceId, const QString &appId, const QString &tagId, const QString &value);
|
||||
QVariantMap createRuleTag(const QString &ruleId, const QString &appId, const QString &tagId, const QString &value);
|
||||
bool comapreRuleTag(const QVariantMap &tag, const QString &ruleId, const QString &appId, const QString &tagId, const QString &value);
|
||||
};
|
||||
|
||||
QVariantMap TestTags::createDeviceTag(const QString &deviceId, const QString &appId, const QString &tagId, const QString &value)
|
||||
{
|
||||
QVariantMap tag;
|
||||
tag.insert("deviceId", deviceId);
|
||||
tag.insert("appId", appId);
|
||||
tag.insert("tagId", tagId);
|
||||
tag.insert("value", value);
|
||||
return tag;
|
||||
}
|
||||
|
||||
QVariantMap TestTags::createRuleTag(const QString &ruleId, const QString &appId, const QString &tagId, const QString &value)
|
||||
{
|
||||
QVariantMap tag;
|
||||
tag.insert("ruleId", ruleId);
|
||||
tag.insert("appId", appId);
|
||||
tag.insert("tagId", tagId);
|
||||
tag.insert("value", value);
|
||||
return tag;
|
||||
}
|
||||
|
||||
bool TestTags::compareDeviceTag(const QVariantMap &tag, const QString &deviceId, const QString &appId, const QString &tagId, const QString &value)
|
||||
{
|
||||
return tag.value("deviceId").toString() == deviceId &&
|
||||
tag.value("appId").toString() == appId &&
|
||||
tag.value("tagId").toString() == tagId &&
|
||||
tag.value("value").toString() == value;
|
||||
}
|
||||
void TestTags::addTag_data()
|
||||
{
|
||||
QTest::addColumn<DeviceId>("deviceId");
|
||||
QTest::addColumn<QString>("appId");
|
||||
QTest::addColumn<QString>("tagId");
|
||||
QTest::addColumn<QString>("value");
|
||||
QTest::addColumn<TagsStorage::TagError>("expectedError");
|
||||
|
||||
QTest::newRow("tagDevice") << m_mockDeviceId << "testtags" << "favorites" << "1" << TagsStorage::TagErrorNoError;
|
||||
QTest::newRow("invalidDevice") << DeviceId::createDeviceId() << "testtags" << "favorites" << "1" << TagsStorage::TagErrorDeviceNotFound;
|
||||
}
|
||||
|
||||
void TestTags::addTag()
|
||||
{
|
||||
QFETCH(DeviceId, deviceId);
|
||||
QFETCH(QString, appId);
|
||||
QFETCH(QString, tagId);
|
||||
QFETCH(QString, value);
|
||||
QFETCH(TagsStorage::TagError, expectedError);
|
||||
|
||||
// enable notificartions
|
||||
QCOMPARE(enableNotifications(), true);
|
||||
|
||||
// Setup connection to mock client
|
||||
QSignalSpy clientSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
|
||||
|
||||
// Create a tag;
|
||||
QVariantMap params;
|
||||
params.insert("tag", createDeviceTag(deviceId.toString(), appId, tagId, value));
|
||||
QVariant response = injectAndWait("Tags.AddTag", params);
|
||||
verifyTagError(response, expectedError);
|
||||
|
||||
if (expectedError != TagsStorage::TagErrorNoError) {
|
||||
// If we expected an error, we can drop out here
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the TagAdded notification is emitted.
|
||||
QVariantMap notificationTagMap = checkNotification(clientSpy, "Tags.TagAdded").toMap().value("params").toMap().value("tag").toMap();
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromVariant(notificationTagMap);
|
||||
QVERIFY2(compareDeviceTag(notificationTagMap, deviceId.toString(), appId, tagId, value), QString("Tag in notification not matching: %1").arg(qUtf8Printable(jsonDoc.toJson())).toLatin1());
|
||||
|
||||
// Try getting the tag via GetTag
|
||||
params.clear();
|
||||
params.insert("deviceId", deviceId.toString());
|
||||
params.insert("appId", appId);
|
||||
params.insert("tagId", tagId);
|
||||
response = injectAndWait("Tags.GetTags", params);
|
||||
QVariantList tagsList = response.toMap().value("params").toMap().value("tags").toList();
|
||||
QCOMPARE(tagsList.count(), 1);
|
||||
QVERIFY2(compareDeviceTag(tagsList.first().toMap(), deviceId.toString(), appId, tagId, value), "Fetched tag isn't matching the one we added");
|
||||
}
|
||||
|
||||
void TestTags::updateTagValue()
|
||||
{
|
||||
// enable notificartions
|
||||
QCOMPARE(enableNotifications(), true);
|
||||
|
||||
// Setup connection to mock client
|
||||
QSignalSpy clientSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
|
||||
|
||||
QString deviceId = m_mockDeviceId.toString();
|
||||
QString appId = "testtags";
|
||||
QString tagId = "changedNotificationTag";
|
||||
|
||||
// Create a Tag
|
||||
QVariantMap params;
|
||||
params.insert("tag", createDeviceTag(deviceId, appId, tagId, "1"));
|
||||
QVariant response = injectAndWait("Tags.AddTag", params);
|
||||
verifyTagError(response, TagsStorage::TagErrorNoError);
|
||||
|
||||
// Check for TagAdded notification
|
||||
QVariantMap notificationTagMap = checkNotification(clientSpy, "Tags.TagAdded").toMap().value("params").toMap().value("tag").toMap();
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromVariant(notificationTagMap);
|
||||
QVERIFY2(compareDeviceTag(notificationTagMap, deviceId, appId, tagId, "1"), QString("Tag in notification not matching: %1").arg(qUtf8Printable(jsonDoc.toJson())).toLatin1());
|
||||
clientSpy.clear();
|
||||
|
||||
// Try getting the changed tag via GetTag
|
||||
params.clear();
|
||||
params.insert("deviceId", deviceId);
|
||||
params.insert("appId", appId);
|
||||
params.insert("tagId", tagId);
|
||||
response = injectAndWait("Tags.GetTags", params);
|
||||
QVariantList tagsList = response.toMap().value("params").toMap().value("tags").toList();
|
||||
QCOMPARE(tagsList.count(), 1);
|
||||
QVERIFY2(compareDeviceTag(tagsList.first().toMap(), deviceId, appId, tagId, "1"), "Fetched tag isn't matching the one we added");
|
||||
|
||||
// Now update the tag
|
||||
params.clear();
|
||||
params.insert("tag", createDeviceTag(deviceId, appId, tagId, "2"));
|
||||
response = injectAndWait("Tags.AddTag", params);
|
||||
verifyTagError(response, TagsStorage::TagErrorNoError);
|
||||
|
||||
// Check for TagAdded notification
|
||||
notificationTagMap = checkNotification(clientSpy, "Tags.TagValueChanged").toMap().value("params").toMap().value("tag").toMap();
|
||||
jsonDoc = QJsonDocument::fromVariant(notificationTagMap);
|
||||
QVERIFY2(compareDeviceTag(notificationTagMap, deviceId, appId, tagId, "2"), QString("Tag in notification not matching: %1").arg(qUtf8Printable(jsonDoc.toJson())).toLatin1());
|
||||
|
||||
// Try getting the changed tag via GetTag
|
||||
params.clear();
|
||||
params.insert("deviceId", deviceId);
|
||||
params.insert("appId", appId);
|
||||
params.insert("tagId", tagId);
|
||||
response = injectAndWait("Tags.GetTags", params);
|
||||
tagsList = response.toMap().value("params").toMap().value("tags").toList();
|
||||
QCOMPARE(tagsList.count(), 1);
|
||||
QVERIFY2(compareDeviceTag(tagsList.first().toMap(), deviceId, appId, tagId, "2"), "Fetched tag isn't matching the one we added");
|
||||
}
|
||||
|
||||
void TestTags::removeTag()
|
||||
{
|
||||
// enable notificartions
|
||||
QCOMPARE(enableNotifications(), true);
|
||||
|
||||
// Setup connection to mock client
|
||||
QSignalSpy clientSpy(m_mockTcpServer, SIGNAL(outgoingData(QUuid,QByteArray)));
|
||||
|
||||
QString deviceId = m_mockDeviceId.toString();
|
||||
QString appId = "testtags";
|
||||
QString tagId = "removeTagTest";
|
||||
QString value = "1";
|
||||
|
||||
// Create a Tag
|
||||
QVariantMap params;
|
||||
params.insert("tag", createDeviceTag(deviceId, appId, tagId, value));
|
||||
QVariant response = injectAndWait("Tags.AddTag", params);
|
||||
verifyTagError(response, TagsStorage::TagErrorNoError);
|
||||
|
||||
// Check for TagAdded notification
|
||||
QVariantMap notificationTagMap = checkNotification(clientSpy, "Tags.TagAdded").toMap().value("params").toMap().value("tag").toMap();
|
||||
QJsonDocument jsonDoc = QJsonDocument::fromVariant(notificationTagMap);
|
||||
QVERIFY2(compareDeviceTag(notificationTagMap, deviceId, appId, tagId, value), QString("Tag in notification not matching: %1").arg(qUtf8Printable(jsonDoc.toJson())).toLatin1());
|
||||
clientSpy.clear();
|
||||
|
||||
// Try getting the tag via GetTag
|
||||
params.clear();
|
||||
params.insert("deviceId", deviceId);
|
||||
params.insert("appId", appId);
|
||||
params.insert("tagId", tagId);
|
||||
response = injectAndWait("Tags.GetTags", params);
|
||||
QVariantList tagsList = response.toMap().value("params").toMap().value("tags").toList();
|
||||
QCOMPARE(tagsList.count(), 1);
|
||||
QVERIFY2(compareDeviceTag(tagsList.first().toMap(), deviceId, appId, tagId, value), "Fetched tag isn't matching the one we added");
|
||||
|
||||
// Now remove the tag
|
||||
params.clear();
|
||||
params.insert("tag", createDeviceTag(deviceId, appId, tagId, QString()));
|
||||
response = injectAndWait("Tags.RemoveTag", params);
|
||||
verifyTagError(response, TagsStorage::TagErrorNoError);
|
||||
|
||||
// Check for TagRemoved notification
|
||||
notificationTagMap = checkNotification(clientSpy, "Tags.TagRemoved").toMap().value("params").toMap().value("tag").toMap();
|
||||
jsonDoc = QJsonDocument::fromVariant(notificationTagMap);
|
||||
QVERIFY2(compareDeviceTag(notificationTagMap, deviceId, appId, tagId, QString()), QString("Tag in notification not matching: %1").arg(qUtf8Printable(jsonDoc.toJson())).toLatin1());
|
||||
|
||||
// Try getting the tag via GetTag
|
||||
params.clear();
|
||||
params.insert("deviceId", deviceId);
|
||||
params.insert("appId", appId);
|
||||
params.insert("tagId", tagId);
|
||||
response = injectAndWait("Tags.GetTags", params);
|
||||
tagsList = response.toMap().value("params").toMap().value("tags").toList();
|
||||
QCOMPARE(tagsList.count(), 0);
|
||||
}
|
||||
|
||||
#include "testtags.moc"
|
||||
QTEST_MAIN(TestTags)
|
||||
7
tests/scripts/gettags.sh
Executable file
7
tests/scripts/gettags.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ -z $1 ]; then
|
||||
echo "usage: $0 host"
|
||||
else
|
||||
(echo '{"id":1, "method":"Tags.GetTags"}'; sleep 1) | nc $1 2222
|
||||
fi
|
||||
7
tests/scripts/tagdevice.sh
Executable file
7
tests/scripts/tagdevice.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ -z $5 ]; then
|
||||
echo "usage: $0 host deviceId appId tagId value"
|
||||
else
|
||||
(echo '{"id":1, "method":"Tags.AddTag", "params": { "tag": {"deviceId": "'$2'", "appId": "'$3'", "tagId": "'$4'", "value":"'$5'"}}}'; sleep 1) | nc $1 2222
|
||||
fi
|
||||
Reference in New Issue
Block a user