Merge branch 'sub-account-manager-rewrite' into 'dev'
Sub-Account Manager Rewrite See merge request Shinobi-Systems/Shinobi!283merge-requests/289/head
commit
a1308c5211
|
@ -4719,7 +4719,7 @@ module.exports = function(s,config,lang){
|
|||
}
|
||||
}
|
||||
},
|
||||
"ONVIF Device Manager": {
|
||||
"ONVIF Device Manager": {
|
||||
"section": "ONVIF Device Manager",
|
||||
"blocks": {
|
||||
"Notice": {
|
||||
|
@ -5186,6 +5186,175 @@ module.exports = function(s,config,lang){
|
|||
]
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
"Sub-Account Manager": {
|
||||
"section": "Sub-Account Manager",
|
||||
"blocks": {
|
||||
"Sub-Accounts": {
|
||||
"name": lang['Sub-Accounts'],
|
||||
"color": "grey",
|
||||
"isSection": true,
|
||||
"id":"monSectionAccountList",
|
||||
"info": [
|
||||
{
|
||||
"fieldType": "table",
|
||||
id: "subAccountsList",
|
||||
}
|
||||
]
|
||||
},
|
||||
"Account Information": {
|
||||
"name": lang['Account Information'],
|
||||
"color": "grey",
|
||||
"isSection": true,
|
||||
"isForm": true,
|
||||
"id":"monSectionAccountInformation",
|
||||
"info": [
|
||||
{
|
||||
hidden: true,
|
||||
"name": "uid",
|
||||
"field": "UID",
|
||||
"fieldType": "text"
|
||||
},
|
||||
{
|
||||
"name": "mail",
|
||||
"field": lang.Email,
|
||||
"fieldType": "text",
|
||||
"default": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"name": "pass",
|
||||
"field": lang.Password,
|
||||
"fieldType": "password",
|
||||
"default": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"name": "password_again",
|
||||
"field": lang['Password Again'],
|
||||
"fieldType": "password",
|
||||
"default": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
forForm: true,
|
||||
"fieldType": "btn",
|
||||
"attribute": `type="reset"`,
|
||||
"class": `btn-default reset-form`,
|
||||
"btnContent": `<i class="fa fa-undo"></i> ${lang['Clear']}`,
|
||||
},
|
||||
{
|
||||
"fieldType": "btn",
|
||||
"class": `btn-success submit-form`,
|
||||
"btnContent": `<i class="fa fa-plus"></i> ${lang['Add New']}`,
|
||||
},
|
||||
{
|
||||
hidden: true,
|
||||
"name": "details",
|
||||
"preFill": "{}",
|
||||
},
|
||||
]
|
||||
},
|
||||
"Account Privileges": {
|
||||
"name": lang['Account Privileges'],
|
||||
"color": "grey",
|
||||
"isSection": true,
|
||||
"id":"monSectionAccountPrivileges",
|
||||
"info": [
|
||||
{
|
||||
"name": "detail=allmonitors",
|
||||
"field": lang['All Monitors and Privileges'],
|
||||
"default": "0",
|
||||
"fieldType": "select",
|
||||
"selector": "h_perm_allmonitors",
|
||||
"possible": [
|
||||
{
|
||||
"name": lang.No,
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": lang.Yes,
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "detail=monitor_create",
|
||||
"field": lang['Can Create and Delete Monitors'],
|
||||
"default": "0",
|
||||
"fieldType": "select",
|
||||
"possible": [
|
||||
{
|
||||
"name": lang.No,
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": lang.Yes,
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "detail=user_change",
|
||||
"field": lang['Can Change User Settings'],
|
||||
"default": "0",
|
||||
"fieldType": "select",
|
||||
"possible": [
|
||||
{
|
||||
"name": lang.No,
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": lang.Yes,
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "detail=view_logs",
|
||||
"field": lang['Can View Logs'],
|
||||
"default": "0",
|
||||
"fieldType": "select",
|
||||
"possible": [
|
||||
{
|
||||
"name": lang.No,
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": lang.Yes,
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "detail=landing_page",
|
||||
"field": lang['Landing Page'],
|
||||
"default": "",
|
||||
"fieldType": "select",
|
||||
"possible": [
|
||||
{
|
||||
"name": lang.Default,
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"name": lang.Timelapse,
|
||||
"value": "timelapse"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"fieldType": "div",
|
||||
"class": "h_perm_allmonitors_input h_perm_allmonitors_1",
|
||||
id: "sub_accounts_permissions",
|
||||
},
|
||||
{
|
||||
"fieldType": "btn",
|
||||
"class": `btn-success submit-form`,
|
||||
"btnContent": `<i class="fa fa-plus"></i> ${lang['Add New']}`,
|
||||
},
|
||||
]
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,17 @@
|
|||
"failedLoginText2": "Please check your login credentials.",
|
||||
"Time Left": "Time Left",
|
||||
"Inverse Trigger": "Inverse Trigger",
|
||||
"Account Privileges": "Account Privileges",
|
||||
"Account Information": "Account Information",
|
||||
"subAccountManager": "Sub-Account Manager",
|
||||
"contactAdmin": "Contact the maintainer of your Shinobi installation.",
|
||||
"accountAdded": "Account Added",
|
||||
"accountAddedText": "Account has been added.",
|
||||
"accountDeleted": "Account Deleted",
|
||||
"accountDeletedText": "Account has been deleted.",
|
||||
"accountActionFailed": "Account Action Failed",
|
||||
"deleteSubAccount": "Delete Sub-Account",
|
||||
"deleteSubAccountText": "Do you want to delete this Sub-Account? You cannot recover it.",
|
||||
"Turn Speed": "Turn Speed",
|
||||
"Session Key": "Session Key",
|
||||
"Login": "Login",
|
||||
|
@ -172,6 +183,8 @@
|
|||
"Started Building": "Started Building",
|
||||
"Add": "Add",
|
||||
"Save": "Save",
|
||||
"Save New": "Save New",
|
||||
"Save Changes": "Save Changes",
|
||||
"Close": "Close",
|
||||
"Don't Show for 1 Week": "Don't Show for 1 Week",
|
||||
"Secure": "Secure",
|
||||
|
@ -452,6 +465,7 @@
|
|||
"NoVideosFoundForDateRange": "No Videos found in this date range. Try setting the start date further back.",
|
||||
"NoLogsFoundForDateRange": "No Logs found in this date range. Try widening the date range.",
|
||||
"monitorEditFailedMaxReached": "Your account has reached the maximum number of cameras that can be created. Speak to an administrator if you would like this changed.",
|
||||
"Sub-Accounts": "Sub-Accounts",
|
||||
"in": "in",
|
||||
"ago": "ago",
|
||||
"a few seconds": "a few seconds",
|
||||
|
@ -503,6 +517,7 @@
|
|||
"Detector Recording Process Exited Prematurely. Restarting.": "Detector Recording Process Exited Prematurely. Restarting.",
|
||||
"Detector Recording Complete": "Detector Recording Complete",
|
||||
"Clear Recorder Process": "Clear Recorder Process",
|
||||
"Clear": "Clear",
|
||||
"Logging": "Logging",
|
||||
"Timelapse": "Timelapse",
|
||||
"Nothing exists": "Nothing exists",
|
||||
|
|
|
@ -403,11 +403,23 @@ module.exports = function(s,config){
|
|||
}
|
||||
})
|
||||
}
|
||||
const knexQueryPromise = (options) => {
|
||||
return new Promise((resolve,reject) => {
|
||||
knexQuery(options,(err,rows) => {
|
||||
resolve({
|
||||
ok: !err,
|
||||
err: err,
|
||||
rows: rows,
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
const connectDatabase = function(){
|
||||
s.databaseEngine = require('knex')(s.databaseOptions)
|
||||
}
|
||||
return {
|
||||
knexQuery: knexQuery,
|
||||
knexQueryPromise: knexQueryPromise,
|
||||
knexError: knexError,
|
||||
cleanSqlWhereObject: cleanSqlWhereObject,
|
||||
processSimpleWhereCondition: processSimpleWhereCondition,
|
||||
|
|
|
@ -20,6 +20,7 @@ module.exports = function(s,config){
|
|||
}
|
||||
const {
|
||||
knexQuery,
|
||||
knexQueryPromise,
|
||||
knexError,
|
||||
cleanSqlWhereObject,
|
||||
processSimpleWhereCondition,
|
||||
|
@ -34,6 +35,7 @@ module.exports = function(s,config){
|
|||
extender(config)
|
||||
})
|
||||
s.knexQuery = knexQuery
|
||||
s.knexQueryPromise = knexQueryPromise
|
||||
s.getDatabaseRows = getDatabaseRows
|
||||
s.sqlQuery = sqlQuery
|
||||
s.connectDatabase = connectDatabase
|
||||
|
|
|
@ -11,7 +11,7 @@ module.exports = function(s,config,lang,app){
|
|||
* API : Administrator : Edit Sub-Account (Account to share cameras with)
|
||||
*/
|
||||
app.all(config.webPaths.adminApiPrefix+':auth/accounts/:ke/edit', function (req,res){
|
||||
s.auth(req.params,function(user){
|
||||
s.auth(req.params,async (user) => {
|
||||
var endData = {
|
||||
ok : false
|
||||
}
|
||||
|
@ -25,10 +25,35 @@ module.exports = function(s,config,lang,app){
|
|||
var mail = form.mail || s.getPostData(req,'mail',false)
|
||||
if(form){
|
||||
var keys = ['details']
|
||||
form.details = s.parseJSON(form.details) || {"sub": 1, "allmonitors": "1"}
|
||||
form.details.sub = 1
|
||||
const updateQuery = {
|
||||
details: s.stringJSON(form.details)
|
||||
}
|
||||
s.knexQuery({
|
||||
if(form.pass && form.pass === form.password_again){
|
||||
updateQuery.pass = s.createHash(form.pass)
|
||||
}
|
||||
if(form.mail){
|
||||
const userCheck = await s.knexQueryPromise({
|
||||
action: "select",
|
||||
columns: "*",
|
||||
table: "Users",
|
||||
where: [
|
||||
['mail','=',form.mail],
|
||||
]
|
||||
})
|
||||
if(userCheck.rows[0]){
|
||||
const foundUser = userCheck.rows[0]
|
||||
if(foundUser.uid === form.uid){
|
||||
updateQuery.mail = form.mail
|
||||
}else{
|
||||
endData.msg = lang['Email address is in use.']
|
||||
s.closeJsonResponse(res,endData)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
await s.knexQueryPromise({
|
||||
action: "update",
|
||||
table: "Users",
|
||||
update: updateQuery,
|
||||
|
@ -125,6 +150,35 @@ module.exports = function(s,config,lang,app){
|
|||
},res,req)
|
||||
})
|
||||
/**
|
||||
* API : Administrator : Get Sub-Account List
|
||||
*/
|
||||
app.get(config.webPaths.adminApiPrefix+':auth/accounts/:ke', function (req,res){
|
||||
s.auth(req.params,function(user){
|
||||
var endData = {
|
||||
ok : false
|
||||
}
|
||||
if(user.details.sub){
|
||||
endData.msg = user.lang['Not Permitted']
|
||||
s.closeJsonResponse(res,endData)
|
||||
return
|
||||
}else{
|
||||
endData.ok = true
|
||||
s.knexQuery({
|
||||
action: "select",
|
||||
columns: "ke,uid,mail,details",
|
||||
table: "Users",
|
||||
where: [
|
||||
['ke','=',req.params.ke],
|
||||
['details','LIKE','%"sub"%']
|
||||
]
|
||||
},function(err,rows){
|
||||
endData.accounts = rows
|
||||
s.closeJsonResponse(res,endData)
|
||||
})
|
||||
}
|
||||
},res,req)
|
||||
})
|
||||
/**
|
||||
* API : Administrator : Add Sub-Account (Account to share cameras with)
|
||||
*/
|
||||
app.post([
|
||||
|
@ -156,16 +210,17 @@ module.exports = function(s,config,lang,app){
|
|||
},function(err,r){
|
||||
if(r && r[0]){
|
||||
//found one exist
|
||||
endData.msg = 'Email address is in use.'
|
||||
endData.msg = lang['Email address is in use.']
|
||||
}else{
|
||||
//create new
|
||||
endData.msg = 'New Account Created'
|
||||
endData.ok = true
|
||||
var newId = s.gid()
|
||||
var details = s.s({
|
||||
sub: "1",
|
||||
var details = s.s(Object.assign({
|
||||
allmonitors: "1"
|
||||
})
|
||||
},s.parseJSON(form.details) || {
|
||||
sub: "1",
|
||||
}))
|
||||
s.knexQuery({
|
||||
action: "insert",
|
||||
table: "Users",
|
||||
|
|
|
@ -171,9 +171,9 @@ module.exports = function(s,config,lang,app,io){
|
|||
return false
|
||||
}
|
||||
switch(true){
|
||||
case search(config.webPaths.admin):
|
||||
return 'admin'
|
||||
break;
|
||||
// case search(config.webPaths.admin):
|
||||
// return 'admin'
|
||||
// break;
|
||||
case search(config.webPaths.super):
|
||||
return 'super'
|
||||
break;
|
||||
|
@ -321,53 +321,6 @@ module.exports = function(s,config,lang,app,io){
|
|||
})
|
||||
break;
|
||||
case'admin':
|
||||
if(!r.details.sub){
|
||||
s.knexQuery({
|
||||
action: "select",
|
||||
columns: "uid,mail,details",
|
||||
table: "Users",
|
||||
where: [
|
||||
['ke','=',r.ke],
|
||||
['details','LIKE','%"sub"%'],
|
||||
]
|
||||
},(err,rr) => {
|
||||
s.knexQuery({
|
||||
action: "select",
|
||||
columns: "*",
|
||||
table: "Monitors",
|
||||
where: [
|
||||
['ke','=',r.ke],
|
||||
]
|
||||
},(err,rrr) => {
|
||||
renderPage(config.renderPaths.admin,{
|
||||
config: s.getConfigWithBranding(req.hostname),
|
||||
$user: response,
|
||||
$subs: rr,
|
||||
$mons: rrr,
|
||||
lang: r.lang,
|
||||
define: s.getDefinitonFile(r.details.lang),
|
||||
customAutoLoad: s.customAutoLoadTree
|
||||
})
|
||||
})
|
||||
})
|
||||
}else{
|
||||
//not admin user
|
||||
var chosenRender = 'home'
|
||||
if(r.details.landing_page && r.details.landing_page !== '' && config.renderPaths[r.details.landing_page]){
|
||||
chosenRender = r.details.landing_page
|
||||
}
|
||||
renderPage(config.renderPaths[chosenRender],{
|
||||
$user:response,
|
||||
config: s.getConfigWithBranding(req.hostname),
|
||||
lang:r.lang,
|
||||
define:s.getDefinitonFile(r.details.lang),
|
||||
addStorage:s.dir.addStorage,
|
||||
fs:fs,
|
||||
__dirname:s.mainDirectory,
|
||||
customAutoLoad: s.customAutoLoadTree
|
||||
});
|
||||
}
|
||||
break;
|
||||
default:
|
||||
var chosenRender = 'home'
|
||||
if(r.details.sub && r.details.landing_page && r.details.landing_page !== '' && config.renderPaths[r.details.landing_page]){
|
||||
|
|
|
@ -0,0 +1,297 @@
|
|||
$(document).ready(function(){
|
||||
var apiPrefix = getAdminApiPrefix()
|
||||
var theWindow = $('#subAccountManager');
|
||||
var accountTable = $('#subAccountsList tbody');
|
||||
var theWindowForm = $('#monSectionAccountInformation');
|
||||
var permissionsSection = $('#monSectionAccountPrivileges');
|
||||
var permissionsMonitorSection = $('#sub_accounts_permissions');
|
||||
var submitButtons = theWindow.find('.submit-form')
|
||||
var loadedSubAccounts = {}
|
||||
var clearTable = function(){
|
||||
accountTable.empty()
|
||||
loadedSubAccounts = {}
|
||||
}
|
||||
var getSubAccounts = function(){
|
||||
$.get(`${apiPrefix}accounts/${$user.ke}`,function(data){
|
||||
clearTable()
|
||||
$.each(data.accounts,function(n,account){
|
||||
loadedSubAccounts[account.uid] = account;
|
||||
drawSubAccountRow(account)
|
||||
})
|
||||
})
|
||||
}
|
||||
var deleteSubAccount = function(email,uid){
|
||||
$.confirm.create({
|
||||
title: lang.deleteSubAccount,
|
||||
body: lang.deleteSubAccountText + '\n' + email,
|
||||
clickOptions: {
|
||||
class: 'btn-danger',
|
||||
title: lang.Delete,
|
||||
},
|
||||
clickCallback: function(){
|
||||
$.post(apiPrefix+'accounts/'+$user.ke+'/delete',{
|
||||
uid: uid,
|
||||
mail: email
|
||||
},function(data){
|
||||
var notifyTitle = lang.accountDeleted
|
||||
var notifyText = lang.accountDeletedText + '\n' + email
|
||||
var notifyColor = 'info'
|
||||
if(data.ok){
|
||||
loadedSubAccounts[uid] = null;
|
||||
accountTable.find('tr[uid="' + uid + '"]').remove()
|
||||
}else{
|
||||
notifyTitle = lang.accountActionFailed
|
||||
notifyText = lang.contactAdmin
|
||||
notifyColor = 'warning'
|
||||
}
|
||||
new PNotify({
|
||||
title : notifyTitle,
|
||||
text : notifyText,
|
||||
type : notifyColor
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
var addSubAccount = function(newAccount,callback){
|
||||
$.post(apiPrefix+'accounts/'+$user.ke+'/register',{
|
||||
data: JSON.stringify(newAccount)
|
||||
},function(data){
|
||||
var notifyTitle
|
||||
var notifyText
|
||||
var notifyColor
|
||||
if(!data.ok && data.msg){
|
||||
notifyTitle = lang.accountActionFailed
|
||||
notifyText = data.msg
|
||||
notifyColor = 'warning'
|
||||
}
|
||||
if(data.user){
|
||||
notifyTitle = lang.accountAdded
|
||||
notifyText = lang.accountAddedText + '\n' + data.user.mail
|
||||
notifyColor = 'success'
|
||||
if(data.user){
|
||||
var account = data.user
|
||||
loadedSubAccounts[account.uid] = account;
|
||||
drawSubAccountRow(account)
|
||||
theWindowForm.find('[name="uid"]').val(account.uid)
|
||||
setSubmitButtonState(lang['Save Changes'],'check')
|
||||
}else{
|
||||
notifyTitle = lang.accountActionFailed
|
||||
notifyText = lang.contactAdmin
|
||||
notifyColor = 'warning'
|
||||
}
|
||||
}
|
||||
new PNotify({
|
||||
title : notifyTitle,
|
||||
text : notifyText,
|
||||
type : notifyColor
|
||||
})
|
||||
callback(data)
|
||||
});
|
||||
}
|
||||
var editSubaccount = function(uid,form,callback){
|
||||
var account = loadedSubAccounts[uid]
|
||||
$.post(apiPrefix+'accounts/'+$user.ke+'/edit',{
|
||||
uid: uid,
|
||||
mail: form.mail,
|
||||
data: form
|
||||
},function(data){
|
||||
if(data.ok){
|
||||
$.each(form,function(n,v){
|
||||
account[n] = v
|
||||
});
|
||||
accountTable.find(`[uid="${account.uid}"] .mail`).text(form.mail)
|
||||
new PNotify({
|
||||
title : 'Account Edited',
|
||||
text : '<b>' + account.mail + '</b> has been updated.',
|
||||
type : 'success'
|
||||
})
|
||||
}else{
|
||||
new PNotify({
|
||||
title : 'Failed to Add Account',
|
||||
text : data.msg,
|
||||
type : 'error'
|
||||
})
|
||||
}
|
||||
callback(data)
|
||||
})
|
||||
}
|
||||
var drawSubAccountRow = function(account){
|
||||
var html = `<tr uid="${account.uid}">
|
||||
<td>
|
||||
<span class="badge btn-primary mail">${account.mail}</span>
|
||||
</td>
|
||||
<td>
|
||||
<code class="uid">${account.uid}</code>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<a class="permission btn btn-sm btn-primary"><i class="fa fa-lock"></i></a>
|
||||
</td>
|
||||
<td class="text-right">
|
||||
<a class="delete btn btn-sm btn-danger"><i class="fa fa-trash-o"></i></a>
|
||||
</td>
|
||||
</tr>`;
|
||||
accountTable.prepend(html)
|
||||
}
|
||||
var permissionTypeNames = [
|
||||
{
|
||||
name: 'monitors',
|
||||
label: lang['Can View Monitor'],
|
||||
},
|
||||
{
|
||||
name: 'monitor_edit',
|
||||
label: lang['Can Edit Monitor'],
|
||||
},
|
||||
{
|
||||
name: 'video_view',
|
||||
label: lang['Can View Videos and Events'],
|
||||
},
|
||||
{
|
||||
name: 'video_delete',
|
||||
label: lang['Can Delete Videos and Events'],
|
||||
},
|
||||
];
|
||||
var drawSelectableForPermissionForm = function(){
|
||||
var html = ''
|
||||
$.each($.ccio.mon,function(n,monitor){
|
||||
html += `<div class="form-group permission-view">`
|
||||
html += `<div><label>${monitor.name} (${monitor.mid})</label></div>`
|
||||
html += `<div><select class="form-control" multiple monitor="${monitor.mid}">`
|
||||
$.each(permissionTypeNames,function(n,permission){
|
||||
html += `<option value="${permission.name}">${permission.label}</option>`
|
||||
})
|
||||
html += `</select></div>`
|
||||
html += `</div>`
|
||||
})
|
||||
permissionsMonitorSection.html(html)
|
||||
}
|
||||
var setPermissionSelectionsToFields = function(uid){
|
||||
var account = loadedSubAccounts[uid]
|
||||
var details = $.parseJSON(account.details)
|
||||
// load values to Account Information : email, password, etc.
|
||||
$.each(account,function(n,v){
|
||||
theWindowForm.find('[name="'+n+'"]').val(v)
|
||||
})
|
||||
// load base privileges
|
||||
permissionsSection.find('[detail]').each(function(n,v){
|
||||
var el = $(v)
|
||||
var key = el.attr('detail')
|
||||
var defaultValue = el.attr('data-default')
|
||||
el.val(details[key] || defaultValue)
|
||||
})
|
||||
permissionsSection.find('[detail="allmonitors"]').change()
|
||||
// load montior specific privileges
|
||||
$.each($.ccio.mon,function(m,monitor){
|
||||
$.each(permissionTypeNames,function(m,permission){
|
||||
if((details[permission.name] || []).indexOf(monitor.mid) > -1){
|
||||
permissionsSection.find(`[monitor="${monitor.mid}"] option[value="${permission.name}"]`).attr("selected", "selected")
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
var openSubAccountEditor = function(uid){
|
||||
var account = loadedSubAccounts[uid]
|
||||
drawSelectableForPermissionForm()
|
||||
setPermissionSelectionsToFields(uid)
|
||||
permissionsSection.show()
|
||||
}
|
||||
var writePermissionsFromFieldsToString = function(){
|
||||
var foundSelected = {}
|
||||
var detailsElement = theWindowForm.find('[name="details"]')
|
||||
var details = JSON.parse(detailsElement.val())
|
||||
details = details ? details : {sub: 1, allmonitors: "1"}
|
||||
// base privileges
|
||||
permissionsSection.find('[detail]').each(function(n,v){
|
||||
var el = $(v)
|
||||
details[el.attr('detail')] = el.val()
|
||||
})
|
||||
// monitor specific privileges
|
||||
permissionsSection.find('.permission-view select').each(function(n,v){
|
||||
var el = $(v)
|
||||
var monitorId = el.attr('monitor')
|
||||
var value = el.val()
|
||||
$.each(value,function(n,permissionNameSelected){
|
||||
if(!foundSelected[permissionNameSelected])foundSelected[permissionNameSelected] = []
|
||||
foundSelected[permissionNameSelected].push(monitorId)
|
||||
})
|
||||
})
|
||||
details = Object.assign(details,foundSelected)
|
||||
detailsElement.val(JSON.stringify(details))
|
||||
}
|
||||
var getCompleteForm = function(){
|
||||
writePermissionsFromFieldsToString()
|
||||
return theWindowForm.serializeObject()
|
||||
}
|
||||
var setSubmitButtonState = function(text,icon){
|
||||
submitButtons.html(`<i class="fa fa-${icon}"></i> ${text}`)
|
||||
}
|
||||
//add new
|
||||
submitButtons.click(function(){
|
||||
theWindowForm.submit()
|
||||
})
|
||||
theWindowForm.submit(function(e){
|
||||
e.preventDefault();
|
||||
var formValues = getCompleteForm()
|
||||
var uid = formValues.uid
|
||||
console.log(formValues)
|
||||
if(formValues.uid){
|
||||
console.log('edit')
|
||||
editSubaccount(uid,formValues,function(data){
|
||||
console.log(data)
|
||||
})
|
||||
}else{
|
||||
addSubAccount(formValues,function(data){
|
||||
console.log(data)
|
||||
})
|
||||
}
|
||||
return false;
|
||||
});
|
||||
//sub simple lister
|
||||
theWindow.on('click','.delete',function(e){
|
||||
var el = $(this).parents('tr')
|
||||
var subAccountEmail = el.find('.mail').text()
|
||||
var subAccountUid = el.attr('uid')
|
||||
deleteSubAccount(subAccountEmail,subAccountUid)
|
||||
})
|
||||
theWindow.on('click','.permission',function(e){
|
||||
var el = $(this).parents('tr')
|
||||
var uid = el.attr('uid')
|
||||
openSubAccountEditor(uid)
|
||||
setSubmitButtonState(lang['Save Changes'],'check')
|
||||
})
|
||||
theWindow.on('click','.reset-form',function(e){
|
||||
permissionsSection.find('[detail]').each(function(n,v){
|
||||
var el = $(v)
|
||||
var key = el.attr('detail')
|
||||
var defaultValue = el.attr('data-default')
|
||||
el.val(defaultValue)
|
||||
})
|
||||
drawSelectableForPermissionForm()
|
||||
setSubmitButtonState(lang['Add New'],'plus')
|
||||
})
|
||||
|
||||
permissionsSection.on('click','[check]',function(e){
|
||||
$(this).parents('.form-group-group').find('select').val($(this).attr('check')).first().change()
|
||||
})
|
||||
// permissionsSection.on('change','[monitor]',function(e){
|
||||
// writePermissionsFromFieldsToString()
|
||||
// });
|
||||
theWindow.on('shown.bs.modal',function() {
|
||||
getSubAccounts()
|
||||
if(theWindowForm.find('[name="uid"]').val() === '')drawSelectableForPermissionForm()
|
||||
})
|
||||
theWindow.on('hidden.bs.modal',function() {
|
||||
clearTable()
|
||||
})
|
||||
permissionsSection.on('change','[detail="allmonitors"]',function(e){
|
||||
var value = $(this).val()
|
||||
var el = $('.permission-view')
|
||||
if(value === '1'){
|
||||
el.hide();
|
||||
}else{
|
||||
el.show()
|
||||
}
|
||||
})
|
||||
// TEST
|
||||
window.getCompleteForm = getCompleteForm
|
||||
})
|
|
@ -0,0 +1,290 @@
|
|||
<!--Sub Account Manager Window-->
|
||||
<div class="modal fade" id="subAccountManager" tabindex="-1" role="dialog" aria-labelledby="subAccountManagerLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<h4 class="modal-title" id="subAccountManagerLabel"><i class="fa fa-group"></i> <%-lang.subAccountManager%></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<%
|
||||
var buildOptions = function(field,possiblities){
|
||||
if(!field)console.error('field',field)
|
||||
var fieldElement = ''
|
||||
possiblities.forEach(function(option){
|
||||
if(option.optgroup){
|
||||
fieldElement += '<optgroup label="' + option.name + '">'
|
||||
fieldElement += buildOptions(field,option.optgroup)
|
||||
fieldElement += '</optgroup>'
|
||||
}else{
|
||||
var selected = ''
|
||||
if(option.value === field.default){
|
||||
selected = 'selected'
|
||||
}
|
||||
fieldElement += '<option value="' + option.value + '" ' + selected + '>' + option.name + '</option>'
|
||||
}
|
||||
})
|
||||
return fieldElement
|
||||
}
|
||||
var drawBlock = function(monitorSettings){
|
||||
if(monitorSettings.evaluation && !eval(monitorSettings.evaluation)){
|
||||
return
|
||||
}
|
||||
var attributes = []
|
||||
var styles = []
|
||||
var sectionClass = []
|
||||
var headerTitle = monitorSettings.headerTitle || lang[monitorSettings.name] || monitorSettings.name
|
||||
if(monitorSettings.hidden === true){
|
||||
styles.push('display:none')
|
||||
}
|
||||
if(monitorSettings.style){
|
||||
styles.push(monitorSettings.style)
|
||||
}
|
||||
if(monitorSettings.isSection === true){
|
||||
attributes.push('section')
|
||||
}
|
||||
if(monitorSettings.attribute){
|
||||
attributes.push(monitorSettings.attribute)
|
||||
}
|
||||
if(!monitorSettings.id){
|
||||
var userSettingsId = monitorSettings.name.replace(/[^a-zA-Z ]/g, '').replace(/[^a-zA-Z ]/g, '').replace(/ /g, '')
|
||||
monitorSettings.id = userSettingsId
|
||||
}
|
||||
attributes.push(`id="${monitorSettings.id}"`)
|
||||
if(monitorSettings.color){
|
||||
sectionClass.push(monitorSettings.color)
|
||||
}
|
||||
if(monitorSettings['section-class']){
|
||||
sectionClass.push(monitorSettings['section-class'])
|
||||
}
|
||||
if(monitorSettings.isAdvanced){ %>
|
||||
<div class="h_us_input h_us_advanced" style="display:none">
|
||||
<% }
|
||||
if(monitorSettings['section-pre-pre-class']){ %>
|
||||
<div class="<%- monitorSettings['section-pre-pre-class'] %>">
|
||||
<% }
|
||||
if(monitorSettings['section-pre-class']){ %>
|
||||
<div class="<%- monitorSettings['section-pre-class'] %>">
|
||||
<% }
|
||||
%>
|
||||
<<%- monitorSettings.isForm ? 'form' : 'div' %> <%- attributes.join(' ') %> style="<%- styles.join(';') %>" class="form-group-group <%- sectionClass.join(' ') %>">
|
||||
<h4 class="monitor-section-header <%- monitorSettings.headerClass %>"><%- headerTitle %>
|
||||
<% if(monitorSettings.headerButtons){ %>
|
||||
<div class="pull-right">
|
||||
<% monitorSettings.headerButtons.forEach(function(button){ %>
|
||||
<a class="btn btn-success btn-xs <%- button.class %>">
|
||||
<% if(button.icon){ %><i class="fa fa-<%- button.icon %>"></i><% } %>
|
||||
<% if(button.text){ %><%- button.text %><% } %>
|
||||
</a>
|
||||
<% }) %>
|
||||
</div>
|
||||
<% } %>
|
||||
</h4>
|
||||
<div class="box-wrapper">
|
||||
<% if(monitorSettings['input-mapping']){ %>
|
||||
<div class="form-group-group forestgreen" style="display:none" input-mapping="<%- monitorSettings['input-mapping'] %>">
|
||||
<h4><%-lang['Input Feed']%>
|
||||
<div class="pull-right">
|
||||
<a class="btn btn-success btn-xs add_map_row"><i class="fa fa-plus-square-o"></i></a>
|
||||
</div>
|
||||
</h4>
|
||||
<div class="choices"></div>
|
||||
</div>
|
||||
<% } %>
|
||||
<% if(monitorSettings.blockquote){ %>
|
||||
<blockquote class="<%- monitorSettings.blockquoteClass || '' %>">
|
||||
<%- monitorSettings.blockquote %>
|
||||
</blockquote>
|
||||
<% } %>
|
||||
<% if(monitorSettings.blocks){
|
||||
monitorSettings.blocks.forEach(function(settingsBlock){
|
||||
drawBlock(settingsBlock)
|
||||
})
|
||||
}
|
||||
if(monitorSettings.info){
|
||||
monitorSettings.info.forEach(function(field){
|
||||
if(field.isFormGroupGroup === true){
|
||||
drawBlock(field)
|
||||
}else{
|
||||
if(field.notForSubAccount === true){
|
||||
var notForSubAccount = '!details.sub'
|
||||
if(!field.evaluation){
|
||||
field.evaluation = notForSubAccount
|
||||
}else{
|
||||
field.evaluation += ' && ' + notForSubAccount
|
||||
}
|
||||
}
|
||||
if(field.evaluation && !eval(field.evaluation)){
|
||||
return
|
||||
}
|
||||
var hidden = ''
|
||||
if(field.hidden === true){
|
||||
hidden = 'style="display:none"'
|
||||
}
|
||||
var fieldClass = []
|
||||
var attributes = []
|
||||
if(field.name && field.name.indexOf('detail=') > -1){
|
||||
attributes.push(field.name)
|
||||
}else if(field.name){
|
||||
attributes.push("name=" + field.name)
|
||||
}
|
||||
if(field.placeholder || field.default){
|
||||
attributes.push(`placeholder="${field.placeholder || field.default}"`)
|
||||
}else if(field.example){
|
||||
attributes.push(`placeholder="Example : ${field.example}"`)
|
||||
}
|
||||
if(field.default){
|
||||
attributes.push(`data-default="${field.default}"`)
|
||||
}
|
||||
if(field.attribute){
|
||||
attributes.push(field.attribute)
|
||||
}
|
||||
if(field.selector){
|
||||
attributes.push(`selector="${field.selector}"`)
|
||||
}
|
||||
if(field.id){
|
||||
attributes.push(`id="${field.id}"`)
|
||||
}
|
||||
if(field.class){
|
||||
fieldClass.push(`${field.class}`)
|
||||
}
|
||||
var possiblities = field.possible || []
|
||||
var fieldType = field.fieldType || 'text'
|
||||
var fieldElement = ''
|
||||
var preFill = field.preFill || ''
|
||||
switch(fieldType){
|
||||
case'btn':
|
||||
baseElement = field.forForm ? 'button' : 'a'
|
||||
fieldElement = `<${baseElement} class="btn btn-block ${fieldClass.join(' ')}" ${attributes.join(' ')}>${field.btnContent}</${baseElement}>`
|
||||
break;
|
||||
case'ul':
|
||||
fieldElement = `<ul ${attributes.join(' ')} class="${fieldClass.join(' ')}" ></ul>`
|
||||
break;
|
||||
case'div':
|
||||
fieldElement = `<div ${attributes.join(' ')} class="${fieldClass.join(' ')}" ></div>`
|
||||
break;
|
||||
case'form':
|
||||
fieldElement = `<form ${attributes.join(' ')} class="${fieldClass.join(' ')}" ></form>`
|
||||
break;
|
||||
case'table':
|
||||
fieldElement = `<table ${attributes.join(' ')} class="${fieldClass.join(' ')}"><tbody></tbody></table>`
|
||||
break;
|
||||
case'number':
|
||||
if(field.numberMin){
|
||||
attributes.push(`min="${field.numberMin}"`)
|
||||
}
|
||||
if(field.numberMax){
|
||||
attributes.push(`max="${field.numberMax}"`)
|
||||
}
|
||||
fieldElement = '<div><input type="number" class="form-control" ' + attributes.join(' ') + '></div>'
|
||||
break;
|
||||
case'password':
|
||||
fieldElement = '<div><input type="password" class="form-control" ' + attributes.join(' ') + '></div>'
|
||||
break;
|
||||
case'text':
|
||||
fieldElement = `<div><input class="form-control" ${attributes.join(' ')} value="${preFill}"></div>`
|
||||
break;
|
||||
case'textarea':
|
||||
fieldElement = '<div><textarea class="form-control" ' + attributes.join(' ') + '></textarea></div>'
|
||||
break;
|
||||
case'select':
|
||||
fieldElement = '<div><select class="form-control" ' + attributes.join(' ') + '>'
|
||||
fieldElement += buildOptions(field,possiblities)
|
||||
fieldElement += '</select></div>'
|
||||
break;
|
||||
}
|
||||
if(field['form-group-class-pre-pre-layer']){ %>
|
||||
<div class="<%- field['form-group-class-pre-pre-layer'] %>">
|
||||
<% }
|
||||
if(field['form-group-class-pre-layer']){ %>
|
||||
<div class="<%- field['form-group-class-pre-layer'] %>">
|
||||
<% }
|
||||
if(fieldType === 'ul' || fieldType === 'div' || fieldType === 'btn' || fieldType === 'table' || fieldType === 'form'){ %>
|
||||
<%- fieldElement %>
|
||||
<% }else{ %>
|
||||
<div <%- hidden %> class="form-group <%- field['form-group-class'] %>">
|
||||
<label><div><span><%- field.field %>
|
||||
<% if(field.description){ %>
|
||||
<small><%- field.description %></small>
|
||||
<% } %>
|
||||
</span></div>
|
||||
<%- fieldElement %>
|
||||
</label>
|
||||
</div>
|
||||
<% }
|
||||
}
|
||||
if(field['form-group-class-pre-layer']){ %>
|
||||
</div>
|
||||
<% }
|
||||
if(field['form-group-class-pre-pre-layer']){ %>
|
||||
</div>
|
||||
<% }
|
||||
})
|
||||
}
|
||||
%>
|
||||
</div>
|
||||
</<%- monitorSettings.isForm ? 'form' : 'div' %>>
|
||||
<%
|
||||
if(monitorSettings['section-pre-class']){ %>
|
||||
</div>
|
||||
<% }
|
||||
if(monitorSettings['section-pre-pre-class']){ %>
|
||||
</div>
|
||||
<% }
|
||||
if(monitorSettings.isAdvanced){ %>
|
||||
</div>
|
||||
<% }
|
||||
}
|
||||
%>
|
||||
<% Object.keys(define['Sub-Account Manager'].blocks).forEach(function(blockKey){
|
||||
var accountSettings = define['Sub-Account Manager'].blocks[blockKey]
|
||||
drawBlock(accountSettings)
|
||||
}) %>
|
||||
<!-- <div class="row">
|
||||
<div class="col-md-4">
|
||||
<table class="table table-striped" id="sub_accounts">
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<form id="sub_accounts_add_form">
|
||||
<div class="form-group-group forestgreen">
|
||||
<h4>Add<small id="msg" class="pull-right" style="color:#fff"></small></h4>
|
||||
<div class="form-group">
|
||||
<label><div><span>Email</span></div>
|
||||
<div><input class="form-control" type="email" name="mail"></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label><div><span>Password</span></div>
|
||||
<div><input class="form-control" type="password" name="pass"></div>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label><div><span>Password Again</span></div>
|
||||
<div><input class="form-control" type="password" name="password_again"></div>
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<button type="reset" class="btn btn-danger"><i class="fa fa-undo"></i> Clear</button>
|
||||
<div class="pull-right">
|
||||
<button type="submit" class="btn btn-success"><i class="fa fa-check"></i> Submit</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default pull-left" data-dismiss="modal"><i class="fa fa-times"></i> <%-lang.Close%></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="<%-window.libURL%>libs/js/dash2.subAccountManager.js"></script>
|
|
@ -1,4 +1,4 @@
|
|||
<!--Confirmation Window-->
|
||||
<!--Sub Account Permission Editor Window-->
|
||||
<div class="modal fade" id="permissions" tabindex="-1" role="dialog" aria-labelledby="permissionsLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<form class="modal-content">
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
<li class="mdl-menu__item" data-toggle="modal" data-target="#shinobihub_viewer"><div><i class="fa fa-home"></i><div><%- lang.ShinobiHub %></div></div></li>
|
||||
<li class="mdl-menu__item" data-toggle="modal" data-target="#eventCounts"><div><i class="fa fa-eye"></i><div><%- lang['Event Counts'] %></div></div></li>
|
||||
<% if(!details.sub){ %>
|
||||
<li class="mdl-menu__item" data-toggle="modal" data-target="#subAccountManager"><div><i class="fa fa-group"></i><div><%- lang.subAccountManager %></div></div></li>
|
||||
<li class="mdl-menu__item" data-toggle="modal" data-target="#onvif_probe"><div><i class="fa fa-rss"></i><div><%- lang.ONVIF %></div></div></li>
|
||||
<li class="mdl-menu__item" data-toggle="modal" data-target="#probe"><div><i class="fa fa-search"></i><div><%- lang.FFprobe %></div></div></li>
|
||||
<li class="mdl-menu__item" data-toggle="modal" data-target="#monitorStates"><div><i class="fa fa-align-right"></i><div><%- lang['Monitor States'] %></div></div></li>
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
<%
|
||||
var details = JSON.parse($user.details)
|
||||
if(!details.sub){ %>
|
||||
<script>
|
||||
window.getAdminApiPrefix = function(piece){
|
||||
return location.search === '?p2p=1' ? location.pathname + '/' : "<%=originalURL%><%=config.webPaths.adminApiPrefix%><%- $user.auth_token %>/"
|
||||
}
|
||||
</script>
|
||||
<% }
|
||||
%>
|
||||
<% include blocks/header %>
|
||||
<script>var $user = <%- JSON.stringify($user) %>;</script>
|
||||
|
@ -172,6 +179,7 @@
|
|||
<% include blocks/schedules.ejs %>
|
||||
<% include blocks/confirm.ejs %>
|
||||
<% include blocks/shinobiHub.ejs %>
|
||||
<% include blocks/subAccountManager.ejs %>
|
||||
<% customAutoLoad.PageBlocks.forEach(function(block){ %>
|
||||
<%- include(block) %>
|
||||
<% }) %>
|
||||
|
@ -231,3 +239,14 @@
|
|||
<% } %>
|
||||
|
||||
<% include blocks/onvifDeviceManager.ejs %>
|
||||
<%
|
||||
if(!details.sub){ %>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
if(`${location.pathname}/` === `<%=config.webPaths.adminApiPrefix%>`){
|
||||
$('#subAccountManager').modal('show')
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<% }
|
||||
%>
|
||||
|
|
Loading…
Reference in New Issue