editing email

This commit is contained in:
Flatlogic Bot 2026-01-25 16:35:29 +00:00
parent a8a48697b3
commit d8387d341e
13 changed files with 193 additions and 50 deletions

View File

@ -213,4 +213,14 @@ WHATSAPP_ENABLED = os.getenv("WHATSAPP_ENABLED", "true").lower() == "true"
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
LOGIN_URL = 'login'
LOGIN_REDIRECT_URL = 'dashboard'
LOGOUT_REDIRECT_URL = 'index'
LOGOUT_REDIRECT_URL = 'index'
# Site URL for Emails
HOST_FQDN = os.getenv("HOST_FQDN", "")
if HOST_FQDN:
if not HOST_FQDN.startswith(("http://", "https://")):
SITE_URL = f"https://{HOST_FQDN}"
else:
SITE_URL = HOST_FQDN
else:
SITE_URL = "http://127.0.0.1:8000"

View File

@ -10,6 +10,7 @@ from django.contrib import messages
from .whatsapp_utils import send_whatsapp_message_detailed
from django.core.mail import send_mail
from django.conf import settings
from .mail import send_html_email
import logging
class ProfileInline(admin.StackedInline):
@ -81,12 +82,12 @@ class PlatformProfileAdmin(admin.ModelAdmin):
email = request.POST.get('email')
if email:
try:
send_mail(
send_html_email(
subject="Test Email from Platform",
message="This is a test email to verify your platform's email configuration.",
from_email=settings.DEFAULT_FROM_EMAIL,
message="This is a test email to verify your platform's email configuration. If you see the logo and nice formatting, it works!",
recipient_list=[email],
fail_silently=False,
title="Test Email",
request=request
)
messages.success(request, f"Success: Test email sent to {email}.")
except Exception as e:
@ -129,4 +130,4 @@ admin.site.register(Parcel, ParcelAdmin)
admin.site.register(Country)
admin.site.register(Governate)
admin.site.register(City)
admin.site.register(PlatformProfile, PlatformProfileAdmin)
admin.site.register(PlatformProfile, PlatformProfileAdmin)

View File

@ -1,9 +1,57 @@
from django.core.mail import send_mail
from django.core.mail import send_mail, EmailMultiAlternatives
from django.template.loader import render_to_string
from django.utils.html import strip_tags
from django.conf import settings
import logging
logger = logging.getLogger(__name__)
def send_html_email(subject, message, recipient_list, title=None, action_url=None, action_text=None, request=None):
"""
Sends a styled HTML email using the platform template.
"""
try:
from .models import PlatformProfile
platform = PlatformProfile.objects.first()
if not platform:
# Create a dummy platform object if none exists, to avoid errors
class DummyPlatform:
name = "Platform"
logo = None
address = ""
platform = DummyPlatform()
# Determine site URL
site_url = settings.SITE_URL if hasattr(settings, 'SITE_URL') else 'http://127.0.0.1:8000'
if request:
site_url = f"{request.scheme}://{request.get_host()}"
context = {
'platform': platform,
'title': title or subject,
'message': message,
'action_url': action_url,
'action_text': action_text,
'site_url': site_url,
}
html_content = render_to_string('emails/base_email.html', context)
text_content = strip_tags(html_content)
msg = EmailMultiAlternatives(subject, text_content, settings.DEFAULT_FROM_EMAIL, recipient_list)
msg.attach_alternative(html_content, "text/html")
msg.send()
return True
except Exception as e:
logger.error(f"Failed to send HTML email: {e}")
# Fallback to plain text
try:
send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, recipient_list)
return True
except Exception as e2:
logger.error(f"Failed to send fallback email: {e2}")
return False
def send_contact_message(name, email, message):
"""
Sends a contact form message to the platform admins.
@ -25,14 +73,13 @@ def send_contact_message(name, email, message):
recipient_list = settings.CONTACT_EMAIL_TO or [settings.DEFAULT_FROM_EMAIL]
send_mail(
# Use HTML email for contact form too, for consistency
return send_html_email(
subject=subject,
message=full_message,
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=recipient_list,
fail_silently=False,
title="New Contact Message"
)
return True
except Exception as e:
logger.error(f"Failed to send contact message: {e}")
return False
return False

View File

@ -0,0 +1,86 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
}
.container {
max-width: 600px;
margin: 20px auto;
background-color: #ffffff;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
overflow: hidden;
}
.header {
background-color: #ffffff;
padding: 20px;
text-align: center;
border-bottom: 3px solid #0d6efd; /* Bootstrap primary blue */
}
.header img {
max-height: 80px;
width: auto;
}
.content {
padding: 30px;
color: #333333;
line-height: 1.6;
}
.footer {
background-color: #f8f9fa;
padding: 20px;
text-align: center;
font-size: 12px;
color: #888888;
}
.button {
display: inline-block;
padding: 10px 20px;
background-color: #0d6efd;
color: #ffffff !important;
text-decoration: none;
border-radius: 5px;
margin-top: 20px;
}
h1, h2, h3 {
color: #2c3e50;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
{% if platform.logo %}
<img src="{{ site_url }}{{ platform.logo.url }}" alt="{{ platform.name }}">
{% else %}
<h1>{{ platform.name }}</h1>
{% endif %}
</div>
<div class="content">
{% if title %}
<h2>{{ title }}</h2>
{% endif %}
{{ message|safe|linebreaks }}
{% if action_url %}
<div style="text-align: center;">
<a href="{{ action_url }}" class="button">{{ action_text|default:"Click here" }}</a>
</div>
{% endif %}
</div>
<div class="footer">
<p>&copy; {% now "Y" %} {{ platform.name }}. All rights reserved.</p>
{% if platform.address %}
<p>{{ platform.address }}</p>
{% endif %}
</div>
</div>
</body>
</html>

View File

@ -8,6 +8,7 @@ urlpatterns = [
path('logout/', auth_views.LogoutView.as_view(next_page='/'), name='logout'),
path('register/', views.register, name='register'),
path('register/verify/', views.verify_registration, name='verify_registration'),
path('dashboard/', views.dashboard, name='dashboard'),
path('shipment-request/', views.shipment_request, name='shipment_request'),
path('accept-parcel/<int:parcel_id>/', views.accept_parcel, name='accept_parcel'),
@ -21,9 +22,9 @@ urlpatterns = [
path('ajax/get-cities/', views.get_cities, name='get_cities'),
path('privacy-policy/', views.privacy_policy, name='privacy_policy'),
path('terms-conditions/', views.terms_conditions, name='terms_conditions'),
path('contact/', views.contact_view, name='contact'),
path('contact/', views.contact, name='contact'),
path('profile/', views.profile_view, name='profile'),
path('profile/edit/', views.edit_profile_view, name='edit_profile'),
path('profile/edit/', views.edit_profile, name='edit_profile'),
path('profile/verify-otp/', views.verify_otp_view, name='verify_otp'),
]

View File

@ -2,6 +2,7 @@ from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth import login, authenticate, logout
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from .models import Parcel, Profile, Country, Governate, City, OTPVerification, PlatformProfile
from .forms import UserRegistrationForm, ParcelForm, ContactForm, UserProfileForm
from django.utils.translation import gettext_lazy as _
@ -21,7 +22,7 @@ from .whatsapp_utils import (
notify_status_change,
send_whatsapp_message
)
from .mail import send_contact_message
from .mail import send_contact_message, send_html_email
def index(request):
tracking_id = request.GET.get('tracking_id')
@ -59,12 +60,12 @@ def register(request):
send_whatsapp_message(phone, f"Your verification code is: {code}")
messages.info(request, _("Verification code sent to WhatsApp."))
else:
send_mail(
_('Verification Code'),
f'Your verification code is: {code}',
settings.DEFAULT_FROM_EMAIL,
[user.email],
fail_silently=False,
send_html_email(
subject=_('Verification Code'),
message=f'Your verification code is: {code}',
recipient_list=[user.email],
title=_('Welcome to Masar!'),
request=request
)
messages.info(request, _("Verification code sent to email."))
@ -117,7 +118,7 @@ def verify_registration(request):
def dashboard(request):
# Ensure profile exists
profile, created = Profile.objects.get_or_create(user=request.user)
if profile.role == 'shipper':
parcels = Parcel.objects.filter(shipper=request.user).order_by('-created_at')
return render(request, 'core/shipper_dashboard.html', {'parcels': parcels})
@ -136,7 +137,7 @@ def shipment_request(request):
if profile.role != 'shipper':
messages.error(request, _("Only shippers can request shipments."))
return redirect('dashboard')
if request.method == 'POST':
form = ParcelForm(request.POST)
if form.is_valid():
@ -159,7 +160,7 @@ def accept_parcel(request, parcel_id):
if profile.role != 'car_owner':
messages.error(request, _("Only car owners can accept shipments."))
return redirect('dashboard')
parcel = get_object_or_404(Parcel, id=parcel_id, status='pending', payment_status='paid')
parcel.carrier = request.user
parcel.status = 'picked_up'
@ -230,7 +231,7 @@ def payment_success(request):
messages.success(request, _("Payment successful! Your shipment is now active."))
else:
messages.warning(request, _("Payment status is pending or failed. Please check your dashboard."))
return redirect('dashboard')
@login_required
@ -263,7 +264,7 @@ def privacy_policy(request):
def terms_conditions(request):
return render(request, 'core/terms_conditions.html')
def contact_view(request):
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
@ -287,7 +288,7 @@ def profile_view(request):
return render(request, 'core/profile.html', {'profile': request.user.profile})
@login_required
def edit_profile_view(request):
def edit_profile(request):
if request.method == 'POST':
form = UserProfileForm(request.POST, request.FILES, instance=request.user.profile)
if form.is_valid():
@ -310,11 +311,11 @@ def edit_profile_view(request):
'city_id': data['city'].id if data['city'] else None,
}
request.session['pending_profile_update'] = safe_data
# 3. Generate OTP
code = ''.join(random.choices(string.digits, k=6))
OTPVerification.objects.create(user=request.user, code=code, purpose='profile_update')
# 4. Send OTP
method = data.get('otp_method', 'email')
if method == 'whatsapp':
@ -326,19 +327,19 @@ def edit_profile_view(request):
# Default to email
# Send to the NEW email address (from the form), not the old one
target_email = data['email']
send_mail(
_('Verification Code'),
f'Your verification code is: {code}',
settings.DEFAULT_FROM_EMAIL,
[target_email],
fail_silently=False,
send_html_email(
subject=_('Verification Code'),
message=f'Your verification code is: {code}',
recipient_list=[target_email],
title=_('Profile Update Verification'),
request=request
)
messages.info(request, _("Verification code sent to email."))
return redirect('verify_otp')
else:
form = UserProfileForm(instance=request.user.profile)
return render(request, 'core/edit_profile.html', {'form': form})
@login_required
@ -390,4 +391,4 @@ def verify_otp_view(request):
except OTPVerification.DoesNotExist:
messages.error(request, _("Invalid code."))
return render(request, 'core/verify_otp.html')
return render(request, 'core/verify_otp.html')

View File

@ -5,6 +5,7 @@ from django.conf import settings
from django.core.mail import send_mail
from django.utils.translation import gettext_lazy as _
from .models import PlatformProfile
from .mail import send_html_email
logger = logging.getLogger(__name__)
@ -149,12 +150,11 @@ Please proceed to payment to make it visible to drivers."""
# Email
if parcel.shipper.email:
try:
send_mail(
send_html_email(
subject='Shipment Request Received - ' + parcel.tracking_number,
message=message,
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=[parcel.shipper.email],
fail_silently=False
title='Shipment Request Received'
)
logger.info(f"Shipment created email sent to {parcel.shipper.email}")
except Exception as e:
@ -176,12 +176,11 @@ Your shipment is now visible to available drivers."""
# Email Shipper
if parcel.shipper.email:
try:
send_mail(
send_html_email(
subject='Payment Successful - ' + parcel.tracking_number,
message=shipper_msg,
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=[parcel.shipper.email],
fail_silently=False
title='Payment Successful'
)
except Exception as e:
logger.error(f"Failed to send payment email to {parcel.shipper.email}: {e}")
@ -205,12 +204,11 @@ Status: {parcel.get_status_display()}"""
if parcel.shipper.email:
try:
send_mail(
send_html_email(
subject='Driver Assigned - ' + parcel.tracking_number,
message=msg,
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=[parcel.shipper.email],
fail_silently=True
title='Driver Assigned'
)
except Exception:
pass
@ -227,12 +225,11 @@ New Status: {parcel.get_status_display()}"""
if parcel.shipper.email:
try:
send_mail(
send_html_email(
subject='Shipment Update - ' + parcel.tracking_number,
message=msg,
from_email=settings.DEFAULT_FROM_EMAIL,
recipient_list=[parcel.shipper.email],
fail_silently=True
title='Shipment Update'
)
except Exception:
pass