Skip to content

Commit

Permalink
Merge pull request #21023 from frappe/version-13-hotfix
Browse files Browse the repository at this point in the history
chore: release v13
  • Loading branch information
phot0n committed May 16, 2023
2 parents 6d90bd8 + 723ec9a commit 2225fb1
Show file tree
Hide file tree
Showing 13 changed files with 86 additions and 24 deletions.
22 changes: 18 additions & 4 deletions frappe/core/doctype/report/report.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,10 +174,18 @@ def execute_script(self, filters):
return self.get_columns(), loc["result"]

def get_data(
self, filters=None, limit=None, user=None, as_dict=False, ignore_prepared_report=False
self,
filters=None,
limit=None,
user=None,
as_dict=False,
ignore_prepared_report=False,
are_default_filters=True,
):
if self.report_type in ("Query Report", "Script Report", "Custom Report"):
columns, result = self.run_query_report(filters, user, ignore_prepared_report)
columns, result = self.run_query_report(
filters, user, ignore_prepared_report, are_default_filters
)
else:
columns, result = self.run_standard_report(filters, limit, user)

Expand All @@ -186,10 +194,16 @@ def get_data(

return columns, result

def run_query_report(self, filters=None, user=None, ignore_prepared_report=False):
def run_query_report(
self, filters=None, user=None, ignore_prepared_report=False, are_default_filters=True
):
columns, result = [], []
data = frappe.desk.query_report.run(
self.name, filters=filters, user=user, ignore_prepared_report=ignore_prepared_report
self.name,
filters=filters,
user=user,
ignore_prepared_report=ignore_prepared_report,
are_default_filters=are_default_filters,
)

for d in data.get("columns"):
Expand Down
2 changes: 1 addition & 1 deletion frappe/desk/query_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ def export_query():
visible_idx = json.loads(visible_idx)

if file_format_type == "Excel":
data = run(report_name, filters, custom_columns=custom_columns)
data = run(report_name, filters, custom_columns=custom_columns, are_default_filters=False)
data = frappe._dict(data)
if not data.columns:
frappe.respond_as_web_page(
Expand Down
7 changes: 5 additions & 2 deletions frappe/desk/reportview.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import frappe.permissions
from frappe import _
from frappe.core.doctype.access_log.access_log import make_access_log
from frappe.model import default_fields, optional_fields
from frappe.model import default_fields, get_permitted_fields, optional_fields
from frappe.model.base_document import get_controller
from frappe.model.db_query import DatabaseQuery
from frappe.utils import cstr, format_duration
Expand Down Expand Up @@ -209,7 +209,10 @@ def update_wildcard_field_param(data):
if (isinstance(data.fields, string_types) and data.fields == "*") or (
isinstance(data.fields, (list, tuple)) and len(data.fields) == 1 and data.fields[0] == "*"
):
data.fields = frappe.db.get_table_columns(data.doctype)
if frappe.get_system_settings("apply_perm_level_on_api_calls"):
data.fields = get_permitted_fields(data.doctype, parenttype=data.parenttype)
else:
data.fields = frappe.db.get_table_columns(data.doctype)
return True

return False
Expand Down
21 changes: 17 additions & 4 deletions frappe/email/doctype/auto_email_report/auto_email_report.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,28 @@ frappe.ui.form.on('Auto Email Report', {
</thead><tbody></tbody></table>').appendTo(wrapper);
$('<p class="text-muted small">' + __("Click table to edit") + '</p>').appendTo(wrapper);

var filters = JSON.parse(frm.doc.filters || '{}');
var filters = {};

let report_filters;

if (frm.doc.report_type === 'Custom Report'
&& frappe.query_reports[frm.doc.reference_report]
&& frappe.query_reports[frm.doc.reference_report].filters) {
if (
frm.doc.report_type === "Custom Report" &&
frappe.query_reports[frm.doc.reference_report] &&
frappe.query_reports[frm.doc.reference_report].filters
) {
if (frm.doc.filters) {
filters = JSON.parse(frm.doc.filters);
} else {
frappe.db.get_value("Report", frm.doc.report, "json", (r) => {
if (r && r.json) {
filters = JSON.parse(r.json).filters || {};
}
});
}

report_filters = frappe.query_reports[frm.doc.reference_report].filters;
} else {
filters = JSON.parse(frm.doc.filters || "{}");
report_filters = frappe.query_reports[frm.doc.report].filters;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ def get_report_content(self):
filters=self.filters,
as_dict=True,
ignore_prepared_report=True,
are_default_filters=False,
)

# add serial numbers
Expand Down
15 changes: 13 additions & 2 deletions frappe/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,10 @@ def delete_fields(args_dict, delete=0):


def get_permitted_fields(
doctype: str, parenttype: Optional[str] = None, user: Optional[str] = None
doctype: str,
parenttype: Optional[str] = None,
user: Optional[str] = None,
permission_type: Optional[str] = None,
) -> List[str]:
meta = frappe.get_meta(doctype)
valid_columns = meta.get_valid_columns()
Expand All @@ -195,9 +198,17 @@ def get_permitted_fields(
if set(valid_columns).issubset(default_fields):
return valid_columns

permitted_fields = meta.get_permitted_fieldnames(parenttype=parenttype, user=user)
if permission_type is None:
permission_type = "select" if frappe.only_has_select_perm(doctype, user=user) else "read"

permitted_fields = meta.get_permitted_fieldnames(
parenttype=parenttype, user=user, permission_type=permission_type
)

if permitted_fields:
if permission_type == "select":
return permitted_fields

meta_fields = meta.default_fields.copy()
optional_meta_fields = [x for x in optional_fields if x in valid_columns]

Expand Down
8 changes: 6 additions & 2 deletions frappe/model/db_query.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ def __init__(self, doctype, user=None):
self.ignore_ifnull = False
self.flags = frappe._dict()
self.reference_doctype = None
self.permission_map = {}

def execute(
self,
Expand Down Expand Up @@ -98,7 +99,6 @@ def execute(
and not frappe.has_permission(self.doctype, "select", user=user)
and not frappe.has_permission(self.doctype, "read", user=user)
):

frappe.flags.error_message = _("Insufficient Permission for {0}").format(
frappe.bold(self.doctype)
)
Expand Down Expand Up @@ -421,6 +421,7 @@ def append_table(self, table_name):
if (not self.flags.ignore_permissions) and (not frappe.has_permission(doctype, ptype=ptype)):
frappe.flags.error_message = _("Insufficient Permission for {0}").format(frappe.bold(doctype))
raise frappe.PermissionError(doctype)
self.permission_map[doctype] = ptype

def set_field_tables(self):
"""If there are more than one table, the fieldname must not be ambiguous.
Expand Down Expand Up @@ -525,7 +526,10 @@ def apply_fieldlevel_read_permissions(self):
return

asterisk_fields = []
permitted_fields = get_permitted_fields(doctype=self.doctype)
permitted_fields = get_permitted_fields(
doctype=self.doctype,
permission_type=self.permission_map.get(self.doctype),
)

for i, field in enumerate(self.fields):
if "distinct" in field.lower():
Expand Down
12 changes: 10 additions & 2 deletions frappe/model/meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ def get_high_permlevel_fields(self):

return self.high_permlevel_fields

def get_permitted_fieldnames(self, parenttype=None, *, user=None):
def get_permitted_fieldnames(self, parenttype=None, *, user=None, permission_type="read"):
"""Build list of `fieldname` with read perm level and all the higher perm levels defined.
Note: If permissions are not defined for DocType, return all the fields with value.
"""
Expand All @@ -505,10 +505,18 @@ def get_permitted_fieldnames(self, parenttype=None, *, user=None):
if self.istable and not parenttype:
return permitted_fieldnames

if not permission_type:
permission_type = "select" if frappe.only_has_select_perm(self.name, user=user) else "read"

if permission_type == "select":
return self.get_search_fields()

if not self.get_permissions(parenttype=parenttype):
return self.get_fieldnames_with_value()

permlevel_access = set(self.get_permlevel_access("read", parenttype, user=user))
permlevel_access = set(
self.get_permlevel_access(permission_type=permission_type, parenttype=parenttype, user=user)
)

for df in self.get_fieldnames_with_value(with_field_meta=True):
if df.permlevel in permlevel_access:
Expand Down
2 changes: 1 addition & 1 deletion frappe/public/js/frappe/form/save.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ frappe.ui.form.save = function (frm, action, callback, btn) {

const is_empty_row = function(cells) {
for (let i = 0; i < cells.length; i++) {
if (locals[doc.doctype][doc.name][cells[i].fieldname]) {
if (locals[doc.doctype][doc.name] && locals[doc.doctype][doc.name][cells[i].fieldname]) {
return false;
}
}
Expand Down
4 changes: 2 additions & 2 deletions frappe/public/js/frappe/model/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -677,8 +677,8 @@ $.extend(frappe.model, {

get_all_docs: function(doc) {
var all = [doc];
for(var key in doc) {
if($.isArray(doc[key])) {
for (var key in doc) {
if ($.isArray(doc[key]) && !key.startsWith("_")) {
var children = doc[key];
for (var i=0, l=children.length; i < l; i++) {
all.push(children[i]);
Expand Down
5 changes: 3 additions & 2 deletions frappe/public/js/frappe/views/reports/report_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -1298,9 +1298,10 @@ frappe.views.ReportView = class ReportView extends frappe.views.ListView {
return filters
.map((f) => {
const [doctype, fieldname, condition, value] = f;
if (condition !== '=') return '';
if (condition !== "=") return "";
const label = frappe.meta.get_label(doctype, fieldname);
const docfield = frappe.meta.get_docfield(doctype, fieldname);
return `<h6>${__(docfield.label)}: ${frappe.format(value, docfield)}</h6>`;
return `<h6>${__(label)}: ${frappe.format(value, docfield)}</h6>`;
})
.join("");
}
Expand Down
7 changes: 7 additions & 0 deletions frappe/tests/test_permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
update_permission_property,
)
from frappe.test_runner import make_test_records_for_doctype
from frappe.tests.test_db_query import enable_permlevel_restrictions

test_dependencies = ["Blogger", "Blog Post", "User", "Contact", "Salutation"]

Expand Down Expand Up @@ -89,6 +90,12 @@ def test_select_permission(self):
self.assertFalse(post.has_permission("read"))
self.assertRaises(frappe.PermissionError, post.save)

with enable_permlevel_restrictions():
permitted_record = frappe.get_list("Blog Post", fields="*", limit=1)[0]
full_record = frappe.get_all("Blog Post", fields="*", limit=1)[0]
self.assertNotEqual(permitted_record, full_record)
self.assertTrue(set(post.meta.get_search_fields()).issubset(set(permitted_record)))

def test_user_permissions_in_doc(self):
add_user_permission("Blog Category", "-test-blog-category-1", "test2@example.com")

Expand Down
4 changes: 2 additions & 2 deletions frappe/workflow/doctype/workflow/workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,15 @@ def set_active(self):

@frappe.whitelist()
def get_fieldnames_for(doctype):
frappe.has_permission(doctype=doctype, ptype='read', throw=True)
frappe.has_permission(doctype=doctype, ptype="read", throw=True)
return [
f.fieldname for f in frappe.get_meta(doctype).fields if f.fieldname not in no_value_fields
]


@frappe.whitelist()
def get_workflow_state_count(doctype, workflow_state_field, states):
frappe.has_permission(doctype=doctype, ptype='read', throw=True)
frappe.has_permission(doctype=doctype, ptype="read", throw=True)
states = frappe.parse_json(states)
result = frappe.get_all(
doctype,
Expand Down

0 comments on commit 2225fb1

Please sign in to comment.