diff --git a/webnotes/__init__.py b/webnotes/__init__.py index a172654527..8c17e4c92d 100644 --- a/webnotes/__init__.py +++ b/webnotes/__init__.py @@ -105,6 +105,7 @@ def init(site, sites_path=None): local.app_modules = None local.user = None local.restrictions = None + local.user_perms = {} setup_module_map() @@ -214,6 +215,7 @@ def set_user(username): local.session["user"] = username local.user = webnotes.profile.Profile(username) local.restrictions = None + local.user_perms = {} def get_request_header(key, default=None): return request.headers.get(key, default) diff --git a/webnotes/core/doctype/docperm/docperm.txt b/webnotes/core/doctype/docperm/docperm.txt index 6e85511458..f03bba0ba8 100644 --- a/webnotes/core/doctype/docperm/docperm.txt +++ b/webnotes/core/doctype/docperm/docperm.txt @@ -2,7 +2,7 @@ { "creation": "2013-02-22 01:27:33", "docstatus": 0, - "modified": "2014-01-20 17:48:11", + "modified": "2014-01-22 14:32:34", "modified_by": "Administrator", "owner": "Administrator" }, @@ -31,19 +31,10 @@ "name": "DocPerm" }, { - "default": "0", "doctype": "DocField", - "fieldname": "permlevel", - "fieldtype": "Int", - "hidden": 0, - "in_list_view": 1, - "label": "Level", - "oldfieldname": "permlevel", - "oldfieldtype": "Int", - "print_width": "40px", - "reqd": 0, - "search_index": 0, - "width": "40px" + "fieldname": "role_and_level", + "fieldtype": "Section Break", + "label": "Role and Level" }, { "doctype": "DocField", @@ -60,6 +51,32 @@ "search_index": 0, "width": "150px" }, + { + "doctype": "DocField", + "fieldname": "column_break_2", + "fieldtype": "Column Break" + }, + { + "default": "0", + "doctype": "DocField", + "fieldname": "permlevel", + "fieldtype": "Int", + "hidden": 0, + "in_list_view": 1, + "label": "Level", + "oldfieldname": "permlevel", + "oldfieldtype": "Int", + "print_width": "40px", + "reqd": 0, + "search_index": 0, + "width": "40px" + }, + { + "doctype": "DocField", + "fieldname": "section_break_4", + "fieldtype": "Section Break", + "label": "Permissions" + }, { "doctype": "DocField", "fieldname": "read", @@ -74,6 +91,13 @@ "search_index": 0, "width": "32px" }, + { + "description": "Only restricted users can access", + "doctype": "DocField", + "fieldname": "restricted", + "fieldtype": "Check", + "label": "Restricted" + }, { "doctype": "DocField", "fieldname": "write", @@ -109,6 +133,11 @@ "in_list_view": 1, "label": "Delete" }, + { + "doctype": "DocField", + "fieldname": "column_break_8", + "fieldtype": "Column Break" + }, { "doctype": "DocField", "fieldname": "submit", @@ -147,6 +176,12 @@ "print_width": "32px", "width": "32px" }, + { + "doctype": "DocField", + "fieldname": "additional_permissions", + "fieldtype": "Section Break", + "label": "Additional Permissions" + }, { "doctype": "DocField", "fieldname": "report", @@ -167,6 +202,11 @@ "fieldtype": "Check", "label": "Import" }, + { + "doctype": "DocField", + "fieldname": "column_break_19", + "fieldtype": "Column Break" + }, { "doctype": "DocField", "fieldname": "print", @@ -180,21 +220,10 @@ "label": "Email" }, { + "description": "This role can restrict users for accessing the record.", "doctype": "DocField", "fieldname": "restrict", "fieldtype": "Check", - "label": "Restrict" - }, - { - "doctype": "DocField", - "fieldname": "match", - "fieldtype": "Data", - "hidden": 0, - "in_list_view": 1, - "label": "Match", - "oldfieldname": "match", - "oldfieldtype": "Data", - "reqd": 0, - "search_index": 0 + "label": "Can Restrict" } ] \ No newline at end of file diff --git a/webnotes/core/doctype/profile/profile.txt b/webnotes/core/doctype/profile/profile.txt index 4101113bb8..d6cb31a1e5 100644 --- a/webnotes/core/doctype/profile/profile.txt +++ b/webnotes/core/doctype/profile/profile.txt @@ -2,7 +2,7 @@ { "creation": "2013-03-07 11:54:44", "docstatus": 0, - "modified": "2014-01-20 17:49:02", + "modified": "2014-01-22 16:05:34", "modified_by": "Administrator", "owner": "Administrator" }, @@ -422,10 +422,10 @@ "delete": 0, "doctype": "DocPerm", "email": 1, - "match": "owner", "permlevel": 0, "print": 1, "report": 1, + "restricted": 1, "role": "All", "submit": 0, "write": 0 diff --git a/webnotes/core/page/permission_manager/permission_manager.js b/webnotes/core/page/permission_manager/permission_manager.js index fc563d4096..7c7e96d124 100644 --- a/webnotes/core/page/permission_manager/permission_manager.js +++ b/webnotes/core/page/permission_manager/permission_manager.js @@ -9,7 +9,7 @@ wn.pages['permission-manager'].onload = function(wrapper) { \

"+wn._("Quick Help for Setting Permissions")+":

\
    \ -
  1. "+wn._("Permissions are set on Roles and Document Types (called DocTypes) by restricting read, edit, make new, delete, submit, cancel, amend, report, import, export, print, email and restrict rights.")+"
  2. \ +
  3. "+wn._("Permissions are set on Roles and Document Types (called DocTypes) by setting read, edit, make new, delete, submit, cancel, amend, report, import, export, print, email and restrict rights.")+"
  4. \
  5. "+wn._("Permissions translate to Users based on what Role they are assigned")+".
  6. \
  7. "+wn._("To set user roles, just go to Setup > Users and click on the user to assign roles.")+"
  8. \
  9. "+wn._("The system provides pre-defined roles, but you can add new roles to set finer permissions")+".
  10. \ @@ -38,16 +38,13 @@ wn.pages['permission-manager'].onload = function(wrapper) {
\ \ \ -

"+wn._("Restricting By User")+":

\ +

"+wn._("Restricting Users")+":

\
    \ -
  1. "+wn._("To restrict a User of a particular Role to documents that are only self-created.")+ - wn._("Click on button in the 'Condition' column and select the option 'User is the creator of the document'")+".
\ - \ - \ -

"+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._("Apart from System Manager, roles with Restrict permission can restrict other users for that Document Type")+"


\ +
  • "+wn._("To explictly give permissions to users to specific records, check the 'Restricted' permssion. To set which user has access to which record, go to User Restrictions")+"
  • "+ + "
  • "+wn._("If 'Restricted' is not checked, you can still restrict permissions based on certain values, like Company or Territory in a document by setting User Restrictions. But unless any restriction is set, a user will have permissions based on the Role.")+"
  • "+ + "
  • "+wn._("If 'Restricted' is checked, the owner is always allowed based on Role.")+"
  • "+ + "
  • "+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")+"

    \ \ "); @@ -208,13 +205,14 @@ wn.PermissionEngine = Class.extend({ .html(d[fieldname]); }; - var add_check = function(cell, d, fieldname) { + var add_check = function(cell, d, fieldname, label) { + if(!label) label = fieldname; if(d.permlevel > 0 && ["read", "write"].indexOf(fieldname)==-1) { return; } var checkbox = $("
    \ - \ + \
    ").appendTo(cell) .attr("data-fieldname", fieldname) .css("text-transform", "capitalize"); @@ -241,6 +239,7 @@ wn.PermissionEngine = Class.extend({ 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, "restricted"); add_check(perm_container, d, "write"); add_check(perm_container, d, "create"); add_check(perm_container, d, "delete"); @@ -252,7 +251,7 @@ wn.PermissionEngine = Class.extend({ add_check(perm_container, d, "export"); add_check(perm_container, d, "print"); add_check(perm_container, d, "email"); - add_check(perm_container, d, "restrict"); + add_check(perm_container, d, "restrict", "Can Restrict"); // buttons me.add_match_button(row, d); diff --git a/webnotes/core/page/permission_manager/permission_manager.py b/webnotes/core/page/permission_manager/permission_manager.py index 4aed3da6ae..a9d14fe0dd 100644 --- a/webnotes/core/page/permission_manager/permission_manager.py +++ b/webnotes/core/page/permission_manager/permission_manager.py @@ -28,9 +28,7 @@ def get_permissions(doctype=None, role=None): @webnotes.whitelist() def remove(doctype, name): - webnotes.only_for("System Manager") - match = webnotes.conn.get_value("DocPerm", name, "`match`") - + webnotes.only_for("System Manager") webnotes.conn.sql("""delete from tabDocPerm where name=%s""", name) validate_and_reset(doctype, for_remove=True) @@ -56,14 +54,7 @@ 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() -def update_match(name, doctype, match=""): - webnotes.only_for("System Manager") - 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 webnotes.core.doctype.doctype.doctype import validate_permissions_for_doctype validate_permissions_for_doctype(doctype, for_remove) diff --git a/webnotes/core/page/user_properties/user_properties.py b/webnotes/core/page/user_properties/user_properties.py index 235c8080f0..45ef74382b 100644 --- a/webnotes/core/page/user_properties/user_properties.py +++ b/webnotes/core/page/user_properties/user_properties.py @@ -58,6 +58,9 @@ def remove(user, name, defkey, defvalue): webnotes.defaults.clear_default(name=name) +def clear_restrictions(doctype): + webnotes.defaults.clear_default(parenttype="Restriction", key=doctype) + @webnotes.whitelist() def add(user, defkey, defvalue): if not webnotes.permissions.can_restrict_user(user, defkey, defvalue): diff --git a/webnotes/model/bean.py b/webnotes/model/bean.py index cb3d3e1a14..ff013d8cc9 100644 --- a/webnotes/model/bean.py +++ b/webnotes/model/bean.py @@ -459,7 +459,7 @@ class Bean: has_restricted_data = False for d in self.doclist: - if not webnotes.permissions.has_only_permitted_data(webnotes.get_doctype(d.doctype), d): + if not webnotes.permissions.has_unrestricted_access(webnotes.get_doctype(d.doctype), d): has_restricted_data = True if has_restricted_data: diff --git a/webnotes/model/doctype.py b/webnotes/model/doctype.py index b13e672a2b..d695f3389a 100644 --- a/webnotes/model/doctype.py +++ b/webnotes/model/doctype.py @@ -400,6 +400,12 @@ class DocTypeDocList(webnotes.model.doclist.DocList): if self[0].name in restricted_types: restricted_fields.append(webnotes._dict({"label":"Name", "fieldname":"name", "options": self[0].name})) return restricted_fields + + def get_permissions(self, user=None): + user_roles = webnotes.get_roles(user) + return [p for p in self.get({"doctype": "DocPerm"}) + if cint(p.permlevel)==0 and (p.role=="All" or p.role in user_roles)] + def rename_field(doctype, old_fieldname, new_fieldname, lookup_field=None): """this function assumes that sync is NOT performed""" diff --git a/webnotes/patches.txt b/webnotes/patches.txt index fde7f98815..cac72e1cbb 100644 --- a/webnotes/patches.txt +++ b/webnotes/patches.txt @@ -5,4 +5,5 @@ execute:webnotes.reload_doc('core', 'doctype', 'page') #2013-13-26 execute:webnotes.reload_doc('core', 'doctype', 'report') #2013-13-26 webnotes.patches.4_0.remove_index_sitemap -webnotes.patches.4_0.add_delete_permission \ No newline at end of file +webnotes.patches.4_0.add_delete_permission +webnotes.patches.4_0.move_match_to_restricted \ No newline at end of file diff --git a/webnotes/patches/4_0/add_delete_permission.py b/webnotes/patches/4_0/add_delete_permission.py index 6ba3cd2eb1..61f19b89ab 100644 --- a/webnotes/patches/4_0/add_delete_permission.py +++ b/webnotes/patches/4_0/add_delete_permission.py @@ -7,6 +7,6 @@ def execute(): webnotes.conn.sql("""update tabDocPerm set `delete`=ifnull(`cancel`,0)""") # can't cancel if can't submit - webnotes.conn.sql("""update tabDocPerm set `cancel`=0 where `submit`=0""") + webnotes.conn.sql("""update tabDocPerm set `cancel`=0 where ifnull(`submit`,0)=0""") webnotes.clear_cache() \ No newline at end of file diff --git a/webnotes/patches/4_0/move_match_to_restricted.py b/webnotes/patches/4_0/move_match_to_restricted.py new file mode 100644 index 0000000000..ecb2f77c0e --- /dev/null +++ b/webnotes/patches/4_0/move_match_to_restricted.py @@ -0,0 +1,9 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import webnotes + +def execute(): + webnotes.reload_doc("core", "doctype", "docperm") + webnotes.conn.sql("""update `tabDocPerm` set restricted=1 where `match`='owner'""") \ No newline at end of file diff --git a/webnotes/permissions.py b/webnotes/permissions.py index ac04413426..9faa9ad4ea 100644 --- a/webnotes/permissions.py +++ b/webnotes/permissions.py @@ -26,35 +26,57 @@ def has_permission(doctype, ptype="read", refdoc=None, verbose=True): if webnotes.session.user=="Administrator": return True - + # get user permissions - perms = get_user_perms(meta, ptype) - - if not perms: + if not get_user_perms(meta).get(ptype): return False elif refdoc: if isinstance(refdoc, basestring): refdoc = webnotes.doc(meta[0].name, refdoc) - if (has_only_permitted_data(meta, refdoc, verbose=verbose) and has_match(perms, refdoc)): + if has_unrestricted_access(meta, refdoc, verbose=verbose): return True else: return False else: return True -def get_user_perms(meta, ptype, user=None): - 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)] +rights = ["read", "write", "create", "submit", "cancel", "amend", + "report", "import", "export", "print", "email", "restrict", "delete", "restricted"] -def has_only_permitted_data(meta, refdoc, verbose=True): +def get_user_perms(meta, user=None): + cache_key = (meta[0].name, user) + if not webnotes.local.user_perms.get(cache_key): + perms = webnotes._dict() + user_roles = webnotes.get_roles(user) + + for p in meta.get({"doctype": "DocPerm"}): + if cint(p.permlevel)==0 and (p.role=="All" or p.role in user_roles): + for ptype in rights: + if ptype == "restricted": + perms[ptype] = perms.get(ptype, 1) and cint(p.get(ptype)) + else: + perms[ptype] = perms.get(ptype, 0) or cint(p.get(ptype)) + + webnotes.local.user_perms[cache_key] = perms + + return webnotes.local.user_perms[cache_key] + +def has_unrestricted_access(meta, refdoc, verbose=True): from webnotes.defaults import get_restrictions restrictions = get_restrictions() - if not restrictions: - return True + + if get_user_perms(meta).restricted: + if refdoc.owner == webnotes.session.user: + # owner is always allowed for restricted permissions + return True + elif not restrictions: + return False + else: + if not restrictions: + return True + # evaluate specific restrictions fields_to_check = meta.get_restricted_fields(restrictions.keys()) has_restricted_data = False @@ -75,20 +97,6 @@ def has_only_permitted_data(meta, refdoc, verbose=True): # check all restrictions before returning return False if has_restricted_data else 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): @@ -106,7 +114,6 @@ 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 @@ -120,8 +127,7 @@ def can_restrict(doctype, docname=None): 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)) + return get_user_perms(meta, user).restrict==1 def has_only_non_restrict_role(meta, user): # check if target user does not have restrict permission @@ -129,8 +135,7 @@ def has_only_non_restrict_role(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)) + return get_user_perms(meta, user).restrict==0 def can_import(doctype, raise_exception=False): if not ("System Manager" in webnotes.get_roles() or has_permission(doctype, "import")): diff --git a/webnotes/public/css/bootstrap.css b/webnotes/public/css/bootstrap.css index dd226f000e..5ad2417d8f 100644 --- a/webnotes/public/css/bootstrap.css +++ b/webnotes/public/css/bootstrap.css @@ -1699,7 +1699,7 @@ output { border-radius: 4px; } .form-control:focus { - border-color: #000; + border-color: #66afe9; outline: 0; } .form-control:-moz-placeholder { diff --git a/webnotes/public/js/wn/form/control.js b/webnotes/public/js/wn/form/control.js index 547efdd03e..f3f5e7339e 100644 --- a/webnotes/public/js/wn/form/control.js +++ b/webnotes/public/js/wn/form/control.js @@ -465,7 +465,7 @@ wn.ui.form.ControlCheck = wn.ui.form.ControlData.extend({ \

    \ \ diff --git a/webnotes/public/js/wn/model/perm.js b/webnotes/public/js/wn/model/perm.js index 207829a4a5..034bbb2a3d 100644 --- a/webnotes/public/js/wn/model/perm.js +++ b/webnotes/public/js/wn/model/perm.js @@ -9,7 +9,7 @@ var SUBMIT = "submit", CANCEL = "cancel", AMEND = "amend"; $.extend(wn.perm, { rights: ["read", "write", "create", "submit", "cancel", "amend", - "report", "import", "export", "print", "email", "restrict", "delete"], + "report", "import", "export", "print", "email", "restrict", "delete", "restricted"], doctype_perm: {}, @@ -55,7 +55,7 @@ $.extend(wn.perm, { perm[0].read = 1; } - if(docname && !wn.perm.has_only_permitted_data(doctype, docname)) { + if(docname && !wn.perm.has_unrestricted_access(doctype, docname, perm[0].restricted)) { // if has restricted data, return not permitted return perm; } @@ -63,14 +63,17 @@ $.extend(wn.perm, { var docperms = wn.model.get("DocPerm", {parent: doctype}); $.each(docperms, function(i, p) { // if user has this role - if(user_roles.indexOf(p.role)!==-1 && - (!docname || wn.perm.has_match(p, doctype, docname))) { + if(user_roles.indexOf(p.role)!==-1) { var permlevel = cint(p.permlevel); if(!perm[permlevel]) { perm[permlevel] = {}; } $.each(wn.perm.rights, function(i, key) { - perm[permlevel][key] = perm[permlevel][key] || (p[key] || 0); + if(key=="restricted") { + perm[permlevel][key] = (perm[permlevel][key] || 1) && (p[key] || 0); + } else { + perm[permlevel][key] = perm[permlevel][key] || (p[key] || 0); + } }); } }); @@ -78,10 +81,19 @@ $.extend(wn.perm, { return perm; }, - has_only_permitted_data: function(doctype, docname) { + has_unrestricted_access: function(doctype, docname, restricted) { var restrictions = wn.defaults.get_restrictions(); - if(!restrictions || $.isEmptyObject(restrictions)) { - return true; + var doc = wn.model.get_doc(doctype, docname); + + if(restricted) { + if(doc.owner==user) return true; + if(!restrictions || $.isEmptyObject(restrictions)) { + return false; + } + } else { + if(!restrictions || $.isEmptyObject(restrictions)) { + return true; + } } // prepare restricted fields @@ -109,33 +121,10 @@ $.extend(wn.perm, { } return fields_to_check; }, - - has_match: function(docperm, doctype, docname) { - if(!docperm.match) return true; - if(docperm.match==="owner") { - var doc = wn.model.get_doc(doctype, docname); - if(doc.owner===user) { - return true; - } - } - return false; - }, - + get_match_rules: function(doctype) { var match_rules = {}; - - // Rule for owner match - var owner_match = false; - $.each(wn.model.get("DocPerm", {parent:doctype}), function(i, docperm) { - if(docperm.match==="owner") { - owner_match = true; - } else { - owner_match = false; - return false; - } - }); - if(owner_match) match_rules["Created By"] = user; - + // Rule for restrictions var restrictions = wn.defaults.get_restrictions(); if(restrictions && !$.isEmptyObject(restrictions)) { diff --git a/webnotes/public/js/wn/request.js b/webnotes/public/js/wn/request.js index 8d87eb4890..5aed5ca3db 100644 --- a/webnotes/public/js/wn/request.js +++ b/webnotes/public/js/wn/request.js @@ -68,9 +68,6 @@ wn.request.call = function(opts) { opts.success && opts.success(data, xhr.responseText); } }, - fail: function(xhr, textStatus) { - opts.error && opts.error(xhr) - }, async: opts.async }; @@ -100,7 +97,14 @@ wn.request.call = function(opts) { }) } - return $.ajax(ajax_args).always(function(data) { + return $.ajax(ajax_args) + .fail(function(xhr, textStatus) { + opts.error && opts.error(xhr) + }) + .always(function(data) { + if(data.responseText) { + data = JSON.parse(data.responseText); + } wn.request.cleanup(opts, data); }); } diff --git a/webnotes/public/js/wn/views/doclistview.js b/webnotes/public/js/wn/views/doclistview.js index e685fe03b3..f553339082 100644 --- a/webnotes/public/js/wn/views/doclistview.js +++ b/webnotes/public/js/wn/views/doclistview.js @@ -104,6 +104,8 @@ wn.views.DocListView = wn.ui.Listing.extend({ show_match_help: function() { var me = this; var match_rules = wn.perm.get_match_rules(this.doctype); + var perm = wn.perm.get_perm(doctype); + if(keys(match_rules).length) { var match_text = [] $.each(match_rules, function(key, values) { @@ -113,6 +115,10 @@ wn.views.DocListView = wn.ui.Listing.extend({ match_text.push(wn._(key) + " = " + wn.utils.comma_or(values)); } }); + + if(perm[0].restricted) { + match_text.push(wn._("Or Created By") + " = " + user); + } wn.utils.set_footnote(this, this.$page.find(".layout-main-section"), "

    " + wn._("Showing only for") + ":

    "; diff --git a/webnotes/website/doctype/blog_post/test_blog_post.py b/webnotes/website/doctype/blog_post/test_blog_post.py index 474b2da74f..48723a7071 100644 --- a/webnotes/website/doctype/blog_post/test_blog_post.py +++ b/webnotes/website/doctype/blog_post/test_blog_post.py @@ -26,13 +26,15 @@ test_records = [ import webnotes import webnotes.defaults import unittest +from webnotes.core.page.user_properties.user_properties import add, remove, get_properties, clear_restrictions + test_dependencies = ["Profile"] class TestBlogPost(unittest.TestCase): def setUp(self): - webnotes.conn.sql("""update tabDocPerm set `match`='' where parent='Blog Post' + webnotes.conn.sql("""update tabDocPerm set `restricted`=0 where parent='Blog Post' and ifnull(permlevel,0)=0""") - webnotes.conn.sql("""update `tabBlog Post` set owner='test1@example.com' + webnotes.conn.sql("""update `tabBlog Post` set owner='test2@example.com' where name='_test-blog-post'""") webnotes.clear_cache(doctype="Blog Post") @@ -47,7 +49,8 @@ class TestBlogPost(unittest.TestCase): def tearDown(self): webnotes.set_user("Administrator") - webnotes.defaults.clear_default(key="Blog Category", parenttype="Restriction") + clear_restrictions("Blog Category") + clear_restrictions("Blog Post") def test_basic_permission(self): post = webnotes.bean("Blog Post", "_test-blog-post") @@ -79,12 +82,17 @@ class TestBlogPost(unittest.TestCase): doc = webnotes.new_doc("Blog Post") self.assertEquals(doc.get("blog_category"), "_Test Blog Category 1") - - def test_owner_match_bean(self): - webnotes.conn.sql("""update tabDocPerm set `match`='owner' where parent='Blog Post' + + def add_restricted_on_blogger(self): + webnotes.conn.sql("""update tabDocPerm set `restricted`=1 where parent='Blog Post' and role='Blogger' and ifnull(permlevel,0)=0""") webnotes.clear_cache(doctype="Blog Post") - + + def test_owner_match_bean(self): + self.add_restricted_on_blogger() + + webnotes.set_user("test2@example.com") + post = webnotes.bean("Blog Post", "_test-blog-post") self.assertTrue(post.has_read_perm()) @@ -92,28 +100,36 @@ class TestBlogPost(unittest.TestCase): self.assertFalse(post1.has_read_perm()) def test_owner_match_report(self): - webnotes.conn.sql("""update tabDocPerm set `match`='owner' where parent='Blog Post' + webnotes.conn.sql("""update tabDocPerm set `restricted`=1 where parent='Blog Post' and ifnull(permlevel,0)=0""") webnotes.clear_cache(doctype="Blog Post") + webnotes.set_user("test2@example.com") + 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 webnotes.core.page.user_properties.user_properties import add, remove, get_properties - - # restrictor can add restriction + + def add_restriction_to_user2(self): 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 + + def test_add_restriction(self): + # restrictor can add restriction + self.add_restriction_to_user2() + def test_not_allowed_to_restrict(self): 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") - + + def test_not_allowed_to_restrict(self): + self.add_restriction_to_user2() + + webnotes.set_user("test2@example.com") + # user can only access restricted blog post bean = webnotes.bean("Blog Post", "_test-blog-post") self.assertTrue(bean.has_read_perm()) @@ -121,12 +137,28 @@ class TestBlogPost(unittest.TestCase): # and not this one bean = webnotes.bean("Blog Post", "_test-blog-post-1") self.assertFalse(bean.has_read_perm()) - + + def test_not_allowed_to_remove_self(self): + self.add_restriction_to_user2() + defname = get_properties("test2@example.com", "Blog Post", "_test-blog-post")[0].name + + webnotes.set_user("test2@example.com") + # user cannot remove their own restriction self.assertRaises(webnotes.PermissionError, remove, "test2@example.com", defname, "Blog Post", "_test-blog-post") - - # but restrictor can + + def test_allow_in_restriction(self): + self.add_restricted_on_blogger() + + webnotes.set_user("test2@example.com") + bean = webnotes.bean("Blog Post", "_test-blog-post-1") + self.assertFalse(bean.has_read_perm()) + webnotes.set_user("test1@example.com") - remove("test2@example.com", defname, "Blog Post", "_test-blog-post") - \ No newline at end of file + add("test2@example.com", "Blog Post", "_test-blog-post-1") + + webnotes.set_user("test2@example.com") + bean = webnotes.bean("Blog Post", "_test-blog-post-1") + + self.assertTrue(bean.has_read_perm()) diff --git a/webnotes/widgets/query_report.py b/webnotes/widgets/query_report.py index ef4ae0ecfe..21d8b5f629 100644 --- a/webnotes/widgets/query_report.py +++ b/webnotes/widgets/query_report.py @@ -120,9 +120,12 @@ def get_filtered_data(ref_doctype, columns, data): matched_columns = get_matched_columns(linked_doctypes, match_filters) for row in data: match = True - for col, idx in matched_columns.items(): - if row[idx] not in match_filters[col]: - match = False + + if not ("owner" in match_filters and matched_columns.get("profile", None)==match_filters["owner"]): + for col, idx in matched_columns.items(): + if row[idx] not in match_filters[col]: + match = False + break if match: result.append(row) diff --git a/webnotes/widgets/reportview.py b/webnotes/widgets/reportview.py index 3ce0e26684..d87e535522 100644 --- a/webnotes/widgets/reportview.py +++ b/webnotes/widgets/reportview.py @@ -204,15 +204,24 @@ def build_match_conditions(doctype, fields=None, as_condition=True): import webnotes.permissions match_filters = {} match_conditions = [] + or_conditions = [] if not getattr(webnotes.local, "reportview_tables", None): webnotes.local.reportview_tables = get_tables(doctype, fields) load_doctypes() + # is restricted + restricted = webnotes.permissions.get_user_perms(webnotes.local.reportview_doctypes[doctype]).restricted + # get restrictions restrictions = webnotes.defaults.get_restrictions() + if restricted: + or_conditions.append('`tab{doctype}`.`owner`="{user}"'.format(doctype=doctype, + user=webnotes.local.session.user)) + match_filters["owner"] = webnotes.session.user + if restrictions: fields_to_check = webnotes.local.reportview_doctypes[doctype].get_restricted_fields(restrictions.keys()) if doctype in restrictions: @@ -223,28 +232,25 @@ def build_match_conditions(doctype, fields=None, as_condition=True): if as_condition: match_conditions.append('`tab{doctype}`.{fieldname} in ({values})'.format(doctype=doctype, fieldname=df.fieldname, - values=", ".join([('"'+v.replace('"', '\"')+'"') for v in restrictions[df.options]]))) + values=", ".join([('"'+v.replace('"', '\"')+'"') \ + for v in restrictions[df.options]]))) else: match_filters.setdefault(df.fieldname, []) match_filters[df.fieldname]= restrictions[df.options] - - # add owner match - owner_match = True - 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 - - if owner_match: - match_conditions.append('`tab{doctype}`.`owner`="{user}"'.format(doctype=doctype, - user=webnotes.local.session.user)) - match_filters["owner"] = [webnotes.local.session.user] - + if as_condition: conditions = " and ".join(match_conditions) doctype_conditions = get_doctype_conditions(doctype) if doctype_conditions: conditions += ' and ' + doctype_conditions if conditions else doctype_conditions + + if or_conditions: + if conditions: + conditions = '({conditions}) or {or_conditions}'.format(conditions=conditions, + or_conditions = ' or '.join(or_conditions)) + else: + conditions = " or ".join(or_conditions) + return conditions else: return match_filters