new permission manager
This commit is contained in:
parent
5054a6848f
commit
9a6e3cf620
13 changed files with 894 additions and 14 deletions
|
|
@ -72,7 +72,8 @@ class DocType:
|
|||
webnotes.msgprint(c + " not allowed in name", raise_exception=1)
|
||||
self.validate_series()
|
||||
self.scrub_field_names()
|
||||
validate_fields(filter(lambda d: d.doctype=="DocField", self.doclist))
|
||||
validate_fields(self.doclist.get({"doctype":"DocField"}))
|
||||
validate_permissions(self.doclist.get({"doctype":"DocPerm"}))
|
||||
self.set_version()
|
||||
|
||||
def on_update(self):
|
||||
|
|
@ -165,9 +166,9 @@ class DocType:
|
|||
|
||||
def validate_fields_for_doctype(doctype):
|
||||
from webnotes.model.doctype import get
|
||||
validate_fields(filter(lambda d: d.doctype=="DocField" and d.parent==doctype,
|
||||
get(doctype, cached=False)))
|
||||
|
||||
validate_fields(get(doctype, cached=False).get({"parent":doctype,
|
||||
"doctype":"DocField"}))
|
||||
|
||||
def validate_fields(fields):
|
||||
def check_illegal_characters(fieldname):
|
||||
for c in ['.', ',', ' ', '-', '&', '%', '=', '"', "'", '*', '$',
|
||||
|
|
@ -211,4 +212,62 @@ def validate_fields(fields):
|
|||
check_illegal_mandatory(d)
|
||||
check_link_table_options(d)
|
||||
check_hidden_and_mandatory(d)
|
||||
|
||||
def validate_permissions_for_doctype(doctype, for_remove=False):
|
||||
from webnotes.model.doctype import get
|
||||
validate_permissions(get(doctype, cached=False).get({"parent":doctype,
|
||||
"doctype":"DocPerm"}), for_remove)
|
||||
|
||||
def validate_permissions(permissions, for_remove=False):
|
||||
def get_txt(d):
|
||||
return "For %s (level %s) in %s:" % (d.role, d.permlevel, d.parent)
|
||||
|
||||
def check_atleast_one_set(d):
|
||||
if not d.read and not d.write and not d.submit and not d.cancel and not d.create:
|
||||
webnotes.msgprint(get_txt(d) + " Atleast one of Read, Write, Create, Submit, Cancel must be set.",
|
||||
raise_exception=True)
|
||||
|
||||
def check_double(d):
|
||||
similar = permissions.get({
|
||||
"role":d.role,
|
||||
"permlevel":d.permlevel,
|
||||
"match": d.match
|
||||
})
|
||||
|
||||
if len(similar) > 1:
|
||||
webnotes.msgprint(get_txt(d) + " Only one rule allowed for a particular Role and Level.",
|
||||
raise_exception=True)
|
||||
|
||||
def check_level_zero_is_set(d):
|
||||
if d.permlevel > 0 and d.role != 'All':
|
||||
if not permissions.get({"role": d.role, "permlevel": 0}):
|
||||
webnotes.msgprint(get_txt(d) + " Higher level permissions are meaningless if level 0 permission is not set.",
|
||||
raise_exception=True)
|
||||
|
||||
if d.create:
|
||||
webnotes.msgprint("Create Permission has no meaning at level " + d.permlevel,
|
||||
raise_exception=True)
|
||||
|
||||
if d.submit:
|
||||
webnotes.msgprint("Submit Permission has no meaning at level " + d.permlevel,
|
||||
raise_exception=True)
|
||||
|
||||
if d.cancel:
|
||||
webnotes.msgprint("Cancel Permission has no meaning at level " + d.permlevel,
|
||||
raise_exception=True)
|
||||
|
||||
if d.amend:
|
||||
webnotes.msgprint("Amend Permission has no meaning at level " + d.permlevel,
|
||||
raise_exception=True)
|
||||
|
||||
if d.match:
|
||||
webnotes.msgprint("Match rules have no meaning at level " + d.permlevel,
|
||||
raise_exception=True)
|
||||
|
||||
for d in permissions:
|
||||
if not d.permlevel: d.permlevel=0
|
||||
check_atleast_one_set(d)
|
||||
if not for_remove:
|
||||
check_double(d)
|
||||
check_level_zero_is_set(d)
|
||||
|
||||
0
core/page/permission_manager/__init__.py
Normal file
0
core/page/permission_manager/__init__.py
Normal file
445
core/page/permission_manager/permission_manager.js
Normal file
445
core/page/permission_manager/permission_manager.js
Normal file
|
|
@ -0,0 +1,445 @@
|
|||
wn.pages['permission-manager'].onload = function(wrapper) {
|
||||
wn.ui.make_app_page({
|
||||
parent: wrapper,
|
||||
title: 'Permission Manager',
|
||||
single_column: true
|
||||
});
|
||||
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(".layout-main");
|
||||
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');
|
||||
},
|
||||
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();
|
||||
this.show_explain();
|
||||
},
|
||||
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");
|
||||
add_cell(row, 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);
|
||||
});
|
||||
},
|
||||
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;
|
||||
me.show_explain();
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
},
|
||||
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]']]});
|
||||
},
|
||||
show_explain: function() {
|
||||
$(".perm-explain").remove();
|
||||
if(!this.get_doctype()) return;
|
||||
var wrapper = $("<div class='perm-explain well'></div>").appendTo(this.body);
|
||||
var doctype = null;
|
||||
var core_finished = false;
|
||||
$.each(this.perm_list, function(i, p) {
|
||||
if(p.parent != doctype) {
|
||||
core_finished = false;
|
||||
doctype = p.parent;
|
||||
$('<h3>For ' + doctype + '</h3><h4>Document Permissions</h4>')
|
||||
.appendTo(wrapper);
|
||||
|
||||
}
|
||||
|
||||
if(p.permlevel==0) {
|
||||
var perms = $.map(["read", "write", "create", "submit", "cancel", "amend"], function(type) {
|
||||
if(p[type]) return type;
|
||||
}).join(", ");
|
||||
if(!p.match) {
|
||||
var _p = $('<p>').html("A user with role <b>"+p.role + "</b> can "
|
||||
+ perms + " a document of type <b>" + doctype + "</b>.")
|
||||
|
||||
} else {
|
||||
if(p.match=="owner") {
|
||||
var _p = $('<p>').html("A user with role <b>"+p.role + "</b> can "
|
||||
+ perms + " <b>" + doctype + "</b> <u>only if</u> that document is created by that user.");
|
||||
} else if(p.match.indexOf(":")!=-1) {
|
||||
var field = p.match.split(":")[0];
|
||||
var _p = $('<p>').html("A user with role <b>"+p.role + "</b> can "
|
||||
+ perms + " <b>" + doctype + "</b> <u>only if</u> <b>"+field+"</b> equals User's Id.");
|
||||
} else {
|
||||
var _p = $('<p>').html("A user with role <b>"+p.role + "</b> can "
|
||||
+ perms + " <b>" + doctype + "</b> <u>only for</u> records with user's <b>"+p.match+"</b> property.");
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if(!core_finished) {
|
||||
core_finished = true;
|
||||
$("<br><h4>Field Level Permissions</h4>").appendTo(wrapper);
|
||||
}
|
||||
var perms = $.map(["read", "write"], function(type) {
|
||||
if(p[type]) return type;
|
||||
}).join(", ");
|
||||
var _p = $('<p>').html("A user with role <b>"+p.role + "</b> can only <u>"
|
||||
+ perms + "</u> fields at level <b>"+ p.permlevel +"</b> in a <b>" + doctype + "</b>.")
|
||||
}
|
||||
|
||||
$("<a>Show Users</a>").appendTo(_p).attr("data-role", p.role)
|
||||
.css("margin-left", "7px")
|
||||
.click(function() {
|
||||
var link = $(this);
|
||||
wn.call({
|
||||
module: "core",
|
||||
page: "permission_manager",
|
||||
method: "get_users_with_role",
|
||||
args: {
|
||||
role: link.attr("data-role"),
|
||||
},
|
||||
callback: function(r) {
|
||||
$.each(r.message, function(i, uid) {
|
||||
msgprint("<a href='#Form/Profile/"+uid+"'>"
|
||||
+ wn.user_info(uid).fullname + "</a> ("+
|
||||
uid+")");
|
||||
});
|
||||
cur_dialog.set_title("Users with role "
|
||||
+ link.attr("data-role"));
|
||||
}
|
||||
});
|
||||
});
|
||||
_p.appendTo(wrapper);
|
||||
})
|
||||
}
|
||||
})
|
||||
72
core/page/permission_manager/permission_manager.py
Normal file
72
core/page/permission_manager/permission_manager.py
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
@webnotes.whitelist(allow_roles=["System Manager", "Administrator"])
|
||||
def get_roles_and_doctypes():
|
||||
return {
|
||||
"doctypes": [d[0] for d in webnotes.conn.sql("""select name from tabDocType where
|
||||
ifnull(istable,0)=0 and
|
||||
ifnull(issingle,0)=0 and
|
||||
module != 'Core' """)],
|
||||
"roles": [d[0] for d in webnotes.conn.sql("""select name from tabRole where name not in
|
||||
('All', 'Guest', 'Administrator')""")]
|
||||
}
|
||||
|
||||
@webnotes.whitelist(allow_roles=["System Manager", "Administrator"])
|
||||
def get_permissions(doctype=None, role=None):
|
||||
return webnotes.conn.sql("""select * from tabDocPerm
|
||||
where %s%s order by parent, permlevel, role""" % (\
|
||||
doctype and (" parent='%s'" % doctype) or "",
|
||||
role and ((doctype and " and " or "") + " role='%s'" % role) or "",
|
||||
), as_dict=True)
|
||||
|
||||
@webnotes.whitelist(allow_roles=["System Manager", "Administrator"])
|
||||
def remove(doctype, name):
|
||||
webnotes.conn.sql("""delete from tabDocPerm where name=%s""", name)
|
||||
validate_and_reset(doctype, for_remove=True)
|
||||
|
||||
@webnotes.whitelist(allow_roles=["System Manager", "Administrator"])
|
||||
def add(parent, role, permlevel):
|
||||
webnotes.doc(fielddata={
|
||||
"doctype":"DocPerm",
|
||||
"__islocal": 1,
|
||||
"parent": parent,
|
||||
"parenttype": "DocType",
|
||||
"parentfield": "permissions",
|
||||
"role": role,
|
||||
"permlevel": permlevel,
|
||||
"read": 1
|
||||
}).save()
|
||||
|
||||
validate_and_reset(parent)
|
||||
|
||||
@webnotes.whitelist(allow_roles=["System Manager", "Administrator"])
|
||||
def update(name, doctype, ptype, value=0):
|
||||
webnotes.conn.sql("""update tabDocPerm set `%s`=%s where name=%s"""\
|
||||
% (ptype, '%s', '%s'), (value, name))
|
||||
validate_and_reset(doctype)
|
||||
|
||||
@webnotes.whitelist(allow_roles=["System Manager", "Administrator"])
|
||||
def update_match(name, doctype, match=""):
|
||||
webnotes.conn.sql("""update tabDocPerm set `match`=%s where name=%s""",
|
||||
(match, name))
|
||||
validate_and_reset(doctype)
|
||||
|
||||
def validate_and_reset(doctype, for_remove=False):
|
||||
from core.doctype.doctype.doctype import validate_permissions_for_doctype
|
||||
validate_permissions_for_doctype(doctype, for_remove)
|
||||
webnotes.clear_cache(doctype=doctype)
|
||||
|
||||
@webnotes.whitelist(allow_roles=["System Manager", "Administrator"])
|
||||
def reset(doctype):
|
||||
webnotes.reset_perms(doctype)
|
||||
webnotes.clear_cache(doctype=doctype)
|
||||
|
||||
@webnotes.whitelist(allow_roles=["System Manager", "Administrator"])
|
||||
def get_users_with_role(role):
|
||||
return [p[0] for p in webnotes.conn.sql("""select distinct tabProfile.name
|
||||
from tabUserRole, tabProfile where
|
||||
tabUserRole.role=%s
|
||||
and tabProfile.name != "Administrator"
|
||||
and tabUserRole.parent = tabProfile.name
|
||||
and ifnull(tabProfile.enabled,0)=1""", role)]
|
||||
21
core/page/permission_manager/permission_manager.txt
Normal file
21
core/page/permission_manager/permission_manager.txt
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
[
|
||||
{
|
||||
"owner": "Administrator",
|
||||
"docstatus": 0,
|
||||
"creation": "2013-01-01 11:00:01",
|
||||
"modified_by": "Administrator",
|
||||
"modified": "2013-01-01 11:00:01"
|
||||
},
|
||||
{
|
||||
"name": "__common__",
|
||||
"title": "Permission Manager",
|
||||
"doctype": "Page",
|
||||
"module": "Core",
|
||||
"standard": "Yes",
|
||||
"page_name": "Permission Manager"
|
||||
},
|
||||
{
|
||||
"name": "permission-manager",
|
||||
"doctype": "Page"
|
||||
}
|
||||
]
|
||||
0
core/page/user_properties/__init__.py
Normal file
0
core/page/user_properties/__init__.py
Normal file
213
core/page/user_properties/user_properties.js
Normal file
213
core/page/user_properties/user_properties.js
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
wn.pages['user-properties'].onload = function(wrapper) {
|
||||
wn.ui.make_app_page({
|
||||
parent: wrapper,
|
||||
title: 'User Properties',
|
||||
single_column: true
|
||||
});
|
||||
wrapper.user_properties = new wn.UserProperties(wrapper);
|
||||
}
|
||||
|
||||
wn.pages['user-properties'].refresh = function(wrapper) {
|
||||
wrapper.user_properties.set_from_route();
|
||||
}
|
||||
|
||||
wn.UserProperties = Class.extend({
|
||||
init: function(wrapper) {
|
||||
this.wrapper = wrapper;
|
||||
this.body = $(this.wrapper).find(".layout-main");
|
||||
this.make();
|
||||
this.refresh();
|
||||
},
|
||||
make: function() {
|
||||
var me = this;
|
||||
wn.call({
|
||||
module:"core",
|
||||
page:"user_properties",
|
||||
method: "get_users_and_links",
|
||||
callback: function(r) {
|
||||
me.options = r.message;
|
||||
me.user_select =
|
||||
me.wrapper.appframe.add_select("users",
|
||||
["Select User..."].concat(r.message.users))
|
||||
.css("width", "200px")
|
||||
.change(function() {
|
||||
wn.set_route("user-properties", $(this).val())
|
||||
});
|
||||
me.property_select =
|
||||
me.wrapper.appframe.add_select("links",
|
||||
["Select Property..."].concat(me.get_link_names()))
|
||||
.css("width", "200px")
|
||||
.change(function() {
|
||||
me.refresh();
|
||||
});
|
||||
me.set_from_route();
|
||||
}
|
||||
});
|
||||
},
|
||||
get_link_names: function() {
|
||||
return $.map(this.options.link_fields, function(l) { return l[0]; });
|
||||
},
|
||||
set_from_route: function() {
|
||||
if(wn.get_route()[1] && this.user_select) {
|
||||
this.user_select.val(wn.get_route()[1]);
|
||||
this.refresh();
|
||||
} else {
|
||||
this.refresh();
|
||||
}
|
||||
},
|
||||
get_user: function() {
|
||||
var user = this.user_select.val();
|
||||
return user=="Select User..." ? null : user;
|
||||
},
|
||||
get_property: function() {
|
||||
var property = this.property_select.val();
|
||||
return property=="Select Property..." ? null : property;
|
||||
},
|
||||
render: function(prop_list) {
|
||||
this.body.empty();
|
||||
this.prop_list = prop_list;
|
||||
if(!prop_list.length) {
|
||||
this.body.html("<div class='alert'>No User Properties found.</div>");
|
||||
} else {
|
||||
this.show_property_table();
|
||||
}
|
||||
this.show_add_property();
|
||||
$("<div class='well'>User Properties appear as default values in forms.\
|
||||
<br>They are also used to restrict permissions \
|
||||
in the <a href='#permission-manager'>Permission Manager</a>\
|
||||
<br>You can also set multiple values for one property. \
|
||||
If so, the permission rules will apply if any of the values match.</div>").appendTo(this.body);
|
||||
},
|
||||
refresh: function() {
|
||||
var me = this;
|
||||
if(!me.user_select) {
|
||||
this.body.html("<div class='alert'>Loading...</div>");
|
||||
return;
|
||||
}
|
||||
if(!me.get_user() && !me.get_property()) {
|
||||
this.body.html("<div class='alert'>Select User or Property to start.</div>");
|
||||
return;
|
||||
}
|
||||
// get permissions
|
||||
wn.call({
|
||||
module: "core",
|
||||
page: "user_properties",
|
||||
method: "get_properties",
|
||||
args: {
|
||||
user: me.get_user(),
|
||||
key: me.get_property()
|
||||
},
|
||||
callback: function(r) {
|
||||
me.render(r.message);
|
||||
}
|
||||
});
|
||||
},
|
||||
show_property_table: function() {
|
||||
var me = this;
|
||||
this.table = $("<table class='table table-bordered'>\
|
||||
<thead><tr></tr></thead>\
|
||||
<tbody></tbody>\
|
||||
</table>").appendTo(this.body);
|
||||
|
||||
$.each([["User", 150], ["Property", 150], ["Value",150], ["", 50]],
|
||||
function(i, col) {
|
||||
$("<th>").html(col[0]).css("width", col[1]+"px")
|
||||
.appendTo(me.table.find("thead tr"));
|
||||
});
|
||||
|
||||
|
||||
$.each(this.prop_list, function(i, d) {
|
||||
var row = $("<tr>").appendTo(me.table.find("tbody"));
|
||||
|
||||
$("<td>").html(d.parent).appendTo(row);
|
||||
$("<td>").html(d.defkey).appendTo(row);
|
||||
$("<td>").html(d.defvalue).appendTo(row);
|
||||
|
||||
me.add_delete_button(row, d);
|
||||
});
|
||||
|
||||
},
|
||||
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-user", d.parent)
|
||||
.click(function() {
|
||||
wn.call({
|
||||
module: "core",
|
||||
page: "user_properties",
|
||||
method: "remove",
|
||||
args: {
|
||||
name: $(this).attr("data-name"),
|
||||
user: $(this).attr("data-user")
|
||||
},
|
||||
callback: function(r) {
|
||||
if(r.exc) {
|
||||
msgprint("Did not remove.");
|
||||
} else {
|
||||
me.refresh();
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
show_add_property: function() {
|
||||
var me = this;
|
||||
$("<button class='btn btn-info'>Add A Property</button>")
|
||||
.appendTo($("<p>").appendTo(this.body))
|
||||
.click(function() {
|
||||
var d = new wn.ui.Dialog({
|
||||
title: "Add New Property",
|
||||
fields: [
|
||||
{fieldtype:"Select", label:"User",
|
||||
options:me.options.users, reqd:1, fieldname:"parent"},
|
||||
{fieldtype:"Select", label:"Property", fieldname:"defkey",
|
||||
options:me.get_link_names(), reqd:1},
|
||||
{fieldtype:"Link", label:"Value", fieldname:"defvalue",
|
||||
options:'[Select]', reqd:1},
|
||||
{fieldtype:"Button", label:"Add"},
|
||||
]
|
||||
});
|
||||
if(me.get_user()) {
|
||||
d.set_value("parent", me.get_user());
|
||||
d.get_input("parent").attr("disabled", true);
|
||||
}
|
||||
if(me.get_property()) {
|
||||
d.set_value("defkey", me.get_property());
|
||||
d.get_input("defkey").attr("disabled", true);
|
||||
}
|
||||
d.fields_dict["defvalue"].get_query = function(txt) {
|
||||
var key = d.get_value("defkey");
|
||||
var doctype = $.map(me.options.link_fields, function(l) {
|
||||
if(l[0]==key) return l[1];
|
||||
})[0];
|
||||
return 'select name from `tab'+doctype
|
||||
+'` where name like "%s"'
|
||||
}
|
||||
d.get_input("add").click(function() {
|
||||
var args = d.get_values();
|
||||
if(!args) {
|
||||
return;
|
||||
}
|
||||
wn.call({
|
||||
module: "core",
|
||||
page: "user_properties",
|
||||
method: "add",
|
||||
args: args,
|
||||
callback: function(r) {
|
||||
if(r.exc) {
|
||||
msgprint("Did not add.");
|
||||
} else {
|
||||
me.refresh();
|
||||
}
|
||||
}
|
||||
})
|
||||
d.hide();
|
||||
});
|
||||
d.show();
|
||||
});
|
||||
|
||||
}
|
||||
})
|
||||
36
core/page/user_properties/user_properties.py
Normal file
36
core/page/user_properties/user_properties.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
from __future__ import unicode_literals
|
||||
import webnotes
|
||||
|
||||
@webnotes.whitelist(allow_roles=["System Manager", "Administrator"])
|
||||
def get_users_and_links():
|
||||
links = list(set(webnotes.conn.sql("""select fieldname, options
|
||||
from tabDocField where fieldtype='Link'
|
||||
and parent not in ('[Select]', 'DocType', 'Module Def')
|
||||
""") + webnotes.conn.sql("""select fieldname, options
|
||||
from `tabCustom Field` where fieldtype='Link'""")))
|
||||
links.sort()
|
||||
|
||||
return {
|
||||
"users": [d[0] for d in webnotes.conn.sql("""select name from tabProfile where
|
||||
ifnull(enabled,0)=1 and
|
||||
name not in ("Administrator", "Guest")""")],
|
||||
"link_fields": links
|
||||
}
|
||||
|
||||
@webnotes.whitelist(allow_roles=["System Manager", "Administrator"])
|
||||
def get_properties(user=None, key=None):
|
||||
return webnotes.conn.sql("""select name, parent, defkey, defvalue
|
||||
from tabDefaultValue
|
||||
where %s%s and parent!='Control Panel' order by parent, defkey""" % (\
|
||||
user and (" parent='%s'" % user) or "",
|
||||
key and ((user and " and " or "") + " defkey='%s'" % key) or "",
|
||||
), as_dict=True)
|
||||
|
||||
@webnotes.whitelist(allow_roles=["System Manager", "Administrator"])
|
||||
def remove(user, name):
|
||||
webnotes.conn.sql("""delete from tabDefaultValue where name=%s""", name)
|
||||
webnotes.clear_cache(user=user)
|
||||
|
||||
@webnotes.whitelist(allow_roles=["System Manager", "Administrator"])
|
||||
def add(parent, defkey, defvalue):
|
||||
webnotes.conn.add_default(defkey, defvalue, parent)
|
||||
21
core/page/user_properties/user_properties.txt
Normal file
21
core/page/user_properties/user_properties.txt
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
[
|
||||
{
|
||||
"owner": "Administrator",
|
||||
"docstatus": 0,
|
||||
"creation": "2013-01-01 18:50:55",
|
||||
"modified_by": "Administrator",
|
||||
"modified": "2013-01-01 18:50:55"
|
||||
},
|
||||
{
|
||||
"name": "__common__",
|
||||
"title": "User Properties",
|
||||
"doctype": "Page",
|
||||
"module": "Core",
|
||||
"standard": "Yes",
|
||||
"page_name": "user-properties"
|
||||
},
|
||||
{
|
||||
"name": "user-properties",
|
||||
"doctype": "Page"
|
||||
}
|
||||
]
|
||||
|
|
@ -86,6 +86,11 @@ $(window).bind('hashchange', function() {
|
|||
wn.route_titles[wn._cur_route] = document.title;
|
||||
|
||||
if(window.location.hash==wn._cur_route)
|
||||
return;
|
||||
return;
|
||||
|
||||
// hide open dialog
|
||||
if(cur_dialog)
|
||||
cur_dialog.hide();
|
||||
|
||||
wn.route();
|
||||
});
|
||||
|
|
@ -113,5 +113,8 @@ wn.ui.FieldGroup = Class.extend({
|
|||
f.set_input(f.df['default'] || '');
|
||||
}
|
||||
}
|
||||
},
|
||||
get_input: function(fieldname) {
|
||||
return $(this.fields_dict[fieldname].input);
|
||||
}
|
||||
});
|
||||
|
|
@ -331,19 +331,23 @@ class Database:
|
|||
|
||||
if self.sql("""select defkey from `tabDefaultValue` where
|
||||
defkey=%s and parent=%s """, (key, parent)):
|
||||
|
||||
# update
|
||||
self.sql("""update `tabDefaultValue` set defvalue=%s
|
||||
where parent=%s and defkey=%s""", (val, parent, key))
|
||||
webnotes.clear_cache()
|
||||
else:
|
||||
from webnotes.model.doc import Document
|
||||
d = Document('DefaultValue')
|
||||
d.parent = parent
|
||||
d.parenttype = 'Control Panel' # does not matter
|
||||
d.parentfield = 'system_defaults'
|
||||
d.defkey = key
|
||||
d.defvalue = val
|
||||
d.save(1)
|
||||
self.add_default(key, val, parent)
|
||||
|
||||
|
||||
def add_default(self, key, val, parent="Control Panel"):
|
||||
d = webnotes.doc('DefaultValue')
|
||||
d.parent = parent
|
||||
d.parenttype = 'Control Panel' # does not matter
|
||||
d.parentfield = 'system_defaults'
|
||||
d.defkey = key
|
||||
d.defvalue = val
|
||||
d.save(1)
|
||||
webnotes.clear_cache()
|
||||
|
||||
def get_default(self, key, parent="Control Panel"):
|
||||
"""get default value"""
|
||||
|
|
|
|||
|
|
@ -291,6 +291,7 @@ def expand_selects(doclist):
|
|||
for d in filter(lambda d: d.fieldtype=='Select' \
|
||||
and (d.options or '').startswith('link:'), doclist):
|
||||
doctype = d.options.split("\n")[0][5:]
|
||||
d.link_doctype = doctype
|
||||
d.options = '\n'.join([''] + [o.name for o in webnotes.conn.sql("""select
|
||||
name from `tab%s` where docstatus<2 order by name asc""" % doctype, as_dict=1)])
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue