diff --git a/core/doctype/docperm/docperm.txt b/core/doctype/docperm/docperm.txt
index 634fb7c1b2..fabc9ae904 100644
--- a/core/doctype/docperm/docperm.txt
+++ b/core/doctype/docperm/docperm.txt
@@ -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",
diff --git a/core/doctype/doctype/doctype.py b/core/doctype/doctype/doctype.py
index 8c4edf6fe2..bb34bba112 100644
--- a/core/doctype/doctype/doctype.py
+++ b/core/doctype/doctype/doctype.py
@@ -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:
diff --git a/core/doctype/doctype/doctype.txt b/core/doctype/doctype/doctype.txt
index eb4674c741..215b73c271 100644
--- a/core/doctype/doctype/doctype.txt
+++ b/core/doctype/doctype/doctype.txt
@@ -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",
diff --git a/core/page/data_import_tool/data_import_tool.py b/core/page/data_import_tool/data_import_tool.py
index 7de21ede29..a79096081a 100644
--- a/core/page/data_import_tool/data_import_tool.py
+++ b/core/page/data_import_tool/data_import_tool.py
@@ -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 '{}')
diff --git a/core/page/permission_manager/permission_manager.js b/core/page/permission_manager/permission_manager.js
index 4f8488bb38..5421f3ad6b 100644
--- a/core/page/permission_manager/permission_manager.js
+++ b/core/page/permission_manager/permission_manager.js
@@ -9,7 +9,7 @@ wn.pages['permission-manager'].onload = function(wrapper) {
\
"+wn._("Quick Help for Setting Permissions")+": \
\
- "+wn._("Permissions are set on Roles and Document Types (called DocTypes) by restricting read, edit, make new, submit, cancel, amend and report rights.")+" \
+ "+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.")+" \
"+wn._("Permissions translate to Users based on what Role they are assigned")+". \
"+wn._("To set user roles, just go to Setup > Users and click on the user to assign roles.")+" \
"+wn._("The system provides pre-defined roles, but you can add new roles to set finer permissions")+". \
@@ -45,8 +45,9 @@ wn.pages['permission-manager'].onload = function(wrapper) {
\
\
"+wn._("Advanced Settings")+": \
- "+wn._("To further restrict permissions based on certain values, like Company or Territory in a document, please go to User Restrictions ")+" "+
- "
"+wn._("Once you have set this, the users will only be able access documents where the link (e.g Company) exists.")+"
\
+ "+wn._("To further restrict permissions based on certain values, like Company or Territory in a document, please go to User Restrictions ")+"
"+
+ ""+wn._("Once you have set this, the users will only be able access documents where the link (e.g Company) exists.")+"
"+
+ ""+wn._("Apart from System Manager, roles with Restrict permission can restrict other users for that Document Type")+"
\
"+wn._("If these instructions where not helpful, please add in your suggestions at GitHub Issues ")+"
\
\
");
@@ -160,37 +161,42 @@ wn.PermissionEngine = Class.extend({
},
show_permission_table: function(perm_list) {
var me = this;
- this.table = $("").appendTo(this.body);
+ this.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) {
+ $.each([["Document Type", 150], ["Role", 150], ["Level", 40],
+ ["Permissions", 270], ["Condition", 100], ["", 40]], function(i, col) {
$("").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 = $(" ").appendTo(row).attr("data-fieldname", fieldname);
- if(is_check) {
- if(d.permlevel > 0 && ["read", "write"].indexOf(fieldname)==-1) {
- cell.html("-");
- } else {
- var input = $(" ")
- .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 $(" ").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 = $("").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 = $("
").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);
diff --git a/core/page/user_properties/user_properties.js b/core/page/user_properties/user_properties.js
index 28f55410a7..b18ac96a8e 100644
--- a/core/page/user_properties/user_properties.js
+++ b/core/page/user_properties/user_properties.js
@@ -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;
diff --git a/core/page/user_properties/user_properties.py b/core/page/user_properties/user_properties.py
index d4357743b4..fdfe7b9f7e 100644
--- a/core/page/user_properties/user_properties.py
+++ b/core/page/user_properties/user_properties.py
@@ -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")
\ No newline at end of file
+ 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)
diff --git a/public/js/wn/form/infobar.js b/public/js/wn/form/infobar.js
index 87ce143a26..69cb9397c8 100644
--- a/public/js/wn/form/infobar.js
+++ b/public/js/wn/form/infobar.js
@@ -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 = {
diff --git a/public/js/wn/misc/user.js b/public/js/wn/misc/user.js
index 0b22d6d163..57a69b8c44 100644
--- a/public/js/wn/misc/user.js
+++ b/public/js/wn/misc/user.js
@@ -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;
diff --git a/public/js/wn/model/model.js b/public/js/wn/model/model.js
index cccfb43ce0..bc340125b3 100644
--- a/public/js/wn/model/model.js
+++ b/public/js/wn/model/model.js
@@ -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];
diff --git a/public/js/wn/views/query_report.js b/public/js/wn/views/query_report.js
index 0134896325..4369cfdebf 100644
--- a/public/js/wn/views/query_report.js
+++ b/public/js/wn/views/query_report.js
@@ -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",
diff --git a/public/js/wn/views/reportview.js b/public/js/wn/views/reportview.js
index adffc5e438..864e830489 100644
--- a/public/js/wn/views/reportview.js
+++ b/public/js/wn/views/reportview.js
@@ -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",
diff --git a/webnotes/__init__.py b/webnotes/__init__.py
index e8ff011192..6ac257e762 100644
--- a/webnotes/__init__.py
+++ b/webnotes/__init__.py
@@ -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)
diff --git a/webnotes/install_lib/install.py b/webnotes/install_lib/install.py
index df2a630424..95ef1199d9 100755
--- a/webnotes/install_lib/install.py
+++ b/webnotes/install_lib/install.py
@@ -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()
diff --git a/webnotes/model/bean.py b/webnotes/model/bean.py
index 6a0e2f871e..60ded8aa76 100644
--- a/webnotes/model/bean.py
+++ b/webnotes/model/bean.py
@@ -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:
diff --git a/webnotes/permissions.py b/webnotes/permissions.py
new file mode 100644
index 0000000000..97589e9d2f
--- /dev/null
+++ b/webnotes/permissions.py
@@ -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))
\ No newline at end of file
diff --git a/webnotes/profile.py b/webnotes/profile.py
index da4ae5d984..b70a214d39 100644
--- a/webnotes/profile.py
+++ b/webnotes/profile.py
@@ -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
diff --git a/webnotes/widgets/reportview.py b/webnotes/widgets/reportview.py
index 3db1fde6ad..37f25dd15a 100644
--- a/webnotes/widgets/reportview.py
+++ b/webnotes/widgets/reportview.py
@@ -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
diff --git a/website/doctype/blog_post/test_blog_post.py b/website/doctype/blog_post/test_blog_post.py
index 53a0e6d3aa..fb258819d9 100644
--- a/website/doctype/blog_post/test_blog_post.py
+++ b/website/doctype/blog_post/test_blog_post.py
@@ -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")
\ No newline at end of file