updates and changes
This commit is contained in:
parent
e9c76dfe18
commit
038a18cacb
@ -208,10 +208,20 @@ ACCOUNT_LOGIN_ON_EMAIL_CONFIRMATION = True
|
|||||||
ACCOUNT_FORMS = {"signup": "recruitment.forms.StaffSignupForm"}
|
ACCOUNT_FORMS = {"signup": "recruitment.forms.StaffSignupForm"}
|
||||||
|
|
||||||
|
|
||||||
# EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
|
||||||
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
# EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
||||||
EMAIL_HOST = "10.10.1.110"
|
|
||||||
EMAIL_PORT = 2225
|
# EMAIL_HOST_PASSWORD = os.getenv("EMAIL_PASSWORD", "mssp.0Q0rSwb.zr6ke4n2k3e4on12.aHwJqnI")
|
||||||
|
# EMAIL_HOST = "smtp.mailersend.net"
|
||||||
|
# EMAIL_PORT = 2525
|
||||||
|
# EMAIL_HOST_USER = "MS_lhygCJ@test-65qngkd8nx3lwr12.mlsender.net"
|
||||||
|
# EMAIL_HOST_PASSWORD = "mssp.0Q0rSwb.zr6ke4n2k3e4on12.aHwJqnI"
|
||||||
|
# EMAIL_USE_TLS = True
|
||||||
|
EMAIL_HOST = 'sandbox.smtp.mailtrap.io'
|
||||||
|
EMAIL_HOST_USER = '38e5179debe69a'
|
||||||
|
EMAIL_HOST_PASSWORD = 'ffa75647d01ecb'
|
||||||
|
EMAIL_PORT = '2525'
|
||||||
|
|
||||||
|
|
||||||
# Crispy Forms Configuration
|
# Crispy Forms Configuration
|
||||||
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
|
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
|
||||||
@ -277,11 +287,11 @@ SOCIALACCOUNT_PROVIDERS = {
|
|||||||
|
|
||||||
# Dynamic Zoom Configuration - will be loaded from database
|
# Dynamic Zoom Configuration - will be loaded from database
|
||||||
# These are fallback values - actual values will be loaded from database at runtime
|
# These are fallback values - actual values will be loaded from database at runtime
|
||||||
ZOOM_ACCOUNT_ID = "HoGikHXsQB2GNDC5Rvyw9A"
|
# ZOOM_ACCOUNT_ID = "HoGikHXsQB2GNDC5Rvyw9A"
|
||||||
ZOOM_CLIENT_ID = "brC39920R8C8azfudUaQgA"
|
# ZOOM_CLIENT_ID = "brC39920R8C8azfudUaQgA"
|
||||||
ZOOM_CLIENT_SECRET = "rvfhjlbID4ychXPOvZ2lYsoAC0B0Ny2L"
|
# ZOOM_CLIENT_SECRET = "rvfhjlbID4ychXPOvZ2lYsoAC0B0Ny2L"
|
||||||
SECRET_TOKEN = "6KdTGyF0SSCSL_V4Xa34aw"
|
# SECRET_TOKEN = "6KdTGyF0SSCSL_V4Xa34aw"
|
||||||
ZOOM_WEBHOOK_API_KEY = "2GNDC5Rvyw9AHoGikHXsQB"
|
# ZOOM_WEBHOOK_API_KEY = "2GNDC5Rvyw9AHoGikHXsQB"
|
||||||
|
|
||||||
# Maximum file upload size (in bytes)
|
# Maximum file upload size (in bytes)
|
||||||
DATA_UPLOAD_MAX_MEMORY_SIZE = 10485760 # 10MB
|
DATA_UPLOAD_MAX_MEMORY_SIZE = 10485760 # 10MB
|
||||||
|
|||||||
@ -12,6 +12,7 @@ from . linkedin_service import LinkedInService
|
|||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
from . models import JobPosting
|
from . models import JobPosting
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
from django.template.loader import render_to_string
|
||||||
from . models import BulkInterviewTemplate,Interview,Message,ScheduledInterview
|
from . models import BulkInterviewTemplate,Interview,Message,ScheduledInterview
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from .utils import get_setting
|
from .utils import get_setting
|
||||||
@ -680,7 +681,6 @@ def create_interview_and_meeting(schedule_id):
|
|||||||
try:
|
try:
|
||||||
schedule = ScheduledInterview.objects.get(pk=schedule_id)
|
schedule = ScheduledInterview.objects.get(pk=schedule_id)
|
||||||
interview = schedule.interview
|
interview = schedule.interview
|
||||||
print("creating zoooooooooooooooooooooooooooooooooooooom meeting")
|
|
||||||
result = create_zoom_meeting(interview.topic, interview.start_time, interview.duration)
|
result = create_zoom_meeting(interview.topic, interview.start_time, interview.duration)
|
||||||
|
|
||||||
if result["status"] == "success":
|
if result["status"] == "success":
|
||||||
@ -963,57 +963,155 @@ from django.conf import settings
|
|||||||
from django.core.mail import EmailMultiAlternatives
|
from django.core.mail import EmailMultiAlternatives
|
||||||
from django.utils.html import strip_tags
|
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')
|
||||||
|
# is_html = '<' in body_message and '>' in body_message
|
||||||
|
|
||||||
|
# if is_html:
|
||||||
|
# plain_message = strip_tags(body_message)
|
||||||
|
# email_obj = EmailMultiAlternatives(subject=subject, body=plain_message, from_email=from_email, to=[recipient])
|
||||||
|
# email_obj.attach_alternative(body_message, "text/html")
|
||||||
|
# else:
|
||||||
|
# email_obj = EmailMultiAlternatives(subject=subject, body=body_message, from_email=from_email, to=[recipient])
|
||||||
|
|
||||||
|
# if attachments:
|
||||||
|
# for attachment in attachments:
|
||||||
|
# if isinstance(attachment, tuple) and len(attachment) == 3:
|
||||||
|
# filename, content, content_type = attachment
|
||||||
|
# email_obj.attach(filename, content, content_type)
|
||||||
|
|
||||||
|
# try:
|
||||||
|
# result=email_obj.send(fail_silently=False)
|
||||||
|
|
||||||
|
# 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(
|
||||||
|
# sender=sender,
|
||||||
|
# recipient=user,
|
||||||
|
# job=job,
|
||||||
|
# subject=subject,
|
||||||
|
# content=body_message, # Store the full HTML or plain content
|
||||||
|
# message_type='DIRECT',
|
||||||
|
# is_read=False, # It's just sent, not read yet
|
||||||
|
# )
|
||||||
|
# logger.info(f"Stored sent message ID {new_message.id} in DB.")
|
||||||
|
# except Exception as e:
|
||||||
|
# logger.error(f"Email sent to {recipient}, but failed to store in DB: {str(e)}")
|
||||||
|
# return result == 1
|
||||||
|
|
||||||
|
# except Exception as e:
|
||||||
|
# logger.error(f"Failed to send email to {recipient}: {str(e)}", exc_info=True)
|
||||||
|
|
||||||
|
def _task_send_individual_email(subject, body_message, recipient, attachments=None, sender=None, job=None, context=None):
|
||||||
|
"""
|
||||||
|
Creates and sends a single email using the branded HTML template.
|
||||||
|
If the context is provided, it renders the branded template.
|
||||||
|
If the context is None, it sends the plain body_message.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
subject (str): The email subject.
|
||||||
|
body_message (str): The main content of the email.
|
||||||
|
recipient (str): The recipient's email address.
|
||||||
|
attachments (list, optional): List of (filename, content, mimetype) tuples.
|
||||||
|
sender (User, optional): The User object who initiated the send.
|
||||||
|
job (Job, optional): The associated Job object (if any).
|
||||||
|
context (dict, optional): Context data for rendering the HTML template.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if the email was successfully sent and logged, False otherwise.
|
||||||
|
"""
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
if is_html:
|
# --- 1. Template Rendering (New Logic) ---
|
||||||
plain_message = strip_tags(body_message)
|
if context:
|
||||||
email_obj = EmailMultiAlternatives(subject=subject, body=plain_message, from_email=from_email, to=[recipient])
|
# 1a. Populate the base context required by the branded template
|
||||||
email_obj.attach_alternative(body_message, "text/html")
|
base_context = {
|
||||||
|
'subject': subject,
|
||||||
|
'user_name': context.pop('user_name', recipient), # Expect user_name from context or default to email
|
||||||
|
'email_message': body_message,
|
||||||
|
'user_email': recipient,
|
||||||
|
'logo_url': context.pop('logo_url', settings.MEDIA_URL + '/images/kaauh-logo.png'),
|
||||||
|
# Merge any other custom context variables
|
||||||
|
**context,
|
||||||
|
}
|
||||||
|
|
||||||
|
try:
|
||||||
|
html_content = render_to_string('emails/email_template.html', base_context)
|
||||||
|
plain_message = strip_tags(html_content)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error rendering HTML template for {recipient}. Sending plain text instead. Error: {e}")
|
||||||
|
html_content = None
|
||||||
|
plain_message = body_message # Fallback to the original body_message
|
||||||
else:
|
else:
|
||||||
email_obj = EmailMultiAlternatives(subject=subject, body=body_message, from_email=from_email, to=[recipient])
|
# Use the original body_message as the plain text body
|
||||||
|
html_content = None
|
||||||
|
plain_message = body_message
|
||||||
|
|
||||||
|
|
||||||
|
# --- 2. Create Email Object ---
|
||||||
|
email_obj = EmailMultiAlternatives(
|
||||||
|
subject=subject,
|
||||||
|
body=plain_message, # Always use plain text for the main body
|
||||||
|
from_email=from_email,
|
||||||
|
to=[recipient]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Attach HTML alternative if rendered successfully
|
||||||
|
if html_content:
|
||||||
|
email_obj.attach_alternative(html_content, "text/html")
|
||||||
|
|
||||||
|
# --- 3. Attachments ---
|
||||||
if attachments:
|
if attachments:
|
||||||
for attachment in attachments:
|
for attachment in attachments:
|
||||||
if isinstance(attachment, tuple) and len(attachment) == 3:
|
if isinstance(attachment, tuple) and len(attachment) == 3:
|
||||||
filename, content, content_type = attachment
|
filename, content, content_type = attachment
|
||||||
email_obj.attach(filename, content, content_type)
|
email_obj.attach(filename, content, content_type)
|
||||||
|
|
||||||
|
# --- 4. Send and Log ---
|
||||||
try:
|
try:
|
||||||
result=email_obj.send(fail_silently=False)
|
# Note: EmailMultiAlternatives inherits from EmailMessage and uses .send()
|
||||||
|
result = email_obj.send(fail_silently=False)
|
||||||
if result==1 and sender and job: # job is none when email sent after message creation
|
|
||||||
|
|
||||||
|
if result == 1 and sender and job: # job is None when email sent after message creation
|
||||||
|
# --- Assuming Message and User are available ---
|
||||||
try:
|
try:
|
||||||
user=get_object_or_404(User,email=recipient)
|
# IMPORTANT: You need to define how to find the User object from the recipient email.
|
||||||
|
# Assuming you have access to the User model and get_object_or_404
|
||||||
|
# User = ... # Define or import your User model
|
||||||
|
# Message = ... # Define or import your Message model
|
||||||
|
|
||||||
|
user = User.objects.get(email=recipient)
|
||||||
new_message = Message.objects.create(
|
new_message = Message.objects.create(
|
||||||
sender=sender,
|
sender=sender,
|
||||||
recipient=user,
|
recipient=user,
|
||||||
job=job,
|
job=job,
|
||||||
subject=subject,
|
subject=subject,
|
||||||
content=body_message, # Store the full HTML or plain content
|
content=html_content or body_message, # Store HTML if sent, otherwise store original body
|
||||||
message_type='DIRECT',
|
message_type='DIRECT',
|
||||||
is_read=False, # It's just sent, not read yet
|
is_read=False,
|
||||||
)
|
)
|
||||||
logger.info(f"Stored sent message ID {new_message.id} in DB.")
|
logger.info(f"Stored sent message ID {new_message.id} for {recipient} in DB.")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Email sent to {recipient}, but failed to store in DB: {str(e)}")
|
logger.error(f"Email sent successfully to {recipient}, but failed to store message in DB: {str(e)}")
|
||||||
return result == 1
|
# Continue execution even if logging fails, as the email was sent
|
||||||
|
|
||||||
|
return result == 1 # Return True if send was successful
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Failed to send email to {recipient}: {str(e)}", exc_info=True)
|
logger.error(f"Failed to send email to {recipient}: {str(e)}", exc_info=True)
|
||||||
|
return False
|
||||||
|
|
||||||
def send_bulk_email_task(subject, customized_sends,attachments=None,sender_user_id=None,job_id=None, hook='recruitment.tasks.email_success_hook'):
|
def send_bulk_email_task(subject, customized_sends,attachments=None,sender_user_id=None,job_id=None, hook='recruitment.tasks.email_success_hook'):
|
||||||
"""
|
"""
|
||||||
Django-Q background task to send pre-formatted email to a list of recipients.,
|
Django-Q background task to send pre-formatted email to a list of recipients.,
|
||||||
Receives arguments directly from the async_task call.
|
Receives arguments directly from the async_task call.
|
||||||
"""
|
"""
|
||||||
print("jhjmfhsdjhfksjhdkfjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjh")
|
|
||||||
logger.info(f"Starting bulk email task for {len(customized_sends)} recipients")
|
logger.info(f"Starting bulk email task for {len(customized_sends)} recipients")
|
||||||
successful_sends = 0
|
successful_sends = 0
|
||||||
total_recipients = len(customized_sends)
|
total_recipients = len(customized_sends)
|
||||||
|
|||||||
118
templates/emails/email_template.html
Normal file
118
templates/emails/email_template.html
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
{% load static %}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>{{ subject }}</title>
|
||||||
|
<style>
|
||||||
|
/* Define your custom colors */
|
||||||
|
:root {
|
||||||
|
--kaauh-teal: #00636e;
|
||||||
|
--kaauh-teal-dark: #004a53;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* General Styling */
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 20px auto;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border: 1px solid #dddddd;
|
||||||
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.05); /* Soft shadow */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header Section */
|
||||||
|
.header {
|
||||||
|
background-color: #00636e; /* --kaauh-teal */
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.logo {
|
||||||
|
max-width: 80px;
|
||||||
|
height: auto;
|
||||||
|
border: 2px solid #ffffff; /* White border to make it pop */
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Content Section */
|
||||||
|
.content {
|
||||||
|
padding: 30px;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
color: #004a53; /* --kaauh-teal-dark for headings */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Button/Call to Action */
|
||||||
|
.button-container {
|
||||||
|
text-align: center;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
.button {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 12px 25px;
|
||||||
|
background-color: #00636e; /* --kaauh-teal */
|
||||||
|
color: #ffffff !important;
|
||||||
|
text-decoration: none;
|
||||||
|
border-radius: 8px;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 16px;
|
||||||
|
/* Simple hover simulation for supporting clients */
|
||||||
|
border-bottom: 4px solid #004a53;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer Section */
|
||||||
|
.footer {
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #777777;
|
||||||
|
border-top: 2px solid #00636e;
|
||||||
|
}
|
||||||
|
.footer a {
|
||||||
|
color: #00636e; /* --kaauh-teal for links */
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<img src="{{ logo_url }}" alt="Your Organization Logo" class="logo">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="content">
|
||||||
|
{% block content %}
|
||||||
|
<h2>Hello {{ user_name }},</h2>
|
||||||
|
|
||||||
|
<p>{{ email_message|safe }}</p>
|
||||||
|
|
||||||
|
{% if cta_link %}
|
||||||
|
<div class="button-container">
|
||||||
|
<a href="{{ cta_link }}" class="button">{{ cta_text|default:"Click to Proceed" }}</a>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<p>If you have any questions, please reply to this email.</p>
|
||||||
|
|
||||||
|
<p>Thank you,</p>
|
||||||
|
<p>The **[Your Organization Name]** Team</p>
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="footer">
|
||||||
|
<p>© {% now "Y" %} Your Organization Name. All rights reserved.</p>
|
||||||
|
<p>This email was sent to {{ user_email }}.</p>
|
||||||
|
<p><a href="{{ unsubscribe_link }}">Unsubscribe</a> | <a href="{{ preferences_link }}">Manage Preferences</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
x
Reference in New Issue
Block a user