{
  "custom": {},
  "params": {},
  "permissions": {
    "securityLevels": [
      {
        "children": [],
        "name": "Authenticated"
      }
    ],
    "type": "AnyOf"
  },
  "propConfig": {
    "custom.mqtt_users": {
      "access": "PRIVATE",
      "binding": {
        "config": {
          "expression": "1"
        },
        "transforms": [
          {
            "code": "\t\n\tfrom com.inductiveautomation.ignition.gateway import IgnitionGateway\n\tcontext\u003dIgnitionGateway.get()\n\t\t\n\tfrom simpleorm.dataset import SQuery\n\t\n\tdistributorModule\u003dcontext.getModuleManager().getModule(\u0027com.cirruslink.mqtt.distributor.gateway\u0027)\n\tuserRecordClass\u003ddistributorModule.getHook().getClass().getClassLoader().loadClass(\u0027com.cirruslink.mqtt.distributor.gateway.record.UserRecord\u0027)\n\tuserRecordMeta\u003duserRecordClass.getField(\u0027META\u0027).get(None)\n\tpi\u003dcontext.getPersistenceInterface()\n\t\n\tusernameField\u003duserRecordClass.getField(\u0027Username\u0027).get(None)\n\tusers\u003dpi.query(SQuery(userRecordMeta).in(usernameField,\u0027mqtt\u0027,\u0027mqtt2\u0027))\n\treturn [{\u0027username\u0027:user.getUsername(),\u0027password\u0027:user.getPassword()} for user in users]\n",
            "type": "script"
          }
        ],
        "type": "expr"
      },
      "persistent": false
    }
  },
  "props": {
    "defaultSize": {
      "height": 618,
      "width": 813
    }
  },
  "root": {
    "children": [
      {
        "meta": {
          "name": "networkHeader"
        },
        "position": {
          "basis": "32px"
        },
        "props": {
          "style": {
            "fontSize": "1.5em",
            "fontWeight": "bold",
            "marginLeft": "0px"
          },
          "text": "Network"
        },
        "type": "ia.display.label"
      },
      {
        "children": [
          {
            "children": [
              {
                "meta": {
                  "name": "label"
                },
                "position": {
                  "basis": "150px",
                  "shrink": 0
                },
                "propConfig": {
                  "props.text": {
                    "binding": {
                      "config": {
                        "expression": "translate(\"Host\") + \":\""
                      },
                      "type": "expr"
                    }
                  }
                },
                "type": "ia.display.label"
              },
              {
                "meta": {
                  "name": "value"
                },
                "position": {
                  "grow": 1
                },
                "propConfig": {
                  "props.text": {
                    "binding": {
                      "config": {
                        "path": "session.props.gateway.address"
                      },
                      "transforms": [
                        {
                          "code": "\timport re\n\tresult \u003d re.match(\u0027https?://([^:]*)(:\\d+)?\u0027, value)\n\tif result:\n\t\treturn result.group(1)\n\treturn \u0027(error determining host)\u0027",
                          "type": "script"
                        }
                      ],
                      "type": "property"
                    }
                  }
                },
                "type": "ia.display.label"
              }
            ],
            "meta": {
              "name": "host"
            },
            "position": {
              "basis": "40px",
              "shrink": 0
            },
            "type": "ia.container.flex"
          },
          {
            "children": [
              {
                "meta": {
                  "name": "label"
                },
                "position": {
                  "basis": "150px",
                  "shrink": 0
                },
                "propConfig": {
                  "props.text": {
                    "binding": {
                      "config": {
                        "expression": "translate(\"Port\") + \":\""
                      },
                      "type": "expr"
                    }
                  }
                },
                "type": "ia.display.label"
              },
              {
                "meta": {
                  "name": "value"
                },
                "position": {
                  "grow": 1
                },
                "props": {
                  "text": 8883
                },
                "type": "ia.display.label"
              }
            ],
            "meta": {
              "name": "port"
            },
            "position": {
              "basis": "40px",
              "shrink": 0
            },
            "type": "ia.container.flex"
          },
          {
            "children": [
              {
                "meta": {
                  "name": "label"
                },
                "position": {
                  "basis": "150px",
                  "shrink": 0
                },
                "propConfig": {
                  "props.text": {
                    "binding": {
                      "config": {
                        "expression": "translate(\"TLS/SSL\") + \":\""
                      },
                      "type": "expr"
                    }
                  }
                },
                "type": "ia.display.label"
              },
              {
                "meta": {
                  "name": "value"
                },
                "position": {
                  "grow": 1
                },
                "props": {
                  "text": "Required"
                },
                "type": "ia.display.label"
              }
            ],
            "meta": {
              "name": "tls"
            },
            "position": {
              "basis": "40px",
              "shrink": 0
            },
            "type": "ia.container.flex"
          },
          {
            "children": [
              {
                "meta": {
                  "name": "label"
                },
                "position": {
                  "basis": "150px",
                  "shrink": 0
                },
                "propConfig": {
                  "props.text": {
                    "binding": {
                      "config": {
                        "expression": "translate(\"Protocol\") + \":\""
                      },
                      "type": "expr"
                    }
                  }
                },
                "type": "ia.display.label"
              },
              {
                "meta": {
                  "name": "value"
                },
                "position": {
                  "grow": 1
                },
                "props": {
                  "text": "MQTT 3.1.1, SparkPlug B"
                },
                "type": "ia.display.label"
              }
            ],
            "meta": {
              "name": "protocol"
            },
            "position": {
              "basis": "40px",
              "shrink": 0
            },
            "type": "ia.container.flex"
          },
          {
            "children": [
              {
                "meta": {
                  "name": "label"
                },
                "position": {
                  "basis": "150px",
                  "shrink": 0
                },
                "propConfig": {
                  "props.text": {
                    "binding": {
                      "config": {
                        "expression": "translate(\"Primary Host ID\") + \":\""
                      },
                      "type": "expr"
                    }
                  }
                },
                "type": "ia.display.label"
              },
              {
                "meta": {
                  "name": "value"
                },
                "position": {
                  "grow": 1
                },
                "props": {
                  "text": "host ID"
                },
                "type": "ia.display.label"
              }
            ],
            "meta": {
              "name": "primary host id"
            },
            "position": {
              "basis": "40px",
              "shrink": 0
            },
            "type": "ia.container.flex"
          }
        ],
        "meta": {
          "name": "network"
        },
        "props": {
          "direction": "column",
          "style": {
            "paddingLeft": "25px"
          }
        },
        "type": "ia.container.flex"
      },
      {
        "children": [
          {
            "meta": {
              "name": "Users"
            },
            "position": {
              "basis": "32px"
            },
            "props": {
              "style": {
                "fontSize": "1.5em",
                "fontWeight": "bold",
                "marginLeft": "-25px"
              },
              "text": "Users"
            },
            "type": "ia.display.label"
          },
          {
            "meta": {
              "name": "UsersFlexRepeater"
            },
            "propConfig": {
              "props.instances": {
                "binding": {
                  "config": {
                    "path": "view.custom.mqtt_users"
                  },
                  "type": "property"
                }
              }
            },
            "props": {
              "direction": "column",
              "path": "Page/Embedded/MqttUserNode",
              "style": {
                "overflowX": "hidden",
                "overflowY": "auto"
              }
            },
            "type": "ia.display.flex-repeater"
          },
          {
            "children": [
              {
                "events": {
                  "component": {
                    "onActionPerformed": {
                      "config": {
                        "script": "\tlenUser\u003d len(self.parent.parent.getChild(\"UsersFlexRepeater\").props.instances)\n\t\n\tif (lenUser \u003d\u003d 0):\n\t\troot\u003dself.view.getChild(\u0027root\u0027)\n\t\tsuccess\u003droot.add_mqtt_user()\n\t\tif success:\n\t\t\troot.refresh_users()\n\t\t\t\n\telse:\n\t\tsystem.perspective.openPopup(\"Confirm\",\u0027Popup/Confirm\u0027, params \u003d {\u0027event_message_type\u0027:\"add_mqtt_user\",\"event_payload\": {},\u0027text\u0027:\u0027All clients will be disconnected!\u0027}, showCloseIcon \u003d True, resizable \u003d True)"
                      },
                      "scope": "G",
                      "type": "script"
                    }
                  }
                },
                "meta": {
                  "name": "button"
                },
                "position": {
                  "shrink": 0
                },
                "props": {
                  "style": {
                    "classes": "Buttons/Small_Button",
                    "fontSize": 18
                  },
                  "text": "Add User"
                },
                "type": "ia.input.button"
              }
            ],
            "meta": {
              "name": "add user"
            },
            "position": {
              "basis": "40px",
              "shrink": 0
            },
            "propConfig": {
              "position.display": {
                "binding": {
                  "config": {
                    "expression": " len({view.custom.mqtt_users})\u003c2"
                  },
                  "type": "expr"
                }
              }
            },
            "props": {
              "style": {
                "fontSize": 18,
                "marginTop": "1em"
              }
            },
            "type": "ia.container.flex"
          }
        ],
        "meta": {
          "name": "users"
        },
        "props": {
          "direction": "column",
          "style": {
            "paddingLeft": "25px"
          }
        },
        "type": "ia.container.flex"
      }
    ],
    "meta": {
      "name": "root"
    },
    "props": {
      "direction": "column",
      "style": {
        "padding": "20px"
      }
    },
    "scripts": {
      "customMethods": [
        {
          "name": "regenerate_mqtt_password",
          "params": [
            "username"
          ],
          "script": "\tfrom simpleorm.dataset import SQuery\n\tfrom com.inductiveautomation.ignition.gateway import IgnitionGateway\n\t#get user record\n\tcontext\u003dIgnitionGateway.get()\n\t\t\n\tdistributorModule\u003dcontext.getModuleManager().getModule(\u0027com.cirruslink.mqtt.distributor.gateway\u0027)\n\tuserRecordClass\u003ddistributorModule.getHook().getClass().getClassLoader().loadClass(\u0027com.cirruslink.mqtt.distributor.gateway.record.UserRecord\u0027)\n\tuserRecordMeta\u003duserRecordClass.getField(\u0027META\u0027).get(None)\n\tpi\u003dcontext.getPersistenceInterface()\n\t# check if user already exists\n\t\n\texistingUser\u003dpi.queryOne(SQuery(userRecordMeta).eq(userRecordClass.getField(\u0027Username\u0027).get(None),username))\n\tif not existingUser:\n\t\treturn False\n\t\n\tnew_password\u003dself.new_random_password()\n\texistingUser.setPassword(new_password)\n\tpi.save(existingUser)\n\tpi.notifyRecordUpdated(existingUser)\n\treturn True"
        },
        {
          "name": "add_mqtt_user",
          "params": [],
          "script": "\tfrom simpleorm.dataset import SQuery\n\tfrom com.inductiveautomation.ignition.gateway import IgnitionGateway\n\t#get user record\n\tcontext\u003dIgnitionGateway.get()\n\t\t\n\tdistributorModule\u003dcontext.getModuleManager().getModule(\u0027com.cirruslink.mqtt.distributor.gateway\u0027)\n\tuserRecordClass\u003ddistributorModule.getHook().getClass().getClassLoader().loadClass(\u0027com.cirruslink.mqtt.distributor.gateway.record.UserRecord\u0027)\n\tuserRecordMeta\u003duserRecordClass.getField(\u0027META\u0027).get(None)\n\tpi\u003dcontext.getPersistenceInterface()\n\t# check if user already exists\n\t\n\texistingUsers\u003dpi.query(SQuery(userRecordMeta).in(userRecordClass.getField(\u0027Username\u0027).get(None),\u0027mqtt\u0027,\u0027mqtt2\u0027))\n\tif len(existingUsers)\u003d\u003d0:\n\t\tusername\u003d\u0027mqtt\u0027\n\telif len(existingUsers)\u003d\u003d1:\n\t\tusername\u003d\u0027mqtt\u0027 if existingUsers.get(0).getUsername()!\u003d\u0027mqtt\u0027 else \u0027mqtt2\u0027\n\telse:\n\t\t#both slots filled. Can\u0027t add another user.\n\t\treturn False\n\t\n\tnewPassword\u003dself.new_random_password()\n\tnewUserRecord\u003dpi.createNew(userRecordMeta)\n\tnewUserRecord.setUsername(username)\n\tnewUserRecord.setPassword(newPassword)\n\tnewUserRecord.setACLs(\u0027RW #\u0027)\n\tpi.save(newUserRecord)\n\tpi.notifyRecordAdded(newUserRecord)\n\treturn True"
        },
        {
          "name": "delete_mqtt_user",
          "params": [
            "username"
          ],
          "script": "\tfrom com.inductiveautomation.ignition.gateway.web.models import KeyValue\n\tfrom simpleorm.dataset import SQuery\n\tfrom com.inductiveautomation.ignition.gateway import IgnitionGateway\n\t\n\tif username not in (\u0027mqtt\u0027,\u0027mqtt2\u0027):\n\t\treturn False\n\t#get user record\n\tcontext\u003dIgnitionGateway.get()\n\t\t\n\tdistributorModule\u003dcontext.getModuleManager().getModule(\u0027com.cirruslink.mqtt.distributor.gateway\u0027)\n\tuserRecordClass\u003ddistributorModule.getHook().getClass().getClassLoader().loadClass(\u0027com.cirruslink.mqtt.distributor.gateway.record.UserRecord\u0027)\n\tuserRecordMeta\u003duserRecordClass.getField(\u0027META\u0027).get(None)\n\tpi\u003dcontext.getPersistenceInterface()\n\t\n\tuserRecord\u003dpi.queryOne(SQuery(userRecordMeta).eq(userRecordClass.getField(\u0027Username\u0027).get(None),username))\n\t\n\tif userRecord:\n\t\tkeyValue\u003dKeyValue(userRecord)\n\t\tuserRecord.deleteRecord()\n\t\tpi.save(userRecord)\n\t\tpi.notifyRecordDeleted(userRecordMeta, keyValue)\n\t\treturn True\n\telse:\n\t\treturn False"
        },
        {
          "name": "new_random_password",
          "params": [],
          "script": "\timport random\n\tpassword_chars\u003d\u0027abcdefghijkmnopqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ2345789\u0027\n\tpassword_length\u003d20\n\tr\u003drandom.SystemRandom()\n\treturn \u0027\u0027.join((r.choice(password_chars) for _ in xrange(password_length)))"
        },
        {
          "name": "refresh_users",
          "params": [],
          "script": "\tself.view.refreshBinding(\"custom.mqtt_users\")"
        }
      ],
      "extensionFunctions": null,
      "messageHandlers": [
        {
          "messageType": "delete_mqtt_user",
          "pageScope": true,
          "script": "\tusername \u003d payload[\"username\"]\n\t\n\troot\u003dself\n\tsuccess\u003droot.delete_mqtt_user(username)\n\tif success:\n\t\troot.refresh_users()",
          "sessionScope": false,
          "viewScope": false
        },
        {
          "messageType": "regenerate_mqtt_password",
          "pageScope": true,
          "script": "\t# implement your handler here\n\t\n\tusername \u003d payload[\"username\"]\n\t\n\troot\u003dself\n\tsuccess\u003droot.regenerate_mqtt_password(username)\n\tif success:\n\t\troot.refresh_users()",
          "sessionScope": false,
          "viewScope": false
        },
        {
          "messageType": "add_mqtt_user",
          "pageScope": true,
          "script": "\t# implement your handler here\n\troot\u003dself\n\tsuccess\u003droot.add_mqtt_user()\n\tif success:\n\t\troot.refresh_users()",
          "sessionScope": false,
          "viewScope": false
        }
      ]
    },
    "type": "ia.container.flex"
  }
}