215 lines
8.7 KiB
Python
215 lines
8.7 KiB
Python
from django import forms
|
|
from . import models
|
|
from django.core.validators import URLValidator
|
|
from django.core.exceptions import ValidationError # Correct import for the exception
|
|
from .validators import validate_hash_tags
|
|
|
|
|
|
class JobPostingForm(forms.ModelForm):
|
|
"""Form for creating and editing job postings"""
|
|
|
|
class Meta:
|
|
model = models.JobPosting
|
|
fields = [
|
|
'title', 'department', 'job_type', 'workplace_type',
|
|
'location_city', 'location_state', 'location_country',
|
|
'description', 'qualifications', 'salary_range', 'benefits',
|
|
'application_url', 'application_deadline', 'application_instructions',
|
|
'position_number', 'reporting_to', 'start_date', 'status',
|
|
'created_by','open_positions','hash_tags'
|
|
]
|
|
widgets = {
|
|
# Basic Information
|
|
'title': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'Assistant Professor of Computer Science',
|
|
'required': True
|
|
}),
|
|
'department': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'Computer Science, Human Resources, etc.'
|
|
}),
|
|
'job_type': forms.Select(attrs={
|
|
'class': 'form-select',
|
|
'required': True
|
|
}),
|
|
'workplace_type': forms.Select(attrs={
|
|
'class': 'form-select',
|
|
'required': True
|
|
}),
|
|
|
|
# Location
|
|
'location_city': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'Boston'
|
|
}),
|
|
'location_state': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'MA'
|
|
}),
|
|
'location_country': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'value': 'United States'
|
|
}),
|
|
|
|
# Job Details
|
|
'description': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 6,
|
|
'placeholder': 'Provide a comprehensive description of the role, responsibilities, and expectations...',
|
|
'required': True
|
|
}),
|
|
'qualifications': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 4,
|
|
'placeholder': 'List required qualifications, skills, education, and experience...'
|
|
}),
|
|
'salary_range': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': '$60,000 - $80,000'
|
|
}),
|
|
'benefits': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 2,
|
|
'placeholder': 'Health insurance, retirement plans, tuition reimbursement, etc.'
|
|
}),
|
|
|
|
# Application Information
|
|
'application_url': forms.URLInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'https://university.edu/careers/job123',
|
|
'required': True
|
|
}),
|
|
'application_deadline': forms.DateInput(attrs={
|
|
'class': 'form-control',
|
|
'type': 'date'
|
|
}),
|
|
'application_instructions': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 3,
|
|
'placeholder': 'Special instructions for applicants (e.g., required documents, reference requirements, etc.)'
|
|
}),
|
|
'open_positions': forms.NumberInput(attrs={
|
|
'class': 'form-control',
|
|
'min': 1,
|
|
'placeholder': 'Number of open positions'
|
|
}),
|
|
'hash_tags': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': '#hiring,#jobopening',
|
|
'validators':validate_hash_tags,
|
|
|
|
}),
|
|
|
|
# Internal Information
|
|
'position_number': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'UNIV-2025-001'
|
|
}),
|
|
'reporting_to': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'Department Chair, Director, etc.'
|
|
}),
|
|
'start_date': forms.DateInput(attrs={
|
|
'class': 'form-control',
|
|
'type': 'date'
|
|
}),
|
|
|
|
'created_by': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'University Administrator'
|
|
}),
|
|
}
|
|
|
|
def __init__(self,*args,**kwargs):
|
|
|
|
# Extract your custom argument BEFORE calling super()
|
|
self.is_anonymous_user = kwargs.pop('is_anonymous_user', False)
|
|
# Now call the parent __init__ with remaining args
|
|
super().__init__(*args, **kwargs)
|
|
|
|
if not self.instance.pk:# Creating new job posting
|
|
if not self.is_anonymous_user:
|
|
self.fields['created_by'].initial = 'University Administrator'
|
|
self.fields['status'].initial = 'Draft'
|
|
self.fields['location_city'].initial='Riyadh'
|
|
self.fields['location_state'].initial='Riyadh Province'
|
|
self.fields['location_country'].initial='Saudi Arabia'
|
|
|
|
|
|
def clean_hash_tags(self):
|
|
hash_tags=self.cleaned_data.get('hash_tags')
|
|
if hash_tags:
|
|
tags=[tag.strip() for tag in hash_tags.split(',') if tag.strip()]
|
|
for tag in tags:
|
|
if not tag.startswith('#'):
|
|
raise forms.ValidationError("Each hashtag must start with '#' symbol and must be comma(,) sepearted.")
|
|
return ','.join(tags)
|
|
return hash_tags # Allow blank
|
|
|
|
def clean_title(self):
|
|
title=self.cleaned_data.get('title')
|
|
if not title or len(title.strip())<3:
|
|
raise forms.ValidationError("Job title must be at least 3 characters long.")
|
|
if len(title)>200:
|
|
raise forms.ValidationError("Job title cannot exceed 200 characters.")
|
|
return title.strip()
|
|
|
|
def clean_description(self):
|
|
description=self.cleaned_data.get('description')
|
|
if not description or len(description.strip())<20:
|
|
raise forms.ValidationError("Job description must be at least 20 characters long.")
|
|
return description.strip() # to remove leading/trailing whitespace
|
|
|
|
def clean_application_url(self):
|
|
url=self.cleaned_data.get('application_url')
|
|
if url:
|
|
validator=URLValidator()
|
|
try:
|
|
validator(url)
|
|
except forms.ValidationError:
|
|
raise forms.ValidationError('Please enter a valid URL (e.g., https://example.com)')
|
|
return url
|
|
|
|
def clean(self):
|
|
"""Cross-field validation"""
|
|
cleaned_data = super().clean()
|
|
|
|
# Validate dates
|
|
start_date = cleaned_data.get('start_date')
|
|
application_deadline = cleaned_data.get('application_deadline')
|
|
|
|
# Perform cross-field validation only if both fields have values
|
|
if start_date and application_deadline:
|
|
if application_deadline > start_date:
|
|
self.add_error('application_deadline',
|
|
'The application deadline must be set BEFORE the job start date.')
|
|
|
|
# # Validate that if status is ACTIVE, we have required fields
|
|
# status = cleaned_data.get('status')
|
|
# if status == 'ACTIVE':
|
|
# if not cleaned_data.get('application_url'):
|
|
# self.add_error('application_url',
|
|
# 'Application URL is required for active jobs.')
|
|
# if not cleaned_data.get('description'):
|
|
# self.add_error('description',
|
|
# 'Job description is required for active jobs.')
|
|
|
|
return cleaned_data
|
|
|
|
|
|
class PostImageUploadForm(forms.ModelForm):
|
|
class Meta:
|
|
model=models.PostImageUpload
|
|
fields=['linkedinpost_image']
|
|
widgets={
|
|
'linkedinpost_image':forms.ClearableFileInput(attrs={'class':'form-control','accept':'.png,.jpg,.jpeg'})
|
|
}
|
|
|
|
|
|
def clean_linkedinpost_image(self):
|
|
linkedinpost_image=self.cleaned_data.get('image')
|
|
if linkedinpost_image:
|
|
if linkedinpost_image.size>2*1024*1024:#2MB limit
|
|
raise forms.ValidationError("Image size should not exceed 2MB.")
|
|
return linkedinpost_image |