|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455 |
- wn.pages['permission-manager'].onload = function(wrapper) {
- wn.ui.make_app_page({
- parent: wrapper,
- title: wn._('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> "+wn._("Quick Help for Setting Permissions")+":</h4>\
- <ol>\
- <li>"+wn._("Permissions are set on Roles and Document Types (called DocTypes) by restricting read, edit, make new, submit, cancel, amend and report rights.")+"</li>\
- <li>"+wn._("Permissions translate to Users based on what Role they are assigned")+".</li>\
- <li>"+wn._("To set user roles, just go to <a href='#List/Profile'>Setup > Users</a> and click on the user to assign roles.")+"</li>\
- <li>"+wn._("The system provides pre-defined roles, but you can <a href='#List/Role'>add new roles</a> to set finer permissions")+".</li>\
- <li>"+wn._("Permissions are automatically translated to Standard Reports and Searches")+".</li>\
- <li>"+wn._("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> "+wn._("Meaning of Submit, Cancel, Amend")+":</h4>\
- <ol>\
- <li>"+wn._("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>"+wn._("<b>Cancel</b> allows you change Submitted documents by cancelling them and amending them.")+
- wn._("Cancel permission also allows the user to delete a document (if it is not linked to any other document).")+"</li>\
- <li>"+wn._("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.")+
- wn._("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-signal'></i> "+wn._("Permission Levels")+":</h4>\
- <ol>\
- <li>"+wn._("Permissions at level 0 are 'Document Level' permissions, i.e. they are primary for access to the document.")+
- wn._("If a User does not have access at Level 0, then higher levels are meaningless")+".</li>\
- <li>"+wn._("Permissions at higher levels are 'Field Level' permissions. All Fields have a 'Permission Level' set against them and the rules defined at that permissions apply to the field. This is useful incase you want to hide or make certain field read-only.")+
- wn._("You can use <a href='#Form/Customize Form'>Customize Form</a> to set levels on fields.")+"</li>\
- </ol>\
- </tr></td>\
- <tr><td>\
- <h4><i class='icon-user'></i> "+wn._("Restricting By User")+":</h4>\
- <ol>\
- <li>"+wn._("To restrict a User of a particular Role to documents that are only self-created.")+
- wn._("Click on button in the 'Condition' column and select the option 'User is the creator of the document'")+".</li>\
- <li>"+wn._("To restrict a User of a particular Role to documents that are explicitly assigned to them")+ ":"+
- + wn._("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> "+wn._("Advanced Settings")+":</h4>\
- <p>"+wn._("To further restrict permissions based on certain values in a document, use the 'Condition' settings.")+" <br><br>"+
- wn._("For example: You want to restrict users to transactions marked with a certain property called 'Territory'")+":</p>\
- <ol>\
- <li>"+wn._("Make sure that the transactions you want to restrict have a Link field 'territory' that maps to a 'Territory' master.")+" "
- +wn._("If not, create a")+
- "<a href='#List/Custom Field'>"+wn._("Custom Field")+"</a>"+ wn._("of type Link")+".</li>\
- <li>"+wn._("In the Permission Manager, click on the button in the 'Condition' column for the Role you want to restrict.")+"</li>\
- <li>"+wn._("A new popup will open that will ask you to select further conditions.")+
- wn._("If the 'territory' Link Field exists, it will give you an option to select it")+".</li>\
- <li>"+wn._("Go to Setup > <a href='#user-properties'>User Properties</a> to set \
- 'territory' for diffent Users.")+"</li>\
- </ol>\
- <p>"+wn._("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();
- return 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",
- [wn._("Select Document Type")+"..."].concat(r.message.doctypes))
- .change(function() {
- wn.set_route("permission-manager", $(this).val())
- });
- me.role_select
- = me.wrapper.appframe.add_select("roles",
- [wn._("Select Role")+"..."].concat(r.message.roles))
- .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() {
- return 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 this.doctype_select.get(0).selectedIndex==0 ? null : doctype;
- },
- get_role: function() {
- var role = this.role_select.val();
- return this.role_select.get(0).selectedIndex==0 ? null : role;
- },
- refresh: function() {
- var me = this;
- if(!me.doctype_select) {
- this.body.html("<div class='alert alert-info'>Loading...</div>");
- return;
- }
- if(!me.get_doctype() && !me.get_role()) {
- this.body.html("<div class='alert alert-info'>"+wn._("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 alert-warning'>"+wn._("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], ["Edit", 50], ["Make New", 50],
- ["Submit", 50], ["Cancel", 50], ["Amend", 50], ["Report", 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'>")
- .prop("checked", d[fieldname] ? true: false)
- .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);
- add_cell(row, d, "report", 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-default btn-small'></button>")
- .html(d.match ? d.match : wn._("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-info");
- },
- add_delete_button: function(row, d) {
- var me = this;
- $("<button class='btn btn-default btn-small'><i class='icon-remove'></i></button>")
- .appendTo($("<td>").appendTo(row))
- .attr("data-name", d.name)
- .attr("data-doctype", d.parent)
- .click(function() {
- return 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.prop("checked") ? 1 : 0
- }
- return wn.call({
- module: "core",
- page: "permission_manager",
- method: "update",
- args: args,
- callback: function(r) {
- if(r.exc) {
- // exception: reverse
- chk.prop("checked", !chk.prop("checked"));
- } else {
- me.get_perm(args.name)[args.ptype]=args.value;
- }
- }
- })
- })
- },
- show_add_rule: function() {
- var me = this;
- $("<button class='btn btn-default btn-info'>"+wn._("Add A New Rule")+"</button>")
- .appendTo($("<p>").appendTo(this.body))
- .click(function() {
- var d = new wn.ui.Dialog({
- title: wn._("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: wn._("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").prop("disabled", true);
- }
- if(me.get_role()) {
- d.set_value("role", me.get_role());
- d.get_input("role").prop("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(wn._("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//"+d.fieldname+"'>User Property</a> <b>"
- +d.fieldname+"</b>.\
- </label>").appendTo(dialog.body);
- });
-
- // button
- $("<button class='btn btn-default 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'))
- return 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+"']").prop("checked", true).focus();
- } else {
- $(dialog.wrapper).find('[value=""]').prop("checked", true).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]']]});
- }
- })
|