|
- wn.pages['permission-manager'].onload = function(wrapper) {
- wn.ui.make_app_page({
- parent: wrapper,
- title: 'Permission Manager',
- single_column: true
- });
- $(wrapper).find(".layout-main").html("<div class='perm-engine'></div>\
- <table class='table table-bordered' style='background-color: #f9f9f9;'>\
- <tr><td>\
- <h4><i class='icon-question-sign'></i> Quick Help for Setting Permissions:</h4>\
- <ol>\
- <li>Permissions are set on Roles and Document Types (called DocTypes) by restricting \
- read, write, create, submit, cancel and amend rights.</li>\
- <li>Permissions translate to Users based on what Role they are assigned.</li>\
- <li>To set user roles, just go to <a href='#List/Profile'>Setup > Users</a> \
- and click on the user to assign roles.</li>\
- <li>The system provides pre-defined roles, but you can <a href='#List/Role'>add new roles</a>\
- to set finer permissions.</li>\
- <li>Permissions are automatically translated to Standard Reports and Searches.</li>\
- <li>As a best practice, do not assign the same set of permission rule to different Roles\
- instead set multiple Roles to the User.</li>\
- </ol>\
- </tr></td>\
- <tr><td>\
- <h4><i class='icon-hand-right'></i> Meaning of Submit, Cancel, Amend:</h4>\
- <ol>\
- <li>Certain documents should not be changed once final, like an\
- Invoice for example. The final state for such documents is called <b>Submitted</b>.\
- You can restrict which roles can Submit.</li>\
- <li><b>Cancel</b> allows you change Submitted documents by cancelling them and amending them.\
- Cancel permissions also allows the user to delete a document (if it is not linked to any other document).</li>\
- <li>When you <b>Amend</b> a document after cancel and save it, it will get a new number that is\
- a version of the old number. For example if you cancel and amend 'INV004' it will become a new\
- document 'INV004-1'. This helps you to keep track of each amendment.</li>\
- </ol>\
- </tr></td>\
- <tr><td>\
- <h4><i class='icon-user'></i> Restricting By User:</h4>\
- <ol>\
- <li>To restrict a User of a particular Role to documents that are only self-created,\
- Click on button in the 'Condition' column and select the option 'User is the creator of the document'.</li>\
- <li>To restrict a User of a particular Role to documents that are explicitly assigned to them,\
- create a Custom Field of type Link (Profile) and then use the 'Condition' settings\
- to map that field to the Permission rule.\
- </ol>\
- </tr></td>\
- <tr><td>\
- <h4><i class='icon-cog'></i> Advanced Settings:</h4>\
- <p>To further restrict permissions based on certain values in a document, use the\
- 'Condition' settings. <br><br>For example: You want to restrict users to transactions marked\
- with a certain property called 'Territory':</p>\
- <ol>\
- <li>Make sure that the transactions you want to restrict have a Link \
- field 'territory' that maps to a 'Territory' master. If not, create a\
- <a href='#List/Custom Field'>Custom Field</a> of type Link.</li>\
- <li>In the Permission Manager, click on the button in the 'Condition' column\
- for the Role you want to restrict.</li>\
- <li>A new pop will open that will ask you to select further conditions. \
- If the 'territory' Link Field exists, it will give you an option to select \
- it.</li>\
- <li>Go to Setup > <a href='#user-properties'>User Properties</a> to set \
- 'territory' for diffent Users.</li>\
- </ol>\
- <p>Once you have set this, the users will only be able access documents with that property</p>\
- <hr>\
- <p>If these instructions where not helpful, please add in your suggestions at\
- <a href='https://github.com/webnotes/wnframework/issues'>GitHub Issues</a></p>\
- </tr></td>\
- </table>");
- wrapper.permission_engine = new wn.PermissionEngine(wrapper);
- }
- wn.pages['permission-manager'].refresh = function(wrapper) {
- wrapper.permission_engine.set_from_route();
- }
-
- wn.PermissionEngine = Class.extend({
- init: function(wrapper) {
- this.wrapper = wrapper;
- this.body = $(this.wrapper).find(".perm-engine");
- this.make();
- this.refresh();
- this.add_check_events();
- },
- make: function() {
- var me = this;
-
- me.make_reset_button();
- wn.call({
- module:"core",
- page:"permission_manager",
- method: "get_roles_and_doctypes",
- callback: function(r) {
- me.options = r.message;
- me.doctype_select
- = me.wrapper.appframe.add_select("doctypes",
- ["Select Document Type..."].concat(r.message.doctypes))
- .css("width", "200px")
- .change(function() {
- wn.set_route("permission-manager", $(this).val())
- });
- me.role_select
- = me.wrapper.appframe.add_select("roles",
- ["Select Role..."].concat(r.message.roles))
- .css("width", "200px")
- .change(function() {
- me.refresh();
- });
- me.set_from_route();
- }
- });
- },
- set_from_route: function() {
- if(wn.get_route()[1] && this.doctype_select) {
- this.doctype_select.val(wn.get_route()[1]);
- this.refresh();
- } else {
- this.refresh();
- }
- },
- make_reset_button: function() {
- var me = this;
- me.reset_button = me.wrapper.appframe.add_button("Reset Permissions", function() {
- if(wn.confirm("Reset Permissions for " + me.get_doctype() + "?", function() {
- wn.call({
- module:"core",
- page:"permission_manager",
- method:"reset",
- args: {
- doctype:me.get_doctype(),
- },
- callback: function() { me.refresh(); }
- });
- }));
- }, 'icon-retweet').toggle(false);
- },
- get_doctype: function() {
- var doctype = this.doctype_select.val();
- return doctype=="Select Document Type..." ? null : doctype;
- },
- get_role: function() {
- var role = this.role_select.val();
- return role=="Select Role..." ? null : role;
- },
- refresh: function() {
- var me = this;
- if(!me.doctype_select) {
- this.body.html("<div class='alert'>Loading...</div>");
- return;
- }
- if(!me.get_doctype() && !me.get_role()) {
- this.body.html("<div class='alert'>Select Document Type or Role to start.</div>");
- return;
- }
- // get permissions
- wn.call({
- module: "core",
- page: "permission_manager",
- method: "get_permissions",
- args: {
- doctype: me.get_doctype(),
- role: me.get_role()
- },
- callback: function(r) {
- me.render(r.message);
- }
- });
- me.reset_button.toggle(me.get_doctype() ? true : false);
- },
- render: function(perm_list) {
- this.body.empty();
- this.perm_list = perm_list;
- if(!perm_list.length) {
- this.body.html("<div class='alert'>No Permissions set for this criteria.</div>");
- } else {
- this.show_permission_table(perm_list);
- }
- this.show_add_rule();
- },
- show_permission_table: function(perm_list) {
- var me = this;
- this.table = $("<table class='table table-bordered'>\
- <thead><tr></tr></thead>\
- <tbody></tbody>\
- </table>").appendTo(this.body);
-
- $.each([["Document Type", 150], ["Role", 100], ["Level",50],
- ["Read", 50], ["Write", 50], ["Create", 50],
- ["Submit", 50], ["Cancel", 50], ["Amend", 50],
- ["Condition", 150], ["", 50]], function(i, col) {
- $("<th>").html(col[0]).css("width", col[1]+"px")
- .appendTo(me.table.find("thead tr"));
- });
-
- var add_cell = function(row, d, fieldname, is_check) {
- var cell = $("<td>").appendTo(row).attr("data-fieldname", fieldname);
- if(is_check) {
- if(d.permlevel > 0 && ["read", "write"].indexOf(fieldname)==-1) {
- cell.html("-");
- } else {
- var input = $("<input type='checkbox'>")
- .attr("checked", d[fieldname] ? "checked": null)
- .attr("data-ptype", fieldname)
- .attr("data-name", d.name)
- .attr("data-doctype", d.parent)
- .appendTo(cell);
- }
- } else {
- cell.html(d[fieldname]);
- }
- return cell;
- }
-
- $.each(perm_list, function(i, d) {
- if(!d.permlevel) d.permlevel = 0;
- var row = $("<tr>").appendTo(me.table.find("tbody"));
- add_cell(row, d, "parent");
- me.set_show_users(add_cell(row, d, "role"), d.role);
-
- var cell = add_cell(row, d, "permlevel");
- if(d.permlevel==0) {
- cell.css("font-weight", "bold");
- row.addClass("warning");
- }
- add_cell(row, d, "read", true);
- add_cell(row, d, "write", true);
- add_cell(row, d, "create", true);
- add_cell(row, d, "submit", true);
- add_cell(row, d, "cancel", true);
- add_cell(row, d, "amend", true);
-
- // buttons
- me.add_match_button(row, d);
- me.add_delete_button(row, d);
- });
- },
- set_show_users: function(cell, role) {
- cell.html("<a href='#'>"+role+"</a>")
- .find("a")
- .attr("data-role", role)
- .click(function() {
- var role = $(this).attr("data-role");
- wn.call({
- module: "core",
- page: "permission_manager",
- method: "get_users_with_role",
- args: {
- role: role
- },
- callback: function(r) {
- r.message = $.map(r.message, function(p) {
- return '<a href="#Form/Profile/'+p+'">'+p+'</a>';
- })
- msgprint("<h4>Users with role "+role+":</h4>"
- + r.message.join("<br>"));
- }
- })
- return false;
- })
- },
- add_match_button: function(row, d) {
- var me = this;
- if(d.permlevel > 0) {
- $("<td>-</td>").appendTo(row);
- return;
- }
- var btn = $("<button class='btn btn-small'></button>")
- .html(d.match ? d.match : "For All Users")
- .appendTo($("<td>").appendTo(row))
- .attr("data-name", d.name)
- .click(function() {
- me.show_match_manager($(this).attr("data-name"));
- });
- if(d.match) btn.addClass("btn-inverse");
- },
- add_delete_button: function(row, d) {
- var me = this;
- $("<button class='btn btn-small'><i class='icon-remove'></i></button>")
- .appendTo($("<td>").appendTo(row))
- .attr("data-name", d.name)
- .attr("data-doctype", d.parent)
- .click(function() {
- wn.call({
- module: "core",
- page: "permission_manager",
- method: "remove",
- args: {
- name: $(this).attr("data-name"),
- doctype: $(this).attr("data-doctype")
- },
- callback: function(r) {
- if(r.exc) {
- msgprint("Did not remove.");
- } else {
- me.refresh();
- }
- }
- })
- });
- },
- add_check_events: function() {
- var me = this;
- this.body.on("click", "input[type='checkbox']", function() {
- var chk = $(this);
- var args = {
- name: chk.attr("data-name"),
- doctype: chk.attr("data-doctype"),
- ptype: chk.attr("data-ptype"),
- value: chk.is(":checked") ? 1 : 0
- }
- wn.call({
- module: "core",
- page: "permission_manager",
- method: "update",
- args: args,
- callback: function(r) {
- if(r.exc) {
- // exception: reverse
- chk.attr("checked", chk.is(":checked") ? null : "checked");
- } else {
- me.get_perm(args.name)[args.ptype]=args.value;
- }
- }
- })
- })
- },
- show_add_rule: function() {
- var me = this;
- $("<button class='btn btn-info'>Add A New Rule</button>")
- .appendTo($("<p>").appendTo(this.body))
- .click(function() {
- var d = new wn.ui.Dialog({
- title: "Add New Permission Rule",
- fields: [
- {fieldtype:"Select", label:"Document Type",
- options:me.options.doctypes, reqd:1, fieldname:"parent"},
- {fieldtype:"Select", label:"Role",
- options:me.options.roles, reqd:1},
- {fieldtype:"Select", label:"Permission Level",
- options:[0,1,2,3,4,5,6,7,8,9], reqd:1, fieldname: "permlevel",
- description:"Level 0 is for document level permissions, higher levels for field level permissions."},
- {fieldtype:"Button", label:"Add"},
- ]
- });
- if(me.get_doctype()) {
- d.set_value("parent", me.get_doctype());
- d.get_input("parent").attr("disabled", true);
- }
- if(me.get_role()) {
- d.set_value("role", me.get_role());
- d.get_input("role").attr("disabled", true);
- }
- d.set_value("permlevel", "0");
- d.get_input("add").click(function() {
- var args = d.get_values();
- if(!args) {
- return;
- }
- wn.call({
- module: "core",
- page: "permission_manager",
- method: "add",
- args: args,
- callback: function(r) {
- if(r.exc) {
- msgprint("Did not add.");
- } else {
- me.refresh();
- }
- }
- })
- d.hide();
- });
- d.show();
- });
- },
- get_perm: function(name) {
- return $.map(this.perm_list, function(d) { if(d.name==name) return d; })[0];
- },
- show_match_manager:function(name) {
- var perm = this.get_perm(name);
- var me = this;
-
- wn.model.with_doctype(perm.parent, function() {
- var dialog = new wn.ui.Dialog({
- title: "Applies for Users",
- });
- $(dialog.body).html("<h4>Rule Applies to Following Users:</h4>\
- <label class='radio'>\
- <input name='perm-rule' type='radio' value=''> All users with role <b>"+perm.role+"</b>.\
- </label>\
- <label class='radio'>\
- <input name='perm-rule' type='radio' value='owner'> The user is the creator of the document.\
- </label>").css("padding", "15px");
-
- // profile fields
- $.each(me.get_profile_fields(perm.parent), function(i, d) {
- $("<label class='radio'>\
- <input name='perm-rule' type='radio' value='"+d.fieldname
- +":user'>Value of field <b>"+d.label+"</b> is the User.\
- </label>").appendTo(dialog.body);
- });
-
- // add options for all link fields
- $.each(me.get_link_fields(perm.parent), function(i, d) {
- $("<label class='radio'>\
- <input name='perm-rule' type='radio' value='"+d.fieldname
- +"'><b>"+d.label+"</b> in <b>"+d.parent+"</b> matches <a href='#user-properties'>User Property</a> <b>"
- +d.fieldname+"</b>.\
- </label>").appendTo(dialog.body);
- });
-
- // button
- $("<button class='btn btn-info'>Update</button>")
- .appendTo($("<p>").appendTo(dialog.body))
- .attr("data-name", perm.name)
- .click(function() {
- var match_value = $(dialog.wrapper).find(":radio:checked").val();
- var perm = me.get_perm($(this).attr('data-name'))
- wn.call({
- module: "core",
- page: "permission_manager",
- method: "update_match",
- args: {
- name: perm.name,
- doctype: perm.parent,
- match: match_value
- },
- callback: function() {
- dialog.hide();
- me.refresh();
- }
- })
- });
- dialog.show();
-
- // select
- if(perm.match) {
- $(dialog.wrapper).find("[value='"+perm.match+"']").attr("checked", "checked").focus();
- } else {
- $(dialog.wrapper).find('[value=""]').attr("checked", "checked").focus();
- }
- });
- },
- get_profile_fields: function(doctype) {
- var profile_fields = wn.model.get("DocField", {parent:doctype,
- fieldtype:"Link", options:"Profile"});
-
- profile_fields = profile_fields.concat(wn.model.get("DocField", {parent:doctype,
- fieldtype:"Select", link_doctype:"Profile"}))
-
- return profile_fields
- },
- get_link_fields: function(doctype) {
- return link_fields = wn.model.get("DocField", {parent:doctype,
- fieldtype:"Link", options:["not in", ["Profile", '[Select]']]});
- }
- })
|