updated the messages creation
This commit is contained in:
parent
8a0f715145
commit
f3f60d4fc5
@ -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")
|
verbose_name_plural = _("Onsite Location Details")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# --- 2. Scheduling Models ---
|
# --- 2. Scheduling Models ---
|
||||||
|
|
||||||
class InterviewSchedule(Base):
|
class InterviewSchedule(Base):
|
||||||
|
|||||||
@ -761,6 +761,7 @@ from django.utils.html import strip_tags
|
|||||||
def _task_send_individual_email(subject, body_message, recipient, attachments,sender,job):
|
def _task_send_individual_email(subject, body_message, recipient, attachments,sender,job):
|
||||||
"""Internal helper to create and send a single email."""
|
"""Internal helper to create and send a single email."""
|
||||||
|
|
||||||
|
|
||||||
from_email = getattr(settings, 'DEFAULT_FROM_EMAIL', 'noreply@kaauh.edu.sa')
|
from_email = getattr(settings, 'DEFAULT_FROM_EMAIL', 'noreply@kaauh.edu.sa')
|
||||||
is_html = '<' in body_message and '>' in body_message
|
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:
|
try:
|
||||||
result=email_obj.send(fail_silently=False)
|
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:
|
try:
|
||||||
user=get_object_or_404(User,email=recipient)
|
user=get_object_or_404(User,email=recipient)
|
||||||
new_message = Message.objects.create(
|
new_message = Message.objects.create(
|
||||||
@ -798,7 +800,7 @@ def _task_send_individual_email(subject, body_message, recipient, attachments,se
|
|||||||
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logger.error("fialed to send email")
|
logger.error("failed to send email")
|
||||||
|
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|||||||
@ -4674,55 +4674,40 @@ def message_create(request):
|
|||||||
message.sender = request.user
|
message.sender = request.user
|
||||||
message.save()
|
message.save()
|
||||||
# Send email if message_type is 'email' and recipient has email
|
# 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:
|
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,
|
subject=message.subject,
|
||||||
message=message.content,
|
body_message=message.content,
|
||||||
recipient_list=[message.recipient.email],
|
recipient=message.recipient.email,
|
||||||
request=request,
|
|
||||||
attachments=None,
|
attachments=None,
|
||||||
async_task_=True,
|
sender=False,
|
||||||
from_interview=False
|
job=False
|
||||||
)
|
)
|
||||||
|
if email_result:
|
||||||
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, "Message sent successfully via email!")
|
messages.success(request, "Message sent successfully via email!")
|
||||||
else:
|
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:
|
except Exception as e:
|
||||||
|
|
||||||
messages.warning(request, f"Message saved but email sending failed: {str(e)}")
|
messages.warning(request, f"Message saved but email sending failed: {str(e)}")
|
||||||
else:
|
else:
|
||||||
|
|
||||||
messages.success(request, "Message sent successfully!")
|
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")
|
return redirect("message_list")
|
||||||
else:
|
else:
|
||||||
|
|
||||||
messages.error(request, "Please correct the errors below.")
|
messages.error(request, "Please correct the errors below.")
|
||||||
else:
|
else:
|
||||||
|
|
||||||
form = MessageForm(request.user)
|
form = MessageForm(request.user)
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
@ -4759,27 +4744,21 @@ def message_reply(request, message_id):
|
|||||||
message.save()
|
message.save()
|
||||||
|
|
||||||
# Send email if message_type is 'email' and recipient has email
|
# 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:
|
try:
|
||||||
from .email_service import send_bulk_email
|
email_result = async_task('recruitment.tasks._task_send_individual_email',
|
||||||
|
|
||||||
email_result = send_bulk_email(
|
|
||||||
subject=message.subject,
|
subject=message.subject,
|
||||||
message=message.content,
|
body_message=message.content,
|
||||||
recipient_list=[message.recipient.email],
|
recipient=message.recipient.email,
|
||||||
request=request,
|
|
||||||
attachments=None,
|
attachments=None,
|
||||||
async_task_=True,
|
sender=False,
|
||||||
from_interview=False
|
job=False
|
||||||
)
|
)
|
||||||
|
if email_result:
|
||||||
if email_result["success"]:
|
messages.success(request, "Message sent successfully via email!")
|
||||||
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!")
|
|
||||||
else:
|
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:
|
except Exception as e:
|
||||||
messages.warning(request, f"Reply saved but email sending failed: {str(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)
|
return redirect("meeting_details", slug=meeting.slug)
|
||||||
|
|
||||||
|
|
||||||
# def schedule_interview_location_form(request,slug):
|
def schedule_interview_location_form(request,slug):
|
||||||
# schedule=get_object_or_404(InterviewSchedule,slug=slug)
|
schedule=get_object_or_404(InterviewSchedule,slug=slug)
|
||||||
# if request.method=='POST':
|
if request.method=='POST':
|
||||||
# form=InterviewScheduleLocationForm(request.POST,instance=schedule)
|
form=InterviewScheduleLocationForm(request.POST,instance=schedule)
|
||||||
# form.save()
|
form.save()
|
||||||
# return redirect('list_meetings')
|
return redirect('list_meetings')
|
||||||
# else:
|
else:
|
||||||
# form=InterviewScheduleLocationForm(instance=schedule)
|
form=InterviewScheduleLocationForm(instance=schedule)
|
||||||
# return render(request,'interviews/schedule_interview_location_form.html',{'form':form,'schedule':schedule})
|
return render(request,'interviews/schedule_interview_location_form.html',{'form':form,'schedule':schedule})
|
||||||
|
|
||||||
|
|
||||||
class MeetingListView(ListView):
|
class MeetingListView(ListView):
|
||||||
@ -5783,6 +5762,7 @@ class MeetingListView(ListView):
|
|||||||
context_object_name = "meetings"
|
context_object_name = "meetings"
|
||||||
paginate_by = 100
|
paginate_by = 100
|
||||||
|
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
# Start with a base queryset, ensuring an InterviewLocation link exists.
|
# Start with a base queryset, ensuring an InterviewLocation link exists.
|
||||||
queryset = super().get_queryset().filter(interview_location__isnull=False).select_related(
|
queryset = super().get_queryset().filter(interview_location__isnull=False).select_related(
|
||||||
@ -5794,6 +5774,7 @@ class MeetingListView(ListView):
|
|||||||
'interview_location__zoommeetingdetails',
|
'interview_location__zoommeetingdetails',
|
||||||
'interview_location__onsitelocationdetails',
|
'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
|
# Get filters from GET request
|
||||||
@ -5807,11 +5788,10 @@ class MeetingListView(ListView):
|
|||||||
if type_filter:
|
if type_filter:
|
||||||
# Use .title() to handle case variations from URL (e.g., 'remote' -> 'Remote')
|
# Use .title() to handle case variations from URL (e.g., 'remote' -> 'Remote')
|
||||||
normalized_type = type_filter.title()
|
normalized_type = type_filter.title()
|
||||||
print(normalized_type)
|
|
||||||
# Assuming InterviewLocation.LocationType is accessible/defined
|
# Assuming InterviewLocation.LocationType is accessible/defined
|
||||||
if normalized_type in ['Remote', 'Onsite']:
|
if normalized_type in ['Remote', 'Onsite']:
|
||||||
queryset = queryset.filter(interview_location__location_type=normalized_type)
|
queryset = queryset.filter(interview_location__location_type=normalized_type)
|
||||||
print(queryset)
|
|
||||||
|
|
||||||
# 3. Search by Topic (stored on InterviewLocation)
|
# 3. Search by Topic (stored on InterviewLocation)
|
||||||
if search_query:
|
if search_query:
|
||||||
@ -5886,6 +5866,28 @@ class MeetingListView(ListView):
|
|||||||
|
|
||||||
return context
|
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):
|
def reschedule_onsite_meeting(request, slug, candidate_id, meeting_id):
|
||||||
"""Handles the rescheduling of an Onsite Interview (updates OnsiteLocationDetails)."""
|
"""Handles the rescheduling of an Onsite Interview (updates OnsiteLocationDetails)."""
|
||||||
job = get_object_or_404(JobPosting, slug=slug)
|
job = get_object_or_404(JobPosting, slug=slug)
|
||||||
|
|||||||
@ -499,7 +499,7 @@
|
|||||||
</h5>
|
</h5>
|
||||||
<p class="text-muted small mb-0">
|
<p class="text-muted small mb-0">
|
||||||
<i class="fas fa-calendar-alt me-1"></i>
|
<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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user