diff --git a/frappe/__init__.py b/frappe/__init__.py
index 8edbd28f04..3ca7ab6b8a 100644
--- a/frappe/__init__.py
+++ b/frappe/__init__.py
@@ -291,9 +291,9 @@ def get_roles(username=None):
else:
return User(username).get_roles()
-def has_permission(doctype, ptype="read", doc=None):
+def has_permission(doctype, ptype="read", doc=None, user=None):
import frappe.permissions
- return frappe.permissions.has_permission(doctype, ptype, doc)
+ return frappe.permissions.has_permission(doctype, ptype, doc, user=user)
def is_table(doctype):
tables = cache().get_value("is_table")
@@ -573,13 +573,13 @@ def build_match_conditions(doctype, as_condition=True):
def get_list(doctype, filters=None, fields=None, or_filters=None, docstatus=None,
group_by=None, order_by=None, limit_start=0, limit_page_length=None,
- as_list=False, debug=False, ignore_permissions=False):
+ as_list=False, debug=False, ignore_permissions=False, user=None):
import frappe.model.db_query
return frappe.model.db_query.DatabaseQuery(doctype).execute(filters=filters,
fields=fields, docstatus=docstatus, or_filters=or_filters,
group_by=group_by, order_by=order_by, limit_start=limit_start,
limit_page_length=limit_page_length, as_list=as_list, debug=debug,
- ignore_permissions=ignore_permissions)
+ ignore_permissions=ignore_permissions, user=user)
run_query = get_list
diff --git a/frappe/core/doctype/event/event.py b/frappe/core/doctype/event/event.py
index ebed036f47..08042022c2 100644
--- a/frappe/core/doctype/event/event.py
+++ b/frappe/core/doctype/event/event.py
@@ -27,14 +27,14 @@ def get_permission_query_conditions():
"roles": "', '".join(frappe.get_roles(frappe.session.user))
}
-def has_permission(doc):
- if doc.event_type=="Public" or doc.owner==frappe.session.user:
+def has_permission(doc, user):
+ if doc.event_type=="Public" or doc.owner==user:
return True
- if doc.get("event_individuals", {"person":frappe.session.user}):
+ if doc.get("event_individuals", {"person": user}):
return True
- if doc.get("event_roles", {"role":("in", frappe.get_roles())}):
+ if doc.get("event_roles", {"role":("in", frappe.get_roles(user))}):
return True
return False
diff --git a/frappe/core/doctype/report/report.json b/frappe/core/doctype/report/report.json
index 26ed9ef6e9..3851d07c40 100644
--- a/frappe/core/doctype/report/report.json
+++ b/frappe/core/doctype/report/report.json
@@ -61,6 +61,15 @@
"permlevel": 0,
"read_only": 0
},
+ {
+ "default": "1",
+ "depends_on": "eval:[\"Query Report\", \"Script Report\"].indexOf(doc.report_type)!==-1",
+ "fieldname": "apply_user_permissions",
+ "fieldtype": "Check",
+ "in_list_view": 0,
+ "label": "Apply User Permissions",
+ "permlevel": 0
+ },
{
"fieldname": "section_break_6",
"fieldtype": "Section Break",
@@ -101,7 +110,7 @@
],
"icon": "icon-table",
"idx": 1,
- "modified": "2014-05-27 03:49:17.001234",
+ "modified": "2014-06-03 07:25:41.509885",
"modified_by": "Administrator",
"module": "Core",
"name": "Report",
diff --git a/frappe/core/doctype/report/report.py b/frappe/core/doctype/report/report.py
index 26c646529c..3be887e102 100644
--- a/frappe/core/doctype/report/report.py
+++ b/frappe/core/doctype/report/report.py
@@ -12,26 +12,26 @@ class Report(Document):
"""only administrator can save standard report"""
if not self.module:
self.module = frappe.db.get_value("DocType", self.ref_doctype, "module")
-
+
if not self.is_standard:
self.is_standard = "No"
if frappe.session.user=="Administrator" and getattr(conf, 'developer_mode',0)==1:
self.is_standard = "Yes"
if self.is_standard == "Yes" and frappe.session.user!="Administrator":
- frappe.msgprint(_("Only Administrator can save a standard report. Please rename and save."),
+ frappe.msgprint(_("Only Administrator can save a standard report. Please rename and save."),
raise_exception=True)
if self.report_type in ("Query Report", "Script Report") \
and frappe.session.user!="Administrator":
frappe.msgprint(_("Only Administrator allowed to create Query / Script Reports"),
raise_exception=True)
-
+
def on_update(self):
self.export_doc()
-
+
def export_doc(self):
from frappe.modules.export_file import export_to_files
if self.is_standard == 'Yes' and (conf.get('developer_mode') or 0) == 1:
- export_to_files(record_list=[['Report', self.name]],
+ export_to_files(record_list=[['Report', self.name]],
record_module=self.module)
diff --git a/frappe/core/doctype/todo/todo.py b/frappe/core/doctype/todo/todo.py
index 936e676c07..caab426276 100644
--- a/frappe/core/doctype/todo/todo.py
+++ b/frappe/core/doctype/todo/todo.py
@@ -14,24 +14,24 @@ class ToDo(Document):
cur_status = frappe.db.get_value("ToDo", self.name, "status")
if cur_status != self.status:
self.add_comment(frappe._("Assignment Status Changed"))
-
+
def add_comment(self, text):
if not self.reference_type and self.reference_name:
return
-
+
comment = frappe.get_doc({
"doctype":"Comment",
"comment_by": frappe.session.user,
"comment_doctype": self.reference_type,
"comment_docname": self.reference_name,
- "comment": """
{text}:
+ "comment": """
""".format(text=text,
status = frappe._(self.status),
name = self.name,
description = self.description)
}).insert(ignore_permissions=True)
-
-
+
+
# todo is viewable if either owner or assigned_to or System Manager in roles
def get_permission_query_conditions():
@@ -39,10 +39,9 @@ def get_permission_query_conditions():
return None
else:
return """(tabToDo.owner = '{user}' or tabToDo.assigned_by = '{user}')""".format(user=frappe.session.user)
-
-def has_permission(doc):
- if "System Manager" in frappe.get_roles():
+
+def has_permission(doc, user):
+ if "System Manager" in frappe.get_roles(user):
return True
else:
- return doc.owner==frappe.session.user or doc.assigned_by==frappe.session.user
-
\ No newline at end of file
+ return doc.owner==user or doc.assigned_by==user
diff --git a/frappe/core/doctype/user/user.json b/frappe/core/doctype/user/user.json
index 354a8515d4..8ab84a2e2a 100644
--- a/frappe/core/doctype/user/user.json
+++ b/frappe/core/doctype/user/user.json
@@ -475,14 +475,13 @@
},
{
"apply_user_permissions": 0,
- "cancel": 0,
"create": 0,
"delete": 0,
- "email": 1,
+ "email": 0,
"permlevel": 0,
- "print": 1,
+ "print": 0,
"read": 1,
- "report": 1,
+ "report": 0,
"role": "All",
"submit": 0,
"write": 0
diff --git a/frappe/core/report/permitted_documents_for_user/__init__.py b/frappe/core/report/permitted_documents_for_user/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/frappe/core/report/permitted_documents_for_user/permitted_documents_for_user.js b/frappe/core/report/permitted_documents_for_user/permitted_documents_for_user.js
new file mode 100644
index 0000000000..f379963284
--- /dev/null
+++ b/frappe/core/report/permitted_documents_for_user/permitted_documents_for_user.js
@@ -0,0 +1,29 @@
+// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+// MIT License. See license.txt
+
+frappe.query_reports["Permitted Documents For User"] = {
+ "filters": [
+ {
+ "fieldname": "user",
+ "label": __("User"),
+ "fieldtype": "Link",
+ "options": "User",
+ "reqd": 1
+ },
+ {
+ "fieldname": "doctype",
+ "label": __("DocType"),
+ "fieldtype": "Link",
+ "options": "DocType",
+ "reqd": 1,
+ "get_query": function() {
+ return {
+ "query": "frappe.core.report.permitted_documents_for_user.permitted_documents_for_user.query_doctypes",
+ "filters": {
+ "user": frappe.query_report.filters_by_name.user.get_value()
+ }
+ }
+ }
+ }
+ ]
+}
diff --git a/frappe/core/report/permitted_documents_for_user/permitted_documents_for_user.json b/frappe/core/report/permitted_documents_for_user/permitted_documents_for_user.json
new file mode 100644
index 0000000000..458baa936c
--- /dev/null
+++ b/frappe/core/report/permitted_documents_for_user/permitted_documents_for_user.json
@@ -0,0 +1,15 @@
+{
+ "apply_user_permissions": 1,
+ "creation": "2014-06-03 05:20:35.218263",
+ "docstatus": 0,
+ "doctype": "Report",
+ "is_standard": "Yes",
+ "modified": "2014-06-03 07:18:17.218526",
+ "modified_by": "Administrator",
+ "module": "Core",
+ "name": "Permitted Documents For User",
+ "owner": "Administrator",
+ "ref_doctype": "User",
+ "report_name": "Permitted Documents For User",
+ "report_type": "Script Report"
+}
\ No newline at end of file
diff --git a/frappe/core/report/permitted_documents_for_user/permitted_documents_for_user.py b/frappe/core/report/permitted_documents_for_user/permitted_documents_for_user.py
new file mode 100644
index 0000000000..3a815577de
--- /dev/null
+++ b/frappe/core/report/permitted_documents_for_user/permitted_documents_for_user.py
@@ -0,0 +1,51 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
+# MIT License. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _, throw
+import frappe.utils.user
+from frappe.permissions import check_admin_or_system_manager
+
+def execute(filters=None):
+ user, doctype = filters.get("user"), filters.get("doctype")
+ validate(user, doctype)
+
+ columns, fields = get_columns_and_fields(doctype)
+ data = frappe.get_list(doctype, fields=fields, as_list=True, user=user)
+
+ return columns, data
+
+def validate(user, doctype):
+ # check if current user is System Manager
+ check_admin_or_system_manager()
+
+ if not user:
+ throw(_("Please specify user"))
+
+ if not doctype:
+ throw(_("Please specify doctype"))
+
+def get_columns_and_fields(doctype):
+ columns = ["Name:Link/{}:200".format(doctype)]
+ fields = ["name"]
+ for df in frappe.get_meta(doctype).fields:
+ if df.in_list_view:
+ fields.append(df.fieldname)
+ fieldtype = "Link/{}".format(df.options) if df.fieldtype=="Link" else df.fieldtype
+ columns.append("{label}:{fieldtype}:{width}".format(label=df.label, fieldtype=fieldtype, width=df.width or 100))
+
+ return columns, fields
+
+def query_doctypes(doctype, txt, searchfield, start, page_len, filters):
+ user = filters.get("user")
+ user_obj = frappe.utils.user.User(user)
+ user_obj.build_permissions()
+ can_read = user_obj.can_read
+
+ out = []
+ for dt in can_read:
+ if txt.lower().replace("%", "") in dt.lower():
+ out.append([dt])
+
+ return out
diff --git a/frappe/core/report/todo/todo.json b/frappe/core/report/todo/todo.json
index 768162f126..f808571789 100644
--- a/frappe/core/report/todo/todo.json
+++ b/frappe/core/report/todo/todo.json
@@ -1,10 +1,11 @@
{
- "creation": "2013-02-25 14:26:30.000000",
+ "apply_user_permissions": 1,
+ "creation": "2013-02-25 14:26:30",
"docstatus": 0,
"doctype": "Report",
"idx": 1,
"is_standard": "Yes",
- "modified": "2014-03-07 15:30:27.000000",
+ "modified": "2014-06-03 07:18:17.374222",
"modified_by": "Administrator",
"module": "Core",
"name": "ToDo",
diff --git a/frappe/model/db_query.py b/frappe/model/db_query.py
index 68e7999e32..e98b06028d 100644
--- a/frappe/model/db_query.py
+++ b/frappe/model/db_query.py
@@ -17,12 +17,13 @@ class DatabaseQuery(object):
self.conditions = []
self.ignore_permissions = False
self.fields = ["name"]
+ self.user = None
def execute(self, query=None, filters=None, fields=None, or_filters=None,
docstatus=None, group_by=None, order_by=None, limit_start=0,
limit_page_length=20, as_list=False, with_childnames=False, debug=False,
- ignore_permissions=False):
- if not frappe.has_permission(self.doctype, "read"):
+ ignore_permissions=False, user=None):
+ if not frappe.has_permission(self.doctype, "read", user=user):
raise frappe.PermissionError
if fields:
@@ -38,7 +39,7 @@ class DatabaseQuery(object):
self.debug = debug
self.as_list = as_list
self.ignore_permissions = ignore_permissions
-
+ self.user = user or frappe.session.user
if query:
return self.run_custom_query(query)
@@ -216,10 +217,10 @@ class DatabaseQuery(object):
if not self.tables: self.extract_tables()
# apply user permissions?
- role_permissions = frappe.permissions.get_role_permissions(frappe.get_meta(self.doctype))
+ role_permissions = frappe.permissions.get_role_permissions(frappe.get_meta(self.doctype), user=self.user)
if role_permissions.get("apply_user_permissions", {}).get("read"):
# get user permissions
- user_permissions = frappe.defaults.get_user_permissions()
+ user_permissions = frappe.defaults.get_user_permissions(self.user)
self.add_user_permissions(user_permissions)
if as_condition:
diff --git a/frappe/patches.txt b/frappe/patches.txt
index 151dc61d95..5e5e4ee87c 100644
--- a/frappe/patches.txt
+++ b/frappe/patches.txt
@@ -5,7 +5,7 @@ execute:frappe.reload_doc('core', 'doctype', 'doctype', force=True) #2014-01-24
execute:frappe.reload_doc('core', 'doctype', 'docfield', force=True) #2014-03-01
execute:frappe.reload_doc('core', 'doctype', 'docperm') #2013-13-26
execute:frappe.reload_doc('core', 'doctype', 'page') #2013-13-26
-execute:frappe.reload_doc('core', 'doctype', 'report') #2013-13-26
+execute:frappe.reload_doc('core', 'doctype', 'report') #2014-06-03
execute:frappe.reload_doc('core', 'doctype', 'version') #2014-02-21
execute:frappe.db.sql("alter table `tabSessions` modify `user` varchar(255), engine=InnoDB")
execute:frappe.db.sql("delete from `tabDocField` where parent='0'")
@@ -33,3 +33,4 @@ frappe.patches.v4_0.update_custom_field_insert_after
frappe.patches.v4_0.set_user_permissions
frappe.patches.v4_0.create_custom_field_for_owner_match
frappe.patches.v4_0.enable_scheduler_in_system_settings
+execute:frappe.db.sql("update tabReport set apply_user_permissions=1") #2014-06-03
diff --git a/frappe/permissions.py b/frappe/permissions.py
index f5146e90c0..9ababa96bc 100644
--- a/frappe/permissions.py
+++ b/frappe/permissions.py
@@ -9,13 +9,16 @@ from frappe.utils import cint
rights = ("read", "write", "create", "delete", "submit", "cancel", "amend",
"print", "email", "report", "import", "export", "set_user_permissions")
-def check_admin_or_system_manager():
- if ("System Manager" not in frappe.get_roles()) and \
- (frappe.session.user!="Administrator"):
+def check_admin_or_system_manager(user=None):
+ if not user: user = frappe.session.user
+
+ if ("System Manager" not in frappe.get_roles(user)) and (user!="Administrator"):
frappe.throw(_("Not permitted"), frappe.PermissionError)
-def has_permission(doctype, ptype="read", doc=None, verbose=True):
+def has_permission(doctype, ptype="read", doc=None, verbose=True, user=None):
"""check if user has permission"""
+ if not user: user = frappe.session.user
+
if frappe.is_table(doctype):
return True
@@ -27,10 +30,10 @@ def has_permission(doctype, ptype="read", doc=None, verbose=True):
if ptype=="import" and not cint(meta.allow_import):
return False
- if frappe.session.user=="Administrator":
+ if user=="Administrator":
return True
- role_permissions = get_role_permissions(meta)
+ role_permissions = get_role_permissions(meta, user=user)
if not role_permissions.get(ptype):
return False
@@ -38,17 +41,16 @@ def has_permission(doctype, ptype="read", doc=None, verbose=True):
if isinstance(doc, basestring):
doc = frappe.get_doc(meta.name, doc)
- if not user_has_permission(doc, verbose=verbose):
+ if not user_has_permission(doc, verbose=verbose, user=user):
return False
- if not has_controller_permissions(doc):
+ if not has_controller_permissions(doc, user=user):
return False
return True
def get_role_permissions(meta, user=None):
- if not user:
- user = frappe.session.user
+ if not user: user = frappe.session.user
cache_key = (meta.name, user)
if not frappe.local.role_permissions.get(cache_key):
@@ -71,9 +73,9 @@ def get_role_permissions(meta, user=None):
return frappe.local.role_permissions[cache_key]
-def user_has_permission(doc, verbose=True):
+def user_has_permission(doc, verbose=True, user=None):
from frappe.defaults import get_user_permissions
- user_permissions = get_user_permissions()
+ user_permissions = get_user_permissions(user)
user_permissions_keys = user_permissions.keys()
def check_user_permission(d):
@@ -99,9 +101,11 @@ def user_has_permission(doc, verbose=True):
return _user_has_permission
-def has_controller_permissions(doc):
+def has_controller_permissions(doc, user=None):
+ if not user: user = frappe.session.user
+
for method in frappe.get_hooks("has_permission").get(doc.doctype, []):
- if not frappe.call(frappe.get_attr(method), doc=doc):
+ if not frappe.call(frappe.get_attr(method), doc=doc, user=user):
return False
return True
diff --git a/frappe/public/js/frappe/form/control.js b/frappe/public/js/frappe/form/control.js
index 4176b1a9c8..34939d351b 100644
--- a/frappe/public/js/frappe/form/control.js
+++ b/frappe/public/js/frappe/form/control.js
@@ -894,7 +894,11 @@ frappe.ui.form.ControlLink = frappe.ui.form.ControlData.extend({
select: function(event, ui) {
me.autocomplete_open = false;
if(ui.item.make_new) {
- me.frm.new_doc(me.df.options, me);
+ if (me.frm) {
+ me.frm.new_doc(me.df.options, me);
+ } else {
+ new_doc(me.df.options);
+ }
return false;
}
diff --git a/frappe/widgets/query_report.py b/frappe/widgets/query_report.py
index d6e5d2f7f3..94f9918c26 100644
--- a/frappe/widgets/query_report.py
+++ b/frappe/widgets/query_report.py
@@ -16,58 +16,58 @@ def get_report_doc(report_name):
doc = frappe.get_doc("Report", report_name)
if not doc.has_permission("read"):
raise frappe.PermissionError("You don't have access to: {report}".format(report=report_name))
-
+
if not frappe.has_permission(doc.ref_doctype, "report"):
raise frappe.PermissionError("You don't have access to get a report on: {doctype}".format(
doctype=doc.ref_doctype))
-
+
return doc
@frappe.whitelist()
def get_script(report_name):
report = get_report_doc(report_name)
-
+
module = frappe.db.get_value("DocType", report.ref_doctype, "module")
module_path = get_module_path(module)
report_folder = os.path.join(module_path, "report", scrub(report.name))
script_path = os.path.join(report_folder, scrub(report.name) + ".js")
-
+
script = None
if os.path.exists(script_path):
with open(script_path, "r") as script:
script = script.read()
-
+
if not script and report.javascript:
script = report.javascript
-
+
if not script:
script = "frappe.query_reports['%s']={}" % report_name
-
+
# load translations
if frappe.lang != "en":
frappe.response["__messages"] = frappe.get_lang_dict("report", report_name)
-
+
return script
@frappe.whitelist()
def run(report_name, filters=()):
report = get_report_doc(report_name)
-
+
if filters and isinstance(filters, basestring):
filters = json.loads(filters)
if not frappe.has_permission(report.ref_doctype, "report"):
- frappe.msgprint(_("Must have report permission to access this report."),
+ frappe.msgprint(_("Must have report permission to access this report."),
raise_exception=True)
-
+
if report.report_type=="Query Report":
if not report.query:
frappe.msgprint(_("Must specify a Query to run"), raise_exception=True)
-
-
+
+
if not report.query.lower().startswith("select"):
frappe.msgprint(_("Query must be a SELECT"), raise_exception=True)
-
+
result = [list(t) for t in frappe.db.sql(report.query, filters)]
columns = [c[0] for c in frappe.db.get_description()]
else:
@@ -76,17 +76,18 @@ def run(report_name, filters=()):
method_name = frappe.local.module_app[scrub(module)] + "." + scrub(module) \
+ ".report." + scrub(report.name) + "." + scrub(report.name) + ".execute"
columns, result = frappe.get_attr(method_name)(frappe._dict(filters))
-
- result = get_filtered_data(report.ref_doctype, columns, result)
-
+
+ if report.apply_user_permissions:
+ result = get_filtered_data(report.ref_doctype, columns, result)
+
if cint(report.add_total_row) and result:
result = add_total_row(result, columns)
-
+
return {
"result": result,
"columns": columns
}
-
+
def add_total_row(result, columns):
total_row = [""]*len(columns)
has_percent = []
@@ -98,14 +99,14 @@ def add_total_row(result, columns):
total_row[i] = flt(total_row[i]) + flt(row[i])
if col[1] == "Percent" and i not in has_percent:
has_percent.append(i)
-
+
for i in has_percent:
total_row[i] = total_row[i] / len(result)
-
+
first_col = columns[0].split(":")
if len(first_col) > 1 and first_col[1] not in ["Currency", "Int", "Float", "Percent"]:
total_row[0] = "Total"
-
+
result.append(total_row)
return result
@@ -114,12 +115,12 @@ def get_filtered_data(ref_doctype, columns, data):
linked_doctypes = get_linked_doctypes(columns)
match_filters = get_user_match_filters(linked_doctypes, ref_doctype)
-
+
if match_filters:
matched_columns = get_matched_columns(linked_doctypes, match_filters)
for row in data:
match = True
-
+
if not ("owner" in match_filters and matched_columns.get("user", None)==match_filters["owner"]):
for col, idx in matched_columns.items():
if row[idx] not in match_filters[col]:
@@ -165,4 +166,4 @@ def get_matched_columns(linked_doctypes, match_filters):
if link_field in match_filters:
col_idx_map[link_field] = idx
- return col_idx_map
\ No newline at end of file
+ return col_idx_map