diff --git a/.env b/.env
index 8d7fbd5..b9e2bf0 100644
--- a/.env
+++ b/.env
@@ -1,3 +1,3 @@
-DB_NAME=haikal_db
-DB_USER=faheed
-DB_PASSWORD=Faheed@215
\ No newline at end of file
+DB_NAME=norahuniversity
+DB_USER=norahuniversity
+DB_PASSWORD=norahuniversity
\ No newline at end of file
diff --git a/static/image/applicant/__init__.py b/static/image/applicant/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/static/image/applicant/admin.py b/static/image/applicant/admin.py
deleted file mode 100644
index 8c38f3f..0000000
--- a/static/image/applicant/admin.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from django.contrib import admin
-
-# Register your models here.
diff --git a/static/image/applicant/apps.py b/static/image/applicant/apps.py
deleted file mode 100644
index 27badf7..0000000
--- a/static/image/applicant/apps.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from django.apps import AppConfig
-
-
-class ApplicantConfig(AppConfig):
- default_auto_field = 'django.db.models.BigAutoField'
- name = 'applicant'
diff --git a/static/image/applicant/forms.py b/static/image/applicant/forms.py
deleted file mode 100644
index 5c5b0b5..0000000
--- a/static/image/applicant/forms.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from django import forms
-from .models import ApplicantForm, FormField
-
-class ApplicantFormCreateForm(forms.ModelForm):
- class Meta:
- model = ApplicantForm
- fields = ['name', 'description']
- widgets = {
- 'name': forms.TextInput(attrs={'class': 'form-control'}),
- 'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
- }
-
-class FormFieldForm(forms.ModelForm):
- class Meta:
- model = FormField
- fields = ['label', 'field_type', 'required', 'help_text', 'choices']
- widgets = {
- 'label': forms.TextInput(attrs={'class': 'form-control'}),
- 'field_type': forms.Select(attrs={'class': 'form-control'}),
- 'help_text': forms.Textarea(attrs={'class': 'form-control', 'rows': 2}),
- 'choices': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Option1, Option2, Option3'}),
- }
\ No newline at end of file
diff --git a/static/image/applicant/forms_builder.py b/static/image/applicant/forms_builder.py
deleted file mode 100644
index c3a43e7..0000000
--- a/static/image/applicant/forms_builder.py
+++ /dev/null
@@ -1,49 +0,0 @@
-from django import forms
-from .models import FormField
-
-# applicant/forms_builder.py
-def create_dynamic_form(form_instance):
- fields = {}
-
- for field in form_instance.fields.all():
- field_kwargs = {
- 'label': field.label,
- 'required': field.required,
- 'help_text': field.help_text
- }
-
- # Use stable field_name instead of database ID
- field_key = field.field_name
-
- if field.field_type == 'text':
- fields[field_key] = forms.CharField(**field_kwargs)
- elif field.field_type == 'email':
- fields[field_key] = forms.EmailField(**field_kwargs)
- elif field.field_type == 'phone':
- fields[field_key] = forms.CharField(**field_kwargs)
- elif field.field_type == 'number':
- fields[field_key] = forms.IntegerField(**field_kwargs)
- elif field.field_type == 'date':
- fields[field_key] = forms.DateField(**field_kwargs)
- elif field.field_type == 'textarea':
- fields[field_key] = forms.CharField(
- widget=forms.Textarea,
- **field_kwargs
- )
- elif field.field_type in ['select', 'radio']:
- choices = [(c.strip(), c.strip()) for c in field.choices.split(',') if c.strip()]
- if not choices:
- choices = [('', '---')]
- if field.field_type == 'select':
- fields[field_key] = forms.ChoiceField(choices=choices, **field_kwargs)
- else:
- fields[field_key] = forms.ChoiceField(
- choices=choices,
- widget=forms.RadioSelect,
- **field_kwargs
- )
- elif field.field_type == 'checkbox':
- field_kwargs['required'] = False
- fields[field_key] = forms.BooleanField(**field_kwargs)
-
- return type('DynamicApplicantForm', (forms.Form,), fields)
\ No newline at end of file
diff --git a/static/image/applicant/migrations/0001_initial.py b/static/image/applicant/migrations/0001_initial.py
deleted file mode 100644
index d7437c3..0000000
--- a/static/image/applicant/migrations/0001_initial.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# Generated by Django 5.2.6 on 2025-10-01 21:41
-
-import django.db.models.deletion
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
- initial = True
-
- dependencies = [
- ('jobs', '0001_initial'),
- ]
-
- operations = [
- migrations.CreateModel(
- name='ApplicantForm',
- fields=[
- ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('name', models.CharField(help_text="Form version name (e.g., 'Version A', 'Version B' etc)", max_length=200)),
- ('description', models.TextField(blank=True, help_text='Optional description of this form version')),
- ('is_active', models.BooleanField(default=False, help_text='Only one form can be active per job')),
- ('created_at', models.DateTimeField(auto_now_add=True)),
- ('updated_at', models.DateTimeField(auto_now=True)),
- ('job_posting', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='applicant_forms', to='jobs.jobposting')),
- ],
- options={
- 'verbose_name': 'Application Form',
- 'verbose_name_plural': 'Application Forms',
- 'ordering': ['-created_at'],
- 'unique_together': {('job_posting', 'name')},
- },
- ),
- migrations.CreateModel(
- name='ApplicantSubmission',
- fields=[
- ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('submitted_at', models.DateTimeField(auto_now_add=True)),
- ('data', models.JSONField()),
- ('ip_address', models.GenericIPAddressField(blank=True, null=True)),
- ('score', models.FloatField(default=0, help_text='Ranking score for the applicant submission')),
- ('form', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='applicant.applicantform')),
- ('job_posting', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='jobs.jobposting')),
- ],
- options={
- 'verbose_name': 'Applicant Submission',
- 'verbose_name_plural': 'Applicant Submissions',
- 'ordering': ['-submitted_at'],
- },
- ),
- migrations.CreateModel(
- name='FormField',
- fields=[
- ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
- ('label', models.CharField(max_length=255)),
- ('field_type', models.CharField(choices=[('text', 'Text'), ('email', 'Email'), ('phone', 'Phone'), ('number', 'Number'), ('date', 'Date'), ('select', 'Dropdown'), ('radio', 'Radio Buttons'), ('checkbox', 'Checkbox'), ('textarea', 'Paragraph Text'), ('file', 'File Upload'), ('image', 'Image Upload')], max_length=20)),
- ('required', models.BooleanField(default=True)),
- ('help_text', models.TextField(blank=True)),
- ('choices', models.TextField(blank=True, help_text='Comma-separated options for select/radio fields')),
- ('order', models.IntegerField(default=0)),
- ('field_name', models.CharField(blank=True, max_length=100)),
- ('form', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='fields', to='applicant.applicantform')),
- ],
- options={
- 'verbose_name': 'Form Field',
- 'verbose_name_plural': 'Form Fields',
- 'ordering': ['order'],
- },
- ),
- ]
diff --git a/static/image/applicant/migrations/__init__.py b/static/image/applicant/migrations/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/static/image/applicant/models.py b/static/image/applicant/models.py
deleted file mode 100644
index 6b35d2f..0000000
--- a/static/image/applicant/models.py
+++ /dev/null
@@ -1,144 +0,0 @@
-# models.py
-from django.db import models
-from django.core.exceptions import ValidationError
-from jobs.models import JobPosting
-from django.urls import reverse
-
-class ApplicantForm(models.Model):
- """Multiple dynamic forms per job posting, only one active at a time"""
- job_posting = models.ForeignKey(
- JobPosting,
- on_delete=models.CASCADE,
- related_name='applicant_forms'
- )
- name = models.CharField(
- max_length=200,
- help_text="Form version name (e.g., 'Version A', 'Version B' etc)"
- )
- description = models.TextField(
- blank=True,
- help_text="Optional description of this form version"
- )
- is_active = models.BooleanField(
- default=False,
- help_text="Only one form can be active per job"
- )
- created_at = models.DateTimeField(auto_now_add=True)
- updated_at = models.DateTimeField(auto_now=True)
-
- class Meta:
- unique_together = ('job_posting', 'name')
- ordering = ['-created_at']
- verbose_name = "Application Form"
- verbose_name_plural = "Application Forms"
-
- def __str__(self):
- status = "(Active)" if self.is_active else "(Inactive)"
- return f"{self.name} for {self.job_posting.title} {status}"
-
- def clean(self):
- """Ensure only one active form per job"""
- if self.is_active:
- existing_active = self.job_posting.applicant_forms.filter(
- is_active=True
- ).exclude(pk=self.pk)
- if existing_active.exists():
- raise ValidationError(
- "Only one active application form is allowed per job posting."
- )
- super().clean()
-
- def activate(self):
- """Set this form as active and deactivate others"""
- self.is_active = True
- self.save()
- # Deactivate other forms
- self.job_posting.applicant_forms.exclude(pk=self.pk).update(
- is_active=False
- )
-
- def get_public_url(self):
- """Returns the public application URL for this job's active form"""
- return reverse('applicant:apply_form', args=[self.job_posting.internal_job_id])
-
-
-class FormField(models.Model):
- FIELD_TYPES = [
- ('text', 'Text'),
- ('email', 'Email'),
- ('phone', 'Phone'),
- ('number', 'Number'),
- ('date', 'Date'),
- ('select', 'Dropdown'),
- ('radio', 'Radio Buttons'),
- ('checkbox', 'Checkbox'),
- ('textarea', 'Paragraph Text'),
- ('file', 'File Upload'),
- ('image', 'Image Upload'),
- ]
-
- form = models.ForeignKey(
- ApplicantForm,
- related_name='fields',
- on_delete=models.CASCADE
- )
- label = models.CharField(max_length=255)
- field_type = models.CharField(max_length=20, choices=FIELD_TYPES)
- required = models.BooleanField(default=True)
- help_text = models.TextField(blank=True)
- choices = models.TextField(
- blank=True,
- help_text="Comma-separated options for select/radio fields"
- )
- order = models.IntegerField(default=0)
- field_name = models.CharField(max_length=100, blank=True)
-
- class Meta:
- ordering = ['order']
- verbose_name = "Form Field"
- verbose_name_plural = "Form Fields"
-
- def __str__(self):
- return f"{self.label} ({self.field_type}) in {self.form.name}"
-
- def save(self, *args, **kwargs):
- if not self.field_name:
- # Create a stable field name from label (e.g., "Full Name" → "full_name")
- import re
- # Use Unicode word characters, including Arabic, for field_name
- self.field_name = re.sub(
- r'[^\w]+',
- '_',
- self.label.lower(),
- flags=re.UNICODE
- ).strip('_')
- # Ensure uniqueness within the form
- base_name = self.field_name
- counter = 1
- while FormField.objects.filter(
- form=self.form,
- field_name=self.field_name
- ).exists():
- self.field_name = f"{base_name}_{counter}"
- counter += 1
- super().save(*args, **kwargs)
-
-
-class ApplicantSubmission(models.Model):
- job_posting = models.ForeignKey(JobPosting, on_delete=models.CASCADE)
- form = models.ForeignKey(ApplicantForm, on_delete=models.CASCADE)
- submitted_at = models.DateTimeField(auto_now_add=True)
- data = models.JSONField()
- ip_address = models.GenericIPAddressField(null=True, blank=True)
- score = models.FloatField(
- default=0,
- help_text="Ranking score for the applicant submission"
- )
-
- class Meta:
- ordering = ['-submitted_at']
- verbose_name = "Applicant Submission"
- verbose_name_plural = "Applicant Submissions"
-
- def __str__(self):
- return f"Submission for {self.job_posting.title} at {self.submitted_at}"
\ No newline at end of file
diff --git a/static/image/applicant/templates/applicant/apply_form.html b/static/image/applicant/templates/applicant/apply_form.html
deleted file mode 100644
index eae2993..0000000
--- a/static/image/applicant/templates/applicant/apply_form.html
+++ /dev/null
@@ -1,94 +0,0 @@
-{% extends 'base.html' %}
-
-{% block title %}
- Apply: {{ job.title }}
-{% endblock %}
-
-{% block content %}
-
-
-
-
- {# --- 1. Job Header and Overview (Fixed/Static Info) --- #}
-
-
{{ job.title }}
-
-
- Your final step to apply for this position.
-
-
-
-
-
- Department: {{ job.department|default:"Not specified" }}
-
-
-
- Location: {{ job.get_location_display }}
-
-
-
- Type: {{ job.get_job_type_display }} • {{ job.get_workplace_type_display }}
-
-
-
-
- {# --- 2. Application Form Section --- #}
-
-
Application Details
-
- {% if applicant_form.description %}
-
{{ applicant_form.description }}
- {% endif %}
-
-
-
-
-
-
-
-
-
-
-{% endblock %}
\ No newline at end of file
diff --git a/static/image/applicant/templates/applicant/create_form.html b/static/image/applicant/templates/applicant/create_form.html
deleted file mode 100644
index e1c616a..0000000
--- a/static/image/applicant/templates/applicant/create_form.html
+++ /dev/null
@@ -1,68 +0,0 @@
-{% extends 'base.html' %}
-
-{% block title %}
- Define Form for {{ job.title }}
-{% endblock %}
-
-{% block content %}
-
-
-
-
-
-
-
- 🛠️ New Application Form Configuration
-
-
-
- You are creating a new form structure for job: {{ job.title }}
-
-
-
-
-
-
-
-{% endblock %}
\ No newline at end of file
diff --git a/static/image/applicant/templates/applicant/edit_form.html b/static/image/applicant/templates/applicant/edit_form.html
deleted file mode 100644
index e9ad842..0000000
--- a/static/image/applicant/templates/applicant/edit_form.html
+++ /dev/null
@@ -1,1020 +0,0 @@
-{% extends 'base.html' %}
-{% load static i18n %}
-
-{% block title %}
-Edit Application Form - {{ applicant_form.name }}
-{% endblock %}
-
-{% block customCSS %}
-
-{% endblock %}
-
-{% block content %}
-
- {% if messages %}
-
- {% for message in messages %}
- -
- {% if message.tags == "success" %}
- ✓
- {% else %}
- !
- {% endif %}
- {{ message }}
-
- {% endfor %}
-
- {% endif %}
-
-
-
-
-
-
-
-{% endblock %}
-
-{% block customJS %}
-
-{% endblock %}
\ No newline at end of file
diff --git a/static/image/applicant/templates/applicant/job_forms_list.html b/static/image/applicant/templates/applicant/job_forms_list.html
deleted file mode 100644
index 7c7253f..0000000
--- a/static/image/applicant/templates/applicant/job_forms_list.html
+++ /dev/null
@@ -1,103 +0,0 @@
-{% extends 'base.html' %}
-
-{% block title %}
- Manage Forms | {{ job.title }}
-{% endblock %}
-
-{% block content %}
-
-
-
-
-
-
-
- Application Forms for "{{ job.title }}"
-
-
- Internal Job ID: **{{ job.internal_job_id }}**
-
-
-
- {# Primary Action Button using the theme color #}
-
- Create New Form
-
-
-
- {% if forms %}
-
-
- {% for form in forms %}
-
- {# Custom styling based on active state #}
-
-
- {# Left Section: Form Details #}
-
-
- {{ form.name }}
-
-
- {# Status Badge #}
- {% if form.is_active %}
-
- Active Form
-
- {% else %}
-
- Inactive
-
- {% endif %}
-
-
- {{ form.description|default:"— No description provided. —" }}
-
-
-
- {# Right Section: Actions #}
-
-
- {% endfor %}
-
-
- {% else %}
-
-
-
No application forms have been created yet for this job.
-
Click the button above to define a new form structure.
-
- {% endif %}
-
-
-
-
-
-{% endblock %}
\ No newline at end of file
diff --git a/static/image/applicant/templates/applicant/review_job_detail.html b/static/image/applicant/templates/applicant/review_job_detail.html
deleted file mode 100644
index 44414b3..0000000
--- a/static/image/applicant/templates/applicant/review_job_detail.html
+++ /dev/null
@@ -1,129 +0,0 @@
-{% extends "base.html" %}
-
-{% block title %}{{ job.title }} - University ATS{% endblock %}
-
-{% block content %}
-
-
-
-
-
-
-
-
- Department: {{ job.department|default:"Not specified" }}
-
-
- Position Number: {{ job.position_number|default:"Not specified" }}
-
-
-
-
-
- Job Type: {{ job.get_job_type_display }}
-
-
- Workplace: {{ job.get_workplace_type_display }}
-
-
-
-
-
- Location: {{ job.get_location_display }}
-
-
- Created By: {{ job.created_by|default:"Not specified" }}
-
-
-
- {% if job.salary_range %}
-
-
- Salary Range: {{ job.salary_range }}
-
-
- {% endif %}
-
- {% if job.start_date %}
-
-
- Start Date: {{ job.start_date }}
-
-
- {% endif %}
-
- {% if job.application_deadline %}
-
-
- Application Deadline: {{ job.application_deadline }}
- {% if job.is_expired %}
- EXPIRED
- {% endif %}
-
-
- {% endif %}
-
-
- {% if job.description %}
-
-
Description
-
{{ job.description|linebreaks }}
-
- {% endif %}
-
- {% if job.qualifications %}
-
-
Qualifications
-
{{ job.qualifications|linebreaks }}
-
- {% endif %}
-
- {% if job.benefits %}
-
-
Benefits
-
{{ job.benefits|linebreaks }}
-
- {% endif %}
-
- {% if job.application_instructions %}
-
-
Application Instructions
-
{{ job.application_instructions|linebreaks }}
-
- {% endif %}
-
-
-
-
-
-
-
-
-
-
-
-
-
Review the job details on the left, then click the button below to submit your application.
-
- Apply for this Position
-
-
- You'll be redirected to our secure application form where you can upload your resume and provide additional details.
-
-
-
-
-
-
-
-
-
-
-{% endblock %}
\ No newline at end of file
diff --git a/static/image/applicant/templates/applicant/thank_you.html b/static/image/applicant/templates/applicant/thank_you.html
deleted file mode 100644
index b93c945..0000000
--- a/static/image/applicant/templates/applicant/thank_you.html
+++ /dev/null
@@ -1,35 +0,0 @@
-{% extends 'base.html' %}
-{% block title %}Application Submitted - {{ job.title }}{% endblock %}
-{% block content %}
-
-
-
-
-
Thank You!
-
Your application has been submitted successfully
-
-
-
Position: {{ job.title }}
-
Job ID: {{ job.internal_job_id }}
-
Department: {{ job.department|default:"Not specified" }}
- {% if job.application_deadline %}
-
Application Deadline: {{ job.application_deadline|date:"F j, Y" }}
- {% endif %}
-
-
-
- We appreciate your interest in joining our team. Our hiring team will review your application
- and contact you if there's a potential match for this position.
-
-
- {% comment %}
{% endcomment %}
-
-
-{% endblock %}
\ No newline at end of file
diff --git a/static/image/applicant/templatetags/__init__.py b/static/image/applicant/templatetags/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/static/image/applicant/templatetags/mytags.py b/static/image/applicant/templatetags/mytags.py
deleted file mode 100644
index b60911d..0000000
--- a/static/image/applicant/templatetags/mytags.py
+++ /dev/null
@@ -1,24 +0,0 @@
-import json
-from django import template
-
-register = template.Library()
-
-@register.filter(name='from_json')
-def from_json(json_string):
- """
- Safely loads a JSON string into a Python object (list or dict).
- """
- try:
- # The JSON string comes from the context and needs to be parsed
- return json.loads(json_string)
- except (TypeError, json.JSONDecodeError):
- # Handle cases where the string is invalid or None/empty
- return []
-
-
-@register.filter(name='split')
-def split_string(value, key=None):
- """Splits a string by the given key (default is space)."""
- if key is None:
- return value.split()
- return value.split(key)
\ No newline at end of file
diff --git a/static/image/applicant/templatetags/signals.py b/static/image/applicant/templatetags/signals.py
deleted file mode 100644
index 8d5f22f..0000000
--- a/static/image/applicant/templatetags/signals.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# from django.db.models.signals import post_save
-# from django.dispatch import receiver
-# from . import models
-#
-# @receiver(post_save, sender=models.Candidate)
-# def parse_resume(sender, instance, created, **kwargs):
-# if instance.resume and not instance.summary:
-# from .utils import extract_summary_from_pdf,match_resume_with_job_description
-# summary = extract_summary_from_pdf(instance.resume.path)
-# if 'error' not in summary:
-# instance.summary = summary
-# instance.save()
-#
-# # match_resume_with_job_description
\ No newline at end of file
diff --git a/static/image/applicant/tests.py b/static/image/applicant/tests.py
deleted file mode 100644
index 7ce503c..0000000
--- a/static/image/applicant/tests.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from django.test import TestCase
-
-# Create your tests here.
diff --git a/static/image/applicant/urls.py b/static/image/applicant/urls.py
deleted file mode 100644
index fa4fe8a..0000000
--- a/static/image/applicant/urls.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from django.urls import path
-from . import views
-
-app_name = 'applicant'
-
-urlpatterns = [
- # Form Management
- path('job//forms/', views.job_forms_list, name='job_forms_list'),
- path('job//forms/create/', views.create_form_for_job, name='create_form'),
- path('form//edit/', views.edit_form, name='edit_form'),
- path('field//delete/', views.delete_field, name='delete_field'),
- path('form//activate/', views.activate_form, name='activate_form'),
-
- # Public Application
- path('apply//', views.apply_form_view, name='apply_form'),
- path('review/job/detail//',views.review_job_detail, name="review_job_detail"),
- path('apply//thank-you/', views.thank_you_view, name='thank_you'),
-]
\ No newline at end of file
diff --git a/static/image/applicant/utils.py b/static/image/applicant/utils.py
deleted file mode 100644
index 4901d72..0000000
--- a/static/image/applicant/utils.py
+++ /dev/null
@@ -1,34 +0,0 @@
-import os
-import fitz # PyMuPDF
-import spacy
-import requests
-from recruitment import models
-from django.conf import settings
-
-nlp = spacy.load("en_core_web_sm")
-
-def extract_text_from_pdf(pdf_path):
- text = ""
- with fitz.open(pdf_path) as doc:
- for page in doc:
- text += page.get_text()
- return text
-
-def extract_summary_from_pdf(pdf_path):
- if not os.path.exists(pdf_path):
- return {'error': 'File not found'}
-
- text = extract_text_from_pdf(pdf_path)
- doc = nlp(text)
- summary = {
- 'name': doc.ents[0].text if doc.ents else '',
- 'skills': [chunk.text for chunk in doc.noun_chunks if len(chunk.text.split()) > 1],
- 'summary': text[:500]
- }
- return summary
-
-def match_resume_with_job_description(resume, job_description,prompt=""):
- resume_doc = nlp(resume)
- job_doc = nlp(job_description)
- similarity = resume_doc.similarity(job_doc)
- return similarity
\ No newline at end of file
diff --git a/static/image/applicant/views.py b/static/image/applicant/views.py
deleted file mode 100644
index 2cb4dc3..0000000
--- a/static/image/applicant/views.py
+++ /dev/null
@@ -1,175 +0,0 @@
-# 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})
\ No newline at end of file