""" New to iteration 2, this router module manages the creation and deletion of form fields that are associated with form templates, allowing dynamic rendering of ticket submission forms. """ from fastapi import ( APIRouter, Request, Depends, ) from fastapi import status as http_status from fastapi.responses import RedirectResponse, JSONResponse from fastapi.templating import Jinja2Templates from sqlalchemy.orm import Session from sqlalchemy import func #import database connection modules and models from ..db.db_connect import get_db from ..models.form_templates import FormTemplate from ..models.form_fields import FormField, FieldType router = APIRouter() templates = Jinja2Templates(directory="app/frontend/templates") #field delete logic @router.get("/form_fields/{field_id}/delete") @router.post("/form_fields/{field_id}/delete") async def delete_form_field( field_id: int, request: Request, db: Session = Depends(get_db), ): """Delete a specific form field by id and redirect back to its template.""" field = db.query(FormField).filter(FormField.id == field_id).first() if not field: return RedirectResponse("/form_menu", status_code=http_status.HTTP_303_SEE_OTHER) template_id = field.template_id try: db.delete(field) db.commit() except Exception: db.rollback() return RedirectResponse( f"/form_templates/{template_id}", status_code=http_status.HTTP_303_SEE_OTHER ) # router returning all fields for a given form template as json response @router.get("/api/form_templates/{template_id}/fields") def get_form_template_fields(template_id: int, db: Session = Depends(get_db)): # query template by id template = db.query(FormTemplate).filter(FormTemplate.id == template_id).first() # error handling for missing template if not template: return JSONResponse({"fields": []}) #query fields associated with the template fields = ( db.query(FormField) .filter(FormField.template_id == template_id) .order_by(FormField.position.asc(), FormField.id.asc()) .all() ) # assign context to payload payload = [ { "id": f.id, "question_text": f.question_text, "type": f.type, "required": bool(f.required), "position": f.position, } for f in fields ] # return json response with fields fir rendering return JSONResponse({"fields": payload}) #router defining field creation logic using a post method @router.post("/form_templates/{template_id}/fields") async def add_form_field( template_id: int, request: Request, db: Session = Depends(get_db), ): # query template by id tpl = db.query(FormTemplate).filter(FormTemplate.id == template_id).first() # error handling for missing template if not tpl: return RedirectResponse("/form_menu", status_code=http_status.HTTP_303_SEE_OTHER) form = await request.form() #format default input data question_text = (form.get("question_text") or "").strip() type_value = (form.get("type") or FieldType.TEXT.value).strip() # checkbox handling for required field #default is false is_required = False try: values = form.getlist("required") except Exception: values = [form.get("required")] for v in values: if str(v).lower() == "true": is_required = True break # if question text input is empty redirect back to template edit page if not question_text: return RedirectResponse( f"/form_templates/{template_id}", status_code=http_status.HTTP_303_SEE_OTHER ) allowed_types = {t.value for t in FieldType} if type_value not in allowed_types: type_value = FieldType.TEXT.value # variable defining the position of the new field next_pos = ( db.query(func.coalesce(func.max(FormField.position), -1)) .filter(FormField.template_id == template_id) .scalar() ) # increment position by 1 try: next_pos = int(next_pos) + 1 except Exception: next_pos = 0 # create new field instance new_field = FormField( template_id=template_id, question_text=question_text, type=type_value, required=bool(is_required), position=next_pos, ) # add and commit new field to database db.add(new_field) try: db.commit() except Exception: db.rollback() # redirect back to the template edit page return RedirectResponse( f"/form_templates/{template_id}", status_code=http_status.HTTP_303_SEE_OTHER )