Some checks failed
Frontend / Unit Tests & Coverage (push) Has been skipped
Regenerate POT file (translatable strings) / Regenerate POT file (develop) (push) Failing after 1m13s
Regenerate POT file (translatable strings) / Regenerate POT file (main-hotfix) (push) Failing after 6s
Server / Tests (frappe ${{ matrix.frappe-branch }}) (push) Has been skipped
Server / Resolve frappe matrix (push) Failing after 1s
Frontend / Lint (push) Failing after 1s
Frontend / Production Build (push) Failing after 1s
Server / Coverage Wrap Up (push) Has been skipped
Frontend / Coverage Wrap Up (push) Has been skipped
118 lines
3.8 KiB
Python
118 lines
3.8 KiB
Python
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors
|
|
# GNU GPLv3 License. See license.txt
|
|
|
|
import frappe
|
|
from frappe import _, get_installed_apps
|
|
from frappe.integrations.frappe_providers.frappecloud_billing import is_fc_site
|
|
from frappe.translate import get_messages_for_boot, get_translated_doctypes
|
|
from frappe.utils import cint, get_system_timezone
|
|
from frappe.utils.telemetry import capture
|
|
|
|
no_cache = 1
|
|
|
|
|
|
def get_context():
|
|
from crm.api import check_app_permission
|
|
|
|
if not check_app_permission():
|
|
frappe.throw(_("You do not have permission to access Frappe CRM"), frappe.PermissionError)
|
|
|
|
redirect_to_set_password()
|
|
|
|
frappe.db.commit()
|
|
context = frappe._dict()
|
|
context.boot = get_boot()
|
|
if frappe.session.user != "Guest":
|
|
capture("active_site", "crm")
|
|
return context
|
|
|
|
|
|
def redirect_to_set_password():
|
|
"""Send users who have no password of their own to the set password page.
|
|
|
|
The Frappe Cloud site owner arrives on a session handed over by the
|
|
dashboard and never sets a password, so they cannot get back in once it
|
|
expires. Invited users are already routed here by `accept_invitation`; this
|
|
covers everyone else, on the same page.
|
|
"""
|
|
from crm.api.user import needs_password_setup
|
|
|
|
if not needs_password_setup():
|
|
return
|
|
|
|
user = frappe.get_doc("User", frappe.session.user)
|
|
link = user._reset_password()
|
|
|
|
# this is a GET request, which is rolled back unless a commit is requested
|
|
frappe.local.flags.commit = True
|
|
|
|
frappe.local.flags.redirect_location = link
|
|
|
|
# 302, not the 301 default: v16+ lets the browser cache a permanent redirect,
|
|
# which would keep sending the user to a spent key long after they set a
|
|
# password. Set on the instance — v15's `Redirect` takes no constructor arg.
|
|
redirect = frappe.Redirect()
|
|
redirect.http_status_code = 302
|
|
raise redirect
|
|
|
|
|
|
@frappe.whitelist(methods=["POST"], allow_guest=True)
|
|
def get_context_for_dev():
|
|
if not frappe.conf.developer_mode:
|
|
frappe.throw(_("This method is only meant for developer mode"))
|
|
return get_boot()
|
|
|
|
|
|
def get_boot():
|
|
return frappe._dict(
|
|
{
|
|
"frappe_version": frappe.__version__,
|
|
"default_route": get_default_route(),
|
|
"site_name": frappe.local.site,
|
|
"socketio_port": frappe.conf.socketio_port,
|
|
"read_only_mode": frappe.flags.read_only,
|
|
"csrf_token": frappe.sessions.get_csrf_token(),
|
|
"setup_complete": cint(frappe.get_system_settings("setup_complete")),
|
|
"sysdefaults": frappe.defaults.get_defaults(),
|
|
"is_demo_site": frappe.conf.get("is_demo_site"),
|
|
"demo_data_created": frappe.db.get_default("crm_demo_data_created") == "1",
|
|
"is_fc_site": is_fc_site(),
|
|
"translated_doctypes": get_translated_doctypes(),
|
|
"translated_messages": get_messages_for_boot(),
|
|
"timezone": {
|
|
"system": get_system_timezone(),
|
|
"user": frappe.db.get_value("User", frappe.session.user, "time_zone")
|
|
or get_system_timezone(),
|
|
},
|
|
"state_options": get_state_options(),
|
|
}
|
|
)
|
|
|
|
|
|
def get_state_options() -> dict[str, list[str]]:
|
|
"""Country -> list of states, so the frontend can render a state dropdown.
|
|
|
|
Sourced from India Compliance's own constant when that app is installed, so the
|
|
options stay in sync with the desk. Returns an empty map (state field stays free
|
|
text) on any failure.
|
|
|
|
This runs inside ``get_boot``, so it must never raise — a failure here would break
|
|
the whole CRM page load. ``get_installed_apps`` can return `[]` or raise in
|
|
unauthenticated/boot contexts (notably on v15), so the lookup is wrapped defensively.
|
|
"""
|
|
try:
|
|
if "india_compliance" not in get_installed_apps():
|
|
return {}
|
|
|
|
from india_compliance.gst_india.constants import INDIAN_STATES
|
|
|
|
return {"India": list(INDIAN_STATES)}
|
|
except Exception:
|
|
# Degrade silently to free-text: this runs in boot, so the except branch
|
|
# must not do anything that can itself raise (e.g. logging to a missing dir).
|
|
return {}
|
|
|
|
|
|
def get_default_route():
|
|
return "/crm"
|