345 lines
10 KiB
Python
345 lines
10 KiB
Python
from functools import lru_cache
|
|
|
|
import frappe
|
|
from frappe import _
|
|
from frappe.geo.country_info import get_all as get_all_countries
|
|
from frappe.model import DEFAULT_FIELDS, display_fieldtypes
|
|
from frappe.utils import get_datetime, now_datetime, today
|
|
from frappe.utils.data import cstr, sbool
|
|
|
|
LAYOUT_FIELDTYPES = set(display_fieldtypes)
|
|
|
|
EVENT_PROPOSAL_EXCLUDE_FIELDS = DEFAULT_FIELDS | {
|
|
"naming_series",
|
|
"amended_from",
|
|
"host",
|
|
"host_company",
|
|
"host_company_logo",
|
|
"additional_notes",
|
|
"status",
|
|
"submitted_by",
|
|
}
|
|
|
|
STANDARD_EXCLUDE_FIELDS = DEFAULT_FIELDS | {
|
|
"additional_fields",
|
|
"event",
|
|
"section_break_additional",
|
|
"submitted_by",
|
|
"status",
|
|
}
|
|
|
|
|
|
@frappe.whitelist(allow_guest=True) # nosemgrep: frappe-semgrep-rules.rules.security.guest-whitelisted-method
|
|
def get_dial_codes() -> list:
|
|
return _get_dial_codes()
|
|
|
|
|
|
@lru_cache(maxsize=1)
|
|
def _get_dial_codes() -> list:
|
|
data = get_all_countries()
|
|
codes = []
|
|
seen = set()
|
|
for country in sorted(data):
|
|
info = data[country]
|
|
isd = info.get("isd", "")
|
|
code = (info.get("code") or "").upper()
|
|
if isd and isd not in seen:
|
|
codes.append({"country": country, "code": code, "dial_code": isd})
|
|
seen.add(isd)
|
|
return codes
|
|
|
|
|
|
def get_form_fields(doctype: str, exclude_fields: set) -> list:
|
|
meta = frappe.get_meta(doctype)
|
|
fields = []
|
|
for df in meta.fields:
|
|
if df.fieldname in exclude_fields:
|
|
continue
|
|
if df.fieldtype in LAYOUT_FIELDTYPES:
|
|
continue
|
|
if df.hidden:
|
|
continue
|
|
if df.read_only:
|
|
continue
|
|
default_value = df.default
|
|
if default_value:
|
|
if default_value == "Today":
|
|
default_value = today()
|
|
elif default_value == "Now":
|
|
default_value = cstr(now_datetime())
|
|
elif default_value.startswith("eval:") or default_value.startswith("%"):
|
|
default_value = None
|
|
|
|
field_data = {
|
|
"fieldname": df.fieldname,
|
|
"fieldtype": df.fieldtype,
|
|
"label": df.label or df.fieldname,
|
|
"options": df.options,
|
|
"reqd": df.reqd,
|
|
"default": default_value,
|
|
"description": df.description,
|
|
}
|
|
if df.fieldtype == "Link" and df.options:
|
|
link_values = frappe.get_all(
|
|
df.options,
|
|
fields=["name"],
|
|
limit_page_length=0,
|
|
order_by="name asc",
|
|
)
|
|
field_data["link_options"] = [d.name for d in link_values]
|
|
if df.fieldtype == "Table" and df.options:
|
|
child_meta = frappe.get_meta(df.options)
|
|
child_fields = []
|
|
for child_df in child_meta.fields:
|
|
if child_df.fieldtype in LAYOUT_FIELDTYPES:
|
|
continue
|
|
if child_df.hidden:
|
|
continue
|
|
child_fields.append(
|
|
{
|
|
"fieldname": child_df.fieldname,
|
|
"fieldtype": child_df.fieldtype,
|
|
"label": child_df.label or child_df.fieldname,
|
|
"options": child_df.options,
|
|
"reqd": child_df.reqd,
|
|
}
|
|
)
|
|
field_data["child_fields"] = child_fields
|
|
fields.append(field_data)
|
|
return fields
|
|
|
|
|
|
def validate_custom_form(event_route: str, form_route: str):
|
|
event_name = frappe.get_cached_value("Pohodex Event Manager Event", {"route": event_route}, "name")
|
|
if not event_name:
|
|
frappe.throw(_("Event not found"), frappe.DoesNotExistError)
|
|
event_doc = frappe.get_cached_doc("Pohodex Event Manager Event", event_name)
|
|
|
|
if not event_doc.is_published:
|
|
frappe.throw(_("Event not found"), frappe.DoesNotExistError)
|
|
|
|
form_row = None
|
|
for row in event_doc.custom_forms:
|
|
if row.route == form_route and row.publish:
|
|
form_row = row
|
|
break
|
|
|
|
if not form_row:
|
|
frappe.throw(_("This form is not available for this event"), frappe.DoesNotExistError)
|
|
|
|
return event_doc, form_row
|
|
|
|
|
|
def get_auto_set_fields(form_doctype: str):
|
|
meta = frappe.get_meta(form_doctype)
|
|
auto_set = {}
|
|
for df in meta.fields:
|
|
if df.fieldname == "event" and df.fieldtype == "Link":
|
|
auto_set["event"] = "from_route"
|
|
elif df.fieldname == "submitted_by" and df.fieldtype == "Link":
|
|
auto_set["submitted_by"] = "session_user"
|
|
return auto_set
|
|
|
|
|
|
@frappe.whitelist(allow_guest=True) # nosemgrep: frappe-semgrep-rules.rules.security.guest-whitelisted-method
|
|
def get_custom_form_data(event_route: str, form_route: str) -> dict:
|
|
event_doc, form_row = validate_custom_form(event_route, form_route)
|
|
form_doctype = form_row.form_doctype
|
|
allow_guest_submission = sbool(event_doc.allow_guest_booking)
|
|
|
|
if not allow_guest_submission and frappe.session.user == "Guest":
|
|
frappe.throw(_("Please log in to submit this form"), frappe.AuthenticationError)
|
|
|
|
event_data = {
|
|
"name": event_doc.name,
|
|
"title": event_doc.title,
|
|
"route": event_doc.route,
|
|
"banner_image": event_doc.banner_image,
|
|
"start_date": event_doc.start_date,
|
|
"end_date": event_doc.end_date,
|
|
"start_time": event_doc.start_time,
|
|
"end_time": event_doc.end_time,
|
|
"time_zone": event_doc.time_zone,
|
|
"venue": event_doc.venue,
|
|
"medium": event_doc.medium,
|
|
"short_description": event_doc.short_description,
|
|
}
|
|
|
|
closed = False
|
|
if form_row.auto_close_at and get_datetime(form_row.auto_close_at) < now_datetime():
|
|
closed = True
|
|
|
|
if closed:
|
|
return {
|
|
"form_fields": [],
|
|
"custom_fields": [],
|
|
"form_title": form_doctype,
|
|
"event": event_data,
|
|
"closed": True,
|
|
"closed_title": form_row.closed_title or _("Submissions Closed"),
|
|
"closed_message": form_row.closed_message or _("Submissions for this form have closed."),
|
|
"success_title": "",
|
|
"success_message": "",
|
|
}
|
|
|
|
auto_set = get_auto_set_fields(form_doctype)
|
|
exclude_fields = STANDARD_EXCLUDE_FIELDS | set(auto_set.keys())
|
|
form_fields = get_form_fields(form_doctype, exclude_fields)
|
|
|
|
form_doctype_meta = frappe.get_meta(form_doctype)
|
|
custom_fields = []
|
|
if form_doctype_meta.has_field("additional_fields"):
|
|
custom_fields = frappe.get_all(
|
|
"Pohodex Event Manager Custom Field",
|
|
filters={
|
|
"event": event_doc.name,
|
|
"applied_to": "Custom Form",
|
|
"custom_form_doctype": form_doctype,
|
|
"enabled": 1,
|
|
},
|
|
fields=[
|
|
"label",
|
|
"fieldname",
|
|
"fieldtype",
|
|
"options",
|
|
"mandatory",
|
|
"placeholder",
|
|
"default_value",
|
|
"order",
|
|
],
|
|
order_by="order asc",
|
|
)
|
|
|
|
return {
|
|
"form_fields": form_fields,
|
|
"custom_fields": custom_fields,
|
|
"form_title": form_doctype_meta.name,
|
|
"event": event_data,
|
|
"closed": False,
|
|
"closed_title": form_row.closed_title or _("Submissions Closed"),
|
|
"closed_message": form_row.closed_message or _("Submissions for this form have closed."),
|
|
"success_title": form_row.success_title or _("Thank you!"),
|
|
"success_message": form_row.success_message or "",
|
|
}
|
|
|
|
|
|
@frappe.whitelist(allow_guest=True) # nosemgrep: frappe-semgrep-rules.rules.security.guest-whitelisted-method
|
|
def submit_custom_form(
|
|
event_route: str, form_route: str, data: dict | str, custom_fields_data: dict | str | None = None
|
|
) -> None:
|
|
event_doc, form_row = validate_custom_form(event_route, form_route)
|
|
form_doctype = form_row.form_doctype
|
|
|
|
if not event_doc.allow_guest_booking and frappe.session.user == "Guest":
|
|
frappe.throw(_("Please login to submit this form"), frappe.AuthenticationError)
|
|
|
|
if form_row.auto_close_at and get_datetime(form_row.auto_close_at) < now_datetime():
|
|
frappe.throw(_("Submissions for this form have closed."))
|
|
|
|
data = frappe.parse_json(data) or {}
|
|
custom_fields_data = frappe.parse_json(custom_fields_data) or {}
|
|
|
|
auto_set = get_auto_set_fields(form_doctype)
|
|
exclude_fields = STANDARD_EXCLUDE_FIELDS | set(auto_set.keys())
|
|
|
|
doc_data = {"doctype": form_doctype}
|
|
|
|
for field, source in auto_set.items():
|
|
if source == "from_route":
|
|
doc_data[field] = event_doc.name
|
|
elif source == "session_user":
|
|
doc_data[field] = frappe.session.user
|
|
|
|
allowed_fieldnames = {f["fieldname"] for f in get_form_fields(form_doctype, exclude_fields)}
|
|
for fieldname, value in data.items():
|
|
if fieldname in allowed_fieldnames:
|
|
doc_data[fieldname] = value
|
|
|
|
meta = frappe.get_meta(form_doctype)
|
|
for df in meta.fields:
|
|
if df.fieldtype == "Table" and df.fieldname not in exclude_fields:
|
|
if df.fieldname in data and isinstance(data[df.fieldname], list):
|
|
doc_data[df.fieldname] = data[df.fieldname]
|
|
|
|
doc = frappe.get_doc(doc_data)
|
|
|
|
if custom_fields_data and meta.has_field("additional_fields"):
|
|
custom_field_definitions = frappe.get_all(
|
|
"Pohodex Event Manager Custom Field",
|
|
filters={
|
|
"event": event_doc.name,
|
|
"applied_to": "Custom Form",
|
|
"custom_form_doctype": form_doctype,
|
|
"enabled": 1,
|
|
},
|
|
fields=["fieldname", "label", "fieldtype"],
|
|
)
|
|
allowed_custom = {cf["fieldname"]: cf for cf in custom_field_definitions}
|
|
|
|
for fieldname, value in custom_fields_data.items():
|
|
if fieldname in allowed_custom and value not in (None, ""):
|
|
cf = allowed_custom[fieldname]
|
|
doc.append(
|
|
"additional_fields",
|
|
{
|
|
"label": cf["label"],
|
|
"fieldname": fieldname,
|
|
"fieldtype": cf["fieldtype"],
|
|
"value": cstr(value),
|
|
},
|
|
)
|
|
|
|
doc.insert(ignore_permissions=True)
|
|
|
|
|
|
def validate_event_proposal_settings():
|
|
settings = frappe.get_cached_doc("Pohodex Event Manager Settings")
|
|
if not settings.accept_event_proposals:
|
|
frappe.throw(_("Event Proposals are not being accepted"), frappe.DoesNotExistError)
|
|
|
|
if not settings.allow_guest_event_proposals and frappe.session.user == "Guest":
|
|
frappe.throw(_("Please log in to submit a proposal"), frappe.AuthenticationError)
|
|
|
|
return settings
|
|
|
|
|
|
@frappe.whitelist(allow_guest=True) # nosemgrep: frappe-semgrep-rules.rules.security.guest-whitelisted-method
|
|
def get_event_proposal_form_data() -> dict:
|
|
settings = validate_event_proposal_settings()
|
|
form_fields = get_form_fields("Event Proposal", EVENT_PROPOSAL_EXCLUDE_FIELDS)
|
|
|
|
return {
|
|
"form_fields": form_fields,
|
|
"form_title": _("Event Proposal"),
|
|
"banner_title": settings.event_proposal_banner_title or _("Propose an Event"),
|
|
"success_title": settings.event_proposal_success_title or _("Thank you!"),
|
|
"success_message": settings.event_proposal_success_message or "",
|
|
}
|
|
|
|
|
|
@frappe.whitelist(allow_guest=True) # nosemgrep: frappe-semgrep-rules.rules.security.guest-whitelisted-method
|
|
def submit_event_proposal(data: dict | str) -> None:
|
|
validate_event_proposal_settings()
|
|
|
|
data = frappe.parse_json(data) or {}
|
|
|
|
doc_data = {"doctype": "Event Proposal"}
|
|
|
|
if frappe.session.user != "Guest":
|
|
doc_data["submitted_by"] = frappe.session.user
|
|
|
|
allowed_fieldnames = {
|
|
f["fieldname"] for f in get_form_fields("Event Proposal", EVENT_PROPOSAL_EXCLUDE_FIELDS)
|
|
}
|
|
for fieldname, value in data.items():
|
|
if fieldname in allowed_fieldnames:
|
|
doc_data[fieldname] = value
|
|
|
|
meta = frappe.get_meta("Event Proposal")
|
|
for df in meta.fields:
|
|
if df.fieldtype == "Table" and df.fieldname not in EVENT_PROPOSAL_EXCLUDE_FIELDS:
|
|
if df.fieldname in data and isinstance(data[df.fieldname], list):
|
|
doc_data[df.fieldname] = data[df.fieldname]
|
|
|
|
frappe.get_doc(doc_data).insert(ignore_permissions=True)
|