From b5584e1d8ea94b689f7b09e8e5c6bd42a053b0ad Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 10 Mar 2025 14:33:40 +0100 Subject: [PATCH 1/3] send email confirmation after lead creation --- .../templates/email/lead_confirmation.html | 115 ++++++++++++++++++ .../templates/email/lead_confirmation.txt | 22 ++++ hub/services/views/leads.py | 43 ++++++- hub/settings.py | 11 ++ 4 files changed, 190 insertions(+), 1 deletion(-) create mode 100644 hub/services/templates/email/lead_confirmation.html create mode 100644 hub/services/templates/email/lead_confirmation.txt diff --git a/hub/services/templates/email/lead_confirmation.html b/hub/services/templates/email/lead_confirmation.html new file mode 100644 index 0000000..e30a7dc --- /dev/null +++ b/hub/services/templates/email/lead_confirmation.html @@ -0,0 +1,115 @@ + + + + + Thank you for contacting Servala + + + +
+
+

Thank you for contacting Servala!

+
+
+

Hello {{ name }},

+ +

Thank you for your interest in our services. We have received your inquiry and will get back to you shortly.

+ +

Here's a summary of the information you provided:

+ + + + + + + + + + + + + + + + + + + {% if service != 'General inquiry' %} + + + + + {% endif %} + {% if provider != 'Not specified' %} + + + + + {% endif %} + {% if plan != 'Not specified' %} + + + + + {% endif %} + {% if message %} + + + + + {% endif %} +
Name{{ name }}
Email{{ email }}
Phone{{ phone }}
Company{{ company }}
Service{{ service }}
Provider{{ provider }}
Plan{{ plan }}
Message{{ message }}
+ +

Our team will review your inquiry and contact you as soon as possible.

+ +

Best regards,
Sir Vala and the Team

+
+ +
+ + \ No newline at end of file diff --git a/hub/services/templates/email/lead_confirmation.txt b/hub/services/templates/email/lead_confirmation.txt new file mode 100644 index 0000000..bce2a5f --- /dev/null +++ b/hub/services/templates/email/lead_confirmation.txt @@ -0,0 +1,22 @@ +Hello {{ name }}, + +Thank you for your interest in our services. We have received your inquiry and will get back to you shortly. + +Here's a summary of the information you provided: + +- Name: {{ name }} +- Email: {{ email }} +- Phone: {{ phone }} +- Company: {{ company }} +{% if service != 'General inquiry' %}- Service: {{ service }}{% endif %} +{% if provider != 'Not specified' %}- Provider: {{ provider }}{% endif %} +{% if plan != 'Not specified' %}- Plan: {{ plan }}{% endif %} +{% if message %}- Message: {{ message }}{% endif %} + +Our team will review your inquiry and contact you as soon as possible. + +Best regards, +Sir Vala and the Team + +-- +This is an automated message. Please do not reply directly to this email. You can reach us at hi@servala.com. \ No newline at end of file diff --git a/hub/services/views/leads.py b/hub/services/views/leads.py index 2e3ccda..7cb3967 100644 --- a/hub/services/views/leads.py +++ b/hub/services/views/leads.py @@ -2,6 +2,10 @@ import logging import time from django.shortcuts import render, redirect from django.contrib import messages +from django.core.mail import send_mail +from django.template.loader import render_to_string +from django.utils.html import strip_tags +from django.conf import settings from hub.services.forms import LeadForm from hub.services.odoo import OdooAPI @@ -130,6 +134,7 @@ def contact_form(request): # Format the final message with all context formatted_context = "
".join(context_info) + original_message = lead.message lead.message = ( lead.message + "

