from django.contrib import admin from django.utils.html import format_html from django.urls import reverse from django.utils import timezone from .models import ( JobPosting, Candidate, TrainingMaterial, ZoomMeeting, FormTemplate, FormStage, FormField, FormSubmission, FieldResponse, SharedFormTemplate, Source, HiringAgency, IntegrationLog,InterviewSchedule ) class FormFieldInline(admin.TabularInline): model = FormField extra = 1 ordering = ('order',) class FormStageInline(admin.TabularInline): model = FormStage extra = 1 ordering = ('order',) inlines = [FormFieldInline] @admin.register(Source) class SourceAdmin(admin.ModelAdmin): list_display = ['name', 'source_type', 'ip_address', 'is_active', 'sync_status', 'created_at'] list_filter = ['source_type', 'is_active', 'sync_status', 'created_at'] search_fields = ['name', 'description'] readonly_fields = ['created_at', 'last_sync_at'] fieldsets = ( ('Basic Information', { 'fields': ('name', 'source_type', 'description') }), ('Technical Details', { 'fields': ('ip_address', 'api_key', 'api_secret', 'trusted_ips') }), ('Integration Status', { 'fields': ('is_active', 'integration_version', 'sync_status', 'last_sync_at', 'created_at') }), ) save_on_top = True actions = ['activate_sources', 'deactivate_sources'] def activate_sources(self, request, queryset): updated = queryset.update(is_active=True) self.message_user(request, f'{updated} sources activated.') activate_sources.short_description = 'Activate selected sources' def deactivate_sources(self, request, queryset): updated = queryset.update(is_active=False) self.message_user(request, f'{updated} sources deactivated.') deactivate_sources.short_description = 'Deactivate selected sources' @admin.register(IntegrationLog) class IntegrationLogAdmin(admin.ModelAdmin): list_display = ['source', 'action', 'endpoint', 'status_code', 'ip_address', 'created_at'] list_filter = ['action', 'status_code', 'source', 'created_at'] search_fields = ['source__name', 'endpoint', 'error_message'] readonly_fields = ['source', 'action', 'endpoint', 'method', 'request_data', 'response_data', 'status_code', 'error_message', 'ip_address', 'user_agent', 'processing_time', 'created_at'] fieldsets = ( ('Request Information', { 'fields': ('source', 'action', 'endpoint', 'method', 'ip_address', 'user_agent') }), ('Data', { 'fields': ('request_data', 'response_data') }), ('Results', { 'fields': ('status_code', 'error_message', 'processing_time', 'created_at') }), ) save_on_top = False date_hierarchy = 'created_at' @admin.register(HiringAgency) class HiringAgencyAdmin(admin.ModelAdmin): list_display = ['name', 'contact_person', 'email', 'phone', 'country', 'created_at'] list_filter = ['country', 'created_at'] search_fields = ['name', 'contact_person', 'email', 'phone', 'notes'] readonly_fields = ['created_at', 'updated_at'] fieldsets = ( ('Basic Information', { 'fields': ('name', 'contact_person', 'email', 'phone', 'website') }), ('Location Details', { 'fields': ('country', 'address') }), ('Additional Information', { 'fields': ('notes', 'created_at', 'updated_at') }), ) save_on_top = True @admin.register(JobPosting) class JobPostingAdmin(admin.ModelAdmin): list_display = ['internal_job_id', 'title', 'department', 'job_type', 'status', 'posted_to_linkedin', 'created_at'] list_filter = ['job_type', 'status', 'workplace_type', 'source', 'created_at'] search_fields = ['title', 'department', 'internal_job_id'] readonly_fields = ['internal_job_id', 'created_at', 'updated_at'] fieldsets = ( ('Basic Information', { 'fields': ('title', 'department', 'job_type', 'workplace_type', 'status') }), ('Location', { 'fields': ('location_city', 'location_state', 'location_country') }), ('Job Details', { 'fields': ('description', 'qualifications', 'salary_range', 'benefits') }), ('Application Information', { 'fields': ('application_url', 'application_deadline', 'application_instructions') }), ('Internal Tracking', { 'fields': ('internal_job_id', 'created_by', 'created_at', 'updated_at') }), ('Integration', { 'fields': ('source', 'open_positions', 'position_number', 'reporting_to', 'start_date') }), ('LinkedIn Integration', { 'fields': ('posted_to_linkedin', 'linkedin_post_id', 'linkedin_post_url', 'linkedin_posted_at') }), ) save_on_top = True actions = ['make_published', 'make_draft', 'mark_as_closed'] def make_published(self, request, queryset): updated = queryset.update(status='PUBLISHED') self.message_user(request, f'{updated} job postings marked as published.') make_published.short_description = 'Mark selected jobs as published' def make_draft(self, request, queryset): updated = queryset.update(status='DRAFT') self.message_user(request, f'{updated} job postings marked as draft.') make_draft.short_description = 'Mark selected jobs as draft' def mark_as_closed(self, request, queryset): updated = queryset.update(status='CLOSED') self.message_user(request, f'{updated} job postings marked as closed.') mark_as_closed.short_description = 'Mark selected jobs as closed' @admin.register(Candidate) class CandidateAdmin(admin.ModelAdmin): list_display = ['full_name', 'job', 'email', 'phone', 'stage', 'applied', 'created_at'] list_filter = ['stage', 'applied', 'created_at', 'job__department'] search_fields = ['first_name', 'last_name', 'email', 'phone'] readonly_fields = ['slug', 'created_at', 'updated_at'] fieldsets = ( ('Personal Information', { 'fields': ('first_name', 'last_name', 'email', 'phone', 'resume') }), ('Application Details', { 'fields': ('job', 'applied', 'stage') }), ('Interview Process', { 'fields': ('exam_date', 'exam_status', 'interview_date', 'interview_status', 'offer_date', 'offer_status', 'join_date') }), ('Scoring', { 'fields': ('match_score', 'strengths', 'weaknesses', 'criteria_checklist') }), ('Additional Information', { 'fields': ('submitted_by_agency', 'created_at', 'updated_at') }), ) save_on_top = True actions = ['mark_as_applied', 'mark_as_not_applied'] def mark_as_applied(self, request, queryset): updated = queryset.update(applied=True) self.message_user(request, f'{updated} candidates marked as applied.') mark_as_applied.short_description = 'Mark selected candidates as applied' def mark_as_not_applied(self, request, queryset): updated = queryset.update(applied=False) self.message_user(request, f'{updated} candidates marked as not applied.') mark_as_not_applied.short_description = 'Mark selected candidates as not applied' @admin.register(TrainingMaterial) class TrainingMaterialAdmin(admin.ModelAdmin): list_display = ['title', 'created_by', 'created_at'] list_filter = ['created_at'] search_fields = ['title', 'content'] readonly_fields = ['created_at', 'updated_at'] fieldsets = ( ('Basic Information', { 'fields': ('title', 'content') }), ('Media', { 'fields': ('video_link', 'file') }), ('Metadata', { 'fields': ('created_by', 'created_at', 'updated_at') }), ) save_on_top = True @admin.register(ZoomMeeting) class ZoomMeetingAdmin(admin.ModelAdmin): list_display = ['topic', 'meeting_id', 'start_time', 'duration', 'created_at'] list_filter = ['timezone', 'created_at'] search_fields = ['topic', 'meeting_id'] readonly_fields = ['created_at', 'updated_at'] fieldsets = ( ('Meeting Details', { 'fields': ('topic', 'meeting_id', 'start_time', 'duration', 'timezone') }), ('Meeting Settings', { 'fields': ('participant_video', 'join_before_host', 'mute_upon_entry', 'waiting_room') }), ('Access', { 'fields': ('join_url',) }), ('System Response', { 'fields': ('zoom_gateway_response', 'created_at', 'updated_at') }), ) save_on_top = True @admin.register(FormTemplate) class FormTemplateAdmin(admin.ModelAdmin): list_display = ['name', 'created_by', 'created_at', 'is_active'] list_filter = ['is_active', 'created_at'] search_fields = ['name', 'description'] readonly_fields = ['created_at', 'updated_at'] inlines = [FormStageInline] fieldsets = ( ('Basic Information', { 'fields': ('name', 'description', 'created_by', 'is_active') }), ('Timeline', { 'fields': ('created_at', 'updated_at') }), ) save_on_top = True @admin.register(FormSubmission) class FormSubmissionAdmin(admin.ModelAdmin): list_display = ['template', 'applicant_name', 'submitted_at', 'submitted_by'] list_filter = ['submitted_at', 'template'] search_fields = ['applicant_name', 'applicant_email'] readonly_fields = ['submitted_at'] fieldsets = ( ('Submission Information', { 'fields': ('template', 'submitted_by', 'submitted_at') }), ('Applicant Information', { 'fields': ('applicant_name', 'applicant_email') }), ) save_on_top = True # Register other models admin.site.register(FormStage) admin.site.register(FormField) admin.site.register(FieldResponse) admin.site.register(InterviewSchedule) # admin.site.register(HiringAgency)