few issue resolved and some ui incosistency resolved
This commit is contained in:
parent
22978a4af5
commit
5db2e09ac8
6
.env
6
.env
@ -1,3 +1,3 @@
|
||||
DB_NAME=norahuniversity
|
||||
DB_USER=norahuniversity
|
||||
DB_PASSWORD=norahuniversity
|
||||
DB_NAME=haikal_db
|
||||
DB_USER=faheed
|
||||
DB_PASSWORD=Faheed@215
|
||||
@ -318,14 +318,7 @@ class PersonForm(forms.ModelForm):
|
||||
pass
|
||||
|
||||
return email.strip()
|
||||
def clean_gpa(self):
|
||||
gpa=self.cleaned_data.get('gpa')
|
||||
pass
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class ApplicationForm(forms.ModelForm):
|
||||
@ -786,6 +779,8 @@ class StaffUserCreationForm(UserCreationForm):
|
||||
user.first_name = self.cleaned_data["first_name"]
|
||||
user.last_name = self.cleaned_data["last_name"]
|
||||
user.username = self.generate_username(user.email)
|
||||
user.password1=self.cleaned_data["password1"]
|
||||
user.password2=self.cleaned_data["password2"]
|
||||
user.is_staff = True
|
||||
if commit:
|
||||
user.save()
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.2.7 on 2025-12-11 11:55
|
||||
# Generated by Django 5.2.7 on 2025-12-11 14:18
|
||||
|
||||
import django.contrib.auth.models
|
||||
import django.contrib.auth.validators
|
||||
@ -97,6 +97,8 @@ class Migration(migrations.Migration):
|
||||
('start_time', models.DateTimeField(db_index=True, verbose_name='Start Time')),
|
||||
('duration', models.PositiveIntegerField(verbose_name='Duration (minutes)')),
|
||||
('status', models.CharField(choices=[('waiting', 'Waiting'), ('started', 'Started'), ('ended', 'Ended'), ('cancelled', 'Cancelled')], db_index=True, default='waiting', max_length=20)),
|
||||
('cancelled_at', models.DateTimeField(blank=True, null=True, verbose_name='Cancelled At')),
|
||||
('cancelled_reason', models.TextField(blank=True, null=True, verbose_name='Cancellation Reason')),
|
||||
('meeting_id', models.CharField(blank=True, max_length=50, null=True, unique=True, verbose_name='External Meeting ID')),
|
||||
('password', models.CharField(blank=True, max_length=20, null=True)),
|
||||
('zoom_gateway_response', models.JSONField(blank=True, null=True)),
|
||||
@ -189,7 +191,7 @@ class Migration(migrations.Migration):
|
||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
||||
('first_name', secured_fields.fields.EncryptedCharField(blank=True, max_length=150, verbose_name='first name')),
|
||||
('user_type', models.CharField(choices=[('staff', 'Staff'), ('agency', 'Agency'), ('candidate', 'Candidate')], default='staff', max_length=20, verbose_name='User Type')),
|
||||
('user_type', models.CharField(choices=[('staff', 'Staff'), ('agency', 'Agency'), ('candidate', 'Candidate')], db_index=True, default='staff', max_length=20, verbose_name='User Type')),
|
||||
('phone', secured_fields.fields.EncryptedCharField(blank=True, null=True, verbose_name='Phone')),
|
||||
('profile_image', models.ImageField(blank=True, null=True, upload_to='profile_pic/', validators=[recruitment.validators.validate_image_size], verbose_name='Profile Image')),
|
||||
('designation', models.CharField(blank=True, max_length=100, null=True, verbose_name='Designation')),
|
||||
@ -586,7 +588,7 @@ class Migration(migrations.Migration):
|
||||
('phone', secured_fields.fields.EncryptedCharField(blank=True, null=True, verbose_name='Phone')),
|
||||
('date_of_birth', models.DateField(blank=True, null=True, verbose_name='Date of Birth')),
|
||||
('gender', models.CharField(blank=True, choices=[('M', 'Male'), ('F', 'Female')], max_length=1, null=True, verbose_name='Gender')),
|
||||
('gpa', models.DecimalField(decimal_places=2, help_text='GPA must be between 0 and 4.', max_digits=3, verbose_name='GPA')),
|
||||
('gpa', models.DecimalField(decimal_places=2, help_text='GPA must be between 0 and 4.', max_digits=3, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(4)], verbose_name='GPA')),
|
||||
('national_id', secured_fields.fields.EncryptedCharField(help_text='Enter the national id or iqama number')),
|
||||
('nationality', django_countries.fields.CountryField(blank=True, max_length=2, null=True, verbose_name='Nationality')),
|
||||
('address', models.TextField(blank=True, null=True, verbose_name='Address')),
|
||||
|
||||
@ -1,199 +0,0 @@
|
||||
# Generated by Django 6.0 on 2025-12-10 21:04
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('recruitment', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='formfield',
|
||||
options={'ordering': ['order']},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='formstage',
|
||||
options={'ordering': ['order']},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='formtemplate',
|
||||
options={'ordering': ['-created_at']},
|
||||
),
|
||||
migrations.RemoveIndex(
|
||||
model_name='formtemplate',
|
||||
name='recruitment_created_c21775_idx',
|
||||
),
|
||||
migrations.RemoveIndex(
|
||||
model_name='formtemplate',
|
||||
name='recruitment_is_acti_ae5efb_idx',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='formfield',
|
||||
old_name='required_message',
|
||||
new_name='error_message',
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='formfield',
|
||||
unique_together={('stage', 'order')},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='formfield',
|
||||
name='help_text',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='formfield',
|
||||
name='max_date',
|
||||
field=models.DateField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='formfield',
|
||||
name='min_date',
|
||||
field=models.DateField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='field_type',
|
||||
field=models.CharField(choices=[('text', 'Text Input'), ('email', 'Email'), ('phone', 'Phone'), ('textarea', 'Text Area'), ('file', 'File Upload'), ('date', 'Date Picker'), ('select', 'Dropdown'), ('radio', 'Radio Buttons'), ('checkbox', 'Checkboxes'), ('number', 'Number')], max_length=20),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='file_types',
|
||||
field=models.CharField(blank=True, default='.pdf,.doc,.docx,.jpg,.jpeg,.png', max_length=200),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='is_predefined',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='label',
|
||||
field=models.CharField(max_length=200),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='max_file_size',
|
||||
field=models.PositiveIntegerField(default=5, help_text='Maximum file size in MB'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='max_files',
|
||||
field=models.PositiveIntegerField(default=1),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='max_length',
|
||||
field=models.PositiveIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='min_length',
|
||||
field=models.PositiveIntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='multiple_files',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='options',
|
||||
field=models.JSONField(blank=True, default=list),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='order',
|
||||
field=models.PositiveIntegerField(default=0),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='placeholder',
|
||||
field=models.CharField(blank=True, max_length=200),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='required',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='validation_pattern',
|
||||
field=models.CharField(blank=True, choices=[('', 'None'), ('email', 'Email'), ('phone', 'Phone'), ('url', 'URL'), ('number', 'Number'), ('alpha', 'Letters Only'), ('alphanum', 'Letters & Numbers'), ('custom', 'Custom Pattern')], max_length=50),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formstage',
|
||||
name='is_predefined',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formstage',
|
||||
name='name',
|
||||
field=models.CharField(max_length=200),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formstage',
|
||||
name='order',
|
||||
field=models.PositiveIntegerField(default=0),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formtemplate',
|
||||
name='created_at',
|
||||
field=models.DateTimeField(auto_now_add=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formtemplate',
|
||||
name='created_by',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formtemplate',
|
||||
name='description',
|
||||
field=models.TextField(blank=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formtemplate',
|
||||
name='is_active',
|
||||
field=models.BooleanField(default=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formtemplate',
|
||||
name='name',
|
||||
field=models.CharField(max_length=200),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formtemplate',
|
||||
name='slug',
|
||||
field=models.SlugField(blank=True, unique=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formtemplate',
|
||||
name='updated_at',
|
||||
field=models.DateTimeField(auto_now=True),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='formstage',
|
||||
unique_together={('template', 'order')},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='formfield',
|
||||
name='is_required',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='formfield',
|
||||
name='min_file_size',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='formfield',
|
||||
name='min_image_height',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='formfield',
|
||||
name='min_image_width',
|
||||
),
|
||||
]
|
||||
@ -1,201 +0,0 @@
|
||||
# Generated by Django 6.0 on 2025-12-10 21:21
|
||||
|
||||
import django.db.models.deletion
|
||||
import django_extensions.db.fields
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('recruitment', '0002_alter_formfield_options_alter_formstage_options_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='formfield',
|
||||
options={'ordering': ['order'], 'verbose_name': 'Form Field', 'verbose_name_plural': 'Form Fields'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='formstage',
|
||||
options={'ordering': ['order'], 'verbose_name': 'Form Stage', 'verbose_name_plural': 'Form Stages'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='formtemplate',
|
||||
options={'ordering': ['-created_at'], 'verbose_name': 'Form Template', 'verbose_name_plural': 'Form Templates'},
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='formfield',
|
||||
old_name='error_message',
|
||||
new_name='required_message',
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='formfield',
|
||||
unique_together=set(),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='formstage',
|
||||
unique_together=set(),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='formfield',
|
||||
name='is_required',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='formfield',
|
||||
name='min_file_size',
|
||||
field=models.FloatField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='formfield',
|
||||
name='min_image_height',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='formfield',
|
||||
name='min_image_width',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='field_type',
|
||||
field=models.CharField(choices=[('text', 'Text Input'), ('email', 'Email'), ('phone', 'Phone'), ('textarea', 'Text Area'), ('file', 'File Upload'), ('date', 'Date Picker'), ('select', 'Dropdown'), ('radio', 'Radio Buttons'), ('checkbox', 'Checkboxes')], help_text='Type of the field', max_length=20),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='file_types',
|
||||
field=models.CharField(blank=True, help_text="Allowed file types (comma-separated, e.g., '.pdf,.doc,.docx')", max_length=200),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='is_predefined',
|
||||
field=models.BooleanField(default=False, help_text='Whether this is a default field'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='label',
|
||||
field=models.CharField(help_text='Label for the field', max_length=200),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='max_file_size',
|
||||
field=models.PositiveIntegerField(default=5, help_text='Maximum file size in MB (default: 5MB)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='max_files',
|
||||
field=models.PositiveIntegerField(default=1, help_text='Maximum number of files allowed (when multiple_files is True)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='max_length',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='min_length',
|
||||
field=models.IntegerField(blank=True, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='multiple_files',
|
||||
field=models.BooleanField(default=False, help_text='Allow multiple files to be uploaded'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='options',
|
||||
field=models.JSONField(blank=True, default=list, help_text='Options for selection fields (stored as JSON array)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='order',
|
||||
field=models.PositiveIntegerField(default=0, help_text='Order of the field in the stage'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='placeholder',
|
||||
field=models.CharField(blank=True, help_text='Placeholder text', max_length=200),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='required',
|
||||
field=models.BooleanField(default=False, help_text='Whether the field is required'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='validation_pattern',
|
||||
field=models.CharField(blank=True, choices=[('', 'None'), ('email', 'Email'), ('phone', 'Phone'), ('url', 'URL'), ('number', 'Number'), ('alpha', 'Letters Only'), ('alphanum', 'Letters & Numbers'), ('custom', 'Custom')], max_length=50),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formstage',
|
||||
name='is_predefined',
|
||||
field=models.BooleanField(default=False, help_text='Whether this is a default resume stage'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formstage',
|
||||
name='name',
|
||||
field=models.CharField(help_text='Name of the stage', max_length=200),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formstage',
|
||||
name='order',
|
||||
field=models.PositiveIntegerField(default=0, help_text='Order of the stage in the form'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formtemplate',
|
||||
name='created_at',
|
||||
field=models.DateTimeField(auto_now_add=True, verbose_name='Created at'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formtemplate',
|
||||
name='created_by',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='form_templates', to=settings.AUTH_USER_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formtemplate',
|
||||
name='description',
|
||||
field=models.TextField(blank=True, help_text='Description of the form template'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formtemplate',
|
||||
name='is_active',
|
||||
field=models.BooleanField(default=False, help_text='Whether this template is active'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formtemplate',
|
||||
name='name',
|
||||
field=models.CharField(help_text='Name of the form template', max_length=200),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formtemplate',
|
||||
name='slug',
|
||||
field=django_extensions.db.fields.RandomCharField(blank=True, editable=False, length=8, unique=True, verbose_name='Slug'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formtemplate',
|
||||
name='updated_at',
|
||||
field=models.DateTimeField(auto_now=True, verbose_name='Updated at'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='formtemplate',
|
||||
index=models.Index(fields=['created_at'], name='recruitment_created_c21775_idx'),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name='formtemplate',
|
||||
index=models.Index(fields=['is_active'], name='recruitment_is_acti_ae5efb_idx'),
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='formfield',
|
||||
name='help_text',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='formfield',
|
||||
name='max_date',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='formfield',
|
||||
name='min_date',
|
||||
),
|
||||
]
|
||||
@ -1,36 +0,0 @@
|
||||
# Generated by Django 6.0 on 2025-12-11 12:34
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('recruitment', '0003_alter_formfield_options_alter_formstage_options_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='formfield',
|
||||
options={'ordering': ['order']},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='formfield',
|
||||
name='is_required',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='field_type',
|
||||
field=models.CharField(choices=[('text', 'Text Input'), ('number', 'Number Input'), ('email', 'Email'), ('phone', 'Phone'), ('textarea', 'Text Area'), ('file', 'File Upload'), ('date', 'Date Picker'), ('select', 'Dropdown'), ('radio', 'Radio Buttons'), ('checkbox', 'Checkboxes')], help_text='Type of the field', max_length=20),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='max_value',
|
||||
field=models.CharField(blank=True, help_text='Max value/date for Number/Date fields', max_length=50),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='min_value',
|
||||
field=models.CharField(blank=True, help_text='Min value/date for Number/Date fields', max_length=50),
|
||||
),
|
||||
]
|
||||
@ -1,37 +0,0 @@
|
||||
# Generated by Django 6.0 on 2025-12-11 13:33
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('recruitment', '0004_alter_formfield_options_remove_formfield_is_required_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='formfield',
|
||||
options={'ordering': ['order'], 'verbose_name': 'Form Field', 'verbose_name_plural': 'Form Fields'},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='formfield',
|
||||
name='is_required',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='field_type',
|
||||
field=models.CharField(choices=[('text', 'Text Input'), ('email', 'Email'), ('phone', 'Phone'), ('textarea', 'Text Area'), ('file', 'File Upload'), ('date', 'Date Picker'), ('select', 'Dropdown'), ('radio', 'Radio Buttons'), ('checkbox', 'Checkboxes')], help_text='Type of the field', max_length=20),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='max_value',
|
||||
field=models.CharField(blank=True, max_length=50),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='formfield',
|
||||
name='min_value',
|
||||
field=models.CharField(blank=True, max_length=50),
|
||||
),
|
||||
]
|
||||
@ -187,6 +187,7 @@ class PersonListView(StaffRequiredMixin, ListView, LoginRequiredMixin):
|
||||
def get_queryset(self):
|
||||
queryset = super().get_queryset().select_related("user")
|
||||
search_query = self.request.GET.get("search", "")
|
||||
print(Person.objects.first().last_name)
|
||||
if search_query:
|
||||
queryset=queryset.filter(
|
||||
Q(first_name=search_query) |
|
||||
@ -225,22 +226,26 @@ class PersonCreateView(CreateView, LoginRequiredMixin, StaffOrAgencyRequiredMixi
|
||||
template_name = "people/create_person.html"
|
||||
form_class = PersonForm
|
||||
success_url = reverse_lazy("person_list")
|
||||
print("from agency")
|
||||
|
||||
|
||||
def form_valid(self, form):
|
||||
if "HX-Request" in self.request.headers:
|
||||
instance = form.save()
|
||||
view = self.request.POST.get("view")
|
||||
if view == "portal":
|
||||
slug = self.request.POST.get("agency")
|
||||
if slug:
|
||||
agency = HiringAgency.objects.get(slug=slug)
|
||||
print(agency)
|
||||
instance.agency = agency
|
||||
instance.save()
|
||||
return redirect("agency_portal_persons_list")
|
||||
if view == "job":
|
||||
return redirect("application_create")
|
||||
|
||||
instance = form.save()
|
||||
view = self.request.POST.get("view")
|
||||
if view == "portal":
|
||||
slug = self.request.POST.get("agency")
|
||||
if slug:
|
||||
agency = HiringAgency.objects.get(slug=slug)
|
||||
print(agency)
|
||||
instance.agency = agency
|
||||
instance.save()
|
||||
|
||||
|
||||
# 2. Add the content to update (e.g., re-render the person list table)
|
||||
# response.content = render_to_string('recruitment/persons_table.html',
|
||||
return redirect("agency_portal_persons_list")
|
||||
if view == "job":
|
||||
return redirect("application_create")
|
||||
return super().form_valid(form)
|
||||
|
||||
|
||||
@ -3114,7 +3119,7 @@ def agency_portal_persons_list(request):
|
||||
| Q(last_name__icontains=search_query)
|
||||
| Q(email__icontains=search_query)
|
||||
| Q(phone=search_query)
|
||||
| Q(job__title__icontains=search_query)
|
||||
|
||||
)
|
||||
|
||||
paginator = Paginator(persons, 20) # Show 20 persons per page
|
||||
@ -3636,7 +3641,7 @@ def message_create(request):
|
||||
|
||||
if message.recipient and message.recipient.email:
|
||||
if request.user.user_type != "staff":
|
||||
message = message.content
|
||||
body = message.content
|
||||
else:
|
||||
body = (
|
||||
message.content
|
||||
@ -5386,19 +5391,19 @@ class ApplicationListView(LoginRequiredMixin, StaffRequiredMixin, ListView):
|
||||
template_name = "recruitment/applications_list.html"
|
||||
context_object_name = "applications"
|
||||
paginate_by = 100
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = (
|
||||
super()
|
||||
.get_queryset()
|
||||
.select_related("person", "job")
|
||||
.prefetch_related("interview_set")
|
||||
|
||||
)
|
||||
|
||||
# Handle search
|
||||
search_query = self.request.GET.get("search", "")
|
||||
job = self.request.GET.get("job", "")
|
||||
stage = self.request.GET.get("stage", "")
|
||||
|
||||
if search_query:
|
||||
queryset = queryset.filter(
|
||||
Q(person__first_name=search_query) |
|
||||
@ -5463,7 +5468,7 @@ class ApplicationCreateView(
|
||||
nationalities = cache.get(cache_key)
|
||||
if nationalities is None:
|
||||
nationalities = list(
|
||||
self.model.objects.values_list("nationality", flat=True)
|
||||
Person.objects.values_list("nationality", flat=True)
|
||||
.filter(nationality__isnull=False)
|
||||
.distinct()
|
||||
.order_by("nationality")
|
||||
@ -5474,6 +5479,7 @@ class ApplicationCreateView(
|
||||
context["nationality"] = nationality
|
||||
context["nationalities"] = nationalities
|
||||
context["search_query"] = self.request.GET.get("search", "")
|
||||
context["person_form"]=PersonForm()
|
||||
return context
|
||||
|
||||
|
||||
|
||||
@ -83,6 +83,7 @@
|
||||
.bg-ACTIVE { background-color: var(--kaauh-teal) !important; }
|
||||
.bg-CLOSED { background-color: var(--kaauh-danger) !important; }
|
||||
.bg-ARCHIVED { background-color: #343a40 !important; }
|
||||
.bg-CANCELLED{background-color: red !important; }
|
||||
|
||||
/* --- TABLE STYLING --- */
|
||||
.table {
|
||||
@ -238,6 +239,7 @@
|
||||
<option value="DRAFT" {% if status_filter == 'DRAFT' %}selected{% endif %}>{% trans "Draft" %}</option>
|
||||
<option value="ACTIVE" {% if status_filter == 'ACTIVE' %}selected{% endif %}>{% trans "Active" %}</option>
|
||||
<option value="CLOSED" {% if status_filter == 'CLOSED' %}selected{% endif %}>{% trans "Closed" %}</option>
|
||||
<option value="CANCELLED" {% if status_filter == 'CANCELLED' %}selected{% endif %}>{% trans "Cancelled" %}</option>
|
||||
<option value="ARCHIVED" {% if status_filter == 'ARCHIVED' %}selected{% endif %}>{% trans "Archived" %}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@ -64,7 +64,7 @@
|
||||
<div class="col-md-3 mb-2">
|
||||
<div class="kaauh-card shadow-sm h-100">
|
||||
<div class="card-body text-center px-2 py-2">
|
||||
<div class="text-primary mb-2">
|
||||
<div class="text-primary-theme mb-2">
|
||||
<i class="fas fa-briefcase fa-2x"></i>
|
||||
</div>
|
||||
<h4 class="card-title">{{ total_assignments }}</h4>
|
||||
@ -75,7 +75,7 @@
|
||||
<div class="col-md-3 mb-2">
|
||||
<div class="kaauh-card shadow-sm h-100 px-2 py-2">
|
||||
<div class="card-body text-center">
|
||||
<div class="text-success mb-2">
|
||||
<div class="text-primary-theme mb-2">
|
||||
<i class="fas fa-check-circle fa-2x"></i>
|
||||
</div>
|
||||
<h4 class="card-title">{{ active_assignments }}</h4>
|
||||
@ -86,7 +86,7 @@
|
||||
<div class="col-md-3 mb-2">
|
||||
<div class="kaauh-card shadow-sm h-100 px-2 py-2">
|
||||
<div class="card-body text-center">
|
||||
<div class="text-info mb-2">
|
||||
<div class="text-primary-theme mb-2">
|
||||
<i class="fas fa-users fa-2x"></i>
|
||||
</div>
|
||||
<h4 class="card-title">{{ total_applications }}</h4>
|
||||
@ -166,7 +166,7 @@
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<small class="text-muted d-block">{% trans "Applications" %}</small>
|
||||
<strong>{{ stats.application_count }} / {{ stats.assignment.max_applications }}</strong>
|
||||
<strong>{{ stats.application_count }} / {{ stats.assignment.max_candidates}}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -174,7 +174,7 @@
|
||||
<div class="mb-3">
|
||||
<div class="d-flex justify-content-between mb-1">
|
||||
<small class="text-muted">{% trans "Submission Progress" %}</small>
|
||||
<small class="text-muted">{{ stats.application_count }}/{{ stats.assignment.max_applications }}</small>
|
||||
<small class="text-muted">{{ stats.application_count }}/{{ stats.assignment.max_candidates }}</small>
|
||||
</div>
|
||||
<div class="progress" style="height: 6px;">
|
||||
{% with progress=stats.application_count %}
|
||||
|
||||
@ -91,7 +91,7 @@
|
||||
id="search"
|
||||
name="q"
|
||||
value="{{ search_query }}"
|
||||
placeholder="{% trans 'Search by name, email, phone, or job title...' %}">
|
||||
placeholder="{% trans 'Search by name, email, phone...' %}">
|
||||
</div>
|
||||
{% comment %} <div class="col-md-3">
|
||||
<label for="stage" class="form-label fw-semibold">
|
||||
@ -122,7 +122,7 @@
|
||||
<div class="col-md-6">
|
||||
<div class="kaauh-card shadow-sm h-100 p-3">
|
||||
<div class="card-body text-center">
|
||||
<div class="text-info mb-2">
|
||||
<div class="text-primary-theme mb-2">
|
||||
<i class="fas fa-users fa-2x"></i>
|
||||
</div>
|
||||
<h4 class="card-title">{{ total_persons }}</h4>
|
||||
@ -133,7 +133,7 @@
|
||||
<div class="col-md-6">
|
||||
<div class="kaauh-card shadow-sm h-100 p-3">
|
||||
<div class="card-body text-center">
|
||||
<div class="text-success mb-2">
|
||||
<div class="text-primary-theme mb-2">
|
||||
<i class="fas fa-check-circle fa-2x"></i>
|
||||
</div>
|
||||
<h4 class="card-title">{{ page_obj|length }}</h4>
|
||||
@ -324,10 +324,12 @@
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="personModalBody">
|
||||
<form id="person_form" hx-post="{% url 'person_create' %}" hx-vals='{"view":"portal","agency":"{{ agency.slug }}"}' hx-select=".persons-list" hx-target=".persons-list" hx-swap="outerHTML"
|
||||
hx-on:afterRequest="$('#personModal').modal('hide')">
|
||||
<form id="person_form" method="post" action="{% url 'person_create' %}" >
|
||||
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="view" value="portal">
|
||||
<input type="hidden" name="agency" value="{{ agency.slug }}">
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-md-4">
|
||||
{{ person_form.first_name|as_crispy_field }}
|
||||
@ -342,6 +344,7 @@
|
||||
<div class="row g-4">
|
||||
<div class="col-md-6">
|
||||
{{ person_form.email|as_crispy_field }}
|
||||
{{person_form.errors}}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{{ person_form.phone|as_crispy_field }}
|
||||
|
||||
@ -98,7 +98,7 @@
|
||||
<div class="d-flex gap-2 mt-1">
|
||||
<button type="button" class="btn btn-outline-secondary btn-sm" data-bs-toggle="modal" data-bs-target="#personModal">
|
||||
<i class="fas fa-user-plus me-1"></i>
|
||||
<span class="d-none d-sm-inline">{% trans "Create New Person" %}</span>
|
||||
<span class="d-none d-sm-inline">{% trans "Create New Applicant" %}</span>
|
||||
</button>
|
||||
<a href="{% url 'application_list' %}" class="btn btn-outline-light btn-sm" title="{% trans 'Back to List' %}">
|
||||
<i class="fas fa-arrow-left"></i>
|
||||
@ -171,6 +171,14 @@
|
||||
{{ person_form.phone|as_crispy_field }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-4">
|
||||
<div class="col-md-6">
|
||||
{{ person_form.gpa|as_crispy_field }}
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
{{ person_form.national_id|as_crispy_field }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-4">
|
||||
<div class="col-md-6">
|
||||
{{ person_form.date_of_birth|as_crispy_field }}
|
||||
|
||||
@ -5,6 +5,15 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="container-fluid">
|
||||
<nav aria-label="breadcrumb">
|
||||
<ol class="breadcrumb">
|
||||
<li class="breadcrumb-item"><a href="{% url 'source_list' %}" class="text-decoration-none text-secondary">{% trans "Souce Settings" %}</a></li>
|
||||
<li class="breadcrumb-item active" aria-current="page" style="
|
||||
color: #F43B5E; /* Rosy Accent Color */
|
||||
font-weight: 600;
|
||||
">{% trans "Source Detail" %}</li>
|
||||
</ol>
|
||||
</nav>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="d-flex justify-content-between align-items-center mb-4">
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<form method="post" class="space-y-4">
|
||||
<form method="post" class="space-y-4">
|
||||
{% csrf_token %}
|
||||
{{ form|crispy }}
|
||||
|
||||
|
||||
@ -112,7 +112,13 @@
|
||||
<p class="text-muted mb-0">{% trans "Manage your personal details and security." %}</p>
|
||||
</div>
|
||||
<div class="rounded-circle bg-primary-subtle text-accent d-flex align-items-center justify-content-center" style="width: 50px; height: 50px; font-size: 1.5rem;">
|
||||
{% if user.first_name %}{{ user.first_name.0 }}{% else %}<i class="fas fa-user"></i>{% endif %}
|
||||
{% if user.profile_image %}
|
||||
<img src="{{ user.profile_image.url }}" alt="{{ user.username }}" class="profile-avatar"
|
||||
style="width: 100px; height: 100px; object-fit: cover; background-color: var(--kaauh-teal); display: inline-block; vertical-align: middle;"
|
||||
title="{% trans 'Your account' %}">
|
||||
{% else %}
|
||||
{% if user.first_name %}{{ user.first_name.0 }}{% else %}<i class="fas fa-user"></i>{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user