# applicant/views.py (Updated edit_form function) from django.shortcuts import render, get_object_or_404, redirect from django.contrib import messages from django.http import Http404, JsonResponse # <-- Import JsonResponse from django.views.decorators.csrf import csrf_exempt # <-- Needed for JSON POST if not using FormData import json # <-- Import json from django.db import transaction # <-- Import transaction # (Keep all your existing imports) from .models import ApplicantForm, FormField, ApplicantSubmission from .forms import ApplicantFormCreateForm, FormFieldForm from jobs.models import JobPosting from .forms_builder import create_dynamic_form # ... (Keep all other functions like job_forms_list, create_form_for_job, etc.) # ... # === FORM MANAGEMENT VIEWS === def job_forms_list(request, job_id): """List all forms for a specific job""" job = get_object_or_404(JobPosting, internal_job_id=job_id) forms = job.applicant_forms.all() return render(request, 'applicant/job_forms_list.html', { 'job': job, 'forms': forms }) def create_form_for_job(request, job_id): """Create a new form for a job""" job = get_object_or_404(JobPosting, internal_job_id=job_id) if request.method == 'POST': form = ApplicantFormCreateForm(request.POST) if form.is_valid(): applicant_form = form.save(commit=False) applicant_form.job_posting = job applicant_form.save() messages.success(request, 'Form created successfully!') return redirect('applicant:job_forms_list', job_id=job_id) else: form = ApplicantFormCreateForm() return render(request, 'applicant/create_form.html', { 'job': job, 'form': form }) @transaction.atomic # Ensures all fields are saved or none are def edit_form(request, form_id): """Edit form details and manage fields, including dynamic builder save.""" applicant_form = get_object_or_404(ApplicantForm, id=form_id) job = applicant_form.job_posting if request.method == 'POST': # --- 1. Handle JSON data from the Form Builder (JavaScript) --- if request.content_type == 'application/json': try: field_data = json.loads(request.body) # Clear existing fields for this form applicant_form.fields.all().delete() # Create new fields from the JSON data for field_config in field_data: # Sanitize/ensure required fields are present FormField.objects.create( form=applicant_form, label=field_config.get('label', 'New Field'), field_type=field_config.get('field_type', 'text'), required=field_config.get('required', True), help_text=field_config.get('help_text', ''), choices=field_config.get('choices', ''), order=field_config.get('order', 0), # field_name will be auto-generated/re-generated on save() if needed ) return JsonResponse({'status': 'success', 'message': 'Form structure saved successfully!'}) except json.JSONDecodeError: return JsonResponse({'status': 'error', 'message': 'Invalid JSON data.'}, status=400) except Exception as e: return JsonResponse({'status': 'error', 'message': f'Server error: {str(e)}'}, status=500) # --- 2. Handle standard POST requests (e.g., saving form details) --- elif 'save_form_details' in request.POST: # Changed the button name for clarity form_details = ApplicantFormCreateForm(request.POST, instance=applicant_form) if form_details.is_valid(): form_details.save() messages.success(request, 'Form details updated successfully!') return redirect('applicant:edit_form', form_id=form_id) # Note: The 'add_field' branch is now redundant since we use the builder, # but you can keep it if you want the old manual way too. # --- GET Request (or unsuccessful POST) --- form_details = ApplicantFormCreateForm(instance=applicant_form) # Get initial fields to load into the JS builder initial_fields_json = list(applicant_form.fields.values( 'label', 'field_type', 'required', 'help_text', 'choices', 'order', 'field_name' )) return render(request, 'applicant/edit_form.html', { 'applicant_form': applicant_form, 'job': job, 'form_details': form_details, 'initial_fields_json': json.dumps(initial_fields_json) }) def delete_field(request, field_id): """Delete a form field""" field = get_object_or_404(FormField, id=field_id) form_id = field.form.id field.delete() messages.success(request, 'Field deleted successfully!') return redirect('applicant:edit_form', form_id=form_id) def activate_form(request, form_id): """Activate a form (deactivates others automatically)""" applicant_form = get_object_or_404(ApplicantForm, id=form_id) applicant_form.activate() messages.success(request, f'Form "{applicant_form.name}" is now active!') return redirect('applicant:job_forms_list', job_id=applicant_form.job_posting.internal_job_id) # === PUBLIC VIEWS (for applicants) === def apply_form_view(request, job_id): """Public application form - serves active form""" job = get_object_or_404(JobPosting, internal_job_id=job_id, status='ACTIVE') if job.is_expired(): raise Http404("Application deadline has passed") try: applicant_form = job.applicant_forms.get(is_active=True) except ApplicantForm.DoesNotExist: raise Http404("No active application form configured for this job") DynamicForm = create_dynamic_form(applicant_form) if request.method == 'POST': form = DynamicForm(request.POST) if form.is_valid(): ApplicantSubmission.objects.create( job_posting=job, form=applicant_form, data=form.cleaned_data, ip_address=request.META.get('REMOTE_ADDR') ) return redirect('applicant:thank_you', job_id=job_id) else: form = DynamicForm() return render(request, 'applicant/apply_form.html', { 'form': form, 'job': job, 'applicant_form': applicant_form }) def review_job_detail(request,job_id): """Public job detail view for applicants""" job = get_object_or_404(JobPosting, internal_job_id=job_id, status='ACTIVE') if job.is_expired(): raise Http404("This job posting has expired.") return render(request,'applicant/review_job_detail.html',{'job':job}) def thank_you_view(request, job_id): job = get_object_or_404(JobPosting, internal_job_id=job_id) return render(request, 'applicant/thank_you.html', {'job': job})