diff --git a/frappe/boot.py b/frappe/boot.py index 7c43c68488..9594635c70 100644 --- a/frappe/boot.py +++ b/frappe/boot.py @@ -12,6 +12,7 @@ from frappe.desk.doctype.route_history.route_history import frequently_visited_l from frappe.desk.form.load import get_meta_bundle from frappe.email.inbox import get_email_accounts from frappe.model.base_document import get_controller +from frappe.permissions import has_permission from frappe.query_builder import DocType from frappe.query_builder.functions import Count from frappe.query_builder.terms import ParameterizedValueWrapper, SubQuery @@ -234,6 +235,9 @@ def get_user_pages_or_reports(parent, cache=False): has_role[p.name] = {"modified": p.modified, "title": p.title} elif parent == "Report": + if not has_permission("Report", raise_exception=False): + return {} + reports = frappe.get_list( "Report", fields=["name", "report_type"], diff --git a/frappe/custom/doctype/custom_field/custom_field.py b/frappe/custom/doctype/custom_field/custom_field.py index 758d9c1e64..8953153be6 100644 --- a/frappe/custom/doctype/custom_field/custom_field.py +++ b/frappe/custom/doctype/custom_field/custom_field.py @@ -18,6 +18,18 @@ class CustomField(Document): self.name = self.dt + "-" + self.fieldname def set_fieldname(self): + restricted = ( + "name", + "parent", + "creation", + "modified", + "modified_by", + "parentfield", + "parenttype", + "file_list", + "flags", + "docstatus", + ) if not self.fieldname: label = self.label if not label: @@ -34,6 +46,9 @@ class CustomField(Document): # fieldnames should be lowercase self.fieldname = self.fieldname.lower() + if self.fieldname in restricted: + self.fieldname = self.fieldname + "1" + def before_insert(self): self.set_fieldname() diff --git a/frappe/custom/doctype/customize_form/customize_form.js b/frappe/custom/doctype/customize_form/customize_form.js index 618186c0de..4ab693b415 100644 --- a/frappe/custom/doctype/customize_form/customize_form.js +++ b/frappe/custom/doctype/customize_form/customize_form.js @@ -314,22 +314,59 @@ frappe.ui.form.on("DocType State", { }, }); -frappe.customize_form.set_primary_action = function (frm) { - frm.page.set_primary_action(__("Update"), function () { - if (frm.doc.doc_type) { - return frm.call({ - doc: frm.doc, - freeze: true, - btn: frm.page.btn_primary, - method: "save_customization", - callback: function (r) { - if (!r.exc) { - frappe.customize_form.clear_locals_and_refresh(frm); - frm.script_manager.trigger("doc_type"); - } - }, - }); +frappe.customize_form.validate_fieldnames = async function (frm) { + for (let i = 0; i < frm.doc.fields.length; i++) { + let field = frm.doc.fields[i]; + + let fieldname = field.label && frappe.model.scrub(field.label).toLowerCase(); + if ( + field.label && + !field.fieldname && + in_list(frappe.model.restricted_fields, fieldname) + ) { + let message = __( + "For field {0} in row {1}, fieldname {2} is restricted it will be renamed as {2}1. Do you want to continue?", + [field.label, field.idx, fieldname] + ); + await pause_to_confirm(message); } + } + + function pause_to_confirm(message) { + return new Promise((resolve) => { + frappe.confirm( + message, + () => resolve(), + () => { + frm.page.btn_primary.prop("disabled", false); + } + ); + }); + } +}; + +frappe.customize_form.save_customization = function (frm) { + if (frm.doc.doc_type) { + return frm.call({ + doc: frm.doc, + freeze: true, + freeze_message: __("Saving Customization..."), + btn: frm.page.btn_primary, + method: "save_customization", + callback: function (r) { + if (!r.exc) { + frappe.customize_form.clear_locals_and_refresh(frm); + frm.script_manager.trigger("doc_type"); + } + }, + }); + } +}; + +frappe.customize_form.set_primary_action = function (frm) { + frm.page.set_primary_action(__("Update"), async () => { + await this.validate_fieldnames(frm); + this.save_customization(frm); }); }; diff --git a/frappe/exceptions.py b/frappe/exceptions.py index f09583e215..20e858c543 100644 --- a/frappe/exceptions.py +++ b/frappe/exceptions.py @@ -244,6 +244,10 @@ class InReadOnlyMode(ValidationError): http_status_code = 503 # temporarily not available +class SessionBootFailed(ValidationError): + http_status_code = 500 + + class TooManyWritesError(Exception): pass diff --git a/frappe/public/js/frappe/desk.js b/frappe/public/js/frappe/desk.js index 4a81e8620b..74e1c4f1e7 100644 --- a/frappe/public/js/frappe/desk.js +++ b/frappe/public/js/frappe/desk.js @@ -34,15 +34,6 @@ frappe.Application = class Application { frappe.socketio.init(); frappe.model.init(); - if (frappe.boot.status === "failed") { - frappe.msgprint({ - message: frappe.boot.error, - title: __("Session Start Failed"), - indicator: "red", - }); - throw "boot failed"; - } - this.load_bootinfo(); this.load_user_permissions(); this.make_nav_bar(); diff --git a/frappe/www/app.py b/frappe/www/app.py index a32fef5748..dcb326af36 100644 --- a/frappe/www/app.py +++ b/frappe/www/app.py @@ -27,8 +27,7 @@ def get_context(context): try: boot = frappe.sessions.get() except Exception as e: - boot = frappe._dict(status="failed", error=str(e)) - print(frappe.get_traceback()) + raise frappe.SessionBootFailed from e # this needs commit csrf_token = frappe.sessions.get_csrf_token()