From 4ff5fb98f807d4bcb5da31715bf809f5dc9da355 Mon Sep 17 00:00:00 2001 From: Adam Wallace Date: Wed, 31 Jul 2024 09:11:40 +0100 Subject: [PATCH 1/2] add CRUD for component, page, form and section config (#13) --- .vscode/launch.json | 30 +- app/blueprints/self_serve/data/data_access.py | 129 ++++- app/blueprints/self_serve/routes.py | 169 +++--- .../{build_form.html => create_form.html} | 2 +- .../{build_page.html => create_page.html} | 2 +- ...add_question.html => create_question.html} | 0 ...build_section.html => create_section.html} | 2 +- .../self_serve/templates/index.html | 20 +- app/db/models/application_config.py | 9 +- app/db/queries/application.py | 282 ++++++++++ build.py | 94 ++++ tests/test_clone.py | 6 + tests/test_db_template_CRUD.py | 521 ++++++++++++++++++ 13 files changed, 1173 insertions(+), 93 deletions(-) rename app/blueprints/self_serve/templates/{build_form.html => create_form.html} (99%) rename app/blueprints/self_serve/templates/{build_page.html => create_page.html} (99%) rename app/blueprints/self_serve/templates/{add_question.html => create_question.html} (100%) rename app/blueprints/self_serve/templates/{build_section.html => create_section.html} (99%) create mode 100644 build.py create mode 100644 tests/test_db_template_CRUD.py diff --git a/.vscode/launch.json b/.vscode/launch.json index 1f849c0..456369a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,15 +10,31 @@ "request": "launch", "module": "flask", "env": { - "FLASK_APP": "app.app.py", - "FLASK_DEBUG": "1" + "FLASK_APP": "app.app.py", + "FLASK_DEBUG": "1" }, - "args": [ - "run", - "--debug" - ], + "args": ["run", "--debug"], "jinja": true, "autoStartBrowser": false - } + }, + { + "name": "Docker Runner FAB", + "type": "python", + "request": "attach", + "connect": { + "host": "localhost", + "port": 5686 + }, + "pathMappings": [ + { + "localRoot": "${workspaceFolder:funding-service-design-fund-application-builder}", + "remoteRoot": "." + } + ], + "justMyCode": true + } + ] + } + ] } diff --git a/app/blueprints/self_serve/data/data_access.py b/app/blueprints/self_serve/data/data_access.py index 853aaff..499aebe 100644 --- a/app/blueprints/self_serve/data/data_access.py +++ b/app/blueprints/self_serve/data/data_access.py @@ -3,6 +3,7 @@ from app.blueprints.self_serve.data.not_a_db import LISTS from app.blueprints.self_serve.data.not_a_db import PAGES from app.blueprints.self_serve.data.not_a_db import SECTIONS +from app.db.queries.application import insert_new_section saved_responses = [] saved_sections = {} @@ -66,20 +67,134 @@ def get_list_by_id(id: str) -> dict: return LISTS.get(id, None) -def save_question(question: dict): +# TODO Implement front end journey that can use the section/form/page/component CRUD operations +# from app.db.queries.application import insert_new_section +# from app.db.queries.application import insert_new_form +# from app.db.queries.application import insert_new_page +# from app.db.queries.application import insert_new_component + + +def save_template_component(component: dict): + """ + TODO: + Save a template component to the database + Parameters: + component: dict The component to save to the database as a template + Returns: + dict The saved component + + component_config = { + "page_id": component.get("page_id"), + "theme_id": component.get("theme_id"), + "title": component.get("title"), + "hint_text": component.get("hint"), + "options": component.get("options"), + "type": component.get("question_type"), + "template_name": component.get("template_name"), + "is_template": True, + "audit_info": component.get("audit_info"), + "page_index": component.get("page_index"), + "theme_index": component.get("theme_index"), + "conditions": component.get("conditions"), + "runner_component_name": component.get("runner_component_name"), + "list_id": component.get("list_id"), + } + + return insert_new_component(component_config) + """ + + # temp in memory solution COMPONENTS.append( { "json_snippet": { "options": {}, - "type": question["question_type"], - "title": question["title"], - "hint": question["hint"], + "type": component["question_type"], + "title": component["title"], + "hint": component["hint"], }, - "id": question["id"], - "builder_display_name": question["builder_display_name"], + "id": component["id"], + "builder_display_name": component["builder_display_name"], } ) -def save_section(section: dict): +def save_template_page(page: dict): + """ + TODO: + Save a template page to the database + Parameters: + page: dict The page to save to the database as a template + Returns: + dict The saved page + + page_config = { + "form_id": page.get("form_id"), + "name_in_apply_json": { + "en": page.get("form_display_name"), + }, + "template_name": page.get("builder_display_name"), + "is_template": True, + "audit_info": page.get("audit_info"), + "form_index": page.get("form_index"), + "display_path": page.get("display_path"), + "controller": page.get("controller"), + } + + return insert_new_page(page_config) + """ + + # Temp in memory solution + PAGES.append(page) + + +def save_template_form(form: dict): + """ + TODO: + Save a template form to the database + Parameters: + form: dict The form to save to the database as a template + Returns: + dict The saved form + form_config = { + "name_in_apply_json": { + "en": form.get("form_title"), + }, + "is_template": True, + "template_name": form.get("builder_display_name"), + "audit_info": form.get("audit_info"), + "section_id": form.get("section_id"), + "section_index": form.get("section_index"), + "runner_publish_name": None # This is a template + } + + insert_new_form(form_config) + """ + + # Temp in memory solution + FORMS.append(form) + + +def save_template_section(section: dict): + """ + TODO: + Save a template section to the database + Parameters: + section: dict The section to save to the database as a template + Returns: + dict The saved section + + section_config = { + "name_in_apply_json": { + "en": section.get("section_display_name"), + }, + "is_template": True, # Assuming this remains a constant value + "template_name": section.get("builder_display_name"), + "description": section.get("description"), + "audit_info": section.get("audit_info"), + } + + return insert_new_section(section_config) + """ + + # Temp in memory solution SECTIONS.append(section) diff --git a/app/blueprints/self_serve/routes.py b/app/blueprints/self_serve/routes.py index 96afaaa..8fb5125 100644 --- a/app/blueprints/self_serve/routes.py +++ b/app/blueprints/self_serve/routes.py @@ -15,10 +15,10 @@ from app.blueprints.self_serve.data.data_access import get_component_by_name from app.blueprints.self_serve.data.data_access import get_pages_to_display_in_builder from app.blueprints.self_serve.data.data_access import get_saved_forms -from app.blueprints.self_serve.data.data_access import save_form -from app.blueprints.self_serve.data.data_access import save_page -from app.blueprints.self_serve.data.data_access import save_question -from app.blueprints.self_serve.data.data_access import save_section +from app.blueprints.self_serve.data.data_access import save_template_component +from app.blueprints.self_serve.data.data_access import save_template_form +from app.blueprints.self_serve.data.data_access import save_template_page +from app.blueprints.self_serve.data.data_access import save_template_section from app.blueprints.self_serve.forms.form_form import FormForm from app.blueprints.self_serve.forms.page_form import PageForm from app.blueprints.self_serve.forms.question_form import QuestionForm @@ -43,38 +43,6 @@ def index(): return render_template("index.html") -@self_serve_bp.route("/build_form", methods=["GET", "POST"]) -def build_form(): - form = FormForm() - if form.validate_on_submit(): - new_form = { - "builder_display_name": form.builder_display_name.data, - "start_page_guidance": form.start_page_guidance.data, - "form_display_name": form.form_title.data, - "id": human_to_kebab_case(form.form_title.data), - "pages": form.selected_pages.data, - } - save_form(new_form) - flash(message=f'Form {new_form["form_display_name"]} was saved') - return redirect(url_for("self_serve_bp.index")) - - available_pages = [] - pages = get_pages_to_display_in_builder() - for page in pages: - questions = [ - x["json_snippet"]["title"] if (x := get_component_by_name(comp_name)) else comp_name - for comp_name in page["component_names"] - ] - available_pages.append( - { - "id": page["id"], - "display_name": page["builder_display_name"], - "hover_info": {"title": page["form_display_name"], "questions": questions}, - } - ) - return render_template("build_form.html", available_pages=available_pages, form=form) - - @self_serve_bp.route("/download_json", methods=["POST"]) def generate_json(): form_json = generate_form_config_from_request()["form_json"] @@ -129,11 +97,40 @@ def view_form_questions(): return render_template("view_questions.html", section_name=form_config["title"], question_html=html) -@self_serve_bp.route("build_section", methods=["GET", "POST"]) -def build_section(): +@self_serve_bp.route("/section_questions", methods=["POST"]) +def view_section_questions(): + # form_config = generate_form_config_from_request() + # print_data = generate_print_data_for_sections( + # sections=[ + # { + # "section_title": form_config["title"], + # "forms": [{"name": form_config["form_id"], "form_data": form_config["form_json"]}], + # } + # ], + # lang="en", + # ) + # html = print_html(print_data) + # return render_template("view_questions.html", section_name=form_config["title"], question_html=html) + pass + + +# CRUD routes + + +# Create routes +@self_serve_bp.route("section", methods=["GET", "POST", "PUT", "DELETE"]) +def section(): + # TODO: Create frontend routes and connect to middleware + if request.method == "GET": + pass + if request.method == "PUT": + pass + if request.method == "DELETE": + pass + form = SectionForm() if form.validate_on_submit(): - save_section(form.as_dict()) + save_template_section(form.as_dict()) flash(message=f"Section '{form['builder_display_name'].data}' was saved") return redirect(url_for("self_serve_bp.index")) @@ -147,22 +144,60 @@ def build_section(): "hover_info": {"title": f["builder_display_name"], "pages": f["pages"]}, } ) - return render_template("build_section.html", available_forms=available_forms, form=form) + # save to db here + return render_template("create_section.html", available_forms=available_forms, form=form) -@self_serve_bp.route("/add_question", methods=["GET", "POST"]) -def add_question(): - form = QuestionForm() - question = form.as_dict() +@self_serve_bp.route("/form", methods=["GET", "POST", "PUT", "DELETE"]) +def form(): + # TODO: Create frontend routes and connect to middleware + if request.method == "GET": + pass + if request.method == "PUT": + pass + if request.method == "DELETE": + pass + + form = FormForm() if form.validate_on_submit(): - save_question(question) - flash(message=f"Question '{question['title']}' was saved") + new_form = { + "builder_display_name": form.builder_display_name.data, + "start_page_guidance": form.start_page_guidance.data, + "form_display_name": form.form_title.data, + "id": human_to_kebab_case(form.form_title.data), + "pages": form.selected_pages.data, + } + save_template_form(new_form) + flash(message=f'Form {new_form["form_display_name"]} was saved') return redirect(url_for("self_serve_bp.index")) - return render_template("add_question.html", form=form) + available_pages = [] + pages = get_pages_to_display_in_builder() + for page in pages: + questions = [ + x["json_snippet"]["title"] if (x := get_component_by_name(comp_name)) else comp_name + for comp_name in page["component_names"] + ] + available_pages.append( + { + "id": page["id"], + "display_name": page["builder_display_name"], + "hover_info": {"title": page["form_display_name"], "questions": questions}, + } + ) + return render_template("create_form.html", available_pages=available_pages, form=form) + + +@self_serve_bp.route("/page", methods=["GET", "POST", "PUT", "DELETE"]) +def page(): + # TODO: Create frontend routes and connect to middleware + if request.method == "GET": + pass + if request.method == "PUT": + pass + if request.method == "DELETE": + pass -@self_serve_bp.route("/build_page", methods=["GET", "POST"]) -def build_page(): form = PageForm() if form.validate_on_submit(): new_page = { @@ -172,7 +207,7 @@ def build_page(): "component_names": form.selected_components.data, "show_in_builder": True, } - save_page(new_page) + save_template_page(new_page) flash(message=f"Page '{form.builder_display_name.data}' was saved") return redirect(url_for("self_serve_bp.index")) components = get_all_components() @@ -184,21 +219,23 @@ def build_page(): } for c in components ] - return render_template("build_page.html", form=form, available_questions=available_questions) + return render_template("create_page.html", form=form, available_questions=available_questions) -@self_serve_bp.route("/section_questions", methods=["POST"]) -def view_section_questions(): - # form_config = generate_form_config_from_request() - # print_data = generate_print_data_for_sections( - # sections=[ - # { - # "section_title": form_config["title"], - # "forms": [{"name": form_config["form_id"], "form_data": form_config["form_json"]}], - # } - # ], - # lang="en", - # ) - # html = print_html(print_data) - # return render_template("view_questions.html", section_name=form_config["title"], question_html=html) - pass +@self_serve_bp.route("/question", methods=["GET", "PUT", "POST", "DELETE"]) +def question(): + # TODO: Create frontend routes and connect to middleware + if request.method == "GET": + pass + if request.method == "PUT": + pass + if request.method == "DELETE": + pass + + form = QuestionForm() + question = form.as_dict() + if form.validate_on_submit(): + save_template_component(question) + flash(message=f"Question '{question['title']}' was saved") + return redirect(url_for("self_serve_bp.index")) + return render_template("create_question.html", form=form) diff --git a/app/blueprints/self_serve/templates/build_form.html b/app/blueprints/self_serve/templates/create_form.html similarity index 99% rename from app/blueprints/self_serve/templates/build_form.html rename to app/blueprints/self_serve/templates/create_form.html index 12ba792..aaa2ce3 100644 --- a/app/blueprints/self_serve/templates/build_form.html +++ b/app/blueprints/self_serve/templates/create_form.html @@ -208,7 +208,7 @@

} function saveForm() { section_form = document.getElementById("form_form") - section_form.setAttribute("action", "{{url_for('self_serve_bp.build_form')}}") + section_form.setAttribute("action", "{{url_for('self_serve_bp.create_form')}}") section_form.submit() } diff --git a/app/blueprints/self_serve/templates/build_page.html b/app/blueprints/self_serve/templates/create_page.html similarity index 99% rename from app/blueprints/self_serve/templates/build_page.html rename to app/blueprints/self_serve/templates/create_page.html index ff95f02..6b73cb5 100644 --- a/app/blueprints/self_serve/templates/build_page.html +++ b/app/blueprints/self_serve/templates/create_page.html @@ -211,7 +211,7 @@

} function savePage() { section_form = document.getElementById("page_form") - section_form.setAttribute("action", "{{url_for('self_serve_bp.build_page')}}") + section_form.setAttribute("action", "{{url_for('self_serve_bp.create_page')}}") section_form.submit() } diff --git a/app/blueprints/self_serve/templates/add_question.html b/app/blueprints/self_serve/templates/create_question.html similarity index 100% rename from app/blueprints/self_serve/templates/add_question.html rename to app/blueprints/self_serve/templates/create_question.html diff --git a/app/blueprints/self_serve/templates/build_section.html b/app/blueprints/self_serve/templates/create_section.html similarity index 99% rename from app/blueprints/self_serve/templates/build_section.html rename to app/blueprints/self_serve/templates/create_section.html index e385e05..d79fd61 100644 --- a/app/blueprints/self_serve/templates/build_section.html +++ b/app/blueprints/self_serve/templates/create_section.html @@ -207,7 +207,7 @@

} function saveSection() { section_form = document.getElementById("section_form") - section_form.setAttribute("action", "{{url_for('self_serve_bp.build_section')}}") + section_form.setAttribute("action", "{{url_for('self_serve_bp.section')}}") section_form.submit() } diff --git a/app/blueprints/self_serve/templates/index.html b/app/blueprints/self_serve/templates/index.html index 212a18f..1c831d4 100644 --- a/app/blueprints/self_serve/templates/index.html +++ b/app/blueprints/self_serve/templates/index.html @@ -19,18 +19,24 @@

What do you want to do?

-

Application Setup

+

Template Setup

Fund Metadata