Added import, export, print, email and restrict permissions

This commit is contained in:
Anand Doshi 2013-12-17 19:03:30 +05:30
parent 3b004ad23e
commit 97ea7f91e2
19 changed files with 371 additions and 188 deletions

View file

@ -2,7 +2,7 @@
{
"creation": "2013-02-22 01:27:33",
"docstatus": 0,
"modified": "2013-07-22 17:01:58",
"modified": "2013-12-17 12:29:13",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -150,6 +150,36 @@
"print_width": "32px",
"width": "32px"
},
{
"doctype": "DocField",
"fieldname": "export",
"fieldtype": "Check",
"label": "Export"
},
{
"doctype": "DocField",
"fieldname": "import",
"fieldtype": "Check",
"label": "Import"
},
{
"doctype": "DocField",
"fieldname": "print",
"fieldtype": "Check",
"label": "Print"
},
{
"doctype": "DocField",
"fieldname": "email",
"fieldtype": "Check",
"label": "Email"
},
{
"doctype": "DocField",
"fieldname": "restrict",
"fieldtype": "Check",
"label": "Restrict"
},
{
"doctype": "DocField",
"fieldname": "match",

View file

@ -229,9 +229,10 @@ def validate_permissions(permissions, for_remove=False):
if doctype:
issingle = cint(webnotes.conn.get_value("DocType", doctype, "issingle"))
issubmittable = cint(webnotes.conn.get_value("DocType", doctype, "is_submittable"))
isimportable = cint(webnotes.conn.get_value("DocType", doctype, "allow_import"))
def get_txt(d):
return "For %s (level %s) in %s row %s:" % (d.role, d.permlevel, d.parent, d.idx)
return "For %s (level %s) in %s, row #%s:" % (d.role, d.permlevel, d.parent, d.idx)
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:
@ -269,10 +270,25 @@ def validate_permissions(permissions, for_remove=False):
if d.amend and not d.write:
webnotes.msgprint(get_txt(d) + " Cannot set Amend if Cancel is not set.",
raise_exception=True)
if (d.fields.get("import") or d.export) and not d.report:
webnotes.msgprint(get_txt(d) + " Cannot set Import or Export permission if Report is not set.",
raise_exception=True)
def remove_report_if_single(d):
if d.report and issingle:
webnotes.msgprint(doctype + " is a single DocType, permission of type Report is meaningless.")
def remove_rights_for_single(d):
if not issingle:
return
if d.report:
webnotes.msgprint("{doctype} {meaningless}".format(doctype=doctype,
meaningless=_("is a single DocType, permission of type Report is meaningless.")))
d.report = 0
d.fields["import"] = 0
d.fields["export"] = 0
if d.restrict:
webnotes.msgprint("{doctype} {meaningless}".format(doctype=doctype,
meaningless=_("is a single DocType, permission of type Restrict is meaningless.")))
d.restrict = 0
def check_if_submittable(d):
if d.submit and not issubmittable:
@ -282,6 +298,11 @@ def validate_permissions(permissions, for_remove=False):
webnotes.msgprint(doctype + " is not Submittable, cannot assign amend rights.",
raise_exception=True)
def check_if_importable(d):
if d.fields.get("import") and not isimportable:
webnotes.throw("{doctype}: {not_importable}".format(doctype=doctype,
not_importable=_("is not allowed to be imported, cannot assign import rights.")))
for d in permissions:
if not d.permlevel:
d.permlevel=0
@ -290,8 +311,9 @@ def validate_permissions(permissions, for_remove=False):
check_double(d)
check_permission_dependency(d)
check_if_submittable(d)
check_if_importable(d)
check_level_zero_is_set(d)
remove_report_if_single(d)
remove_rights_for_single(d)
def make_module_and_roles(doclist, perm_doctype="DocPerm"):
try:

View file

@ -2,7 +2,7 @@
{
"creation": "2013-02-18 13:36:19",
"docstatus": 0,
"modified": "2013-11-26 10:57:00",
"modified": "2013-12-17 14:32:51",
"modified_by": "Administrator",
"owner": "Administrator"
},
@ -321,28 +321,6 @@
"reqd": 0,
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "allow_print",
"fieldtype": "Check",
"hidden": 0,
"label": "Hide Print",
"oldfieldname": "allow_print",
"oldfieldtype": "Check",
"reqd": 0,
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "allow_email",
"fieldtype": "Check",
"hidden": 0,
"label": "Hide Email",
"oldfieldname": "allow_email",
"oldfieldtype": "Check",
"reqd": 0,
"search_index": 0
},
{
"doctype": "DocField",
"fieldname": "allow_copy",

View file

@ -34,7 +34,8 @@ def get_doctype_options():
@webnotes.whitelist()
def get_template(doctype=None, parent_doctype=None, all_doctypes="No", with_data="No"):
webnotes.check_admin_or_system_manager()
import webnotes.permissions
webnotes.permissions.check_admin_or_system_manager()
all_doctypes = all_doctypes=="Yes"
if not parent_doctype:
parent_doctype = doctype
@ -217,8 +218,9 @@ def get_template(doctype=None, parent_doctype=None, all_doctypes="No", with_data
@webnotes.whitelist()
def upload(rows = None, submit_after_import=None, ignore_encoding_errors=False, overwrite=False, ignore_links=False):
"""upload data"""
import webnotes.permissions
webnotes.flags.mute_emails = True
webnotes.check_admin_or_system_manager()
webnotes.permissions.check_admin_or_system_manager()
# extra input params
params = json.loads(webnotes.form_dict.get("params") or '{}')

View file

@ -9,7 +9,7 @@ wn.pages['permission-manager'].onload = function(wrapper) {
<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 are set on Roles and Document Types (called DocTypes) by restricting read, edit, make new, submit, cancel, amend, report, import, export, print, email and restrict 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>\
@ -45,8 +45,9 @@ wn.pages['permission-manager'].onload = function(wrapper) {
</tr></td>\
<tr><td>\
<h4><i class='icon-cog'></i> "+wn._("Advanced Settings")+":</h4>\
<p>"+wn._("To further restrict permissions based on certain values, like Company or Territory in a document, please go to <a href='#user-properties'>User Restrictions</a>")+" <br><br>"+
"<p>"+wn._("Once you have set this, the users will only be able access documents where the link (e.g Company) exists.")+"</p><hr>\
<p>"+wn._("To further restrict permissions based on certain values, like Company or Territory in a document, please go to <a href='#user-properties'>User Restrictions</a>")+"</p>"+
"<p>"+wn._("Once you have set this, the users will only be able access documents where the link (e.g Company) exists.")+"</p>"+
"<p>"+wn._("Apart from System Manager, roles with Restrict permission can restrict other users for that Document Type")+"</p><hr>\
<p>"+wn._("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>");
@ -160,37 +161,42 @@ wn.PermissionEngine = Class.extend({
},
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);
this.table = $("<div class='table-responsive'>\
<table class='table table-bordered'>\
<thead><tr></tr></thead>\
<tbody></tbody>\
</table>\
</div>").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) {
$.each([["Document Type", 150], ["Role", 150], ["Level", 40],
["Permissions", 270], ["Condition", 100], ["", 40]], 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 $("<td>").appendTo(row)
.attr("data-fieldname", fieldname)
.html(d[fieldname]);
};
var add_check = function(cell, d, fieldname) {
if(d.permlevel > 0 && ["read", "write"].indexOf(fieldname)==-1) {
return;
}
return cell;
}
var checkbox = $("<div class='col-md-4'><div class='checkbox'>\
<label><input type='checkbox'>"+fieldname+"</input></label>\
</div></div>").appendTo(cell)
.attr("data-fieldname", fieldname)
.css("text-transform", "capitalize");
checkbox.find("input")
.prop("checked", d[fieldname] ? true: false)
.attr("data-ptype", fieldname)
.attr("data-name", d.name)
.attr("data-doctype", d.parent)
};
$.each(perm_list, function(i, d) {
if(!d.permlevel) d.permlevel = 0;
@ -203,13 +209,21 @@ wn.PermissionEngine = Class.extend({
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);
var perm_cell = add_cell(row, d, "permissions").css("padding-top", 0);
var perm_container = $("<div class='row'></div>").appendTo(perm_cell);
add_check(perm_container, d, "read");
add_check(perm_container, d, "write");
add_check(perm_container, d, "create");
add_check(perm_container, d, "submit");
add_check(perm_container, d, "cancel");
add_check(perm_container, d, "amend");
add_check(perm_container, d, "report");
add_check(perm_container, d, "import");
add_check(perm_container, d, "export");
add_check(perm_container, d, "print");
add_check(perm_container, d, "email");
add_check(perm_container, d, "restrict");
// buttons
me.add_match_button(row, d);

View file

@ -79,7 +79,7 @@ wn.UserProperties = Class.extend({
});
},
get_link_names: function() {
return $.map(this.options.link_fields, function(l) { return l[0]; });
return this.options.link_fields;
},
set_from_route: function() {
var me = this;

View file

@ -4,30 +4,41 @@
from __future__ import unicode_literals
import webnotes
import webnotes.defaults
import webnotes.permissions
@webnotes.whitelist()
def get_users_and_links():
webnotes.only_for(("Restriction Manager", "System Manager"))
return {
"users": webnotes.conn.sql_list("""select name from tabProfile where
ifnull(enabled,0)=1 and
name not in ("Administrator", "Guest")"""),
"link_fields": webnotes.conn.sql("""select name, name from tabDocType
where ifnull(issingle,0)=0 and ifnull(istable,0)=0""")
"link_fields": get_restrictable_doctypes()
}
@webnotes.whitelist()
def get_properties(parent=None, defkey=None, defvalue=None):
webnotes.only_for(("Restriction Manager", "System Manager"))
if defkey and not webnotes.permissions.can_restrict(defkey, defvalue):
raise webnotes.PermissionError
conditions, values = _build_conditions(locals())
return webnotes.conn.sql("""select name, parent, defkey, defvalue
properties = webnotes.conn.sql("""select name, parent, defkey, defvalue
from tabDefaultValue
where parent not in ('Control Panel', '__global')
and substr(defkey,1,1)!='_'
and parenttype='Restriction'
{conditions}
order by parent, defkey""".format(conditions=conditions), values, as_dict=True)
if not defkey:
out = []
doctypes = get_restrictable_doctypes()
for p in properties:
if p.defkey in doctypes:
out.append(p)
properties = out
return properties
def _build_conditions(filters):
conditions = []
@ -40,17 +51,34 @@ def _build_conditions(filters):
return "\n".join(conditions), values
@webnotes.whitelist()
def remove(user, name):
webnotes.only_for(("Restriction Manager", "System Manager"))
def remove(user, name, defkey, defvalue):
if not webnotes.permissions.can_restrict_user(user, defkey, defvalue):
raise webnotes.PermissionError
webnotes.defaults.clear_default(name=name)
@webnotes.whitelist()
def add(user, defkey, defvalue):
webnotes.only_for(("Restriction Manager", "System Manager"))
if not webnotes.permissions.can_restrict_user(user, defkey, defvalue):
raise webnotes.PermissionError
# check if already exists
d = webnotes.conn.sql("""select name from tabDefaultValue
where parent=%s and parenttype='Restriction' and defkey=%s and defvalue=%s""", (user, defkey, defvalue))
if not d:
webnotes.defaults.add_default(defkey, defvalue, user, "Restriction")
webnotes.defaults.add_default(defkey, defvalue, user, "Restriction")
def get_restrictable_doctypes():
user_roles = webnotes.get_roles()
condition = ""
values = []
if "System Manager" not in user_roles:
condition = """and exists(select `tabDocPerm`.name from `tabDocPerm`
where `tabDocPerm`.parent=`tabDocType`.name and restrict=1
and `tabDocPerm`.name in ({roles}))""".format(roles=", ".join(["%s"]*len(user_roles)))
values = user_roles
return webnotes.conn.sql_list("""select name from tabDocType
where ifnull(issingle,0)=0 and ifnull(istable,0)=0 {condition}""".format(condition=condition),
values)

View file

@ -35,7 +35,7 @@ wn.ui.form.InfoBar = Class.extend({
function() { me.frm.toolbar.show_linked_with(); });
// link to user restrictions
if(wn.user.can_restrict()) {
if(wn.model.can_restrict(me.frm.doctype)) {
this.$user_properties = this.appframe.add_icon_btn("2", "icon-shield",
wn._("User Permission Restrictions"), function() {
wn.route_options = {

View file

@ -125,10 +125,6 @@ $.extend(wn.user, {
is_report_manager: function() {
return wn.user.has_role(['Administrator', 'System Manager', 'Report Manager']);
},
can_restrict: function() {
return wn.user.has_role(["Restriction Manager", "System Manager"]);
},
});
wn.session_alive = true;

View file

@ -120,24 +120,24 @@ $.extend(wn.model, {
},
can_create: function(doctype) {
return wn.boot.profile.can_create.indexOf(doctype)!=-1;
return wn.boot.profile.can_create.indexOf(doctype)!==-1;
},
can_read: function(doctype) {
return wn.boot.profile.can_read.indexOf(doctype)!=-1;
return wn.boot.profile.can_read.indexOf(doctype)!==-1;
},
can_write: function(doctype) {
return wn.boot.profile.can_write.indexOf(doctype)!=-1;
return wn.boot.profile.can_write.indexOf(doctype)!==-1;
},
can_get_report: function(doctype) {
return wn.boot.profile.can_get_report.indexOf(doctype)!=-1;
return wn.boot.profile.can_get_report.indexOf(doctype)!==-1;
},
can_delete: function(doctype) {
if(!doctype) return false;
return wn.boot.profile.can_cancel.indexOf(doctype)!=-1;
return wn.boot.profile.can_cancel.indexOf(doctype)!==-1;
},
is_submittable: function(doctype) {
@ -145,6 +145,26 @@ $.extend(wn.model, {
return locals.DocType[doctype] && locals.DocType[doctype].is_submittable;
},
can_import: function(doctype) {
return wn.boot.profile.can_import.indexOf(doctype)!==-1;
},
can_export: function(doctype) {
return wn.boot.profile.can_export.indexOf(doctype)!==-1;
},
can_print: function(doctype) {
return wn.boot.profile.can_print.indexOf(doctype)!==-1;
},
can_email: function(doctype) {
return wn.boot.profile.can_email.indexOf(doctype)!==-1;
},
can_restrict: function(doctype) {
return wn.boot.profile.can_restrict.indexOf(doctype)!==-1;
},
has_value: function(dt, dn, fn) {
// return true if property has value
var val = locals[dt] && locals[dt][dn] && locals[dt][dn][fn];

View file

@ -74,7 +74,7 @@ wn.views.QueryReport = Class.extend({
"icon-download");
wn.utils.disable_export_btn(export_btn);
if(wn.user.can_restrict()) {
if(wn.model.can_restrict("Report")) {
this.appframe.add_primary_action(wn._("User Restrictions"), function() {
wn.route_options = {
property: "Report",

View file

@ -514,7 +514,7 @@ wn.views.ReportView = wn.ui.Listing.extend({
make_user_restrictions: function() {
var me = this;
if(this.docname && wn.user.can_restrict()) {
if(this.docname && wn.model.can_restrict("Report")) {
this.page.appframe.add_button(wn._("User Permission Restrictions"), function() {
wn.route_options = {
property: "Report",

View file

@ -327,86 +327,18 @@ def get_roles(username=None):
return user.get_roles()
else:
return webnotes.profile.Profile(username).get_roles()
def check_admin_or_system_manager():
if ("System Manager" not in get_roles()) and \
(session.user!="Administrator"):
msgprint("Only Allowed for Role System Manager or Administrator", raise_exception=True)
def has_permission(doctype, ptype="read", refdoc=None):
"""check if user has permission"""
if session.user=="Administrator" or conn.get_value("DocType", doctype, "istable")==1:
return True
import webnotes.permissions
return webnotes.permissions.has_permission(doctype, ptype, refdoc)
meta = get_doctype(doctype)
# get user permissions
perms = get_user_perms(meta, ptype)
if not perms:
return False
elif refdoc:
if isinstance(refdoc, basestring):
refdoc = doc(meta[0].name, refdoc)
if has_only_permitted_data(meta, refdoc) and has_match(perms, refdoc):
return True
else:
return False
else:
return True
def get_user_perms(meta, ptype, user=None):
from webnotes.utils import cint
user_roles = get_roles(user)
return [p for p in meta.get({"doctype": "DocPerm"})
if cint(p.get(ptype))==1 and cint(p.permlevel)==0 and (p.role=="All" or p.role in user_roles)]
def clear_perms(doctype):
conn.sql("""delete from tabDocPerm where parent=%s""", doctype)
def has_only_permitted_data(meta, refdoc):
from webnotes.defaults import get_restrictions
has_restricted_data = False
restrictions = get_restrictions()
if restrictions:
fields_to_check = meta.get_restricted_fields(restrictions.keys())
if meta[0].name in restrictions:
fields_to_check.append(_dict({"label":"Name", "fieldname":"name", "options": meta[0].name}))
for df in fields_to_check:
if refdoc.get(df.fieldname) and refdoc.get(df.fieldname) not in restrictions[df.options]:
msg = "{not_allowed}: {doctype} {having} {label} = {value}".format(
not_allowed=_("Sorry, you are not allowed to access"), doctype=_(df.options),
having=_("having"), label=_(df.label), value=refdoc.get(df.fieldname))
if refdoc.parentfield:
msg = "{doctype}, {row} #{idx}, ".format(doctype=_(refdoc.doctype),
row=_("Row"), idx=refdoc.idx) + msg
msgprint(msg)
has_restricted_data = True
if has_restricted_data:
# check all restrictions before returning
return False
else:
return True
def has_match(perms, refdoc):
"""check owner match (if exists)"""
for p in perms:
if p.get("match")=="owner":
if refdoc.get("owner")==local.session.user:
# owner matches :)
return True
else:
# found a permission without owner match :)
return True
# no match :(
return False
def reset_perms(doctype):
clear_perms(doctype)
reload_doc(conn.get_value("DocType", doctype, "module"),
"DocType", doctype, force=True)
def generate_hash():
"""Generates random hash for session id"""
@ -472,13 +404,6 @@ def delete_doc(doctype=None, name=None, doclist = None, force=0, ignore_doctypes
webnotes.model.delete_doc.delete_doc(doctype, name, doclist, force, ignore_doctypes,
for_reload, ignore_permissions)
def clear_perms(doctype):
conn.sql("""delete from tabDocPerm where parent=%s""", doctype)
def reset_perms(doctype):
clear_perms(doctype)
reload_doc(conn.get_value("DocType", doctype, "module"), "DocType", doctype, force=True)
def reload_doc(module, dt=None, dn=None, plugin=None, force=False):
import webnotes.modules
return webnotes.modules.reload_doc(module, dt, dn, plugin=plugin, force=force)

View file

@ -150,7 +150,6 @@ class Installer:
'parenttype':'Profile', 'parentfield':'user_roles'},
{'doctype': "Role", "role_name": "Report Manager"},
{'doctype': "Role", "role_name": "Restriction Manager"},
]
webnotes.conn.begin()

View file

@ -13,6 +13,7 @@ import webnotes
from webnotes import _, msgprint
from webnotes.utils import cint, cstr, flt
from webnotes.model.doc import Document
import webnotes.permissions
try:
from startup.bean_handlers import on_method
except ImportError:
@ -459,7 +460,7 @@ class Bean:
has_restricted_data = False
for d in self.doclist:
if not webnotes.has_only_permitted_data(webnotes.get_doctype(d.doctype), d):
if not webnotes.permissions.has_only_permitted_data(webnotes.get_doctype(d.doctype), d):
has_restricted_data = True
if has_restricted_data:

129
webnotes/permissions.py Normal file
View file

@ -0,0 +1,129 @@
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
# MIT License. See license.txt
from __future__ import unicode_literals
import webnotes
from webnotes import _, msgprint, _dict
from webnotes.utils import cint
def check_admin_or_system_manager():
if ("System Manager" not in webnotes.get_roles()) and \
(webnotes.session.user!="Administrator"):
msgprint("Only Allowed for Role System Manager or Administrator", raise_exception=True)
def has_permission(doctype, ptype="read", refdoc=None):
"""check if user has permission"""
if webnotes.session.user=="Administrator" or webnotes.conn.get_value("DocType", doctype, "istable")==1:
return True
meta = webnotes.get_doctype(doctype)
# get user permissions
perms = get_user_perms(meta, ptype)
if not perms:
return False
elif refdoc:
if isinstance(refdoc, basestring):
refdoc = webnotes.doc(meta[0].name, refdoc)
if has_only_permitted_data(meta, refdoc) and has_match(perms, refdoc):
return True
else:
return False
else:
return True
def get_user_perms(meta, ptype, user=None):
from webnotes.utils import cint
user_roles = webnotes.get_roles(user)
return [p for p in meta.get({"doctype": "DocPerm"})
if cint(p.get(ptype))==1 and cint(p.permlevel)==0 and (p.role=="All" or p.role in user_roles)]
def has_only_permitted_data(meta, refdoc):
from webnotes.defaults import get_restrictions
has_restricted_data = False
restrictions = get_restrictions()
if restrictions:
fields_to_check = meta.get_restricted_fields(restrictions.keys())
if meta[0].name in restrictions:
fields_to_check.append(_dict({"label":"Name", "fieldname":"name", "options": meta[0].name}))
for df in fields_to_check:
if refdoc.get(df.fieldname) and refdoc.get(df.fieldname) not in restrictions[df.options]:
msg = "{not_allowed}: {doctype} {having} {label} = {value}".format(
not_allowed=_("Sorry, you are not allowed to access"), doctype=_(df.options),
having=_("having"), label=_(df.label), value=refdoc.get(df.fieldname))
if refdoc.parentfield:
msg = "{doctype}, {row} #{idx}, ".format(doctype=_(refdoc.doctype),
row=_("Row"), idx=refdoc.idx) + msg
msgprint(msg)
has_restricted_data = True
if has_restricted_data:
# check all restrictions before returning
return False
else:
return True
def has_match(perms, refdoc):
"""check owner match (if exists)"""
for p in perms:
if p.get("match")=="owner":
if refdoc.get("owner")==webnotes.local.session.user:
# owner matches :)
return True
else:
# found a permission without owner match :)
return True
# no match :(
return False
def can_restrict_user(user, doctype, docname=None):
if not can_restrict(doctype, docname):
return False
meta = webnotes.get_doctype(doctype)
# check if target user does not have restrict permission
if has_non_restrict_role(meta, user):
return True
return False
def can_restrict(doctype, docname=None):
# System Manager can always restrict
if "System Manager" in webnotes.get_roles():
return True
meta = webnotes.get_doctype(doctype)
# check if current user has read permission for docname
if docname and not has_permission(doctype, "read", docname):
return False
# check if current user has a role with restrict permission
if not has_restrict_permission(meta):
return False
return True
def has_restrict_permission(meta=None, user=None):
return any((perm for perm in get_user_perms(meta, "read", user)
if cint(perm.restrict)==1))
def has_non_restrict_role(meta, user):
# check if target user does not have restrict permission
if has_restrict_permission(meta, user):
return False
# and has non-restrict role
return any((perm for perm in get_user_perms(meta, "read", user)
if cint(perm.restrict)==0))

View file

@ -22,6 +22,11 @@ class Profile:
self.can_cancel = []
self.can_search = []
self.can_get_report = []
self.can_import = []
self.can_export = []
self.can_print = []
self.can_email = []
self.can_restrict = []
self.allow_modules = []
self.in_create = []
@ -43,7 +48,8 @@ class Profile:
"""build map of permissions at level 0"""
self.perm_map = {}
for r in webnotes.conn.sql("""select parent, `read`, `write`, `create`, `submit`, `cancel`, `report`
for r in webnotes.conn.sql("""select parent, `read`, `write`, `create`, `submit`, `cancel`,
`report`, `import`, `export`, `print`, `email`, `restrict`
from tabDocPerm where docstatus=0
and ifnull(permlevel,0)=0
and parent not like "old_parent:%%"
@ -54,7 +60,8 @@ class Profile:
if not dt in self.perm_map:
self.perm_map[dt] = {}
for k in ('read', 'write', 'create', 'submit', 'cancel', 'report'):
for k in ('read', 'write', 'create', 'submit', 'cancel', 'report'
'import', 'export', 'print', 'email', 'restrict'):
if not self.perm_map[dt].get(k):
self.perm_map[dt][k] = r.get(k)
@ -91,6 +98,10 @@ class Profile:
if (p.get('read') or p.get('write') or p.get('create')):
if p.get('report'):
self.can_get_report.append(dt)
for key in ("import", "export", "print", "email", "restrict"):
if p.get(key):
getattr(self, "can_" + key).append(dt)
if not dtp.get('istable'):
if not dtp.get('issingle') and not dtp.get('read_only'):
self.can_search.append(dt)
@ -144,15 +155,13 @@ class Profile:
d['roles'] = self.get_roles()
d['defaults'] = self.get_defaults()
d['can_create'] = self.can_create
d['can_write'] = self.can_write
d['can_read'] = list(set(self.can_read))
d['can_cancel'] = list(set(self.can_cancel))
d['can_get_report'] = list(set(self.can_get_report))
d['allow_modules'] = self.allow_modules
d['all_read'] = self.all_read
d['can_search'] = list(set(self.can_search))
d['in_create'] = self.in_create
for key in ("can_create", "can_write", "can_read", "can_cancel",
"can_get_report", "allow_modules", "all_read", "can_search",
"in_create", "can_export", "can_import", "can_print", "can_email",
"can_restrict"):
d[key] = list(set(getattr(self, key)))
return d

View file

@ -187,6 +187,7 @@ def build_filter_conditions(filters, conditions):
def build_match_conditions(doctype, fields=None, as_condition=True):
"""add match conditions if applicable"""
import webnotes.permissions
match_filters = {}
match_conditions = []
@ -215,7 +216,7 @@ def build_match_conditions(doctype, fields=None, as_condition=True):
# add owner match
owner_match = True
for p in webnotes.get_user_perms(webnotes.local.reportview_doctypes[doctype], "read"):
for p in webnotes.permissions.get_user_perms(webnotes.local.reportview_doctypes[doctype], "read"):
if not (p.match and p.match=="owner"):
owner_match = False
break

View file

@ -38,7 +38,10 @@ class TestBlogPost(unittest.TestCase):
webnotes.clear_cache(doctype="Blog Post")
profile = webnotes.bean("Profile", "test1@example.com")
profile.get_controller().add_roles(["Website Manager"])
profile.get_controller().add_roles("Website Manager")
profile = webnotes.bean("Profile", "test2@example.com")
profile.get_controller().add_roles("Blogger")
webnotes.set_user("test1@example.com")
@ -86,7 +89,6 @@ class TestBlogPost(unittest.TestCase):
post1 = webnotes.bean("Blog Post", "_test-blog-post-1")
self.assertFalse(post1.has_read_perm())
def test_owner_match_report(self):
webnotes.conn.sql("""update tabDocPerm set `match`='owner' where parent='Blog Post'
and ifnull(permlevel,0)=0""")
@ -95,7 +97,34 @@ class TestBlogPost(unittest.TestCase):
names = [d.name for d in webnotes.get_list("Blog Post", fields=["name", "owner"])]
self.assertTrue("_test-blog-post" in names)
self.assertFalse("_test-blog-post-1" in names)
def test_restrict(self):
from core.page.user_properties.user_properties import add, remove, get_properties
# restrictor can add restriction
webnotes.set_user("test1@example.com")
add("test2@example.com", "Blog Post", "_test-blog-post")
defname = get_properties("test2@example.com", "Blog Post", "_test-blog-post")[0].name
webnotes.set_user("test2@example.com")
# this user can't add restriction
self.assertRaises(webnotes.PermissionError, add,
"test2@example.com", "Blog Post", "_test-blog-post")
# user can only access restricted blog post
bean = webnotes.bean("Blog Post", "_test-blog-post")
self.assertTrue(bean.has_read_perm())
# and not this one
bean = webnotes.bean("Blog Post", "_test-blog-post-1")
self.assertFalse(bean.has_read_perm())
# user cannot remove their own restriction
self.assertRaises(webnotes.PermissionError, remove,
"test2@example.com", defname, "Blog Post", "_test-blog-post")
# but restrictor can
webnotes.set_user("test1@example.com")
remove("test2@example.com", defname, "Blog Post", "_test-blog-post")