seitime-frappe/frappe/utils/messages.py
2025-03-10 21:02:13 +05:30

169 lines
4.3 KiB
Python

import functools
import sys
from typing import Literal
import frappe
from frappe import _
from frappe.utils import strip_html_tags
from frappe.utils.data import safe_decode
_strip_html_tags = functools.lru_cache(maxsize=1024)(strip_html_tags)
def msgprint(
msg: str,
title: str | None = None,
raise_exception: bool | type[Exception] | Exception = False,
as_table: bool = False,
as_list: bool = False,
indicator: Literal["blue", "green", "orange", "red", "yellow"] | None = None,
alert: bool = False,
primary_action: dict | None = None,
is_minimizable: bool = False,
wide: bool = False,
*,
realtime=False,
) -> None:
"""Print a message to the user (via HTTP response).
Messages are sent in the `__server_messages` property in the
response JSON and shown in a pop-up / modal.
:param msg: Message.
:param title: [optional] Message title. Default: "Message".
:param raise_exception: [optional] Raise given exception and show message.
:param as_table: [optional] If `msg` is a list of lists, render as HTML table.
:param as_list: [optional] If `msg` is a list, render as un-ordered list.
:param primary_action: [optional] Bind a primary server/client side action.
:param is_minimizable: [optional] Allow users to minimize the modal
:param wide: [optional] Show wide modal
:param realtime: Publish message immediately using websocket.
"""
import inspect
msg = safe_decode(msg)
out = frappe._dict(message=msg)
def _raise_exception():
if raise_exception:
if inspect.isclass(raise_exception) and issubclass(raise_exception, Exception):
exc = raise_exception(msg)
elif isinstance(raise_exception, Exception):
exc = raise_exception
exc.args = (msg,)
else:
exc = frappe.ValidationError(msg)
if out.__frappe_exc_id:
exc.__frappe_exc_id = out.__frappe_exc_id
raise exc
if frappe.flags.mute_messages:
_raise_exception()
return
if as_table and type(msg) in (list, tuple):
out.as_table = 1
if as_list and type(msg) in (list, tuple):
out.as_list = 1
if sys.stdin and sys.stdin.isatty():
if out.as_list:
msg = [_strip_html_tags(msg) for msg in out.message]
else:
msg = _strip_html_tags(out.message)
if frappe.flags.print_messages and out.message:
print(f"Message: {_strip_html_tags(out.message)}")
out.title = title or _("Message", context="Default title of the message dialog")
if not indicator and raise_exception:
indicator = "red"
if indicator:
out.indicator = indicator
if is_minimizable:
out.is_minimizable = is_minimizable
if alert:
out.alert = 1
if raise_exception:
out.raise_exception = 1
out.__frappe_exc_id = frappe.generate_hash()
if primary_action:
out.primary_action = primary_action
if wide:
out.wide = wide
if realtime:
frappe.publish_realtime(event="msgprint", message=out)
else:
frappe.message_log.append(out)
_raise_exception()
def toast(message: str, indicator: Literal["blue", "green", "orange", "red", "yellow"] | None = None):
msgprint(message, indicator=indicator, alert=True)
def clear_messages():
frappe.local.message_log = []
def get_message_log() -> list[dict]:
return [msg_out for msg_out in frappe.local.message_log]
def clear_last_message():
if len(frappe.local.message_log) > 0:
frappe.local.message_log = frappe.local.message_log[:-1]
def throw(
msg: str,
exc: type[Exception] | Exception = frappe.ValidationError,
title: str | None = None,
is_minimizable: bool = False,
wide: bool = False,
as_list: bool = False,
primary_action=None,
) -> None:
"""Throw execption and show message (`msgprint`).
:param msg: Message.
:param exc: Exception class. Default `frappe.ValidationError`
:param title: [optional] Message title. Default: "Message".
:param is_minimizable: [optional] Allow users to minimize the modal
:param wide: [optional] Show wide modal
:param as_list: [optional] If `msg` is a list, render as un-ordered list.
:param primary_action: [optional] Bind a primary server/client side action.
"""
msgprint(
msg,
raise_exception=exc,
title=title,
indicator="red",
is_minimizable=is_minimizable,
wide=wide,
as_list=as_list,
primary_action=primary_action,
)
def throw_permission_error():
throw(_("Not permitted"), frappe.PermissionError)
__all__ = [
"clear_last_message",
"clear_messages",
"get_message_log",
"msgprint",
"throw",
"throw_permission_error",
"toast",
]