Merge branch 'sub-account-manager-rewrite' into 'dev'

Sub-Account Manager Rewrite

See merge request Shinobi-Systems/Shinobi!283
merge-requests/289/head
Moe 2021-02-07 22:06:01 +00:00
commit a1308c5211
11 changed files with 872 additions and 59 deletions

View File

@ -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> &nbsp; ${lang['Clear']}`,
},
{
"fieldType": "btn",
"class": `btn-success submit-form`,
"btnContent": `<i class="fa fa-plus"></i> &nbsp; ${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> &nbsp; ${lang['Add New']}`,
},
]
},
}
}
}
}

View File

@ -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",

View File

@ -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,

View File

@ -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

View File

@ -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",

View File

@ -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]){

View File

@ -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
})

View File

@ -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">&times;</span>
</button>
<h4 class="modal-title" id="subAccountManagerLabel"><i class="fa fa-group"></i> &nbsp; <%-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>

View File

@ -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">

View File

@ -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>

View File

@ -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>
<% }
%>