@@ -108,6 +108,7 @@ def init(site, sites_path=None): | |||
local.user = None | |||
local.role_permissions = {} | |||
local.valid_columns = {} | |||
local.new_doc_templates = {} | |||
local.jenv = None | |||
local.jloader =None | |||
@@ -429,14 +430,14 @@ def reset_metadata_version(): | |||
cache().set_value("metadata_version", v) | |||
return v | |||
def new_doc(doctype, parent_doc=None, parentfield=None): | |||
def new_doc(doctype, parent_doc=None, parentfield=None, as_dict=False): | |||
"""Returns a new document of the given DocType with defaults set. | |||
:param doctype: DocType of the new document. | |||
:param parent_doc: [optional] add to parent document. | |||
:param parentfield: [optional] add against this `parentfield`.""" | |||
from frappe.model.create_new import get_new_doc | |||
return get_new_doc(doctype, parent_doc, parentfield) | |||
return get_new_doc(doctype, parent_doc, parentfield, as_dict=as_dict) | |||
def set_value(doctype, docname, fieldname, value): | |||
"""Set document value. Calls `frappe.client.set_value`""" | |||
@@ -1,52 +1,60 @@ | |||
[ | |||
{ | |||
"doctype": "User", | |||
"email": "test@example.com", | |||
"enabled": 1, | |||
"first_name": "_Test", | |||
"new_password": "testpassword", | |||
"doctype": "User", | |||
"email": "test@example.com", | |||
"enabled": 1, | |||
"first_name": "_Test", | |||
"new_password": "testpassword", | |||
"user_roles": [ | |||
{ | |||
"doctype": "UserRole", | |||
"parentfield": "user_roles", | |||
"doctype": "UserRole", | |||
"parentfield": "user_roles", | |||
"role": "_Test Role" | |||
}, | |||
}, | |||
{ | |||
"doctype": "UserRole", | |||
"parentfield": "user_roles", | |||
"doctype": "UserRole", | |||
"parentfield": "user_roles", | |||
"role": "System Manager" | |||
} | |||
] | |||
}, | |||
}, | |||
{ | |||
"doctype": "User", | |||
"email": "test1@example.com", | |||
"first_name": "_Test1", | |||
"doctype": "User", | |||
"email": "test1@example.com", | |||
"first_name": "_Test1", | |||
"new_password": "testpassword" | |||
}, | |||
}, | |||
{ | |||
"doctype": "User", | |||
"email": "test2@example.com", | |||
"first_name": "_Test2", | |||
"new_password": "testpassword" | |||
}, | |||
"doctype": "User", | |||
"email": "test2@example.com", | |||
"first_name": "_Test2", | |||
"new_password": "testpassword", | |||
"enabled": 1 | |||
}, | |||
{ | |||
"doctype": "User", | |||
"email": "testperm@example.com", | |||
"first_name": "_Test Perm", | |||
"new_password": "testpassword", | |||
"enabled": 1 | |||
}, | |||
{ | |||
"doctype": "User", | |||
"email": "testdelete@example.com", | |||
"enabled": 1, | |||
"first_name": "_Test", | |||
"new_password": "testpassword", | |||
"doctype": "User", | |||
"email": "testdelete@example.com", | |||
"enabled": 1, | |||
"first_name": "_Test", | |||
"new_password": "testpassword", | |||
"user_roles": [ | |||
{ | |||
"doctype": "UserRole", | |||
"parentfield": "user_roles", | |||
"doctype": "UserRole", | |||
"parentfield": "user_roles", | |||
"role": "_Test Role 2" | |||
}, | |||
}, | |||
{ | |||
"doctype": "UserRole", | |||
"parentfield": "user_roles", | |||
"doctype": "UserRole", | |||
"parentfield": "user_roles", | |||
"role": "System Manager" | |||
} | |||
] | |||
} | |||
] | |||
] |
@@ -15,6 +15,9 @@ class TestUser(unittest.TestCase): | |||
frappe.db.sql("""delete from tabUserRole where role='_Test Role 2'""") | |||
delete_doc("Role","_Test Role 2") | |||
if frappe.db.exists("User", "_test@example.com"): | |||
delete_doc("User", "_test@example.com") | |||
user = frappe.copy_doc(test_records[1]) | |||
user.email = "_test@example.com" | |||
user.insert() | |||
@@ -50,3 +53,21 @@ class TestUser(unittest.TestCase): | |||
frappe.db.set_value("Website Settings", "Website Settings", "_test", "_test_val") | |||
self.assertEquals(frappe.db.get_value("Website Settings", None, "_test"), "_test_val") | |||
self.assertEquals(frappe.db.get_value("Website Settings", "Website Settings", "_test"), "_test_val") | |||
def test_high_permlevel_validations(self): | |||
user = frappe.get_meta("User") | |||
self.assertTrue("user_roles" in [d.fieldname for d in user.get_high_permlevel_fields()]) | |||
frappe.set_user("testperm@example.com") | |||
me = frappe.get_doc("User", "testperm@example.com") | |||
me.add_roles("System Manager") | |||
self.assertTrue("System Manager" not in [d.role for d in me.get("user_roles")]) | |||
frappe.set_user("Administrator") | |||
me = frappe.get_doc("User", "testperm@example.com") | |||
me.add_roles("System Manager") | |||
self.assertTrue("System Manager" in [d.role for d in me.get("user_roles")]) |
@@ -2,12 +2,13 @@ | |||
# MIT License. See license.txt | |||
from __future__ import unicode_literals | |||
import frappe, json, sys | |||
import frappe, sys | |||
from frappe import _ | |||
from frappe.utils import cint, flt, now, cstr, strip_html | |||
from frappe.model import default_fields | |||
from frappe.model.naming import set_new_name | |||
from frappe.modules import load_doctype_module | |||
from frappe.model import display_fieldtypes | |||
_classes = {} | |||
@@ -471,6 +472,29 @@ class BaseDocument(object): | |||
else: | |||
return True | |||
def reset_values_if_no_permlevel_access(self, has_access_to, high_permlevel_fields): | |||
"""If the user does not have permissions at permlevel > 0, then reset the values to original / default""" | |||
to_reset = [] | |||
for df in high_permlevel_fields: | |||
if df.permlevel not in has_access_to and df.fieldtype not in display_fieldtypes: | |||
to_reset.append(df) | |||
if to_reset: | |||
if self.is_new(): | |||
# if new, set default value | |||
ref_doc = frappe.new_doc(self.doctype) | |||
else: | |||
# get values from old doc | |||
if self.parent: | |||
self.parent_doc.get_latest() | |||
ref_doc = [d for d in self.parent_doc.get(self.parentfield) if d.name == self.name][0] | |||
else: | |||
ref_doc = self.get_latest() | |||
for df in to_reset: | |||
self.set(df.fieldname, ref_doc.get(df.fieldname)) | |||
def _filter(data, filters, limit=None): | |||
"""pass filters as: | |||
{"key": "val", "key": ["!=", "val"], | |||
@@ -7,37 +7,51 @@ Create a new document with defaults set | |||
""" | |||
import frappe | |||
from frappe.utils import nowdate, nowtime, cint, flt, now_datetime | |||
from frappe.utils import nowdate, nowtime, now_datetime | |||
import frappe.defaults | |||
from frappe.model.db_schema import type_map | |||
import copy | |||
def get_new_doc(doctype, parent_doc = None, parentfield = None): | |||
doc = frappe.get_doc({ | |||
"doctype": doctype, | |||
"__islocal": 1, | |||
"owner": frappe.session.user, | |||
"docstatus": 0 | |||
}) | |||
def get_new_doc(doctype, parent_doc = None, parentfield = None, as_dict=False): | |||
if not doctype in frappe.local.new_doc_templates: | |||
# cache a copy of new doc as it is called | |||
# frequently for inserts | |||
doc = frappe.get_doc({ | |||
"doctype": doctype, | |||
"__islocal": 1, | |||
"owner": frappe.session.user, | |||
"docstatus": 0 | |||
}) | |||
user_permissions = frappe.defaults.get_user_permissions() | |||
user_permissions = frappe.defaults.get_user_permissions() | |||
if parent_doc: | |||
doc.parent = parent_doc.name | |||
doc.parenttype = parent_doc.doctype | |||
defaults = frappe.defaults.get_defaults() | |||
if parentfield: | |||
doc.parentfield = parentfield | |||
for df in doc.meta.get("fields"): | |||
if df.fieldtype in type_map: | |||
default_value = get_default_value(df, defaults, user_permissions, parent_doc) | |||
doc.set(df.fieldname, default_value) | |||
doc._fix_numeric_types() | |||
doc = doc.get_valid_dict() | |||
doc["doctype"] = doctype | |||
doc["__islocal"] = 1 | |||
defaults = frappe.defaults.get_defaults() | |||
frappe.local.new_doc_templates[doctype] = doc | |||
for df in doc.meta.get("fields"): | |||
if df.fieldtype in type_map: | |||
default_value = get_default_value(df, defaults, user_permissions, parent_doc) | |||
doc.set(df.fieldname, default_value) | |||
doc = copy.deepcopy(frappe.local.new_doc_templates[doctype]) | |||
doc._fix_numeric_types() | |||
if parent_doc: | |||
doc["parent"] = parent_doc.name | |||
doc["parenttype"] = parent_doc.doctype | |||
if parentfield: | |||
doc["parentfield"] = parentfield | |||
return doc | |||
if as_dict: | |||
return doc | |||
else: | |||
return frappe.get_doc(doc) | |||
def get_default_value(df, defaults, user_permissions, parent_doc): | |||
user_permissions_exist = (df.fieldtype=="Link" | |||
@@ -8,7 +8,6 @@ from frappe.utils import flt, cint, cstr, now, get_datetime_str | |||
from frappe.model.base_document import BaseDocument, get_controller | |||
from frappe.model.naming import set_new_name | |||
from werkzeug.exceptions import NotFound, Forbidden | |||
from frappe.model import display_fieldtypes | |||
import hashlib, json | |||
# once_only validation | |||
@@ -84,7 +83,7 @@ class Document(BaseDocument): | |||
# incorrect arguments. let's not proceed. | |||
raise frappe.DataError("Document({0}, {1})".format(arg1, arg2)) | |||
self.dont_update_if_missing = [] | |||
self._default_new_docs = {} | |||
self.flags = frappe._dict() | |||
def load_from_db(self): | |||
@@ -122,6 +121,11 @@ class Document(BaseDocument): | |||
else: | |||
self.set(df.fieldname, []) | |||
def get_latest(self): | |||
if not getattr(self, "latest", None): | |||
self.latest = frappe.get_doc(self.doctype, self.name) | |||
return self.latest | |||
def check_permission(self, permtype, permlabel=None): | |||
"""Raise `frappe.PermissionError` if not permitted""" | |||
if not self.has_permission(permtype): | |||
@@ -301,37 +305,18 @@ class Document(BaseDocument): | |||
if self.flags.ignore_permissions or frappe.flags.in_install: | |||
return | |||
self.get_high_permlevel_fields() | |||
if not self.high_permlevel_fields: | |||
return | |||
has_access_to = self.get_permlevel_access() | |||
to_reset = [] | |||
for df in self.high_permlevel_fields: | |||
if df.permlevel not in has_access_to and df.fieldtype not in display_fieldtypes: | |||
to_reset.append(df) | |||
high_permlevel_fields = self.meta.get_high_permlevel_fields() | |||
if to_reset: | |||
if self.is_new(): | |||
# if new, set default value | |||
for df in to_reset: | |||
self.set(df.fieldname, df.default or None) | |||
if high_permlevel_fields: | |||
self.reset_values_if_no_permlevel_access(has_access_to, high_permlevel_fields) | |||
else: | |||
# get values from old doc | |||
old = frappe.get_doc(self.doctype, self.name) | |||
for df in to_reset: | |||
self.set(df.fieldname, old.get(df.fieldname)) | |||
def get_high_permlevel_fields(self): | |||
"""Build list of fields with high perm level and all the higher perm levels defined.""" | |||
self.high_permlevel_fields = [] | |||
self.high_permlevels = [] | |||
for df in self.meta.fields: | |||
if df.permlevel > 0: | |||
self.high_permlevel_fields.append(df) | |||
if not df.permlevel in self.high_permlevels: | |||
self.high_permlevels.append(df.permlevel) | |||
# check for child tables | |||
for df in self.meta.get_table_fields(): | |||
high_permlevel_fields = frappe.get_meta(df.options).meta.get_high_permlevel_fields() | |||
if high_permlevel_fields: | |||
for d in self.get(df.fieldname): | |||
d.reset_values_if_no_permlevel_access(has_access_to, high_permlevel_fields) | |||
def get_permlevel_access(self): | |||
user_roles = frappe.get_roles() | |||
@@ -347,12 +332,12 @@ class Document(BaseDocument): | |||
if frappe.flags.in_import: | |||
return | |||
new_doc = frappe.new_doc(self.doctype) | |||
new_doc = frappe.new_doc(self.doctype, as_dict=True) | |||
self.update_if_missing(new_doc) | |||
# children | |||
for df in self.meta.get_table_fields(): | |||
new_doc = frappe.new_doc(df.options) | |||
new_doc = frappe.new_doc(df.options, as_dict=True) | |||
value = self.get(df.fieldname) | |||
if isinstance(value, list): | |||
for d in value: | |||
@@ -578,7 +563,7 @@ class Document(BaseDocument): | |||
self.run_method("on_update_after_submit") | |||
frappe.cache().set_value("last_modified:" + self.doctype, self.modified) | |||
self.latest = None | |||
def check_no_back_links_exist(self): | |||
"""Check if document links to any active document before Cancel.""" | |||
@@ -213,6 +213,16 @@ class Meta(Document): | |||
return fields | |||
def get_high_permlevel_fields(self): | |||
"""Build list of fields with high perm level and all the higher perm levels defined.""" | |||
if not hasattr(self, "high_permlevel_fields"): | |||
self.high_permlevel_fields = [] | |||
for df in self.fields: | |||
if df.permlevel > 0: | |||
self.high_permlevel_fields.append(df) | |||
return self.high_permlevel_fields | |||
doctype_table_fields = [ | |||
frappe._dict({"fieldname": "fields", "options": "DocField"}), | |||
frappe._dict({"fieldname": "permissions", "options": "DocPerm"}) | |||
@@ -193,14 +193,14 @@ def make_test_records_for_doctype(doctype, verbose=0, force=False): | |||
def make_test_objects(doctype, test_records, verbose=None): | |||
records = [] | |||
if not frappe.get_meta(doctype).issingle: | |||
existing = frappe.get_all(doctype, filters={"name":("like", "_T-" + doctype + "-%")}) | |||
if existing: | |||
return [d.name for d in existing] | |||
existing = frappe.get_all(doctype, filters={"name":("like", "_Test " + doctype + "%")}) | |||
if existing: | |||
return [d.name for d in existing] | |||
# if not frappe.get_meta(doctype).issingle: | |||
# existing = frappe.get_all(doctype, filters={"name":("like", "_T-" + doctype + "-%")}) | |||
# if existing: | |||
# return [d.name for d in existing] | |||
# | |||
# existing = frappe.get_all(doctype, filters={"name":("like", "_Test " + doctype + "%")}) | |||
# if existing: | |||
# return [d.name for d in existing] | |||
for doc in test_records: | |||
if not doc.get("doctype"): | |||
@@ -146,4 +146,3 @@ class TestDocument(unittest.TestCase): | |||
d.validate_update_after_submit() | |||
d.meta.get_field("starts_on").allow_on_submit = 0 | |||