# SPDX-FileCopyrightText: 2024-2025 Helmholtz-Zentrum Dresden-Rossendorf e.V (HZDR)
# SPDX-License-Identifier: Apache-2.0
import logging
from bson import ObjectId
from flask import (
Blueprint,
current_app,
flash,
jsonify,
redirect,
render_template,
request,
session,
url_for,
)
from flask_login import login_required
from labfrog.campaign_layout_setup import (
build_campaign_layout_setup_context,
handle_campaign_layout_setup_submission,
)
from labfrog.db import get_db
from labfrog.form_feedback import current_username, flash_form_errors
from labfrog.forms import DynamicForm, FieldSelectionForm
from labfrog.helpers.choices import normalize_choice_value, ordered_unique_strings
from labfrog.helpers.layout import (
_ensure_shot_identity_fields,
available_campaign_names,
build_layout_inventory,
field_layout_filter,
find_mode_layout_doc,
get_campaign_layout_doc,
paired_mode,
resolve_layout_selections,
split_layout_picker_fields,
upsert_field_layout_doc,
)
from labfrog.helpers.urls import get_safe_return_url
from labfrog.request_state import refresh_diagnostic_choice_cache
blueprint = Blueprint("field_selection", __name__)
def _default_edit_password():
password = (current_app.config.get("DEFAULT_EDIT_PASSWORD") or "").strip()
return password or None
def _demo_edit_password():
if not current_app.config.get("DEMO_MODE"):
return None
password = (current_app.config.get("DEMO_EDIT_PASSWORD") or "").strip()
return password or None
def _normalize_demo_name(value: str | None) -> str:
if not value:
return ""
text = str(value).strip()
if len(text) >= 2 and text[0] == text[-1] and text[0] in {'"', "'"}:
return text[1:-1].strip()
return text
def _password_for_layout(layout_name: str | None) -> str | None:
normalized = _normalize_demo_name(layout_name)
if normalized == "DEFAULT":
return _default_edit_password()
demo_default_layout = (current_app.config.get("DEMO_DEFAULT_LAYOUT") or "").strip()
if not current_app.config.get("DEMO_MODE") or not demo_default_layout:
return None
if normalized == _normalize_demo_name(demo_default_layout):
return _demo_edit_password()
return None
def _layout_is_demo_locked(layout_name: str | None) -> bool:
return bool(_password_for_layout(layout_name))
def _demo_password_valid(request_obj, layout_name: str | None = None) -> bool:
password = _password_for_layout(layout_name)
if not password:
return True
provided = None
if request_obj.is_json:
payload = request_obj.get_json(silent=True) or {}
provided = payload.get("demo_edit_password")
if provided is None:
provided = request_obj.form.get("demo_edit_password")
if provided is None:
provided = request_obj.args.get("demo_edit_password")
return provided == password
def _campaign_choices() -> list[str]:
"""Return available campaign names for layout mapping."""
return available_campaign_names()
def _non_selectable_layout_fields(mode: str) -> set[str]:
base_fields = {
"Campaign",
"target",
"material",
"thickness",
"notes",
"mode",
"date_time",
"update_date_time",
"comments",
}
if mode == "set":
base_fields.update({"set_number", "set_length", "shot_number_list"})
else:
base_fields.add("shot_number")
return base_fields
def _filter_layout_picker_fields(
all_fields: list[str],
visible_fields: list[str],
always_include: list[str] | None,
mode: str,
) -> tuple[list[str], list[str]]:
excluded = set(always_include or []) | _non_selectable_layout_fields(mode)
filtered_all = [field for field in all_fields if field not in excluded]
filtered_visible = [field for field in visible_fields if field not in excluded]
return filtered_all, filtered_visible
[docs]
@blueprint.route("/campaign_layout_setup", methods=["GET", "POST"])
@login_required
def campaign_layout_setup():
"""Guide users when a campaign has no mapped form layout yet."""
mode = (
"set"
if request.values.get("mode") == "set" or session.get("mode") == "set"
else "shot"
)
campaign = normalize_choice_value(
request.values.get("campaign") or session.get("selected_campaign") or ""
)
next_url = get_safe_return_url(
request.values.get("next"),
url_for("add_entry.add_entry" if mode == "shot" else "edit_entry.edit_entry"),
)
session["selected_campaign"] = campaign
session["mode"] = mode
PARAMETERS_DB = current_app.config["MONGODB_COLLECTION_FOR_SETTINGS"]
parameters_collection = get_db()[PARAMETERS_DB]
existing_layout = get_campaign_layout_doc(parameters_collection, mode, campaign)
if existing_layout and existing_layout.get("layout_name"):
return redirect(next_url)
if request.method == "POST":
response = handle_campaign_layout_setup_submission(
parameters_collection, mode, campaign, next_url, request.form
)
if response is not None:
return response
return render_template(
"campaign_layout_setup.html",
active_tab="field_selection",
selected_layout=_get_selected_source_layout(mode),
**build_campaign_layout_setup_context(
parameters_collection, mode, campaign, next_url
),
)
def _diagnostic_names() -> list[str]:
diagnostics_db = get_db()["diagnostics"]
names = {
doc.get("DisplayName")
for doc in diagnostics_db.find({}, {"DisplayName": 1, "_id": 0})
if doc.get("DisplayName")
}
return sorted(names)
def _get_selected_source_layout(mode: str) -> str:
"""Return the shared source field layout for management views."""
return (
session.get("selected_layout")
or session.get(f"selected_source_layout_{mode}")
or session.get(f"selected_source_layout_{paired_mode(mode)}")
or "DEFAULT"
)
def _set_selected_source_layout(mode: str, layout_name: str) -> None:
"""Persist the source field layout as one shared campaign-level selection."""
normalized = layout_name or "DEFAULT"
session["selected_layout"] = normalized
session[f"selected_source_layout_{mode}"] = normalized
session[f"selected_source_layout_{paired_mode(mode)}"] = normalized
def _set_selected_source_layout_pair(
parameters_collection,
*,
mode: str,
layout_name: str,
) -> None:
"""Persist the active layout as the shared selection for both modes."""
del parameters_collection
_set_selected_source_layout(mode, layout_name)
def _resolved_layout_picker_fields(
parameters_collection,
*,
layout_data: dict | None,
mode: str,
all_fields: list[str],
always_include: list[str] | None,
) -> tuple[list[str], list[str]]:
"""Return mode-filtered selected and visible picker fields for one layout."""
if not layout_data:
return [], []
_, _, selected_fields = resolve_layout_selections(layout_data)
if selected_fields:
_, visible_fields = _filter_layout_picker_fields(
list(all_fields), list(selected_fields), always_include, mode
)
elif layout_data.get("layout_name", "DEFAULT") == "DEFAULT":
selected_fields = list(all_fields)
visible_fields = list(all_fields)
else:
visible_fields = []
return selected_fields, visible_fields
def _sync_diagnostics_from_selected(selected_fields):
"""Update diagnostics_only + DIAG_NAMES/TOOLTIPS from selected fields."""
if not selected_fields:
session["diagnostics_only"] = []
return []
diagnostics_db = get_db()["diagnostics"]
diag_names = {
doc.get("DisplayName")
for doc in diagnostics_db.find({}, {"DisplayName": 1, "_id": 0})
if doc.get("DisplayName")
}
diagnostics_only = [
field
for field in ordered_unique_strings(selected_fields)
if field in diag_names
]
session["diagnostics_only"] = diagnostics_only
refresh_diagnostic_choice_cache(diagnostics_only)
return diagnostics_only
def _layout_picker_campaign_choices(
applied_campaigns: list[str] | None = None,
) -> list[str]:
"""Return campaign choices plus any campaigns already bound to the layout."""
return ordered_unique_strings([
"NONE",
*available_campaign_names(applied_campaigns or []),
])
def _field_selection_render_context(
parameters_collection,
*,
form,
all_fields: list[str],
visible_fields: list[str],
selected_layout: str,
picker_selected_layout: str | None = None,
applied_campaigns: list[str],
diag_names: set[str],
campaigns: list[str] | None = None,
setup_wizard: bool = False,
wizard_saved: bool = False,
wizard_next_url: str | None = None,
organize_prompt: bool = False,
organize_prompt_url: str | None = None,
draft_mode: str = "",
):
"""Build the shared template context for the field-selection picker UI."""
mode = session.get("mode", "shot")
available_layouts, layouts = build_layout_inventory(parameters_collection, mode)
protected_layouts = []
if _default_edit_password():
protected_layouts.append("DEFAULT")
demo_default_layout = (current_app.config.get("DEMO_DEFAULT_LAYOUT") or "").strip()
if (
current_app.config.get("DEMO_MODE")
and demo_default_layout
and _demo_edit_password()
):
protected_layouts.append(_normalize_demo_name(demo_default_layout))
return {
"active_tab": "form_layout",
"form": form,
"available_layouts": available_layouts,
"Layouts": layouts,
"selected_layout": selected_layout,
"picker_selected_layout": (
picker_selected_layout
if picker_selected_layout is not None
else selected_layout
),
"applied_campaigns": applied_campaigns,
"campaigns": campaigns or _layout_picker_campaign_choices(applied_campaigns),
"diagnostic_names": sorted(diag_names),
"setup_wizard": setup_wizard,
"wizard_saved": wizard_saved,
"wizard_next_url": wizard_next_url,
"organize_prompt": organize_prompt,
"organize_prompt_url": organize_prompt_url,
"draft_mode": draft_mode,
"layout_picker_label": (
"Start from previously config" if draft_mode == "fresh" else "Choose layout"
),
"layout_picker_placeholder": (
"-- Saved configs --" if draft_mode == "fresh" else "-- Select a Layout --"
),
"layout_picker_help": (
"Optionally preload fields from a saved config before saving this campaign's field layout."
if draft_mode == "fresh"
else "Choose an existing field layout or enter a name to save a new one. Move fields between the lists, then save the field layout."
),
**split_layout_picker_fields(all_fields, visible_fields, diag_names),
"protected_layouts": sorted(set(protected_layouts)),
"layout_password_required": bool(protected_layouts),
}
#######################################################################################################################################
[docs]
@blueprint.route("/field_selection", methods=["GET", "POST"]) # canonical alias
@blueprint.route("/select_fields", methods=["GET", "POST"]) # current public path
@login_required
def field_selection():
"""
Render the layout picker and persist layout field/campaign selections.
"""
SELECTED_FIELDS_LIST = session.get("SELECTED_FIELDS_LIST", [])
visible_fields = list(SELECTED_FIELDS_LIST)
PARAMETERS_DB = current_app.config["MONGODB_COLLECTION_FOR_SETTINGS"]
parameters_collection = get_db()[PARAMETERS_DB]
mode = session.get("mode", "shot")
all_fields = list(DynamicForm.get_all_fields(collection=PARAMETERS_DB, mode=mode))
always_include = session.get("always_include")
all_fields, visible_fields = _filter_layout_picker_fields(
all_fields, visible_fields, always_include, mode
)
diag_names = set(_diagnostic_names())
form = FieldSelectionForm(all_fields=all_fields, selected_fields=visible_fields)
draft_mode = (request.args.get("draft_mode") or "").strip()
draft_layout_name = (request.args.get("draft_layout_name") or "").strip()
draft_campaign = normalize_choice_value(request.args.get("draft_campaign") or "")
draft_source_layout = (request.args.get("draft_source_layout") or "").strip()
setup_wizard = (request.args.get("setup_wizard") or "").strip() == "1"
wizard_saved = (request.args.get("wizard_saved") or "").strip() == "1"
organize_prompt = (request.args.get("organize_prompt") or "").strip() == "1"
selected_layout = draft_layout_name or _get_selected_source_layout(mode)
picker_selected_layout = (
draft_source_layout
if draft_mode == "clone"
else ("" if draft_mode == "fresh" else selected_layout)
)
current_responsible_person = current_username(default="")
if selected_layout != "Default":
form.layout_name.data = selected_layout
form.responsible_person.data = current_responsible_person
layout_data = None
if draft_mode == "clone" and draft_source_layout:
layout_data = find_mode_layout_doc(
parameters_collection, draft_source_layout, mode
)
elif not draft_mode:
layout_data = find_mode_layout_doc(parameters_collection, selected_layout, mode)
applied_campaigns = []
if layout_data:
form.description.data = layout_data.get("description")
form.responsible_person.data = current_responsible_person
selected_parameters, selected_diagnostics, selected_from_layout = (
resolve_layout_selections(layout_data)
)
form.selected_fields.data = selected_from_layout
applied_campaigns = layout_data.get("campaigns") or []
_, visible_fields = _resolved_layout_picker_fields(
parameters_collection,
layout_data=layout_data,
mode=mode,
all_fields=all_fields,
always_include=always_include,
)
if not draft_mode:
session["SELECTED_FIELDS_LIST"] = _ensure_shot_identity_fields(
selected_from_layout
)
session["diagnostics_only"] = list(selected_diagnostics)
_sync_diagnostics_from_selected(session["SELECTED_FIELDS_LIST"])
elif draft_mode == "fresh":
visible_fields = []
form.selected_fields.data = []
form.description.data = ""
if draft_campaign:
applied_campaigns = [draft_campaign]
if "submit" in request.form and form.validate_on_submit():
layout_name = request.form["layout_name"]
form.layout_name.data = layout_name
if _layout_is_demo_locked(layout_name) and not _demo_password_valid(
request, layout_name
):
flash(
f"Layout {layout_name} is protected. Password required to modify.",
"error",
)
return redirect(url_for("field_selection.field_selection"))
form.description.data = request.form.get("description")
form.responsible_person.data = current_responsible_person
selected_parameters = request.form.getlist("selected_parameters")
selected_diagnostics = request.form.getlist("selected_diagnostics")
selected_fields = request.form.getlist("selected_fields")
form.selected_fields.data = selected_fields
applied_campaigns = request.form.getlist("campaigns")
if not applied_campaigns:
flash("Please select at least one campaign.", "error")
return render_template(
"field_selection.html",
**_field_selection_render_context(
parameters_collection,
form=form,
all_fields=all_fields,
visible_fields=selected_fields,
selected_layout=selected_layout,
picker_selected_layout=picker_selected_layout,
applied_campaigns=applied_campaigns,
diag_names=diag_names,
setup_wizard=setup_wizard or draft_mode in {"clone", "fresh"},
wizard_saved=wizard_saved,
draft_mode=draft_mode,
),
)
form.data["selected_fields"] = selected_fields
session["SELECTED_FIELDS_LIST"] = _ensure_shot_identity_fields(selected_fields)
diagnostics_only = _sync_diagnostics_from_selected(
session["SELECTED_FIELDS_LIST"]
)
normalized_diagnostics = selected_diagnostics or diagnostics_only
upsert_field_layout_doc(
parameters_collection,
layout_name=layout_name,
mode=mode,
description=request.form.get("description"),
responsible_person=current_responsible_person,
campaigns=applied_campaigns,
selected_parameters=selected_parameters,
selected_diagnostics=normalized_diagnostics,
)
upsert_field_layout_doc(
parameters_collection,
layout_name=layout_name,
mode=paired_mode(mode),
description=request.form.get("description"),
responsible_person=current_responsible_person,
campaigns=applied_campaigns,
selected_parameters=selected_parameters,
selected_diagnostics=normalized_diagnostics,
)
_set_selected_source_layout_pair(
parameters_collection,
mode=mode,
layout_name=layout_name,
)
session.pop("_flashes", None)
flash(f"Layout {layout_name} saved successfully!", "success")
session["template_selected"] = True
if draft_mode in {"clone", "fresh"} or setup_wizard:
wizard_campaign = (
applied_campaigns[0]
if applied_campaigns
else draft_campaign or session.get("selected_campaign", "")
)
return redirect(
url_for(
"field_selection.field_selection",
setup_wizard="1",
wizard_saved="1",
draft_layout_name=layout_name,
draft_campaign=wizard_campaign,
)
)
prompt_campaign = (
applied_campaigns[0]
if applied_campaigns
else session.get("selected_campaign", "")
)
return redirect(
url_for(
"field_selection.field_selection",
organize_prompt="1",
draft_layout_name=layout_name,
draft_campaign=prompt_campaign,
)
)
flash_form_errors(form, logger=logging.getLogger(__name__))
return render_template(
"field_selection.html",
**_field_selection_render_context(
parameters_collection,
form=form,
all_fields=all_fields,
visible_fields=visible_fields,
selected_layout=selected_layout,
picker_selected_layout=picker_selected_layout,
applied_campaigns=applied_campaigns,
diag_names=diag_names,
setup_wizard=setup_wizard or draft_mode in {"clone", "fresh"},
wizard_saved=wizard_saved,
wizard_next_url=(
url_for(
"organize_sections.organize_sections",
setup_wizard="1",
draft_layout_name=selected_layout,
draft_campaign=(
draft_campaign or session.get("selected_campaign", "")
),
)
if (setup_wizard or draft_mode in {"clone", "fresh"}) and wizard_saved
else None
),
organize_prompt=organize_prompt,
organize_prompt_url=(
url_for(
"organize_sections.organize_sections",
draft_layout_name=selected_layout,
draft_campaign=(
draft_campaign or session.get("selected_campaign", "")
),
)
if organize_prompt
else None
),
draft_mode=draft_mode,
),
)
[docs]
@blueprint.route("/fetch_layout_fields", methods=["POST"]) # legacy alias
@blueprint.route("/select_fields/load_layout", methods=["POST"])
def fetch_layout_fields():
"""
Fetch the field data for a selected layout from the database.
This route retrieves the custom field data associated with a particular layout
selected by the user.
Returns:
jsonify: Returns a JSON representation of the field data for the selected layout.
"""
visible_fields = list(session.get("SELECTED_FIELDS_LIST", []))
mode = session.get("mode", "shot")
PARAMETERS_DB = current_app.config["MONGODB_COLLECTION_FOR_SETTINGS"]
parameters_collection = get_db()[PARAMETERS_DB]
always_include = session.get("always_include", [])
if always_include is None:
base_fields_ions = parameters_collection.find_one({
"layout_name": "DEFAULT",
"mode": mode,
})
always_include = list(base_fields_ions.get("always_include"))
session["always_include"] = always_include
all_fields = list(DynamicForm.get_all_fields(collection=PARAMETERS_DB, mode=mode))
all_fields, visible_fields = _filter_layout_picker_fields(
all_fields, visible_fields, always_include, mode
)
selected_layout = request.form.get("selected_layout")
preview_only = (request.form.get("preview_only") or "").strip() == "1"
layout_data = find_mode_layout_doc(parameters_collection, selected_layout, mode)
if not layout_data:
return jsonify([])
selected_from_layout, visible_fields = _resolved_layout_picker_fields(
parameters_collection,
layout_data=layout_data,
mode=mode,
all_fields=all_fields,
always_include=always_include,
)
# print("all fields to choose from", all_fields)
form = FieldSelectionForm(all_fields=all_fields, selected_fields=visible_fields)
if layout_data:
form.layout_name.data = layout_data.get("layout_name")
form.description.data = layout_data.get("description")
form.responsible_person.data = layout_data.get("responsible_person")
form.selected_fields.data = selected_from_layout
if layout_data:
selected_fields = ordered_unique_strings(visible_fields)
non_selected_fields = [
field
for field in ordered_unique_strings(all_fields)
if field not in selected_fields
]
response_data = {
"layout_name": layout_data.get("layout_name"),
"description": layout_data.get("description"),
"responsible_person": layout_data.get("responsible_person"),
"selected_fields": selected_fields,
"non_selected_fields": non_selected_fields,
"campaigns": layout_data.get("campaigns", []),
}
if not preview_only:
session["SELECTED_FIELDS_LIST"] = _ensure_shot_identity_fields(
selected_fields
)
_sync_diagnostics_from_selected(session["SELECTED_FIELDS_LIST"])
selected_layout = response_data["layout_name"]
_set_selected_source_layout_pair(
parameters_collection,
mode=mode,
layout_name=selected_layout,
)
return jsonify(response_data)
return jsonify([]) # Return an empty list if the layout is not found
[docs]
@blueprint.route("/modify_layout/<layout_id>", methods=["GET", "POST"]) # legacy alias
@blueprint.route("/select_fields/modify_layout/<layout_id>", methods=["GET", "POST"])
def modify_layout(layout_id):
"""
Render and persist edits to an existing saved layout.
"""
SELECTED_FIELDS_LIST = session.get("SELECTED_FIELDS_LIST", [])
visible_fields = SELECTED_FIELDS_LIST
mode = session.get("mode", "shot")
PARAMETERS_DB = current_app.config["MONGODB_COLLECTION_FOR_SETTINGS"]
parameters_collection = get_db()[PARAMETERS_DB]
always_include = session.get("always_include")
if always_include is None:
base_fields_ions = parameters_collection.find_one({
"layout_name": "DEFAULT",
"mode": mode,
})
always_include = list(base_fields_ions.get("always_include"))
session["always_include"] = always_include
all_fields = list(DynamicForm.get_all_fields(collection=PARAMETERS_DB, mode=mode))
all_fields, visible_fields = _filter_layout_picker_fields(
all_fields, visible_fields, always_include, mode
)
layout_data = parameters_collection.find_one({"_id": ObjectId(layout_id)})
selected_layout = request.form.get("selected_layout") or (
layout_data.get("layout_name")
if layout_data is not None
else _get_selected_source_layout(mode)
)
current_responsible_person = current_username(default="")
if layout_data is not None:
_selected_from_layout, visible_fields = _resolved_layout_picker_fields(
parameters_collection,
layout_data=layout_data,
mode=mode,
all_fields=all_fields,
always_include=always_include,
)
else:
visible_fields = all_fields
diag_names = set(_diagnostic_names())
form = FieldSelectionForm(all_fields=all_fields, selected_fields=visible_fields)
if layout_data:
form.layout_name.data = layout_data.get("layout_name")
form.description.data = layout_data.get("description")
form.responsible_person.data = layout_data.get("responsible_person")
form.selected_fields.data = visible_fields
if request.method == "POST" and "submit" in request.form:
if layout_data and _layout_is_demo_locked(layout_data.get("layout_name")):
if not _demo_password_valid(request, layout_data.get("layout_name")):
flash(
f"Layout {layout_data.get('layout_name')} is protected. Password required to modify.",
"error",
)
return redirect(url_for("field_selection.field_selection"))
form.layout_name.data = request.form["layout_name"]
form.description.data = request.form["description"]
form.responsible_person.data = current_responsible_person
selected_parameters = request.form.getlist("selected_parameters")
selected_diagnostics = request.form.getlist("selected_diagnostics")
form.selected_fields.data = request.form.getlist("selected_fields")
applied_campaigns = request.form.getlist("campaigns")
if not applied_campaigns:
flash("Please select at least one campaign.", "error")
return render_template(
"field_selection.html",
**_field_selection_render_context(
parameters_collection,
form=form,
all_fields=all_fields,
visible_fields=form.selected_fields.data,
selected_layout=selected_layout,
picker_selected_layout=selected_layout,
applied_campaigns=applied_campaigns,
diag_names=diag_names,
campaigns=_layout_picker_campaign_choices(applied_campaigns),
),
)
# Get the layout data from the form or request
diagnostics_only = _sync_diagnostics_from_selected(
request.form.getlist("selected_fields")
)
normalized_diagnostics = selected_diagnostics or diagnostics_only
upsert_field_layout_doc(
parameters_collection,
layout_name=request.form["layout_name"],
mode=mode,
description=request.form["description"],
responsible_person=form.responsible_person.data,
campaigns=applied_campaigns,
selected_parameters=selected_parameters,
selected_diagnostics=normalized_diagnostics,
)
upsert_field_layout_doc(
parameters_collection,
layout_name=request.form["layout_name"],
mode=paired_mode(mode),
description=request.form["description"],
responsible_person=form.responsible_person.data,
campaigns=applied_campaigns,
selected_parameters=selected_parameters,
selected_diagnostics=normalized_diagnostics,
)
session["SELECTED_FIELDS_LIST"] = _ensure_shot_identity_fields(
request.form.getlist("selected_fields")
)
selected_layout = request.form["layout_name"]
_set_selected_source_layout_pair(
parameters_collection,
mode=mode,
layout_name=selected_layout,
)
flash(
f"Layout {request.form['layout_name']} modified successfully!",
"success",
)
return redirect(url_for("field_selection.field_selection"))
applied_campaigns = []
if layout_data:
applied_campaigns = layout_data.get("campaigns") or []
campaign_choices = _layout_picker_campaign_choices(applied_campaigns)
return render_template(
"field_selection.html",
**_field_selection_render_context(
parameters_collection,
form=form,
all_fields=all_fields,
visible_fields=visible_fields,
selected_layout=selected_layout,
picker_selected_layout=selected_layout,
applied_campaigns=applied_campaigns,
diag_names=diag_names,
campaigns=campaign_choices,
),
)
[docs]
@blueprint.route(
"/delete_layout/<layout_id>", methods=["POST", "DELETE"]
) # legacy alias
@blueprint.route("/select_fields/delete_layout/<layout_id>", methods=["POST", "DELETE"])
def delete_layout(layout_id):
"""
Delete a specific layout identified by its ID.
The route allows users to delete a specific layout from the database based on its ID.
Returns:
str: A response message indicating the success or failure of the deletion operation.
"""
PARAMETERS_DB = current_app.config["MONGODB_COLLECTION_FOR_SETTINGS"]
parameters_collection = get_db()[PARAMETERS_DB]
if request.method == "POST":
# Convert the layout_id to ObjectId
layout_id = ObjectId(layout_id)
# Delete the layout based on ObjectId
layout_doc = parameters_collection.find_one(
{"_id": layout_id}, {"layout_name": 1}
)
if layout_doc and _layout_is_demo_locked(layout_doc.get("layout_name")):
if not _demo_password_valid(request, layout_doc.get("layout_name")):
return "Password required to delete protected layout", 403
result = parameters_collection.delete_one({"_id": layout_id})
if result.deleted_count == 1:
return "Layout deleted successfully", 200
return "Layout not found", 404
# Handle GET requests or other HTTP methods if needed
return "Method not allowed", 405
#######################################################################################################################################