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()