temporaryats/jobs/models.py
2025-10-02 14:56:59 +03:00

189 lines
7.7 KiB
Python

# jobs/models.py
from django.db import models
from django.utils import timezone
from django.core.validators import URLValidator
from .validators import validate_image_size, validate_hash_tags
import uuid
import os
class JobPosting(models.Model):
# Basic Job Information
JOB_TYPES = [
('FULL_TIME', 'Full-time'),
('PART_TIME', 'Part-time'),
('CONTRACT', 'Contract'),
('INTERNSHIP', 'Internship'),
('FACULTY', 'Faculty'),
('TEMPORARY', 'Temporary'),
]
WORKPLACE_TYPES = [
('ON_SITE', 'On-site'),
('REMOTE', 'Remote'),
('HYBRID', 'Hybrid'),
]
# Core Fields
title = models.CharField(max_length=200)
department = models.CharField(max_length=100, blank=True)
job_type = models.CharField(max_length=20, choices=JOB_TYPES, default='FULL_TIME')
workplace_type = models.CharField(max_length=20, choices=WORKPLACE_TYPES, default='ON_SITE')
# Location
location_city = models.CharField(max_length=100, blank=True)
location_state = models.CharField(max_length=100, blank=True)
location_country = models.CharField(max_length=100, default='United States')
# Job Details
description = models.TextField(help_text="Full job description including responsibilities and requirements")
qualifications = models.TextField(blank=True, help_text="Required qualifications and skills")
salary_range = models.CharField(max_length=200, blank=True, help_text="e.g., $60,000 - $80,000")
benefits = models.TextField(blank=True, help_text="Benefits offered")
# Application Information
application_url = models.URLField(validators=[URLValidator()], help_text="URL where candidates apply")
application_deadline = models.DateField(null=True, blank=True)
application_instructions = models.TextField(blank=True, help_text="Special instructions for applicants")
# Internal Tracking
internal_job_id = models.CharField(max_length=50, primary_key=True, editable=False)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
created_by = models.CharField(max_length=100, blank=True, help_text="Name of person who created this job")
# Status Fields
STATUS_CHOICES = [
('DRAFT', 'Draft'),
('ACTIVE', 'Active'),
('CLOSED', 'Closed'),
('ARCHIVED', 'Archived'),
]
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='DRAFT')
#hashtags for social media
hash_tags = models.CharField(max_length=200, blank=True, help_text="Comma-separated hashtags for linkedin post like #hiring,#jobopening",validators=[validate_hash_tags])
# LinkedIn Integration Fields
linkedin_post_id = models.CharField(max_length=200, blank=True, help_text="LinkedIn post ID after posting")
linkedin_post_url = models.URLField(blank=True, help_text="Direct URL to LinkedIn post")
posted_to_linkedin = models.BooleanField(default=False)
linkedin_post_status = models.CharField(max_length=50, blank=True, help_text="Status of LinkedIn posting")
linkedin_posted_at = models.DateTimeField(null=True, blank=True)
# University Specific Fields
position_number = models.CharField(max_length=50, blank=True, help_text="University position number")
reporting_to = models.CharField(max_length=100, blank=True, help_text="Who this position reports to")
start_date = models.DateField(null=True, blank=True, help_text="Desired start date")
open_positions = models.PositiveIntegerField(default=1, help_text="Number of open positions for this job")
class Meta:
ordering = ['-created_at']
verbose_name = "Job Posting"
verbose_name_plural = "Job Postings"
def __str__(self):
return f"{self.title} - {self.get_status_display()}"
def save(self, *args, **kwargs):
# Generate unique internal job ID if not exists
if not self.internal_job_id:
prefix = "UNIV"
year = timezone.now().year
# Get next sequential number
last_job = JobPosting.objects.filter(
internal_job_id__startswith=f"{prefix}-{year}-"
).order_by('internal_job_id').last()
if last_job:
last_num = int(last_job.internal_job_id.split('-')[-1])
next_num = last_num + 1
else:
next_num = 1
self.internal_job_id = f"{prefix}-{year}-{next_num:04d}"
super().save(*args, **kwargs)
def get_location_display(self):
"""Return formatted location string"""
parts = []
if self.location_city:
parts.append(self.location_city)
if self.location_state:
parts.append(self.location_state)
if self.location_country and self.location_country != 'United States':
parts.append(self.location_country)
return ', '.join(parts) if parts else 'Not specified'
def is_expired(self):
"""Check if application deadline has passed"""
if self.application_deadline:
return self.application_deadline < timezone.now().date()
return False
def image_file_name(instance, filename):
ext = os.path.splitext(filename)[-1]
new_filename = f'{instance.id}{ext}'
return f'uploads/linkedinpost/images/{new_filename}'
class PostImageUpload(models.Model):
id = models.UUIDField(
primary_key=True,
default=uuid.uuid4,
editable=False,
unique=True
)
job_posting = models.ForeignKey(JobPosting, on_delete=models.CASCADE, related_name='files')
linkedinpost_image=models.ImageField(upload_to=image_file_name, blank=True, null=True,validators=[validate_image_size], help_text="Image file (Max size: 2MB). Accepted formats: .png, .jpg, .jpeg")
uploaded_at = models.DateTimeField(auto_now_add=True)
class Meta:
verbose_name = "Job File"
verbose_name_plural = "Job Files"
def __str__(self):
return f"File for {self.job_posting.title}-{self.job_posting.internal_job_id} - {self.file.name}"
# class JobApplication(models.Model):
# # Job reference
# job_posting = models.ForeignKey(JobPosting, on_delete=models.CASCADE,related_name='applications')
# # Personal Information
# first_name = models.CharField(max_length=100)
# last_name = models.CharField(max_length=100)
# email = models.EmailField()
# phone = models.CharField(max_length=20, blank=True)
# # Resume and Documents
# resume = models.FileField(upload_to='resumes/', help_text="PDF or Word document")
# cover_letter = models.FileField(upload_to='cover_letters/', blank=True)
# # Additional Information
# linkedin_profile = models.URLField(blank=True, help_text="Your LinkedIn profile URL")
# portfolio_url = models.URLField(blank=True, help_text="Portfolio or personal website")
# salary_expectations = models.CharField(max_length=100, blank=True)
# availability = models.CharField(max_length=100, blank=True)
# # Application Details
# applied_at = models.DateTimeField(auto_now_add=True)
# status = models.CharField(max_length=20, default='RECEIVED', choices=[
# ('RECEIVED', 'Received'),
# ('UNDER_REVIEW', 'Under Review'),
# ('INTERVIEW', 'Interview Scheduled'),
# ('OFFER', 'Offer Extended'),
# ('REJECTED', 'Rejected'),
# ('HIRED', 'Hired'),
# ])
# class Meta:
# ordering = ['-applied_at']
# verbose_name = "Job Application"
# verbose_name_plural = "Job Applications"
# def __str__(self):
# return f"{self.first_name} {self.last_name} - {self.job_posting.title}"