diff --git a/core/doctype/doctype/doctype.py b/core/doctype/doctype/doctype.py index 1fcf757b66..065f0b872c 100644 --- a/core/doctype/doctype/doctype.py +++ b/core/doctype/doctype/doctype.py @@ -144,46 +144,41 @@ class DocType: if allow_attach is checked and the column file_list doesn't exist, create a new field 'file_list' """ - if self.doc.allow_attach and not self.doc.fields.get("__islocal"): - import webnotes.model.doctype - temp_doclist = webnotes.model.doctype.get(self.doc.name) - if 'file_list' not in [d.fieldname for d in temp_doclist if \ - d.doctype=='DocField']: - new = self.doc.addchild('fields', 'DocField', self.doclist) - new.label = 'File List' - new.fieldtype = 'Text' - new.fieldname = 'file_list' - new.hidden = 1 - new.permlevel = 0 - new.print_hide = 1 - new.no_copy = 1 - idx_list = [d.idx for d in temp_doclist if d.idx] - max_idx = idx_list and max(idx_list) or 0 - new.idx = max_idx + 1 + if self.doc.allow_attach: + if not webnotes.conn.sql("""select name from tabDocField + where fieldname = 'file_list' and parent = %s""", self.doc.name): + new = self.doc.addchild('fields', 'DocField', self.doclist) + new.label = 'File List' + new.fieldtype = 'Text' + new.fieldname = 'file_list' + new.hidden = 1 + new.permlevel = 0 + new.print_hide = 1 + new.no_copy = 1 + new.idx = self.get_max_idx() + 1 def make_amendable(self): """ - if is_submittable is set, add amended_from - docfields + if is_submittable is set, add amended_from docfields """ if self.doc.is_submittable: - import webnotes.model.doctype - temp_doclist = webnotes.model.doctype.get(self.doc.name) - max_idx = max([d.idx for d in temp_doclist if d.idx]) - max_idx = max_idx and max_idx or 0 - if 'amended_from' not in [d.fieldname for d in temp_doclist if \ - d.doctype=='DocField']: - new = self.doc.addchild('fields', 'DocField', self.doclist) - new.label = 'Amended From' - new.fieldtype = 'Link' - new.fieldname = 'amended_from' - new.options = self.doc.name - new.permlevel = 0 - new.read_only = 1 - new.print_hide = 1 - new.no_copy = 1 - new.idx = max_idx + 1 - max_idx += 1 + if not webnotes.conn.sql("""select name from tabDocField + where fieldname = 'amended_from' and parent = %s""", self.doc.name): + new = self.doc.addchild('fields', 'DocField', self.doclist) + new.label = 'Amended From' + new.fieldtype = 'Link' + new.fieldname = 'amended_from' + new.options = self.doc.name + new.permlevel = 0 + new.read_only = 1 + new.print_hide = 1 + new.no_copy = 1 + new.idx = self.get_max_idx() + 1 + + def get_max_idx(self): + max_idx = webnotes.conn.sql("""select max(idx) from `tabDocField` where parent = %s""", + self.doc.name) + return max_idx and max_idx[0][0] or 0 def validate_fields_for_doctype(doctype): from webnotes.model.doctype import get diff --git a/core/page/permission_manager/permission_manager.py b/core/page/permission_manager/permission_manager.py index 236a9cd84b..25e4b9846d 100644 --- a/core/page/permission_manager/permission_manager.py +++ b/core/page/permission_manager/permission_manager.py @@ -1,5 +1,6 @@ from __future__ import unicode_literals import webnotes +import webnotes.defaults @webnotes.whitelist(allow_roles=["System Manager", "Administrator"]) def get_roles_and_doctypes(): @@ -22,8 +23,13 @@ def get_permissions(doctype=None, role=None): @webnotes.whitelist(allow_roles=["System Manager", "Administrator"]) def remove(doctype, name): + match = webnotes.conn.get_value("DocPerm", name, "match") + webnotes.conn.sql("""delete from tabDocPerm where name=%s""", name) validate_and_reset(doctype, for_remove=True) + + if match: + webnotes.defaults.clear_cache() @webnotes.whitelist(allow_roles=["System Manager", "Administrator"]) def add(parent, role, permlevel): @@ -46,11 +52,15 @@ def update(name, doctype, ptype, value=0): % (ptype, '%s', '%s'), (value, name)) validate_and_reset(doctype) + if ptype == "read" and webnotes.conn.get_value("DocPerm", name, "match"): + webnotes.defaults.clear_cache() + @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) + webnotes.defaults.clear_cache() def validate_and_reset(doctype, for_remove=False): from core.doctype.doctype.doctype import validate_permissions_for_doctype @@ -61,6 +71,7 @@ def validate_and_reset(doctype, for_remove=False): def reset(doctype): webnotes.reset_perms(doctype) webnotes.clear_cache(doctype=doctype) + webnotes.defaults.clear_cache() @webnotes.whitelist(allow_roles=["System Manager", "Administrator"]) def get_users_with_role(role): diff --git a/public/js/wn/misc/user.js b/public/js/wn/misc/user.js index 317da9ce4a..e40dd1751c 100644 --- a/public/js/wn/misc/user.js +++ b/public/js/wn/misc/user.js @@ -54,17 +54,18 @@ $.extend(wn.user, { } }); } + + if(!modules_list || !modules_list.length) { + // all modules + modules_list = keys(wn.modules).sort(); + } + // filter hidden modules if(wn.boot.hidden_modules && modules_list) { var hidden_list = JSON.parse(wn.boot.hidden_modules); var modules_list = $.map(modules_list, function(m) { if(hidden_list.indexOf(m)==-1) return m; else return null; }); - } - - if(!modules_list || !modules_list.length) { - // all modules - modules_list = keys(wn.modules).sort(); } // hide based on permission diff --git a/webnotes/__init__.py b/webnotes/__init__.py index f6badd934c..854a6cc2de 100644 --- a/webnotes/__init__.py +++ b/webnotes/__init__.py @@ -275,8 +275,12 @@ def has_permission(doctype, ptype="read", doc=None): # no valid permission found if match_failed: - key = match_failed.keys()[0] - msgprint(_("Not allowed for: ") + key + "=" + match_failed[key]) + doctypelist = get_doctype(doctype) + msg = _("Not allowed for: ") + for key in match_failed: + msg += "\n" + (doctypelist.get_field(key) and doctypelist.get_label(key) or key) \ + + " = " + (match_failed[key] or "None") + msgprint(msg) return False else: return perms and True or False diff --git a/webnotes/client.py b/webnotes/client.py index 25ac4440b0..ef58459768 100644 --- a/webnotes/client.py +++ b/webnotes/client.py @@ -33,13 +33,13 @@ def get(doctype, name=None, filters=None): return [d.fields for d in webnotes.bean(doctype, name).doclist] @webnotes.whitelist() -def get_value(doctype, fieldname, filters=None, as_dict=True): +def get_value(doctype, fieldname, filters=None, as_dict=True, debug=False): if not webnotes.has_permission(doctype): webnotes.msgprint("No Permission", raise_exception=True) if fieldname and fieldname.startswith("["): fieldname = json.loads(fieldname) - return webnotes.conn.get_value(doctype, json.loads(filters), fieldname, as_dict=as_dict) + return webnotes.conn.get_value(doctype, json.loads(filters), fieldname, as_dict=as_dict, debug=debug) @webnotes.whitelist() def insert(doclist): diff --git a/webnotes/db.py b/webnotes/db.py index dc3bcab399..1f62ba844e 100644 --- a/webnotes/db.py +++ b/webnotes/db.py @@ -260,18 +260,28 @@ class Database: filter's key is passed by map function build conditions like: * ifnull(`fieldname`, default_value) = %(fieldname)s - * `fieldname` = %(fieldname)s + * `fieldname` [=, !=, >, >=, <, <=] %(fieldname)s """ + _operator = "=" + value = filters.get(key) + if isinstance(value, (list, tuple)): + _operator = value[0] + filters[key] = value[1] + + if _operator not in ["=", "!=", ">", ">=", "<", "<=", "like"]: + _operator = "=" + if "[" in key: split_key = key.split("[") - return "ifnull(`" + split_key[0] + "`, " + split_key[1][:-1] + ") = %(" + key + ")s" + return "ifnull(`" + split_key[0] + "`, " + split_key[1][:-1] + ") " \ + + _operator + " %(" + key + ")s" else: - return "`" + key + "` = %(" + key + ")s" + return "`" + key + "` " + _operator + " %(" + key + ")s" if isinstance(filters, basestring): filters = { "name": filters } conditions = map(_build_condition, filters) - + return " and ".join(conditions), filters def get(self, doctype, filters=None, as_dict=True): @@ -282,7 +292,8 @@ class Database: For Single DocType, let filters be = None""" ret = self.get_values(doctype, filters, fieldname, ignore, as_dict, debug) - return ret and (len(ret[0]) > 1 and ret[0] or ret[0][0]) or None + + return ret and ((len(ret[0]) > 1 or as_dict) and ret[0] or ret[0][0]) or None def get_values(self, doctype, filters=None, fieldname="name", ignore=None, as_dict=False, debug=False): fields = fieldname diff --git a/webnotes/defaults.py b/webnotes/defaults.py index 1fa9f27aa4..8c9c0ba265 100644 --- a/webnotes/defaults.py +++ b/webnotes/defaults.py @@ -115,11 +115,29 @@ def get_defaults_for(parent="Control Panel"): defaults[d.defkey].append(d.defvalue) else: defaults[d.defkey] = d.defvalue + + if webnotes.session and parent == webnotes.session.user: + defaults.update(get_defaults_for_match(defaults)) webnotes.cache().set_value("__defaults:" + parent, defaults) return defaults +def get_defaults_for_match(userd): + """ if a profile based match condition exists for a user's role + and no user property is specified for that match key, + set default value as user's profile for that match key""" + user_roles = webnotes.get_roles() + out = {} + + for role, match in webnotes.conn.sql("""select distinct role, `match` + from `tabDocPerm` where ifnull(permlevel, 0)=0 and `read`=1 + and `match` like "%:user" """): + if role in user_roles and match.split(":")[0] not in userd: + out[match.split(":")[0]] = webnotes.session.user + + return out + def clear_cache(parent=None): def all_profiles(): return webnotes.conn.sql_list("select name from tabProfile") + ["Control Panel"] diff --git a/webnotes/model/bean.py b/webnotes/model/bean.py index 3c5a03907f..bafc5ff165 100644 --- a/webnotes/model/bean.py +++ b/webnotes/model/bean.py @@ -34,6 +34,7 @@ from webnotes.utils import cint, cstr from webnotes.model.doc import Document class DocstatusTransitionError(webnotes.ValidationError): pass +class BeanPermissionError(webnotes.ValidationError): pass class Bean: """ @@ -334,7 +335,7 @@ class Bean: def no_permission_to(self, ptype): webnotes.msgprint(("%s (%s): " % (self.doc.name, _(self.doc.doctype))) + \ - _("No Permission to ") + ptype, raise_exception=True) + _("No Permission to ") + ptype, raise_exception=BeanPermissionError) def check_no_back_links_exist(self): from webnotes.model.utils import check_if_doc_is_linked diff --git a/webnotes/profile.py b/webnotes/profile.py index 3ad5ce003d..089787b67b 100644 --- a/webnotes/profile.py +++ b/webnotes/profile.py @@ -47,7 +47,7 @@ class Profile: def get_roles(self): """get list of roles""" if not self.roles: - self.roles = webnotes.get_roles() + self.roles = webnotes.get_roles(self.name) return self.roles def build_doctype_map(self): diff --git a/webnotes/tests/test_db.py b/webnotes/tests/test_db.py new file mode 100644 index 0000000000..67236cbcb4 --- /dev/null +++ b/webnotes/tests/test_db.py @@ -0,0 +1,43 @@ +# Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com) +# +# MIT License (MIT) +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF +# CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +# OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +from __future__ import unicode_literals +import unittest +import webnotes +from webnotes.test_runner import make_test_records + +class TestDB(unittest.TestCase): + def test_get_value(self): + webnotes.conn.sql("""delete from `tabProfile` where name not in ('Administrator', 'Guest')""") + + make_test_records("Profile") + + self.assertEquals(webnotes.conn.get_value("Profile", {"name": ["=", "Administrator"]}), "Administrator") + self.assertEquals(webnotes.conn.get_value("Profile", {"name": ["like", "Admin%"]}), "Administrator") + self.assertEquals(webnotes.conn.get_value("Profile", {"name": ["!=", "Guest"]}), "Administrator") + + from webnotes.utils import nowdate + self.assertEquals(webnotes.conn.get_value("Profile", {"modified": ["<", nowdate()]}), "Administrator") + self.assertEquals(webnotes.conn.get_value("Profile", {"modified": ["<=", nowdate()]}), "Administrator") + self.assertEquals(webnotes.conn.get_value("Profile", {"modified": [">", nowdate()]}), "test1@example.com") + self.assertEquals(webnotes.conn.get_value("Profile", {"modified": [">=", nowdate()]}), "test1@example.com") + + \ No newline at end of file