diff --git a/libnymea-app-core/configuration/mqttpolicies.cpp b/libnymea-app-core/configuration/mqttpolicies.cpp
index dfe4dba4..c03a5235 100644
--- a/libnymea-app-core/configuration/mqttpolicies.cpp
+++ b/libnymea-app-core/configuration/mqttpolicies.cpp
@@ -71,6 +71,27 @@ void MqttPolicies::addPolicy(MqttPolicy *policy)
emit countChanged();
}
+void MqttPolicies::removePolicy(MqttPolicy *policy)
+{
+ int idx = m_list.indexOf(policy);
+ if (idx < 0) {
+ return;
+ }
+ beginRemoveRows(QModelIndex(), idx, idx);
+ m_list.takeAt(idx)->deleteLater();
+ endRemoveRows();
+}
+
+MqttPolicy *MqttPolicies::getPolicy(const QString &clientId) const
+{
+ foreach (MqttPolicy* policy, m_list) {
+ if (policy->clientId() == clientId) {
+ return policy;
+ }
+ }
+ return nullptr;
+}
+
MqttPolicy *MqttPolicies::get(int index) const
{
if (index < 0 || index >= m_list.count()){
diff --git a/libnymea-app-core/configuration/mqttpolicies.h b/libnymea-app-core/configuration/mqttpolicies.h
index 887676ae..ae7a5d7c 100644
--- a/libnymea-app-core/configuration/mqttpolicies.h
+++ b/libnymea-app-core/configuration/mqttpolicies.h
@@ -28,6 +28,7 @@ public:
void addPolicy(MqttPolicy *policy);
void removePolicy(MqttPolicy *policy);
+ Q_INVOKABLE MqttPolicy* getPolicy(const QString &clientId) const;
Q_INVOKABLE MqttPolicy* get(int index) const;
void clear();
diff --git a/libnymea-app-core/configuration/mqttpolicy.cpp b/libnymea-app-core/configuration/mqttpolicy.cpp
index c1bb2f5a..ee476a44 100644
--- a/libnymea-app-core/configuration/mqttpolicy.cpp
+++ b/libnymea-app-core/configuration/mqttpolicy.cpp
@@ -5,8 +5,8 @@ MqttPolicy::MqttPolicy(const QString &clientId, const QString &username, const Q
m_clientId(clientId),
m_username(username),
m_password(password),
- m_allowedSubscribeTopicFilters(allowedSubscribeTopicFilters),
- m_allowedPublishTopicFilters(allowedPublishTopicFilters)
+ m_allowedPublishTopicFilters(allowedPublishTopicFilters),
+ m_allowedSubscribeTopicFilters(allowedSubscribeTopicFilters)
{
}
@@ -75,3 +75,8 @@ void MqttPolicy::setAllowedSubscribeTopicFilters(const QStringList &allowedSubsc
emit allowedSubscribeTopicFiltersChanged();
}
}
+
+MqttPolicy *MqttPolicy::clone()
+{
+ return new MqttPolicy(m_clientId, m_username, m_password, m_allowedPublishTopicFilters, m_allowedSubscribeTopicFilters, this);
+}
diff --git a/libnymea-app-core/configuration/mqttpolicy.h b/libnymea-app-core/configuration/mqttpolicy.h
index 09e4d8bb..8f809967 100644
--- a/libnymea-app-core/configuration/mqttpolicy.h
+++ b/libnymea-app-core/configuration/mqttpolicy.h
@@ -35,6 +35,7 @@ public:
QStringList allowedSubscribeTopicFilters() const;
void setAllowedSubscribeTopicFilters(const QStringList &allowedSubscribeTopicFilters);
+ Q_INVOKABLE MqttPolicy* clone();
signals:
void clientIdChanged();
void usernameChanged();
diff --git a/libnymea-app-core/configuration/nymeaconfiguration.cpp b/libnymea-app-core/configuration/nymeaconfiguration.cpp
index 452e2299..79eed28e 100644
--- a/libnymea-app-core/configuration/nymeaconfiguration.cpp
+++ b/libnymea-app-core/configuration/nymeaconfiguration.cpp
@@ -134,7 +134,7 @@ ServerConfiguration *NymeaConfiguration::createServerConfiguration(const QString
MqttPolicy *NymeaConfiguration::createMqttPolicy() const
{
- return new MqttPolicy();
+ return new MqttPolicy(QString(), QString(), QString(), {"#"}, {"#"});
}
void NymeaConfiguration::setTcpServerConfiguration(ServerConfiguration *configuration)
@@ -214,7 +214,7 @@ void NymeaConfiguration::deleteMqttPolicy(const QString &clientId)
{
QVariantMap params;
params.insert("clientId", clientId);
- m_client->sendCommand("Configuration.RemoveMqttPolicy", params);
+ m_client->sendCommand("Configuration.DeleteMqttPolicy", params, this, "deleteMqttPolicyReply");
}
void NymeaConfiguration::getConfigurationsResponse(const QVariantMap ¶ms)
@@ -347,6 +347,11 @@ void NymeaConfiguration::setMqttPolicyReply(const QVariantMap ¶ms)
qDebug() << "Set MQTT policy reply" << params;
}
+void NymeaConfiguration::deleteMqttPolicyReply(const QVariantMap ¶ms)
+{
+ qDebug() << "Delete MQTT policy reply" << params;
+}
+
void NymeaConfiguration::notificationReceived(const QVariantMap ¬ification)
{
QString notif = notification.value("notification").toString();
@@ -421,7 +426,7 @@ void NymeaConfiguration::notificationReceived(const QVariantMap ¬ification)
}
if (notif == "Configuration.MqttPolicyChanged") {
MqttPolicy *policy = nullptr;
- QVariantMap policyMap = notification.value("params").toMap();
+ QVariantMap policyMap = notification.value("params").toMap().value("policy").toMap();
for (int i = 0; i < m_mqttPolicies->rowCount(); i++) {
if (m_mqttPolicies->get(i)->clientId() == policyMap.value("clientId").toString()) {
policy = m_mqttPolicies->get(i);
@@ -436,8 +441,17 @@ void NymeaConfiguration::notificationReceived(const QVariantMap ¬ification)
policy->setPassword(policyMap.value("password").toString());
policy->setAllowedPublishTopicFilters(policyMap.value("allowedPublishTopicFilters").toStringList());
policy->setAllowedSubscribeTopicFilters(policyMap.value("allowedSubscribeTopicFilters").toStringList());
+ qDebug() << "MQTT policy added" << policy->clientId() << policy->username() << policy->password();
return;
}
+ if (notif == "Configuration.MqttPolicyRemoved") {
+ MqttPolicy* policy = m_mqttPolicies->getPolicy(notification.value("params").toMap().value("clientId").toString());
+ if (!policy) {
+ qWarning() << "Reveived a policy removed notification for apolicy we don't know";
+ return;
+ }
+ m_mqttPolicies->removePolicy(policy);
+ }
qDebug() << "Unhandled Configuration notification" << notif << notification;
}
diff --git a/libnymea-app-core/configuration/nymeaconfiguration.h b/libnymea-app-core/configuration/nymeaconfiguration.h
index a7b9ee46..83e8f9dd 100644
--- a/libnymea-app-core/configuration/nymeaconfiguration.h
+++ b/libnymea-app-core/configuration/nymeaconfiguration.h
@@ -92,6 +92,7 @@ private:
Q_INVOKABLE void deleteMqttConfigReply(const QVariantMap ¶ms);
Q_INVOKABLE void getMqttPoliciesReply(const QVariantMap ¶ms);
Q_INVOKABLE void setMqttPolicyReply(const QVariantMap ¶ms);
+ Q_INVOKABLE void deleteMqttPolicyReply(const QVariantMap ¶ms);
Q_INVOKABLE void notificationReceived(const QVariantMap ¬ification);
diff --git a/nymea-app/resources.qrc b/nymea-app/resources.qrc
index 088ac41d..1b02648e 100644
--- a/nymea-app/resources.qrc
+++ b/nymea-app/resources.qrc
@@ -138,6 +138,6 @@
ui/devicelistpages/SmartMeterDeviceListPage.qml
ui/system/MqttBrokerSettingsPage.qml
ui/system/ServerConfigurationDialog.qml
- ui/system/MqttPolicyDialog.qml
+ ui/system/MqttPolicyPage.qml
diff --git a/nymea-app/ui/system/MqttBrokerSettingsPage.qml b/nymea-app/ui/system/MqttBrokerSettingsPage.qml
index 8bc1f99e..0d7e0781 100644
--- a/nymea-app/ui/system/MqttBrokerSettingsPage.qml
+++ b/nymea-app/ui/system/MqttBrokerSettingsPage.qml
@@ -21,49 +21,6 @@ Page {
// anchors { left: parent.left; top: parent.top; right: parent.right }
anchors.fill: parent
// layoutDirection: Qt.
- Label {
- Layout.fillWidth: true
- Layout.margins: app.margins
- text: qsTr("MQTT permissions")
- wrapMode: Text.WordWrap
- color: app.accentColor
- }
-
- ListView {
- Layout.fillWidth: true
- Layout.preferredHeight: contentHeight
- model: engine.nymeaConfiguration.mqttPolicies
- delegate: MeaListItemDelegate {
- width: parent.width
- iconName: "../images/account.svg"
- text: qsTr("Client ID: %1").arg(model.clientId)
- subText: qsTr("Username: %1").arg(model.username)
- progressive: false
- canDelete: true
- onDeleteClicked: {
- engine.nymeaConfiguration.deleteMqttPolicy(model.clientId)
- }
- }
- }
-
- Button {
- Layout.fillWidth: true
- Layout.margins: app.margins
- text: qsTr("Add")
- onClicked: {
- var component = Qt.createComponent(Qt.resolvedUrl("MqttPolicyDialog.qml"));
- var popup = component.createObject(root, { policy: engine.nymeaConfiguration.createMqttPolicy() });
- popup.accepted.connect(function() {
- engine.nymeaConfiguration.updateMqttPolicy(popup.policy)
- popup.policy.destroy();
- })
- popup.rejected.connect(function() {
- popup.policy.destroy();
- })
- popup.open()
- }
- }
-
Label {
Layout.fillWidth: true
Layout.leftMargin: app.margins
@@ -77,8 +34,11 @@ Page {
ListView {
Layout.fillWidth: true
Layout.minimumHeight: 0
- Layout.preferredHeight: contentHeight
+ Layout.preferredHeight: Math.min(contentHeight, 120)
model: engine.nymeaConfiguration.mqttServerConfigurations
+ clip: true
+ ScrollBar.vertical: ScrollBar {}
+
delegate: ConnectionInterfaceDelegate {
width: parent.width
canDelete: true
@@ -96,14 +56,13 @@ Page {
}
onDeleteClicked: {
- print("should delete")
engine.nymeaConfiguration.deleteMqttServerConfiguration(model.id)
}
}
}
Button {
Layout.fillWidth: true
- Layout.margins: app.margins
+ Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
text: qsTr("Add")
onClicked: {
var config = engine.nymeaConfiguration.createServerConfiguration("0.0.0.0", 1883 + engine.nymeaConfiguration.mqttServerConfigurations.count, false, false);
@@ -119,6 +78,61 @@ Page {
popup.open()
}
}
+ Label {
+ Layout.fillWidth: true
+ Layout.leftMargin: app.margins; Layout.topMargin: app.margins; Layout.rightMargin: app.margins
+ text: qsTr("MQTT permissions")
+ wrapMode: Text.WordWrap
+ color: app.accentColor
+ }
+
+ ListView {
+ Layout.fillWidth: true
+ Layout.preferredHeight: Math.min(contentHeight, parent.height * .4)
+ model: engine.nymeaConfiguration.mqttPolicies
+ clip: true
+ ScrollBar.vertical: ScrollBar {}
+ delegate: MeaListItemDelegate {
+ width: parent.width
+ iconName: "../images/account.svg"
+ text: qsTr("Client ID: %1").arg(model.clientId)
+ subText: qsTr("Username: %1").arg(model.username)
+ progressive: false
+ canDelete: true
+ onClicked: {
+ var page = pageStack.push(Qt.resolvedUrl("MqttPolicyPage.qml"), { policy: engine.nymeaConfiguration.mqttPolicies.get(index).clone() });
+ page.accepted.connect(function() {
+ if (page.policy.clientId !== model.clientId) {
+ engine.nymeaConfiguration.deleteMqttPolicy(model.clientId);
+ }
+ engine.nymeaConfiguration.updateMqttPolicy(page.policy)
+ page.policy.destroy();
+ })
+ page.rejected.connect(function() {
+ page.policy.destroy();
+ })
+ }
+ onDeleteClicked: {
+ engine.nymeaConfiguration.deleteMqttPolicy(model.clientId)
+ }
+ }
+ }
+
+ Button {
+ Layout.fillWidth: true
+ Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
+ text: qsTr("Add")
+ onClicked: {
+ var page = pageStack.push(Qt.resolvedUrl("MqttPolicyPage.qml"), { policy: engine.nymeaConfiguration.createMqttPolicy() });
+ page.accepted.connect(function() {
+ engine.nymeaConfiguration.updateMqttPolicy(page.policy)
+ page.policy.destroy();
+ })
+ page.rejected.connect(function() {
+ page.policy.destroy();
+ })
+ }
+ }
Item {
Layout.fillWidth: true
Layout.fillHeight: true
diff --git a/nymea-app/ui/system/MqttPolicyDialog.qml b/nymea-app/ui/system/MqttPolicyDialog.qml
deleted file mode 100644
index 596912c1..00000000
--- a/nymea-app/ui/system/MqttPolicyDialog.qml
+++ /dev/null
@@ -1,57 +0,0 @@
-import QtQuick 2.9
-import QtQuick.Controls 2.1
-import QtQuick.Controls.Material 2.1
-import QtQuick.Layouts 1.1
-import Nymea 1.0
-
-Dialog {
- id: root
- title: qsTr("Mqtt permission")
- width: parent.width * .8
- x: (parent.width - width) / 2
- y: (parent.height - height) / 2
-
- property MqttPolicy policy: null
- standardButtons: Dialog.Ok | Dialog.Cancel
-
- ColumnLayout {
- anchors { left: parent.left; top: parent.top; right: parent.right }
- RowLayout {
- Label {
- text: qsTr("Client ID:")
- Layout.fillWidth: true
- }
- TextField {
- id: clientIdTextField
- Layout.fillWidth: true
- text: root.policy ? root.policy.clientId : ""
- onEditingFinished: root.policy.clientId = text
- }
- }
- RowLayout {
- Label {
- text: qsTr("Username:")
- Layout.fillWidth: true
- }
- TextField {
- id: usernameTextField
- Layout.fillWidth: true
- text: root.policy ? root.policy.username : ""
- onEditingFinished: root.policy.username = text
- }
- }
-
- RowLayout {
- Label {
- text: qsTr("Password:")
- Layout.fillWidth: true
- }
- TextField {
- Layout.fillWidth: true
- text: root.policy ? root.policy.password : ""
- onEditingFinished: root.policy.password = text
- }
- }
-
- }
-}
diff --git a/nymea-app/ui/system/MqttPolicyPage.qml b/nymea-app/ui/system/MqttPolicyPage.qml
new file mode 100644
index 00000000..7b6274a6
--- /dev/null
+++ b/nymea-app/ui/system/MqttPolicyPage.qml
@@ -0,0 +1,186 @@
+import QtQuick 2.9
+import QtQuick.Controls 2.1
+import QtQuick.Controls.Material 2.1
+import QtQuick.Layouts 1.1
+import Nymea 1.0
+import "../components"
+
+Page {
+ id: root
+ header: GuhHeader {
+ text: qsTr("Mqtt permission")
+ onBackPressed: {
+ root.rejected();
+ pageStack.pop();
+ }
+ HeaderButton {
+ imageSource: "../images/tick.svg"
+ enabled: clientIdTextField.isValid
+ onClicked: {
+ root.accepted();
+ pageStack.pop();
+ }
+ }
+ }
+ property MqttPolicy policy: null
+
+ signal accepted();
+ signal rejected()
+
+ ColumnLayout {
+ anchors { left: parent.left; top: parent.top; right: parent.right; bottom: parent.bottom }
+ RowLayout {
+ Layout.leftMargin: app.margins; Layout.rightMargin: app.margins; Layout.topMargin: app.margins
+ spacing: app.margins
+ Label {
+ text: qsTr("Client ID:")
+ Layout.fillWidth: true
+ }
+ TextField {
+ id: clientIdTextField
+ Layout.fillWidth: true
+ text: root.policy ? root.policy.clientId : ""
+ onEditingFinished: root.policy.clientId = text
+ placeholderText: qsTr("E.g. Sensor_1")
+ property bool isEmpty: displayText.length === 0
+ property bool isDuplicate: clientIdTextField.displayText != root.policy.clientId && engine.nymeaConfiguration.mqttPolicies.getPolicy(clientIdTextField.displayText) !== null
+ property bool isValid: !isEmpty && !isDuplicate
+ }
+ }
+ Label {
+ Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
+ text: clientIdTextField.isDuplicate ? qsTr("%1 is already used").arg(clientIdTextField.displayText) : qsTr("Can't be blank")
+ font.pixelSize: app.smallFont
+ Layout.alignment: Qt.AlignRight
+ color: "red"
+ visible: !clientIdTextField.isValid
+ }
+
+ RowLayout {
+ Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
+ Label {
+ text: qsTr("Username:")
+ Layout.fillWidth: true
+ }
+ TextField {
+ id: usernameTextField
+ Layout.fillWidth: true
+ text: root.policy ? root.policy.username : ""
+ onEditingFinished: root.policy.username = text
+ placeholderText: qsTr("Optional")
+ }
+ }
+
+ RowLayout {
+ Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
+ Label {
+ text: qsTr("Password:")
+ Layout.fillWidth: true
+ }
+ TextField {
+ Layout.fillWidth: true
+ text: root.policy ? root.policy.password : ""
+ onEditingFinished: root.policy.password = text
+ placeholderText: qsTr("Optional")
+ }
+ }
+
+ ThinDivider {}
+
+ Label {
+ Layout.fillWidth: true
+ Layout.leftMargin: app.margins; Layout.rightMargin: app.margins; Layout.topMargin: app.margins
+ text: qsTr("Allowed publish topics")
+ }
+ ListView {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ model: root.policy.allowedPublishTopicFilters
+ ScrollBar.vertical: ScrollBar {}
+ clip: true
+ delegate: MeaListItemDelegate {
+ width: parent.width
+ text: modelData
+ canDelete: true
+ progressive: false
+ onDeleteClicked: {
+ root.policy.allowedPublishTopicFilters.splice(index, 1)
+ }
+ }
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+ Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
+ property bool add: false
+ TextField {
+ id: pubField
+ Layout.fillWidth: parent.add
+ Layout.preferredWidth: parent.add ? undefined : 0
+ Behavior on width {
+ NumberAnimation {}
+ }
+ }
+ Button {
+ Layout.fillWidth: !parent.add
+ text: parent.add ? qsTr("OK") : qsTr("Add")
+ enabled: !parent.add || pubField.displayText.length > 0
+ onClicked: {
+ if (parent.add) {
+ root.policy.allowedPublishTopicFilters.push(pubField.displayText)
+ pubField.clear();
+ }
+ parent.add = !parent.add;
+ }
+ }
+ }
+
+ ThinDivider {}
+
+ Label {
+ Layout.fillWidth: true
+ Layout.leftMargin: app.margins; Layout.rightMargin: app.margins; Layout.topMargin: app.margins
+ text: qsTr("Allowed subscribe filters")
+ }
+ ListView {
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ model: root.policy.allowedSubscribeTopicFilters
+ ScrollBar.vertical: ScrollBar {}
+ clip: true
+ delegate: MeaListItemDelegate {
+ width: parent.width
+ text: modelData
+ canDelete: true
+ progressive: false
+ onDeleteClicked: {
+ root.policy.allowedSubscribeTopicFilters.splice(index, 1)
+ }
+ }
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+ Layout.leftMargin: app.margins; Layout.rightMargin: app.margins; Layout.bottomMargin: app.margins
+ property bool add: false
+ TextField {
+ id: subField
+ Layout.fillWidth: parent.add
+ Layout.preferredWidth: parent.add ? undefined : 0
+ }
+ Button {
+ Layout.fillWidth: !parent.add;
+ Behavior on width { NumberAnimation {} }
+ text: parent.add ? qsTr("OK") : qsTr("Add")
+ enabled: !parent.add || subField.displayText.length > 0
+ onClicked: {
+ if (parent.add) {
+ root.policy.allowedSubscribeTopicFilters.push(subField.displayText)
+ subField.clear();
+ }
+ parent.add = !parent.add;
+ }
+ }
+ }
+ }
+}