mirror of
https://github.com/xiaoxinpro/nginx-proxy-manager-zh.git
synced 2025-01-22 12:58:13 -05:00
Added user permissions, delete user
This commit is contained in:
parent
4a59ef9925
commit
30924a6922
@ -1,11 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
const _ = require('lodash');
|
||||
const error = require('../lib/error');
|
||||
const userModel = require('../models/user');
|
||||
const authModel = require('../models/auth');
|
||||
const gravatar = require('gravatar');
|
||||
const internalToken = require('./token');
|
||||
const _ = require('lodash');
|
||||
const error = require('../lib/error');
|
||||
const userModel = require('../models/user');
|
||||
const userPermissionModel = require('../models/user_permission');
|
||||
const authModel = require('../models/auth');
|
||||
const gravatar = require('gravatar');
|
||||
const internalToken = require('./token');
|
||||
|
||||
function omissions () {
|
||||
return ['is_deleted'];
|
||||
@ -56,7 +57,23 @@ const internalUser = {
|
||||
}
|
||||
})
|
||||
.then(user => {
|
||||
return internalUser.get(access, {id: user.id});
|
||||
// Create permissions row as well
|
||||
let is_admin = data.roles.indexOf('admin') !== -1;
|
||||
|
||||
return userPermissionModel
|
||||
.query()
|
||||
.insert({
|
||||
user_id: user.id,
|
||||
visibility: is_admin ? 'all' : 'user',
|
||||
proxy_hosts: 'manage',
|
||||
redirection_hosts: 'manage',
|
||||
dead_hosts: 'manage',
|
||||
streams: 'manage',
|
||||
access_lists: 'manage'
|
||||
})
|
||||
.then(() => {
|
||||
return internalUser.get(access, {id: user.id, expand: ['permissions']});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
@ -145,6 +162,7 @@ const internalUser = {
|
||||
.query()
|
||||
.where('is_deleted', 0)
|
||||
.andWhere('id', data.id)
|
||||
.allowEager('[permissions]')
|
||||
.first();
|
||||
|
||||
// Custom omissions
|
||||
@ -377,6 +395,50 @@ const internalUser = {
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Access} access
|
||||
* @param {Object} data
|
||||
* @return {Promise}
|
||||
*/
|
||||
setPermissions: (access, data) => {
|
||||
return access.can('users:permissions', data.id)
|
||||
.then(() => {
|
||||
return internalUser.get(access, {id: data.id});
|
||||
})
|
||||
.then(user => {
|
||||
if (user.id !== data.id) {
|
||||
// Sanity check that something crazy hasn't happened
|
||||
throw new error.InternalValidationError('User could not be updated, IDs do not match: ' + user.id + ' !== ' + data.id);
|
||||
}
|
||||
|
||||
return user;
|
||||
})
|
||||
.then(user => {
|
||||
// Get perms row, patch if it exists
|
||||
return userPermissionModel
|
||||
.query()
|
||||
.where('user_id', user.id)
|
||||
.first()
|
||||
.then(existing_auth => {
|
||||
if (existing_auth) {
|
||||
// patch
|
||||
return userPermissionModel
|
||||
.query()
|
||||
.where('user_id', user.id)
|
||||
.patchAndFetchById(existing_auth.id, _.assign({user_id: user.id}, data));
|
||||
} else {
|
||||
// insert
|
||||
return userPermissionModel
|
||||
.query()
|
||||
.insertAndFetch(_.assign({user_id: user.id}, data));
|
||||
}
|
||||
})
|
||||
.then(permissions => {
|
||||
return true;
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {Access} access
|
||||
* @param {Object} data
|
||||
|
7
src/backend/lib/access/users-permissions.json
Normal file
7
src/backend/lib/access/users-permissions.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "roles#/definitions/admin"
|
||||
}
|
||||
]
|
||||
}
|
@ -43,6 +43,124 @@ exports.up = function (knex/*, Promise*/) {
|
||||
})
|
||||
.then(() => {
|
||||
logger.info('[' + migrate_name + '] user Table created');
|
||||
|
||||
return knex.schema.createTable('user_permission', table => {
|
||||
table.increments().primary();
|
||||
table.dateTime('created_on').notNull();
|
||||
table.dateTime('modified_on').notNull();
|
||||
table.integer('user_id').notNull().unsigned();
|
||||
table.string('visibility').notNull();
|
||||
table.string('proxy_hosts').notNull();
|
||||
table.string('redirection_hosts').notNull();
|
||||
table.string('dead_hosts').notNull();
|
||||
table.string('streams').notNull();
|
||||
table.string('access_lists').notNull();
|
||||
table.unique('user_id');
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
logger.info('[' + migrate_name + '] user_permission Table created');
|
||||
|
||||
return knex.schema.createTable('proxy_host', table => {
|
||||
table.increments().primary();
|
||||
table.dateTime('created_on').notNull();
|
||||
table.dateTime('modified_on').notNull();
|
||||
table.integer('owner_user_id').notNull().unsigned();
|
||||
table.integer('is_deleted').notNull().unsigned().defaultTo(0);
|
||||
table.string('domain_name').notNull();
|
||||
table.string('forward_ip').notNull();
|
||||
table.integer('forward_port').notNull().unsigned();
|
||||
table.integer('access_list_id').notNull().unsigned().defaultTo(0);
|
||||
table.integer('ssl_enabled').notNull().unsigned().defaultTo(0);
|
||||
table.string('ssl_provider').notNull().defaultTo('');
|
||||
table.integer('ssl_forced').notNull().unsigned().defaultTo(0);
|
||||
table.integer('caching_enabled').notNull().unsigned().defaultTo(0);
|
||||
table.integer('block_exploits').notNull().unsigned().defaultTo(0);
|
||||
table.json('meta').notNull();
|
||||
table.unique(['domain_name', 'is_deleted']);
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
logger.info('[' + migrate_name + '] proxy_host Table created');
|
||||
|
||||
return knex.schema.createTable('redirection_host', table => {
|
||||
table.increments().primary();
|
||||
table.dateTime('created_on').notNull();
|
||||
table.dateTime('modified_on').notNull();
|
||||
table.integer('owner_user_id').notNull().unsigned();
|
||||
table.integer('is_deleted').notNull().unsigned().defaultTo(0);
|
||||
table.string('domain_name').notNull();
|
||||
table.string('forward_domain_name').notNull();
|
||||
table.integer('preserve_path').notNull().unsigned().defaultTo(0);
|
||||
table.integer('ssl_enabled').notNull().unsigned().defaultTo(0);
|
||||
table.string('ssl_provider').notNull().defaultTo('');
|
||||
table.integer('block_exploits').notNull().unsigned().defaultTo(0);
|
||||
table.json('meta').notNull();
|
||||
table.unique(['domain_name', 'is_deleted']);
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
logger.info('[' + migrate_name + '] redirection_host Table created');
|
||||
|
||||
return knex.schema.createTable('dead_host', table => {
|
||||
table.increments().primary();
|
||||
table.dateTime('created_on').notNull();
|
||||
table.dateTime('modified_on').notNull();
|
||||
table.integer('owner_user_id').notNull().unsigned();
|
||||
table.integer('is_deleted').notNull().unsigned().defaultTo(0);
|
||||
table.string('domain_name').notNull();
|
||||
table.integer('ssl_enabled').notNull().unsigned().defaultTo(0);
|
||||
table.string('ssl_provider').notNull().defaultTo('');
|
||||
table.json('meta').notNull();
|
||||
table.unique(['domain_name', 'is_deleted']);
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
logger.info('[' + migrate_name + '] dead_host Table created');
|
||||
|
||||
return knex.schema.createTable('stream', table => {
|
||||
table.increments().primary();
|
||||
table.dateTime('created_on').notNull();
|
||||
table.dateTime('modified_on').notNull();
|
||||
table.integer('owner_user_id').notNull().unsigned();
|
||||
table.integer('is_deleted').notNull().unsigned().defaultTo(0);
|
||||
table.integer('incoming_port').notNull().unsigned();
|
||||
table.string('forward_ip').notNull();
|
||||
table.integer('forwarding_port').notNull().unsigned();
|
||||
table.integer('tcp_forwarding').notNull().unsigned().defaultTo(0);
|
||||
table.integer('udp_forwarding').notNull().unsigned().defaultTo(0);
|
||||
table.json('meta').notNull();
|
||||
table.unique(['incoming_port', 'is_deleted']);
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
logger.info('[' + migrate_name + '] stream Table created');
|
||||
|
||||
return knex.schema.createTable('access_list', table => {
|
||||
table.increments().primary();
|
||||
table.dateTime('created_on').notNull();
|
||||
table.dateTime('modified_on').notNull();
|
||||
table.integer('owner_user_id').notNull().unsigned();
|
||||
table.integer('is_deleted').notNull().unsigned().defaultTo(0);
|
||||
table.string('name').notNull();
|
||||
table.json('meta').notNull();
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
logger.info('[' + migrate_name + '] access_list Table created');
|
||||
|
||||
return knex.schema.createTable('access_list_auth', table => {
|
||||
table.increments().primary();
|
||||
table.dateTime('created_on').notNull();
|
||||
table.dateTime('modified_on').notNull();
|
||||
table.integer('access_list_id').notNull().unsigned();
|
||||
table.string('username').notNull();
|
||||
table.string('password').notNull();
|
||||
table.json('meta').notNull();
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
logger.info('[' + migrate_name + '] access_list_auth Table created');
|
||||
});
|
||||
|
||||
};
|
||||
|
@ -3,8 +3,9 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
const db = require('../db');
|
||||
const Model = require('objection').Model;
|
||||
const db = require('../db');
|
||||
const Model = require('objection').Model;
|
||||
const UserPermission = require('./user_permission');
|
||||
|
||||
Model.knex(db);
|
||||
|
||||
@ -30,6 +31,22 @@ class User extends Model {
|
||||
return ['roles'];
|
||||
}
|
||||
|
||||
static get relationMappings () {
|
||||
return {
|
||||
permissions: {
|
||||
relation: Model.HasOneRelation,
|
||||
modelClass: UserPermission,
|
||||
join: {
|
||||
from: 'user.id',
|
||||
to: 'user_permission.user_id'
|
||||
},
|
||||
modify: function (qb) {
|
||||
qb.omit(['id', 'created_on', 'modified_on', 'user_id']);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = User;
|
||||
|
30
src/backend/models/user_permission.js
Normal file
30
src/backend/models/user_permission.js
Normal file
@ -0,0 +1,30 @@
|
||||
// Objection Docs:
|
||||
// http://vincit.github.io/objection.js/
|
||||
|
||||
'use strict';
|
||||
|
||||
const db = require('../db');
|
||||
const Model = require('objection').Model;
|
||||
|
||||
Model.knex(db);
|
||||
|
||||
class UserPermission extends Model {
|
||||
$beforeInsert () {
|
||||
this.created_on = Model.raw('NOW()');
|
||||
this.modified_on = Model.raw('NOW()');
|
||||
}
|
||||
|
||||
$beforeUpdate () {
|
||||
this.modified_on = Model.raw('NOW()');
|
||||
}
|
||||
|
||||
static get name () {
|
||||
return 'UserPermission';
|
||||
}
|
||||
|
||||
static get tableName () {
|
||||
return 'user_permission';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UserPermission;
|
@ -183,12 +183,12 @@ router
|
||||
});
|
||||
|
||||
/**
|
||||
* Specific user service settings
|
||||
* Specific user permissions
|
||||
*
|
||||
* /api/users/123/services
|
||||
* /api/users/123/permissions
|
||||
*/
|
||||
router
|
||||
.route('/:user_id/services')
|
||||
.route('/:user_id/permissions')
|
||||
.options((req, res) => {
|
||||
res.sendStatus(204);
|
||||
})
|
||||
@ -196,18 +196,18 @@ router
|
||||
.all(userIdFromMe)
|
||||
|
||||
/**
|
||||
* POST /api/users/123/services
|
||||
* PUT /api/users/123/permissions
|
||||
*
|
||||
* Sets Service Settings for a user
|
||||
* Set some or all permissions for a user
|
||||
*/
|
||||
.post((req, res, next) => {
|
||||
.put((req, res, next) => {
|
||||
apiValidator({$ref: 'endpoints/users#/links/5/schema'}, req.body)
|
||||
.then(payload => {
|
||||
payload.id = req.params.user_id;
|
||||
return internalUser.setServiceSettings(res.locals.access, payload);
|
||||
return internalUser.setPermissions(res.locals.access, payload);
|
||||
})
|
||||
.then(result => {
|
||||
res.status(200)
|
||||
res.status(201)
|
||||
.send(result);
|
||||
})
|
||||
.catch(next);
|
||||
|
@ -206,6 +206,49 @@
|
||||
"targetSchema": {
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Set Permissions",
|
||||
"description": "Sets Permissions for a User",
|
||||
"href": "/users/{definitions.identity.example}/permissions",
|
||||
"access": "private",
|
||||
"method": "PUT",
|
||||
"rel": "update",
|
||||
"http_header": {
|
||||
"$ref": "../examples.json#/definitions/auth_header"
|
||||
},
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"visibility": {
|
||||
"type": "string",
|
||||
"pattern": "^(all|user)$"
|
||||
},
|
||||
"access_lists": {
|
||||
"type": "string",
|
||||
"pattern": "^(hidden|view|manage)$"
|
||||
},
|
||||
"dead_hosts": {
|
||||
"type": "string",
|
||||
"pattern": "^(hidden|view|manage)$"
|
||||
},
|
||||
"proxy_hosts": {
|
||||
"type": "string",
|
||||
"pattern": "^(hidden|view|manage)$"
|
||||
},
|
||||
"redirection_hosts": {
|
||||
"type": "string",
|
||||
"pattern": "^(hidden|view|manage)$"
|
||||
},
|
||||
"streams": {
|
||||
"type": "string",
|
||||
"pattern": "^(hidden|view|manage)$"
|
||||
}
|
||||
}
|
||||
},
|
||||
"targetSchema": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
|
@ -1,11 +1,12 @@
|
||||
'use strict';
|
||||
|
||||
const fs = require('fs');
|
||||
const NodeRSA = require('node-rsa');
|
||||
const config = require('config');
|
||||
const logger = require('./logger').global;
|
||||
const userModel = require('./models/user');
|
||||
const authModel = require('./models/auth');
|
||||
const fs = require('fs');
|
||||
const NodeRSA = require('node-rsa');
|
||||
const config = require('config');
|
||||
const logger = require('./logger').global;
|
||||
const userModel = require('./models/user');
|
||||
const userPermissionModel = require('./models/user_permission');
|
||||
const authModel = require('./models/auth');
|
||||
|
||||
module.exports = function () {
|
||||
return new Promise((resolve, reject) => {
|
||||
@ -54,7 +55,7 @@ module.exports = function () {
|
||||
.select(userModel.raw('COUNT(`id`) as `count`'))
|
||||
.where('is_deleted', 0)
|
||||
.first('count')
|
||||
.then((row) => {
|
||||
.then(row => {
|
||||
if (!row.count) {
|
||||
// Create a new user and set password
|
||||
logger.info('Creating a new user: admin@example.com with password: changeme');
|
||||
@ -79,6 +80,19 @@ module.exports = function () {
|
||||
type: 'password',
|
||||
secret: 'changeme',
|
||||
meta: {}
|
||||
})
|
||||
.then(() => {
|
||||
return userPermissionModel
|
||||
.query()
|
||||
.insert({
|
||||
user_id: user.id,
|
||||
visibility: 'all',
|
||||
proxy_hosts: 'manage',
|
||||
redirection_hosts: 'manage',
|
||||
dead_hosts: 'manage',
|
||||
streams: 'manage',
|
||||
access_lists: 'manage'
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -224,6 +224,16 @@ module.exports = {
|
||||
*/
|
||||
loginAs: function (id) {
|
||||
return fetch('post', 'users/' + id + '/login');
|
||||
},
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Integer} id
|
||||
* @param {Object} perms
|
||||
* @returns {Promise}
|
||||
*/
|
||||
setPermissions: function (id, perms) {
|
||||
return fetch('put', 'users/' + id + '/permissions', perms);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -52,6 +52,19 @@ module.exports = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* User Permissions Form
|
||||
*
|
||||
* @param model
|
||||
*/
|
||||
showUserPermissions: function (model) {
|
||||
if (Cache.User.isAdmin()) {
|
||||
require(['./main', './user/permissions'], function (App, View) {
|
||||
App.UI.showModalDialog(new View({model: model}));
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* User Password Form
|
||||
*
|
||||
@ -65,6 +78,19 @@ module.exports = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* User Delete Confirm
|
||||
*
|
||||
* @param model
|
||||
*/
|
||||
showUserDeleteConfirm: function (model) {
|
||||
if (Cache.User.isAdmin() && model.get('id') !== Cache.User.get('id')) {
|
||||
require(['./main', './user/delete'], function (App, View) {
|
||||
App.UI.showModalDialog(new View({model: model}));
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Error
|
||||
*
|
||||
|
@ -110,7 +110,7 @@ const App = Mn.Application.extend({
|
||||
* @returns {Promise}
|
||||
*/
|
||||
bootstrap: function () {
|
||||
return Api.Users.getById('me')
|
||||
return Api.Users.getById('me', ['permissions'])
|
||||
.then(response => {
|
||||
Cache.User.set(response);
|
||||
Tokens.setCurrentName(response.nickname || response.name);
|
||||
|
19
src/frontend/js/app/user/delete.ejs
Normal file
19
src/frontend/js/app/user/delete.ejs
Normal file
@ -0,0 +1,19 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Delete <%- name %></h5>
|
||||
<button type="button" class="close cancel" aria-label="Close" data-dismiss="modal"> </button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-md-12">
|
||||
Are you sure you want to delete <strong><%- name %></strong>?
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary cancel" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-danger save">Yes I'm Sure</button>
|
||||
</div>
|
||||
</div>
|
38
src/frontend/js/app/user/delete.js
Normal file
38
src/frontend/js/app/user/delete.js
Normal file
@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
const Mn = require('backbone.marionette');
|
||||
const template = require('./delete.ejs');
|
||||
const Controller = require('../controller');
|
||||
const Api = require('../api');
|
||||
const App = require('../main');
|
||||
|
||||
require('jquery-serializejson');
|
||||
|
||||
module.exports = Mn.View.extend({
|
||||
template: template,
|
||||
className: 'modal-dialog',
|
||||
|
||||
ui: {
|
||||
form: 'form',
|
||||
buttons: '.modal-footer button',
|
||||
cancel: 'button.cancel',
|
||||
save: 'button.save'
|
||||
},
|
||||
|
||||
events: {
|
||||
|
||||
'click @ui.save': function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
Api.Users.delete(this.model.get('id'))
|
||||
.then(() => {
|
||||
Controller.showUsers();
|
||||
App.UI.closeModal();
|
||||
})
|
||||
.catch(err => {
|
||||
alert(err.message);
|
||||
this.ui.buttons.prop('disabled', false).removeClass('btn-disabled');
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
@ -25,25 +25,27 @@
|
||||
<div class="invalid-feedback secret-error"></div>
|
||||
</div>
|
||||
</div>
|
||||
<% if (!isSelf()) { %>
|
||||
<div class="col-sm-12 col-md-12">
|
||||
<div class="form-label">Roles</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-6">
|
||||
<div class="form-group">
|
||||
<div class="form-label">Switches</div>
|
||||
<div class="custom-switches-stacked">
|
||||
<label class="custom-switch">
|
||||
<input type="checkbox" class="custom-switch-input" name="is_admin" value="1"<%- isAdmin() ? ' checked' : '' %>>
|
||||
<span class="custom-switch-indicator"></span>
|
||||
<span class="custom-switch-description">Administrator</span>
|
||||
</label>
|
||||
<label class="custom-switch">
|
||||
<input type="checkbox" class="custom-switch-input" name="is_disabled" value="1"<%- is_disabled ? ' checked' : '' %>>
|
||||
<span class="custom-switch-indicator"></span>
|
||||
<span class="custom-switch-description">Disabled</span>
|
||||
</label>
|
||||
</div>
|
||||
<label class="custom-switch">
|
||||
<input type="checkbox" class="custom-switch-input" name="is_admin" value="1"<%- isAdmin() ? ' checked' : '' %><%- isSelf() ? ' disabled' : '' %>>
|
||||
<span class="custom-switch-indicator"></span>
|
||||
<span class="custom-switch-description">Administrator</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-6 col-md-6">
|
||||
<div class="form-group">
|
||||
<label class="custom-switch">
|
||||
<input type="checkbox" class="custom-switch-input" name="is_disabled" value="1"<%- is_disabled ? ' checked' : '' %><%- isSelf() ? ' disabled' : '' %>>
|
||||
<span class="custom-switch-indicator"></span>
|
||||
<span class="custom-switch-description">Disabled</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
@ -58,7 +58,12 @@ module.exports = Mn.View.extend({
|
||||
}
|
||||
|
||||
view.model.set(result);
|
||||
App.UI.closeModal();
|
||||
App.UI.closeModal(function () {
|
||||
if (method === Api.Users.create) {
|
||||
// Show permissions dialog immediately
|
||||
Controller.showUserPermissions(view.model);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
this.ui.error.text(err.message).show();
|
||||
|
140
src/frontend/js/app/user/permissions.ejs
Normal file
140
src/frontend/js/app/user/permissions.ejs
Normal file
@ -0,0 +1,140 @@
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Permissions for <%- name %></h5>
|
||||
<button type="button" class="close cancel" aria-label="Close" data-dismiss="modal"> </button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form>
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-md-12">
|
||||
|
||||
<% if (isAdmin()) { %>
|
||||
<div class="alert alert-icon alert-secondary" role="alert">
|
||||
<i class="fe fe-alert-triangle mr-2" aria-hidden="true"></i>
|
||||
This user is an Administrator and some items cannot be altered
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="form-label">Item Visibility</label>
|
||||
<div class="selectgroup w-100">
|
||||
<label class="selectgroup-item">
|
||||
<input type="radio" name="visibility" value="user" class="selectgroup-input"<%- getPerm('visibility') !== 'all' ? ' checked' : '' %>>
|
||||
<span class="selectgroup-button">Created Items Only</span>
|
||||
</label>
|
||||
<label class="selectgroup-item">
|
||||
<input type="radio" name="visibility" value="all" class="selectgroup-input"<%- getPerm('visibility') === 'all' ? ' checked' : '' %>>
|
||||
<span class="selectgroup-button">All Items</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12 col-md-12">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Proxy Hosts</label>
|
||||
<div class="selectgroup w-100">
|
||||
<label class="selectgroup-item">
|
||||
<input type="radio" name="proxy_hosts" value="manage" class="selectgroup-input" <%- getPermProps('proxy_hosts', 'manage', true) %>>
|
||||
<span class="selectgroup-button">Manage</span>
|
||||
</label>
|
||||
<label class="selectgroup-item">
|
||||
<input type="radio" name="proxy_hosts" value="view" class="selectgroup-input" <%- getPermProps('proxy_hosts', 'view') %>>
|
||||
<span class="selectgroup-button">View Only</span>
|
||||
</label>
|
||||
<label class="selectgroup-item">
|
||||
<input type="radio" name="proxy_hosts" value="hidden" class="selectgroup-input" <%- getPermProps('proxy_hosts', 'hidden') %>>
|
||||
<span class="selectgroup-button">Hidden</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12 col-md-12">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Redirection Hosts</label>
|
||||
<div class="selectgroup w-100">
|
||||
<label class="selectgroup-item">
|
||||
<input type="radio" name="redirection_hosts" value="manage" class="selectgroup-input" <%- getPermProps('redirection_hosts', 'manage', true) %>>
|
||||
<span class="selectgroup-button">Manage</span>
|
||||
</label>
|
||||
<label class="selectgroup-item">
|
||||
<input type="radio" name="redirection_hosts" value="view" class="selectgroup-input" <%- getPermProps('redirection_hosts', 'view') %>>
|
||||
<span class="selectgroup-button">View Only</span>
|
||||
</label>
|
||||
<label class="selectgroup-item">
|
||||
<input type="radio" name="redirection_hosts" value="hidden" class="selectgroup-input" <%- getPermProps('redirection_hosts', 'hidden') %>>
|
||||
<span class="selectgroup-button">Hidden</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12 col-md-12">
|
||||
<div class="form-group">
|
||||
<label class="form-label">404 Hosts</label>
|
||||
<div class="selectgroup w-100">
|
||||
<label class="selectgroup-item">
|
||||
<input type="radio" name="dead_hosts" value="manage" class="selectgroup-input" <%- getPermProps('dead_hosts', 'manage', true) %>>
|
||||
<span class="selectgroup-button">Manage</span>
|
||||
</label>
|
||||
<label class="selectgroup-item">
|
||||
<input type="radio" name="dead_hosts" value="view" class="selectgroup-input" <%- getPermProps('dead_hosts', 'view') %>>
|
||||
<span class="selectgroup-button">View Only</span>
|
||||
</label>
|
||||
<label class="selectgroup-item">
|
||||
<input type="radio" name="dead_hosts" value="hidden" class="selectgroup-input" <%- getPermProps('dead_hosts', 'hidden') %>>
|
||||
<span class="selectgroup-button">Hidden</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12 col-md-12">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Streams</label>
|
||||
<div class="selectgroup w-100">
|
||||
<label class="selectgroup-item">
|
||||
<input type="radio" name="streams" value="manage" class="selectgroup-input" <%- getPermProps('streams', 'manage', true) %>>
|
||||
<span class="selectgroup-button">Manage</span>
|
||||
</label>
|
||||
<label class="selectgroup-item">
|
||||
<input type="radio" name="streams" value="view" class="selectgroup-input" <%- getPermProps('streams', 'view') %>>
|
||||
<span class="selectgroup-button">View Only</span>
|
||||
</label>
|
||||
<label class="selectgroup-item">
|
||||
<input type="radio" name="streams" value="hidden" class="selectgroup-input" <%- getPermProps('streams', 'hidden') %>>
|
||||
<span class="selectgroup-button">Hidden</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12 col-md-12">
|
||||
<div class="form-group">
|
||||
<label class="form-label">Access Lists</label>
|
||||
<div class="selectgroup w-100">
|
||||
<label class="selectgroup-item">
|
||||
<input type="radio" name="access_lists" value="manage" class="selectgroup-input" <%- getPermProps('access_lists', 'manage', true) %>>
|
||||
<span class="selectgroup-button">Manage</span>
|
||||
</label>
|
||||
<label class="selectgroup-item">
|
||||
<input type="radio" name="access_lists" value="view" class="selectgroup-input" <%- getPermProps('access_lists', 'view') %>>
|
||||
<span class="selectgroup-button">View Only</span>
|
||||
</label>
|
||||
<label class="selectgroup-item">
|
||||
<input type="radio" name="access_lists" value="hidden" class="selectgroup-input" <%- getPermProps('access_lists', 'hidden') %>>
|
||||
<span class="selectgroup-button">Hidden</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary cancel" data-dismiss="modal">Cancel</button>
|
||||
<button type="button" class="btn btn-teal save">Save</button>
|
||||
</div>
|
||||
</div>
|
99
src/frontend/js/app/user/permissions.js
Normal file
99
src/frontend/js/app/user/permissions.js
Normal file
@ -0,0 +1,99 @@
|
||||
'use strict';
|
||||
|
||||
const Mn = require('backbone.marionette');
|
||||
const template = require('./permissions.ejs');
|
||||
const Controller = require('../controller');
|
||||
const Cache = require('../cache');
|
||||
const Api = require('../api');
|
||||
const App = require('../main');
|
||||
const UserModel = require('../../models/user');
|
||||
|
||||
require('jquery-serializejson');
|
||||
|
||||
module.exports = Mn.View.extend({
|
||||
template: template,
|
||||
className: 'modal-dialog',
|
||||
|
||||
ui: {
|
||||
form: 'form',
|
||||
buttons: '.modal-footer button',
|
||||
cancel: 'button.cancel',
|
||||
save: 'button.save',
|
||||
error: '.secret-error'
|
||||
},
|
||||
|
||||
events: {
|
||||
|
||||
'click @ui.save': function (e) {
|
||||
e.preventDefault();
|
||||
|
||||
let view = this;
|
||||
let data = this.ui.form.serializeJSON();
|
||||
|
||||
// Manipulate
|
||||
if (view.model.isAdmin()) {
|
||||
// Force some attributes for admin
|
||||
data = _.assign({}, data, {
|
||||
access_lists: 'manage',
|
||||
dead_hosts: 'manage',
|
||||
proxy_hosts: 'manage',
|
||||
redirection_hosts: 'manage',
|
||||
streams: 'manage'
|
||||
});
|
||||
}
|
||||
|
||||
this.ui.buttons.prop('disabled', true).addClass('btn-disabled');
|
||||
|
||||
Api.Users.setPermissions(view.model.get('id'), data)
|
||||
.then(() => {
|
||||
if (view.model.get('id') === Cache.User.get('id')) {
|
||||
Cache.User.set({permissions: data});
|
||||
}
|
||||
|
||||
view.model.set({permissions: data});
|
||||
App.UI.closeModal();
|
||||
})
|
||||
.catch(err => {
|
||||
this.ui.error.text(err.message).show();
|
||||
this.ui.buttons.prop('disabled', false).removeClass('btn-disabled');
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
templateContext: function () {
|
||||
let perms = this.model.get('permissions');
|
||||
let is_admin = this.model.isAdmin();
|
||||
|
||||
return {
|
||||
getPerm: function (key) {
|
||||
if (perms !== null && typeof perms[key] !== 'undefined') {
|
||||
return perms[key];
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
getPermProps: function (key, item, forced_admin) {
|
||||
if (forced_admin && is_admin) {
|
||||
return 'checked disabled';
|
||||
} else if (is_admin) {
|
||||
return 'disabled';
|
||||
} else if (perms !== null && typeof perms[key] !== 'undefined' && perms[key] === item) {
|
||||
return 'checked';
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
|
||||
isAdmin: function () {
|
||||
return is_admin;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
if (typeof options.model === 'undefined' || !options.model) {
|
||||
this.model = new UserModel.Model();
|
||||
}
|
||||
}
|
||||
});
|
@ -19,8 +19,9 @@
|
||||
<div class="item-action dropdown">
|
||||
<a href="#" data-toggle="dropdown" class="icon"><i class="fe fe-more-vertical"></i></a>
|
||||
<div class="dropdown-menu dropdown-menu-right">
|
||||
<a href="#" class="edit-user dropdown-item"><i class="dropdown-icon fe fe-edit"></i> Edit User</a>
|
||||
<a href="#" class="set-password dropdown-item"><i class="dropdown-icon fe fe-shield"></i> Set Password</a>
|
||||
<a href="#" class="edit-user dropdown-item"><i class="dropdown-icon fe fe-edit"></i> Edit Details</a>
|
||||
<a href="#" class="edit-permissions dropdown-item"><i class="dropdown-icon fe fe-shield"></i> Edit Permissions</a>
|
||||
<a href="#" class="set-password dropdown-item"><i class="dropdown-icon fe fe-lock"></i> Set Password</a>
|
||||
<% if (!isSelf()) { %>
|
||||
<a href="#" class="login dropdown-item"><i class="dropdown-icon fe fe-log-in"></i> Sign in as User</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
|
@ -12,10 +12,11 @@ module.exports = Mn.View.extend({
|
||||
tagName: 'tr',
|
||||
|
||||
ui: {
|
||||
edit: 'a.edit-user',
|
||||
password: 'a.set-password',
|
||||
login: 'a.login',
|
||||
delete: 'a.delete-user'
|
||||
edit: 'a.edit-user',
|
||||
permissions: 'a.edit-permissions',
|
||||
password: 'a.set-password',
|
||||
login: 'a.login',
|
||||
delete: 'a.delete-user'
|
||||
},
|
||||
|
||||
events: {
|
||||
@ -24,6 +25,11 @@ module.exports = Mn.View.extend({
|
||||
Controller.showUserForm(this.model);
|
||||
},
|
||||
|
||||
'click @ui.permissions': function (e) {
|
||||
e.preventDefault();
|
||||
Controller.showUserPermissions(this.model);
|
||||
},
|
||||
|
||||
'click @ui.password': function (e) {
|
||||
e.preventDefault();
|
||||
Controller.showUserPasswordForm(this.model);
|
||||
@ -31,7 +37,7 @@ module.exports = Mn.View.extend({
|
||||
|
||||
'click @ui.delete': function (e) {
|
||||
e.preventDefault();
|
||||
//Controller.showUserDeleteConfirm(this.model);
|
||||
Controller.showUserDeleteConfirm(this.model);
|
||||
},
|
||||
|
||||
'click @ui.login': function (e) {
|
||||
|
@ -31,7 +31,7 @@ module.exports = Mn.View.extend({
|
||||
onRender: function () {
|
||||
let view = this;
|
||||
|
||||
Api.Users.getAll()
|
||||
Api.Users.getAll(['permissions'])
|
||||
.then(response => {
|
||||
if (!view.isDestroyed() && response && response.length) {
|
||||
view.showChildView('list_region', new ListView({
|
||||
|
@ -12,7 +12,8 @@ const model = Backbone.Model.extend({
|
||||
nickname: '',
|
||||
email: '',
|
||||
is_disabled: false,
|
||||
roles: []
|
||||
roles: [],
|
||||
permissions: null
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -24,7 +24,8 @@ module.exports = {
|
||||
'vector-map': 'tabler-ui/dist/assets/js/vendors/jquery-jvectormap-2.0.3.min',
|
||||
'vector-map-de': 'tabler-ui/dist/assets/js/vendors/jquery-jvectormap-de-merc',
|
||||
'vector-map-world': 'tabler-ui/dist/assets/js/vendors/jquery-jvectormap-world-mill',
|
||||
'circle-progress': 'tabler-ui/dist/assets/js/vendors/circle-progress.min'
|
||||
'circle-progress': 'tabler-ui/dist/assets/js/vendors/circle-progress.min',
|
||||
'c3': 'tabler-ui/dist/assets/js/vendors/chart.bundle.min'
|
||||
}
|
||||
},
|
||||
module: {
|
||||
|
Loading…
Reference in New Issue
Block a user