" + formatted_context if lead.message @@ -144,9 +149,45 @@ def contact_form(request): odoo_lead_id = odoo.create_lead(lead, lead_title) lead.odoo_lead_id = odoo_lead_id lead.save() - logger.info(f"Successfully created lead with Odoo ID: {odoo_lead_id}") + # Send confirmation email + try: + # Prepare context for email template + email_context = { + "name": lead.name, + "email": lead.email, + "company": lead.company or "Not provided", + "phone": lead.phone or "Not provided", + "message": original_message, + "service": service_name or "General inquiry", + "provider": offering_name or "Not specified", + "plan": plan_name or "Not specified", + } + + # Render email content from template + html_message = render_to_string( + "email/lead_confirmation.html", email_context + ) + plain_message = render_to_string( + "email/lead_confirmation.txt", email_context + ) + # Send the email + send_mail( + subject=f'Thank you for contacting Servala about {service_name or "our services"}', + message=plain_message, + html_message=html_message, + from_email=settings.DEFAULT_FROM_EMAIL, + recipient_list=[lead.email], + fail_silently=False, + ) + logger.info(f"Confirmation email sent to {lead.email}") + except Exception as e: + # Log error but don't stop the process + logger.error( + f"Failed to send confirmation email: {str(e)}", exc_info=True + ) + # Redirect to thank you page return redirect("services:thank_you") diff --git a/hub/settings.py b/hub/settings.py index 36d89e5..63eaaad 100644 --- a/hub/settings.py +++ b/hub/settings.py @@ -184,6 +184,17 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" MEDIA_URL = "/media/" MEDIA_ROOT = env.path("MEDIA_ROOT", default=BASE_DIR / "media") + +# Email settings using Mailgun EU region +EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" +EMAIL_HOST = "smtp.eu.mailgun.org" +EMAIL_PORT = 587 +EMAIL_USE_TLS = True +EMAIL_HOST_USER = env.str("EMAIL_HOST_USER") +EMAIL_HOST_PASSWORD = env.str("EMAIL_HOST_PASSWORD") +DEFAULT_FROM_EMAIL = env.str("DEFAULT_FROM_EMAIL", default="noreply@mail.servala.com") + + ODOO_CONFIG = { "url": env.str("ODOO_URL", default="http://localhost:8069"), "db": env.str("ODOO_DB", default="odoo"), From 7bd09ec6aa10e288e47ef1aff92b13c5be40ed5e Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 10 Mar 2025 17:43:17 +0100 Subject: [PATCH 2/3] set a default to allow building --- hub/settings.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hub/settings.py b/hub/settings.py index 63eaaad..226cf66 100644 --- a/hub/settings.py +++ b/hub/settings.py @@ -190,8 +190,8 @@ EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend" EMAIL_HOST = "smtp.eu.mailgun.org" EMAIL_PORT = 587 EMAIL_USE_TLS = True -EMAIL_HOST_USER = env.str("EMAIL_HOST_USER") -EMAIL_HOST_PASSWORD = env.str("EMAIL_HOST_PASSWORD") +EMAIL_HOST_USER = env.str("EMAIL_HOST_USER", default="none") +EMAIL_HOST_PASSWORD = env.str("EMAIL_HOST_PASSWORD", default="none") DEFAULT_FROM_EMAIL = env.str("DEFAULT_FROM_EMAIL", default="noreply@mail.servala.com") From 3f6fc4a86e49ec5ca0eae82fecc5e4c40256fadd Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 12 Mar 2025 06:41:33 +0100 Subject: [PATCH 3/3] allow manual ordering of cloud provider --- hub/services/admin.py | 12 ++++++++-- ...oudprovider_options_cloudprovider_order.py | 22 +++++++++++++++++++ hub/services/models.py | 4 ++++ hub/services/views/providers.py | 2 +- 4 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 hub/services/migrations/0020_alter_cloudprovider_options_cloudprovider_order.py diff --git a/hub/services/admin.py b/hub/services/admin.py index 9a67782..3ba72d8 100644 --- a/hub/services/admin.py +++ b/hub/services/admin.py @@ -68,11 +68,19 @@ class CategoryAdmin(admin.ModelAdmin): @admin.register(CloudProvider) -class CloudProviderAdmin(admin.ModelAdmin): - list_display = ("name", "slug", "logo_preview", "disable_listing", "is_featured") +class CloudProviderAdmin(SortableAdminMixin, admin.ModelAdmin): + list_display = ( + "name", + "slug", + "logo_preview", + "disable_listing", + "is_featured", + "order", + ) search_fields = ("name", "description") prepopulated_fields = {"slug": ("name",)} inlines = [OfferingInline] + ordering = ("order",) def logo_preview(self, obj): if obj.logo: diff --git a/hub/services/migrations/0020_alter_cloudprovider_options_cloudprovider_order.py b/hub/services/migrations/0020_alter_cloudprovider_options_cloudprovider_order.py new file mode 100644 index 0000000..ebf436d --- /dev/null +++ b/hub/services/migrations/0020_alter_cloudprovider_options_cloudprovider_order.py @@ -0,0 +1,22 @@ +# Generated by Django 5.1.5 on 2025-03-12 05:37 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("services", "0019_alter_websitefaq_options_websitefaq_order"), + ] + + operations = [ + migrations.AlterModelOptions( + name="cloudprovider", + options={"ordering": ["order"]}, + ), + migrations.AddField( + model_name="cloudprovider", + name="order", + field=models.IntegerField(default=0), + ), + ] diff --git a/hub/services/models.py b/hub/services/models.py index 0a70614..b547d71 100644 --- a/hub/services/models.py +++ b/hub/services/models.py @@ -97,9 +97,13 @@ class CloudProvider(models.Model): null=True, blank=True, ) + order = models.IntegerField(default=0) is_featured = models.BooleanField(default=False) disable_listing = models.BooleanField(default=False) + class Meta: + ordering = ["order"] + def __str__(self): return self.name diff --git a/hub/services/views/providers.py b/hub/services/views/providers.py index 84d5df1..92eba64 100644 --- a/hub/services/views/providers.py +++ b/hub/services/views/providers.py @@ -9,7 +9,7 @@ from hub.services.models import ( def provider_list(request): providers = ( CloudProvider.objects.filter(disable_listing=False) - .order_by("name") + .order_by("order") .prefetch_related("offerings", "consulting_partners") )