Warning : The code presented here has not been tested. It is likely that you will find typo or code errors that must be fixed.
I'm not using templates
You should use, that is, if you want to do something whose possibilities are limited in one way, you should look for some other way that gives you the possibility to do it.
Taking into account the following ER diagram (I know it is NoSQL, but it is only for illustration):
We can deduce that:
- A
Permiso
is the access given to a Rol
on a given SubMenu
.
- A
Rol
is a set of Permisos
predetermined, giving it a name. For example, the Rol
Administrador
can have permissions to:
With this data we could build a scheme in Mongo.
Creation of models
Role
const RoleSchema = mongoose.Schema(
{
name: {
type: String,
required: true
},
permissions: [{
type: String,
ref: 'Permission'
}]
});
Permission
const PermissionSchema = mongoose.Schema(
{
name: {
type: String,
required: true
},
description: {
type: String,
required: true
}
});
MenuItem
const MenuItemSchema = mongoose.Schema(
{
label: {
type: String,
required: true
},
url: {
type: String,
required: true
},
permissions: [{
type: String,
ref: 'Permission',
required: true
}]
});
Menu
const MenuSchema = mongoose.Schema(
{
label: {
type: String,
required: true
},
url: {
type: String,
required: false,
default: '#'
},
roles: [{
type: String,
ref: 'Role'
}],
items: [{
type: String,
ref: 'MenuItem'
}]
});
Once you have the whole scheme, there are two things left:
When the user logs in, bring the menu according to their role.
That menu must be processed in view engine
in order to build the menu.
Creating the menu with Handlebars
The first thing we have to do is get the menus and the items according to the user's role and permissions (I assume you know how to check Mongo). Then, we created the complete menu in handlebars
.
menu.hbs
<ul class="menu">
{{#each menus as menu}}
{{#ifRoleAllowed menu.roles id ../user.roles}}
<li>
<a href="{{menu.url}}">
{{menu.label}}
</a>
<ul>
{{#each menu.items as item}}
{{#ifPermInRole item.permissions id ../user.roles}}
<li>
<a href="{{item.url}}">
{{item.label}}
</a>
</li>
{{/ifPermInRole}}
{{/each}}
</ul>
</li>
{{/ifRoleAllowed}}
{{/each}}
</ul>
The helper ifRoleAllowed
and ifPermInRole
do not belong to Handlebars
. Handlebars allows you to extend it using custom helpers. Thus, we can create a helper that tells us if the user is allowed for the action of that menu and / or item:
ifRoleAllowed
Handlebars.registerHelper('ifRoleAllowed', function(mroles, uroles, options) {
let isAllowed = false;
mroles.forEach(mrole => {
if(!isAllowed) {
uroles.forEach(urole => {
// son roles iguales
if(urole === mrole) {
isAllowed = true;
}
});
}
});
if(isAllowed) {
return options.fn(this);
}
return options.inverse(this);
});
ifPermInRole
Handlebars.registerHelper('ifPermInRole', function(perms, roles, options) {
let isAllowed = false;
perms.forEach(perm => {
if(!isAllowed) {
roles.forEach(role => {
if(role.contains(perm)) {
isAllowed = true;
}
});
}
});
if(isAllowed) {
return options.fn(this);
}
return options.inverse(this);
});