diff --git a/frappe/app.py b/frappe/app.py index 2d0931af64..9373689380 100644 --- a/frappe/app.py +++ b/frappe/app.py @@ -324,9 +324,8 @@ def make_form_dict(request: Request): frappe.throw(_("Invalid request arguments")) +@handle_does_not_exist_error def handle_exception(e): - e = handle_does_not_exist_error(e) - response = None http_status_code = getattr(e, "http_status_code", 500) accept_header = frappe.get_request_header("Accept") or "" diff --git a/frappe/core/doctype/communication/email.py b/frappe/core/doctype/communication/email.py index 2bcba512d0..f3a1aed7fa 100755 --- a/frappe/core/doctype/communication/email.py +++ b/frappe/core/doctype/communication/email.py @@ -9,7 +9,6 @@ import frappe import frappe.email.smtp from frappe import _ from frappe.email.email_body import get_message_id -from frappe.permissions import check_doctype_permission from frappe.utils import ( cint, get_datetime, diff --git a/frappe/desk/desk_page.py b/frappe/desk/desk_page.py index 182c2f9ef7..ed79a1e2df 100644 --- a/frappe/desk/desk_page.py +++ b/frappe/desk/desk_page.py @@ -4,7 +4,6 @@ import frappe -@frappe.whitelist() def get(name): """ Return the :term:`doclist` of the `Page` specified by `name` @@ -23,11 +22,10 @@ def get(name): @frappe.whitelist(allow_guest=True) -def getpage(): +def getpage(name: str): """ Load the page from `frappe.form` and send it via `frappe.response` """ - page = frappe.form_dict.get("name") - doc = get(page) + doc = get(name) frappe.response.docs.append(doc) diff --git a/frappe/desk/page/backups/backups.py b/frappe/desk/page/backups/backups.py index 6f0fface42..d428835fa2 100644 --- a/frappe/desk/page/backups/backups.py +++ b/frappe/desk/page/backups/backups.py @@ -10,9 +10,9 @@ from frappe.utils.data import convert_utc_to_system_timezone def get_context(context): def get_time(path): dt = os.path.getmtime(path) - return convert_utc_to_system_timezone(datetime.datetime.utcfromtimestamp(dt)).strftime( - "%a %b %d %H:%M %Y" - ) + return convert_utc_to_system_timezone( + datetime.datetime.fromtimestamp(dt, tz=datetime.timezone.utc) + ).strftime("%a %b %d %H:%M %Y") def get_encrytion_status(path): if "-enc" in path: diff --git a/frappe/email/receive.py b/frappe/email/receive.py index c1be68803c..514db646f2 100644 --- a/frappe/email/receive.py +++ b/frappe/email/receive.py @@ -389,7 +389,7 @@ class Email: if self.mail["Date"]: try: utc = email.utils.mktime_tz(email.utils.parsedate_tz(self.mail["Date"])) - utc_dt = datetime.datetime.utcfromtimestamp(utc) + utc_dt = datetime.datetime.fromtimestamp(utc, tz=datetime.timezone.utc) self.date = convert_utc_to_system_timezone(utc_dt).strftime("%Y-%m-%d %H:%M:%S") except Exception: self.date = now() diff --git a/frappe/model/document.py b/frappe/model/document.py index 0f12928524..a7c820cea4 100644 --- a/frappe/model/document.py +++ b/frappe/model/document.py @@ -1314,6 +1314,8 @@ class Document(BaseDocument, DocRef): def clear_cache(self): frappe.clear_document_cache(self.doctype, self.name) + frappe.db.after_commit.add(lambda: frappe.clear_document_cache(self.doctype, self.name)) + frappe.db.after_rollback.add(lambda: frappe.clear_document_cache(self.doctype, self.name)) def reset_seen(self): """Clear _seen property and set current user as seen""" diff --git a/frappe/permissions.py b/frappe/permissions.py index b502470965..a05ba784bd 100644 --- a/frappe/permissions.py +++ b/frappe/permissions.py @@ -853,12 +853,20 @@ def check_doctype_permission(doctype: str, ptype: str = "read") -> None: frappe.local.message_log = _message_log -def handle_does_not_exist_error(e: Exception) -> Exception: - if isinstance(e, frappe.DoesNotExistError) and (doctype := getattr(e, "doctype", None)): - try: - check_doctype_permission(doctype) +def handle_does_not_exist_error(fn): + """ + Decorator to override DoesNotExistError when handling exceptions. + Requires the first argument to be an Exception. + """ - except frappe.PermissionError as _e: - return _e + @functools.wraps(fn) + def wrapper(e, *args, **kwargs): + if isinstance(e, frappe.DoesNotExistError) and (doctype := getattr(e, "doctype", None)): + try: + check_doctype_permission(doctype) + except frappe.PermissionError as _e: + return fn(_e, *args, **kwargs) - return e + return fn(e, *args, **kwargs) + + return wrapper diff --git a/frappe/public/js/frappe/form/grid_row.js b/frappe/public/js/frappe/form/grid_row.js index 27972efc74..3b6fee1ede 100644 --- a/frappe/public/js/frappe/form/grid_row.js +++ b/frappe/public/js/frappe/form/grid_row.js @@ -1005,7 +1005,7 @@ export default class GridRow { .data("df", df) .appendTo(this.row) .on("click", function (event) { - if (df.fieldtype === "Link") { + if (df.fieldtype === "Link" || df.fieldtype === "Dynamic Link") { frappe.utils.sleep(500).then(() => { let element_position = event.target.getBoundingClientRect(); $(this) diff --git a/frappe/website/serve.py b/frappe/website/serve.py index 3df257aa25..61d77e59e6 100644 --- a/frappe/website/serve.py +++ b/frappe/website/serve.py @@ -20,18 +20,21 @@ def get_response(path=None, http_status_code=200) -> Response: return renderer_instance.render() except Exception as e: - e = handle_does_not_exist_error(e) + return handle_exception(e, endpoint, path, http_status_code) - if isinstance(e, frappe.Redirect): - return RedirectPage(endpoint or path, e.http_status_code).render() - if isinstance(e, frappe.PermissionError): - return NotPermittedPage(endpoint, http_status_code, exception=e).render() +@handle_does_not_exist_error +def handle_exception(e, endpoint, path, http_status_code): + if isinstance(e, frappe.Redirect): + return RedirectPage(endpoint or path, e.http_status_code).render() - if isinstance(e, frappe.PageDoesNotExistError): - return NotFoundPage(endpoint, http_status_code).render() + if isinstance(e, frappe.PermissionError): + return NotPermittedPage(endpoint, http_status_code, exception=e).render() - return ErrorPage(exception=e).render() + if isinstance(e, frappe.PageDoesNotExistError): + return NotFoundPage(endpoint, http_status_code).render() + + return ErrorPage(exception=e).render() def get_response_content(path=None, http_status_code=200) -> str: diff --git a/frappe/website/website_generator.py b/frappe/website/website_generator.py index 038f22d4bd..17d2a6f1bb 100644 --- a/frappe/website/website_generator.py +++ b/frappe/website/website_generator.py @@ -70,6 +70,9 @@ class WebsiteGenerator(Document): super().clear_cache() clear_cache(self.route) + frappe.db.after_commit.add(lambda: clear_cache(self.route)) + frappe.db.after_rollback.add(lambda: clear_cache(self.route)) + def scrub(self, text): return cleanup_page_name(text).replace("_", "-") diff --git a/frappe/www/contact.py b/frappe/www/contact.py index 1d6db31f68..c9a43c7d7a 100644 --- a/frappe/www/contact.py +++ b/frappe/www/contact.py @@ -6,7 +6,7 @@ from contextlib import suppress import frappe from frappe import _ from frappe.rate_limiter import rate_limit -from frappe.utils import validate_email_address +from frappe.utils import escape_html, validate_email_address sitemap = 1 @@ -30,6 +30,8 @@ def get_context(context): def send_message(sender, message, subject="Website Query"): sender = validate_email_address(sender, throw=True) + message = escape_html(message) + with suppress(frappe.OutgoingEmailError): if forward_to_email := frappe.db.get_single_value("Contact Us Settings", "forward_to_email"): frappe.sendmail(recipients=forward_to_email, reply_to=sender, content=message, subject=subject)