From 038a18cacb84e3244212816cf3a21cd8ec9067bf Mon Sep 17 00:00:00 2001 From: ismail Date: Sat, 13 Dec 2025 15:00:40 +0300 Subject: [PATCH] updates and changes --- NorahUniversity/settings.py | 28 ++++-- recruitment/tasks.py | 138 +++++++++++++++++++++++---- templates/emails/email_template.html | 118 +++++++++++++++++++++++ 3 files changed, 255 insertions(+), 29 deletions(-) create mode 100644 templates/emails/email_template.html diff --git a/NorahUniversity/settings.py b/NorahUniversity/settings.py index bc0e691..3cb69bf 100644 --- a/NorahUniversity/settings.py +++ b/NorahUniversity/settings.py @@ -208,10 +208,20 @@ ACCOUNT_LOGIN_ON_EMAIL_CONFIRMATION = True ACCOUNT_FORMS = {"signup": "recruitment.forms.StaffSignupForm"} -# EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" -EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" -EMAIL_HOST = "10.10.1.110" -EMAIL_PORT = 2225 +EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" +# EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend" + +# 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_ALLOWED_TEMPLATE_PACKS = "bootstrap5" @@ -277,11 +287,11 @@ SOCIALACCOUNT_PROVIDERS = { # Dynamic Zoom Configuration - will be loaded from database # These are fallback values - actual values will be loaded from database at runtime -ZOOM_ACCOUNT_ID = "HoGikHXsQB2GNDC5Rvyw9A" -ZOOM_CLIENT_ID = "brC39920R8C8azfudUaQgA" -ZOOM_CLIENT_SECRET = "rvfhjlbID4ychXPOvZ2lYsoAC0B0Ny2L" -SECRET_TOKEN = "6KdTGyF0SSCSL_V4Xa34aw" -ZOOM_WEBHOOK_API_KEY = "2GNDC5Rvyw9AHoGikHXsQB" +# ZOOM_ACCOUNT_ID = "HoGikHXsQB2GNDC5Rvyw9A" +# ZOOM_CLIENT_ID = "brC39920R8C8azfudUaQgA" +# ZOOM_CLIENT_SECRET = "rvfhjlbID4ychXPOvZ2lYsoAC0B0Ny2L" +# SECRET_TOKEN = "6KdTGyF0SSCSL_V4Xa34aw" +# ZOOM_WEBHOOK_API_KEY = "2GNDC5Rvyw9AHoGikHXsQB" # Maximum file upload size (in bytes) DATA_UPLOAD_MAX_MEMORY_SIZE = 10485760 # 10MB diff --git a/recruitment/tasks.py b/recruitment/tasks.py index 3ee69b0..2512399 100644 --- a/recruitment/tasks.py +++ b/recruitment/tasks.py @@ -12,6 +12,7 @@ from . linkedin_service import LinkedInService from django.shortcuts import get_object_or_404 from . models import JobPosting from django.utils import timezone +from django.template.loader import render_to_string from . models import BulkInterviewTemplate,Interview,Message,ScheduledInterview from django.contrib.auth import get_user_model from .utils import get_setting @@ -680,7 +681,6 @@ def create_interview_and_meeting(schedule_id): try: schedule = ScheduledInterview.objects.get(pk=schedule_id) interview = schedule.interview - print("creating zoooooooooooooooooooooooooooooooooooooom meeting") result = create_zoom_meeting(interview.topic, interview.start_time, interview.duration) if result["status"] == "success": @@ -963,57 +963,155 @@ from django.conf import settings from django.core.mail import EmailMultiAlternatives 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.""" +# 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 + +# 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') - 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") + # --- 1. Template Rendering (New Logic) --- + if context: + # 1a. Populate the base context required by the branded template + 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: - 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: for attachment in attachments: if isinstance(attachment, tuple) and len(attachment) == 3: filename, content, content_type = attachment email_obj.attach(filename, content, content_type) + # --- 4. Send and Log --- try: - result=email_obj.send(fail_silently=False) - - if result==1 and sender and job: # job is none when email sent after message creation + # 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 + # --- Assuming Message and User are available --- 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( sender=sender, recipient=user, job=job, 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', - 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: - logger.error(f"Email sent to {recipient}, but failed to store in DB: {str(e)}") - return result == 1 + logger.error(f"Email sent successfully to {recipient}, but failed to store message in DB: {str(e)}") + # Continue execution even if logging fails, as the email was sent + + return result == 1 # Return True if send was successful except Exception as e: 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'): """ Django-Q background task to send pre-formatted email to a list of recipients., Receives arguments directly from the async_task call. """ - print("jhjmfhsdjhfksjhdkfjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjh") logger.info(f"Starting bulk email task for {len(customized_sends)} recipients") successful_sends = 0 total_recipients = len(customized_sends) diff --git a/templates/emails/email_template.html b/templates/emails/email_template.html new file mode 100644 index 0000000..45cce84 --- /dev/null +++ b/templates/emails/email_template.html @@ -0,0 +1,118 @@ +{% load static %} + + + + + + {{ subject }} + + + +
+
+ +
+ +
+ {% block content %} +

Hello {{ user_name }},

+ +

{{ email_message|safe }}

+ + {% if cta_link %} + + {% endif %} + +

If you have any questions, please reply to this email.

+ +

Thank you,

+

The **[Your Organization Name]** Team

+ {% endblock %} +
+ + +
+ + \ No newline at end of file