Browse Source

Added device password functionality. Other minor changes and corrections.

master
Ruel Tmeizeh - RuhNet 2 years ago
parent
commit
b7f9a5f2e8
10 changed files with 231 additions and 30 deletions
  1. +3
    -3
      README.md
  2. +184
    -2
      app.js
  3. +12
    -4
      i18n/en-US.json
  4. +5
    -5
      metadata/app.json
  5. +0
    -0
      metadata/icon/provisioner_icon.png
  6. BIN
      metadata/screenshots/provisioner_screenshot.png
  7. +6
    -13
      style/app.css
  8. +2
    -2
      views/aclinfo.html
  9. +16
    -0
      views/devicepassword.html
  10. +3
    -1
      views/layout.html

+ 3
- 3
README.md View File

@ -10,10 +10,10 @@ Clone the repository to your Monster UI apps directory (often /var/www/html/mons
```bash
cd /var/www/html/monster-ui/apps
git clone https://github.com/ruhnet/monster-ui-ruhnet-provisioner provisioner
git clone https://github.com/ruhnet/monster-ui-ruhnet-provisioner ruhnet-provisioner
sup crossbar_maintenance init_app '/var/www/html/monster-ui/apps/provisioner' \
'http://mycrossbarapi.tld:8000/v2'
sup crossbar_maintenance init_app '/var/www/html/monster-ui/apps/ruhnet-provisioner' \
'https://mycrossbarapi.tld:8443/v2'
```
![Provisioner Screen](https://github.com/ruhnet/monster-ui-ruhnet-provisioner/raw/master/metadata/screenshots/Provisioner.png)


+ 184
- 2
app.js View File

@ -19,6 +19,46 @@ define(function (require) {
'url': 'api/{accountId}/initialtoken',
'verb': 'GET'
},
'provisioner.phone_configfile.list': {
'apiRoot': monster.config.api.provisioner,
'url': 'api/{accountId}/files/customconfigs',
'verb': 'GET'
},
'provisioner.phone_configfile.get': {
'apiRoot': monster.config.api.provisioner,
'url': 'api/{accountId}/files/customconfigs',
'verb': 'GET'
},
'provisioner.phone_configfile.add': {
'apiRoot': monster.config.api.provisioner,
'url': 'api/{accountId}/files/customconfigs',
'verb': 'PUT'
},
'provisioner.phone_configfile.remove': {
'apiRoot': monster.config.api.provisioner,
'url': 'api/{accountId}/files/customconfigs',
'verb': 'DELETE'
},
'provisioner.account_configfile.list': {
'apiRoot': monster.config.api.provisioner,
'url': 'api/{accountId}/files/accountconfigs',
'verb': 'GET'
},
'provisioner.account_configfile.get': {
'apiRoot': monster.config.api.provisioner,
'url': 'api/{accountId}/files/accountconfigs',
'verb': 'GET'
},
'provisioner.account_configfile.add': {
'apiRoot': monster.config.api.provisioner,
'url': 'api/{accountId}/files/accountconfigs',
'verb': 'PUT'
},
'provisioner.account_configfile.remove': {
'apiRoot': monster.config.api.provisioner,
'url': 'api/{accountId}/files/accountconfigs',
'verb': 'DELETE'
},
'provisioner.acls.list': {
'apiRoot': monster.config.api.provisioner,
'url': 'api/{accountId}/acl',
@ -33,6 +73,21 @@ define(function (require) {
'apiRoot': monster.config.api.provisioner,
'url': 'api/{accountId}/acl',
'verb': 'DELETE'
},
'provisioner.devicepassword.get': {
'apiRoot': monster.config.api.provisioner,
'url': 'api/{accountId}/devicepassword',
'verb': 'GET'
},
'provisioner.devicepassword.set': {
'apiRoot': monster.config.api.provisioner,
'url': 'api/{accountId}/devicepassword',
'verb': 'POST'
},
'provisioner.devicepassword.delete': {
'apiRoot': monster.config.api.provisioner,
'url': 'api/{accountId}/devicepassword',
'verb': 'DELETE'
}
},
@ -92,6 +147,7 @@ define(function (require) {
$(document).ready(function (e) {
loadProvUrl();
loadAcls();
loadDevicePassword();
//setInterval(loadParkingLot, 30000);
});
@ -99,6 +155,7 @@ define(function (require) {
$template.find("#refresh").on("click", function (e) {
loadProvUrl();
loadAcls();
loadDevicePassword();
});
@ -152,7 +209,6 @@ define(function (require) {
});
} //end function loadProvUrl();
function loadAcls() {
self.getAcls(function (aclinfo) {
var $aclinfo = $(
@ -183,8 +239,134 @@ define(function (require) {
});
} //end function loadAcls();
function loadDevicePassword() {
self.getDevicePassword(function (devicepassword) {
var $devicepassword = $(
self.getTemplate({
name: "devicepassword",
data: {
devicepassword: devicepassword,
},
})
);
$template.find(".devicepassword").empty().append($devicepassword);
///Delete device password binding
$template.find(".devicepassword-delete").on("click", function (e) {
self.deleteDevicePassword("#devicepassword");
});
//Add device password binding
$template.find("#devicepassword-set-button").on("click", function (e) {
let dp = $template.find("#devicepassword-set-input")[0].value;
if (dp.length >= 3) { //min length 3 chars
self.setDevicePassword(dp);
} else {
monster.ui.alert("Password too short: must be at least 3 characters.");
}
});
});
} //end function loadDevicePassword();
}, //bindEvents
updateDevicePasswordTemplate: function (devicepassword) {
var self = this;
var $aclinfo = $(
app.getTemplate({
name: "devicepassword",
data: {
devicepassword: devicepassword,
},
})
);
},
getDevicePassword: function (callback) {
var self = this;
monster.request({
resource: "provisioner.devicepassword.get",
data: {
accountId: self.accountId,
userId: monster.apps.auth.currentUser.id,
},
success: function(res) {
//console.log(data);
callback(res.data);
},
error: function(res) {
if (res.status == 404) {
callback([]); //Populate results with nothing
} else if (res.status == 401) {
monster.util.logoutAndReload();
} else {
monster.ui.alert("ERROR: Failed to get account device password: " + parsedError);
callback([]); //Populate results with nothing
}
}
});
}, //end getDevicePassword
setDevicePassword: function(devicepassword) {
var self = this;
monster.request({
resource: "provisioner.devicepassword.set",
data: {
accountId: self.accountId,
userId: monster.apps.auth.currentUser.id,
data: {
password: devicepassword
}
},
success: function(res) {
//console.log(data);
let newpassword = `<div id="devicepassword" title="account-device-password" class="devicepassword-entry">${devicepassword}&nbsp;&nbsp;<i class="fa fa-remove devicepassword-delete"></i></div>`;
$("#devicepassword-list").append(newpassword);
$('#refresh').click(); //??
},
error: function(res) {
if (res.status == 401) {
//monster.util.logoutAndReload();
} else {
monster.ui.alert("ERROR: Failed to add account device password: " + parsedError);
}
}
});
},
deleteDevicePassword: function(devicepassword) {
var self = this;
monster.request({
resource: "provisioner.devicepassword.delete",
data: {
accountId: self.accountId,
userId: monster.apps.auth.currentUser.id,
data: {
devicepassword: devicepassword
}
},
success: function(res) {
//console.log(data);
//self.getAcls(self.updateAclsTemplate);
//"select[title='" + acl + "']").remove();
$('#refresh').click();
},
error: function(res) {
if (res.status == 401) {
monster.util.logoutAndReload();
} else {
monster.ui.alert("ERROR: Failed to delete account device password: " + parsedError);
}
}
});
},
updateAclsTemplate: function (aclinfo) {
var self = this;
var $aclinfo = $(
@ -251,7 +433,7 @@ define(function (require) {
success: function(res) {
//console.log(data);
//acl = res.data.acls[res.data.acls.length - 1];
let newacl = `<div id="${acl}" title="${acl}" class="acl-entry">${acl}&nbsp;&nbsp;<i class="fa fa-remove delete-acl"></i></div>`;
let newacl = `<div id="${acl}" title="${acl}" class="acl-entry">${acl}&nbsp;&nbsp;<i class="fa fa-remove acl-delete"></i></div>`;
$("#acl-list").append(newacl);
$('#refresh').click();
},


+ 12
- 4
i18n/en-US.json View File

@ -8,17 +8,25 @@
"helptext": "Retrieve a call by clicking the red panel, the slot number, or the caller name/number. Call the person who parked the call by clicking their name or number. The parking lot will auto-refresh every 30 seconds."
},
"provurl": {
"description":"Provisioning URL",
"subtitle":"(Does not require IP ACL)",
"tooltip":"For clients at an IP ACL address/network, you may use a shortened generic form of the URL, by replacing the account ID and secret token with an 'x'. E.g. 'https://provisioner.mydomain.com/p/x/x'"
"description": "Provisioning URL",
"subtitle": "(Does not require IP ACL)",
"tooltip": "For clients at an IP ACL address/network, you may use a shortened generic form of the URL, by replacing the account ID and secret token with an 'x'. E.g. 'https://provisioner.mydomain.com/p/x/x'"
},
"acls": {
"description": "IP ACLs",
"noAcls": "No IP ACLs defined on this account.",
"addAcl": {
"tooltip":"IP network (v4 or v6) or single address in CIDR format. E.g. 198.51.100.128/32 or 2001:1a:4c9::18/112",
"tooltip": "IP network (v4 or v6) or single address in CIDR format. E.g. 198.51.100.128/32 or 2001:1a:4c9::18/112",
"aclAddButton": "Add ACL"
}
},
"devicePassword": {
"description": "Device Password",
"notset": "No device password is set on this account. Devices will have their admin password set to their own MAC address (all lowercase with no colons e.g.: 'a2fe805b735d').",
"setDevicePassword": {
"tooltip": "Set the password used for devices in this account. (The phone web interface password.)",
"passwordSetButton": "Set Password"
}
}
}
}

+ 5
- 5
metadata/app.json View File

@ -1,11 +1,12 @@
{
"name": "provisioner",
"name": "ruhnet-provisioner",
"i18n": {
"en-US": {
"label": "RuhNet Provisioner",
"description": "Control provisioner settings.",
"features": [
"Add Phone Models",
"Set Device Password",
"Control IP ACLs"
]
}
@ -13,15 +14,14 @@
"tags": [
"developer"
],
"icon": "Provisioner_app.png",
"icon": "provisioner_icon.png",
"api_url": "",
"author": "RuhNet",
"version": "1.0",
"version": "1.1",
"license": "GPLv3",
"price": 0,
"screenshots": [
"Provisioner1.png",
"Provisioner2.png"
"provisioner_screenshot.png"
],
"urls": {
"documentation": "{documentation_url}",


metadata/icon/Provisioner_icon.png → metadata/icon/provisioner_icon.png View File


BIN
metadata/screenshots/provisioner_screenshot.png View File

Before After
Width: 1255  |  Height: 843  |  Size: 72 KiB

+ 6
- 13
style/app.css View File

@ -7,19 +7,7 @@ div.account-settings {
flex-direction: column;
}
div.provurlinfo-wrapper {
/* width: 100%; */
display:flex;
flex-wrap: wrap;
flex-direction: column;
margin: 10px;
padding: 10px;
border: 1px solid lightgrey;
border-radius: 10px;
background: #f8f8f8;
}
div.aclinfo-wrapper {
div.section-wrapper {
/* width: 100%; */
display:flex;
flex-wrap: wrap;
@ -35,6 +23,11 @@ div.aclinfo-wrapper {
cursor: pointer;
}
.devicepassword-entry {
padding: 5px;
font-size: +1.2em;
}
.acl-entry {
padding: 5px;
font-size: +1.2em;


+ 2
- 2
views/aclinfo.html View File

@ -1,4 +1,4 @@
<div class="aclinfo-wrapper">
<div class="section-wrapper">
<h4 id="acl-list-description">{{ i18n.provisioner.acls.description }}</h4>
<div id="acl-list">
{{#each acls}}
@ -11,7 +11,7 @@
</div>
<hr />
<div id="acl-add" class="form-control">
<input id="acl-add-input" type="text" name="acl-add" placeholder="111.222.111.222/32"/><i class="fa fa-question-circle" data-toggle="tooltip" title="{{ i18n.provisioner.addAcl.tooltip }}"></i><br />
<input id="acl-add-input" type="text" name="acl-add" placeholder="111.222.111.222/32"/><i class="fa fa-question-circle" data-toggle="tooltip" title="{{ i18n.provisioner.acls.addAcl.tooltip }}"></i><br />
<button id="acl-add-button" class="btn btn-primary">{{ i18n.provisioner.acls.addAcl.aclAddButton }}</button>
</div>
</div>

+ 16
- 0
views/devicepassword.html View File

@ -0,0 +1,16 @@
<div class="section-wrapper">
<h4 id="devicepassword-description">{{ i18n.provisioner.devicePassword.description }}</h4>
<div id="devicepassword-list">
{{#if devicepassword}}
<div id="devicepassword" title="account-device-password" class="devicepassword-entry">{{devicepassword}}&nbsp;&nbsp;<i class="fa fa-remove devicepassword-delete"></i></div>
{{else}}
<!-- In a loop, you need to use '@root' to come back to the global scope and use the i18n variable -->
<div>{{ @root.i18n.provisioner.devicePassword.notset }}</div>
{{/if}}
</div>
<div id="devicepassword-set" class="form-control">
<input id="devicepassword-set-input" type="text" name="devicepassword-set" placeholder="NewPa$$w0rD"/><i class="fa fa-question-circle" data-toggle="tooltip" title="{{ i18n.provisioner.devicePassword.setDevicePassword.tooltip }}"></i><br />
<button id="devicepassword-set-button" class="btn btn-primary">{{ i18n.provisioner.devicePassword.setDevicePassword.passwordSetButton }}</button>
</div>
</div>

+ 3
- 1
views/layout.html View File

@ -7,11 +7,13 @@
<div class="account-settings">
<h3>Account Settings</h3>
<div class="provurlinfo-wrapper">
<div class="section-wrapper">
<h4 id="provurl-description">{{ i18n.provisioner.provurl.description }} <i class="fa fa-question-circle" data-toggle="tooltip" title="{{ i18n.provisioner.provurl.tooltip }}"></i></h4>
<div id="provurl">{{provurl}}</div>
</div>
<div class="devicepassword"></div>
<div class="aclinfo"></div>
</div>


Loading…
Cancel
Save