frontend #36
@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-23 09:22
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('recruitment', '0003_jobposting_cv_zip_file_jobposting_zip_created'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='interviewschedule',
|
||||
name='template_location',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='schedule_templates', to='recruitment.interviewlocation', verbose_name='Location Template (Zoom/Onsite)'),
|
||||
),
|
||||
]
|
||||
@ -0,0 +1,19 @@
|
||||
# Generated by Django 5.2.7 on 2025-11-23 09:41
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('recruitment', '0004_alter_interviewschedule_template_location'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='interviewschedule',
|
||||
name='template_location',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='schedule_templates', to='recruitment.interviewlocation', verbose_name='Location Template (Zoom/Onsite)'),
|
||||
),
|
||||
]
|
||||
@ -1162,6 +1162,9 @@ class OnsiteLocationDetails(InterviewLocation):
|
||||
verbose_name_plural = _("Onsite Location Details")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# --- 2. Scheduling Models ---
|
||||
|
||||
class InterviewSchedule(Base):
|
||||
|
||||
@ -760,6 +760,7 @@ from django.utils.html import strip_tags
|
||||
|
||||
def _task_send_individual_email(subject, body_message, recipient, attachments,sender,job):
|
||||
"""Internal helper to create and send a single email."""
|
||||
|
||||
|
||||
from_email = getattr(settings, 'DEFAULT_FROM_EMAIL', 'noreply@kaauh.edu.sa')
|
||||
is_html = '<' in body_message and '>' in body_message
|
||||
@ -780,7 +781,8 @@ def _task_send_individual_email(subject, body_message, recipient, attachments,se
|
||||
try:
|
||||
result=email_obj.send(fail_silently=False)
|
||||
|
||||
if result==1:
|
||||
if result==1 and sender and job: # job is none when email sent after message creation
|
||||
|
||||
try:
|
||||
user=get_object_or_404(User,email=recipient)
|
||||
new_message = Message.objects.create(
|
||||
@ -798,7 +800,7 @@ def _task_send_individual_email(subject, body_message, recipient, attachments,se
|
||||
|
||||
|
||||
else:
|
||||
logger.error("fialed to send email")
|
||||
logger.error("failed to send email")
|
||||
|
||||
|
||||
except Exception as e:
|
||||
|
||||
@ -4674,55 +4674,40 @@ def message_create(request):
|
||||
message.sender = request.user
|
||||
message.save()
|
||||
# Send email if message_type is 'email' and recipient has email
|
||||
if message.message_type == 'email' and message.recipient and message.recipient.email:
|
||||
|
||||
if message.recipient and message.recipient.email:
|
||||
|
||||
try:
|
||||
from .email_service import send_bulk_email
|
||||
|
||||
|
||||
email_result = send_bulk_email(
|
||||
email_result = async_task('recruitment.tasks._task_send_individual_email',
|
||||
subject=message.subject,
|
||||
message=message.content,
|
||||
recipient_list=[message.recipient.email],
|
||||
request=request,
|
||||
body_message=message.content,
|
||||
recipient=message.recipient.email,
|
||||
attachments=None,
|
||||
async_task_=True,
|
||||
from_interview=False
|
||||
sender=False,
|
||||
job=False
|
||||
)
|
||||
|
||||
if email_result["success"]:
|
||||
message.is_email_sent = True
|
||||
message.email_address = message.recipient.email
|
||||
message.save(update_fields=['is_email_sent', 'email_address'])
|
||||
if email_result:
|
||||
messages.success(request, "Message sent successfully via email!")
|
||||
else:
|
||||
messages.warning(request, f"Message saved but email failed: {email_result.get('message', 'Unknown error')}")
|
||||
|
||||
messages.warning(request, f"email failed: {email_result.get('message', 'Unknown error')}")
|
||||
|
||||
except Exception as e:
|
||||
|
||||
messages.warning(request, f"Message saved but email sending failed: {str(e)}")
|
||||
else:
|
||||
|
||||
messages.success(request, "Message sent successfully!")
|
||||
|
||||
["recipient", "job", "subject", "content", "message_type"]
|
||||
recipient_email = form.cleaned_data['recipient'].email # Assuming recipient is a User or Model with an 'email' field
|
||||
subject = form.cleaned_data['subject']
|
||||
custom_message = form.cleaned_data['content']
|
||||
job_id = form.cleaned_data['job'].id if 'job' in form.cleaned_data and form.cleaned_data['job'] else None
|
||||
sender_user_id = request.user.id
|
||||
|
||||
task_id = async_task(
|
||||
'recruitment.tasks.send_bulk_email_task',
|
||||
subject,
|
||||
custom_message, # Pass the custom message
|
||||
[recipient_email], # Pass the specific recipient as a list of one
|
||||
|
||||
sender_user_id=sender_user_id,
|
||||
job_id=job_id,
|
||||
hook='recruitment.tasks.email_success_hook')
|
||||
|
||||
logger.info(f"{task_id} queued.")
|
||||
|
||||
return redirect("message_list")
|
||||
else:
|
||||
|
||||
messages.error(request, "Please correct the errors below.")
|
||||
else:
|
||||
|
||||
form = MessageForm(request.user)
|
||||
|
||||
context = {
|
||||
@ -4759,27 +4744,21 @@ def message_reply(request, message_id):
|
||||
message.save()
|
||||
|
||||
# Send email if message_type is 'email' and recipient has email
|
||||
if message.message_type == 'email' and message.recipient and message.recipient.email:
|
||||
if message.recipient and message.recipient.email:
|
||||
try:
|
||||
from .email_service import send_bulk_email
|
||||
|
||||
email_result = send_bulk_email(
|
||||
email_result = async_task('recruitment.tasks._task_send_individual_email',
|
||||
subject=message.subject,
|
||||
message=message.content,
|
||||
recipient_list=[message.recipient.email],
|
||||
request=request,
|
||||
body_message=message.content,
|
||||
recipient=message.recipient.email,
|
||||
attachments=None,
|
||||
async_task_=True,
|
||||
from_interview=False
|
||||
sender=False,
|
||||
job=False
|
||||
)
|
||||
|
||||
if email_result["success"]:
|
||||
message.is_email_sent = True
|
||||
message.email_address = message.recipient.email
|
||||
message.save(update_fields=['is_email_sent', 'email_address'])
|
||||
messages.success(request, "Reply sent successfully via email!")
|
||||
if email_result:
|
||||
messages.success(request, "Message sent successfully via email!")
|
||||
else:
|
||||
messages.warning(request, f"Reply saved but email failed: {email_result.get('message', 'Unknown error')}")
|
||||
|
||||
messages.warning(request, f"email failed: {email_result.get('message', 'Unknown error')}")
|
||||
|
||||
except Exception as e:
|
||||
messages.warning(request, f"Reply saved but email sending failed: {str(e)}")
|
||||
@ -5763,15 +5742,15 @@ def send_interview_email(request, slug):
|
||||
return redirect("meeting_details", slug=meeting.slug)
|
||||
|
||||
|
||||
# def schedule_interview_location_form(request,slug):
|
||||
# schedule=get_object_or_404(InterviewSchedule,slug=slug)
|
||||
# if request.method=='POST':
|
||||
# form=InterviewScheduleLocationForm(request.POST,instance=schedule)
|
||||
# form.save()
|
||||
# return redirect('list_meetings')
|
||||
# else:
|
||||
# form=InterviewScheduleLocationForm(instance=schedule)
|
||||
# return render(request,'interviews/schedule_interview_location_form.html',{'form':form,'schedule':schedule})
|
||||
def schedule_interview_location_form(request,slug):
|
||||
schedule=get_object_or_404(InterviewSchedule,slug=slug)
|
||||
if request.method=='POST':
|
||||
form=InterviewScheduleLocationForm(request.POST,instance=schedule)
|
||||
form.save()
|
||||
return redirect('list_meetings')
|
||||
else:
|
||||
form=InterviewScheduleLocationForm(instance=schedule)
|
||||
return render(request,'interviews/schedule_interview_location_form.html',{'form':form,'schedule':schedule})
|
||||
|
||||
|
||||
class MeetingListView(ListView):
|
||||
@ -5782,6 +5761,7 @@ class MeetingListView(ListView):
|
||||
template_name = "meetings/list_meetings.html"
|
||||
context_object_name = "meetings"
|
||||
paginate_by = 100
|
||||
|
||||
|
||||
def get_queryset(self):
|
||||
# Start with a base queryset, ensuring an InterviewLocation link exists.
|
||||
@ -5794,8 +5774,9 @@ class MeetingListView(ListView):
|
||||
'interview_location__zoommeetingdetails',
|
||||
'interview_location__onsitelocationdetails',
|
||||
)
|
||||
# Note: Printing the queryset here can consume memory for large sets.
|
||||
|
||||
# Note: Printing the queryset here can consume memory for large sets.
|
||||
|
||||
# Get filters from GET request
|
||||
search_query = self.request.GET.get("q")
|
||||
status_filter = self.request.GET.get("status")
|
||||
@ -5807,12 +5788,11 @@ class MeetingListView(ListView):
|
||||
if type_filter:
|
||||
# Use .title() to handle case variations from URL (e.g., 'remote' -> 'Remote')
|
||||
normalized_type = type_filter.title()
|
||||
print(normalized_type)
|
||||
|
||||
# Assuming InterviewLocation.LocationType is accessible/defined
|
||||
if normalized_type in ['Remote', 'Onsite']:
|
||||
queryset = queryset.filter(interview_location__location_type=normalized_type)
|
||||
print(queryset)
|
||||
|
||||
|
||||
# 3. Search by Topic (stored on InterviewLocation)
|
||||
if search_query:
|
||||
queryset = queryset.filter(interview_location__topic__icontains=search_query)
|
||||
@ -5886,6 +5866,28 @@ class MeetingListView(ListView):
|
||||
|
||||
return context
|
||||
|
||||
|
||||
# class MeetingListView(ListView):
|
||||
# """
|
||||
# A unified view to list both Remote and Onsite Scheduled Interviews.
|
||||
# """
|
||||
# model = InterviewLocation
|
||||
# template_name = "meetings/list_meetings.html"
|
||||
# context_object_name = "meetings"
|
||||
|
||||
|
||||
|
||||
# def get_queryset(self):
|
||||
# # Start with a base queryset, ensuring an InterviewLocation link exists.
|
||||
# queryset = super().get_queryset().prefetch_related(
|
||||
# 'zoommeetingdetails',
|
||||
# 'onsitelocationdetails',
|
||||
# )
|
||||
# print(queryset)
|
||||
|
||||
# return queryset
|
||||
|
||||
|
||||
def reschedule_onsite_meeting(request, slug, candidate_id, meeting_id):
|
||||
"""Handles the rescheduling of an Onsite Interview (updates OnsiteLocationDetails)."""
|
||||
job = get_object_or_404(JobPosting, slug=slug)
|
||||
|
||||
@ -499,7 +499,7 @@
|
||||
</h5>
|
||||
<p class="text-muted small mb-0">
|
||||
<i class="fas fa-calendar-alt me-1"></i>
|
||||
{% trans "Applied" %}: {{ application.applied_date|date:"d M Y" }}
|
||||
{% trans "Applied" %}: {{ application.created_at|date:"d M Y" }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user