37733-vm/core/views.py
2026-01-24 08:44:46 +00:00

759 lines
30 KiB
Python

from .thawani import ThawaniClient
from datetime import timedelta
from django.shortcuts import render, redirect, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.contrib.auth import login, authenticate, logout
from django.utils import timezone
from django.urls import reverse
from .models import Profile, Truck, Shipment, Bid, Message, OTPCode, Country, City, AppSetting, Banner, HomeSection, Transaction, ContactMessage
from .forms import (
TruckForm, ShipmentForm, BidForm, UserRegistrationForm,
OTPVerifyForm, ShipperOfferForm, RenewSubscriptionForm, AppSettingForm,
ContactForm
)
from django.contrib import messages
from django.utils.translation import gettext as _
from django.db.models import Q
from django.contrib.auth.models import User
from .whatsapp import send_whatsapp_message
from django.contrib.auth.forms import AuthenticationForm
from django.core.mail import send_mail
from django.conf import settings
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
from django.contrib.sites.shortcuts import get_current_site
import json
import logging
import os
logger = logging.getLogger(__name__)
def home(request):
"""Render the landing screen for MASAR CARGO."""
banners = Banner.objects.filter(is_active=True)
home_sections = HomeSection.objects.filter(is_active=True).order_by('order')
context = {
"deployment_timestamp": timezone.now().timestamp(),
"banners": banners,
"home_sections": home_sections,
}
return render(request, "core/index.html", context)
def register(request):
app_settings = AppSetting.objects.first()
subscription_enabled = (app_settings.subscription_enabled and app_settings.thawani_enabled) if app_settings else False
# Simplified fees dictionary for JS
# Ensuring keys are exactly as they appear in Profile.ROLE_CHOICES
fees = {
'SHIPPER': {
'MONTHLY': str(app_settings.shipper_monthly_fee) if app_settings else "0.00",
'ANNUAL': str(app_settings.shipper_annual_fee) if app_settings else "0.00",
},
'TRUCK_OWNER': {
'MONTHLY': str(app_settings.truck_owner_monthly_fee) if app_settings else "0.00",
'ANNUAL': str(app_settings.truck_owner_annual_fee) if app_settings else "0.00",
}
}
if request.method == 'POST':
form = UserRegistrationForm(request.POST)
if form.is_valid():
# Store data in session to be used after OTP verification
registration_data = {
'username': form.cleaned_data['username'],
'email': form.cleaned_data['email'],
'password': form.data['password1'], # We need raw password to create user later
'role': form.cleaned_data['role'],
'phone_number': form.cleaned_data['phone_number'],
'country_code': form.cleaned_data['country_code'],
'subscription_plan': form.cleaned_data.get('subscription_plan', 'NONE'),
}
request.session['registration_data'] = registration_data
# Send OTP
full_phone = f"{registration_data['country_code']}{registration_data['phone_number']}"
otp = OTPCode.generate_code(full_phone)
msg = _("Your verification code for MASAR CARGO is: %(code)s") % {"code": otp.code}
if send_whatsapp_message(full_phone, msg):
messages.info(request, _("A verification code has been sent to your WhatsApp."))
return redirect('verify_otp_registration')
else:
messages.error(request, _("Failed to send verification code. Please check your phone number."))
else:
messages.error(request, _("Please correct the errors below."))
else:
form = UserRegistrationForm()
return render(request, 'registration/register.html', {
'form': form,
'subscription_enabled': subscription_enabled,
'fees_json': json.dumps(fees)
})
def verify_otp_registration(request):
registration_data = request.session.get('registration_data')
if not registration_data:
return redirect('register')
if request.method == 'POST':
form = OTPVerifyForm(request.POST)
if form.is_valid():
code = form.cleaned_data['otp_code']
full_phone = f"{registration_data['country_code']}{registration_data['phone_number']}"
otp_record = OTPCode.objects.filter(phone_number=full_phone, code=code, is_used=False).last()
if otp_record and otp_record.is_valid():
otp_record.is_used = True
otp_record.save()
# Create user
user = User.objects.create_user(
username=registration_data['username'],
email=registration_data['email'],
password=registration_data['password']
)
profile = user.profile
profile.role = registration_data['role']
profile.phone_number = registration_data['phone_number']
profile.country_code = registration_data['country_code']
profile.subscription_plan = registration_data.get('subscription_plan', 'NONE')
profile.save()
login(request, user)
if 'registration_data' in request.session:
del request.session['registration_data']
if profile.subscription_plan != 'NONE':
return thawani_checkout(request, profile.subscription_plan)
messages.success(request, _("Registration successful. Welcome!"))
return redirect('dashboard')
else:
messages.error(request, _("Invalid or expired verification code."))
else:
form = OTPVerifyForm()
return render(request, 'registration/verify_otp.html', {'form': form, 'purpose': 'registration'})
def custom_login(request):
if request.method == 'POST':
form = AuthenticationForm(request, data=request.POST)
if form.is_valid():
user = form.get_user()
profile = user.profile
if not profile.phone_number:
messages.error(request, _("Your account does not have a phone number. Please contact admin."))
return redirect('login')
# Store user ID in session temporarily
request.session['pre_otp_user_id'] = user.id
# Send OTP
full_phone = profile.full_phone_number
otp = OTPCode.generate_code(full_phone)
msg = _("Your login verification code for MASAR CARGO is: %(code)s") % {"code": otp.code}
if send_whatsapp_message(full_phone, msg):
messages.info(request, _("A verification code has been sent to your WhatsApp."))
return redirect('verify_otp_login')
else:
# If WhatsApp fails, maybe allow login but warn? Or strictly enforce?
# For now, strictly enforce
messages.error(request, _("Failed to send verification code. Please check your connection."))
else:
messages.error(request, _("Invalid username or password."))
else:
form = AuthenticationForm()
return render(request, 'registration/login.html', {'form': form})
def verify_otp_login(request):
user_id = request.session.get('pre_otp_user_id')
if not user_id:
return redirect('login')
user = get_object_or_404(User, id=user_id)
profile = user.profile
if request.method == 'POST':
form = OTPVerifyForm(request.POST)
if form.is_valid():
code = form.cleaned_data['otp_code']
full_phone = profile.full_phone_number
otp_record = OTPCode.objects.filter(phone_number=full_phone, code=code, is_used=False).last()
if otp_record and otp_record.is_valid():
otp_record.is_used = True
otp_record.save()
login(request, user)
if 'pre_otp_user_id' in request.session:
del request.session['pre_otp_user_id']
messages.success(request, _("Logged in successfully!"))
return redirect('dashboard')
else:
messages.error(request, _("Invalid or expired verification code."))
else:
form = OTPVerifyForm()
return render(request, 'registration/verify_otp.html', {'form': form, 'purpose': 'login'})
@login_required
def dashboard(request):
profile, created = Profile.objects.get_or_create(user=request.user)
if profile.role == 'SHIPPER':
my_shipments = Shipment.objects.filter(shipper=request.user).order_by('-created_at')
# In the new flow, Shippers place bids.
my_bids = Bid.objects.filter(shipment__shipper=request.user).order_by('-created_at')
return render(request, 'core/shipper_dashboard.html', {
'shipments': my_shipments,
'bids': my_bids
})
elif profile.role == 'TRUCK_OWNER':
approved_trucks = Truck.objects.filter(owner=request.user, is_approved=True)
pending_trucks = Truck.objects.filter(owner=request.user, is_approved=False)
# Truck owners receive bids in the new flow
my_received_bids = Bid.objects.filter(truck_owner=request.user).order_by('-created_at')
return render(request, 'core/truck_owner_dashboard.html', {
'trucks': approved_trucks,
'pending_trucks': pending_trucks,
'bids': my_received_bids
})
elif profile.role == 'ADMIN' or request.user.is_superuser:
pending_trucks = Truck.objects.filter(is_approved=False).order_by('-created_at')
approved_trucks = Truck.objects.filter(is_approved=True).order_by('-created_at')
# Subscription stats
today = timezone.now().date()
total_profiles = Profile.objects.exclude(role='ADMIN')
active_subscriptions = 0
expired_subscriptions = 0
for p in total_profiles:
if p.is_expired():
expired_subscriptions += 1
else:
active_subscriptions += 1
context = {
'total_users': User.objects.count(),
'total_trucks': Truck.objects.count(),
'total_shipments': Shipment.objects.count(),
'total_bids': Bid.objects.count(),
'pending_trucks': pending_trucks,
'approved_trucks': approved_trucks,
'active_subscriptions': active_subscriptions,
'expired_subscriptions': expired_subscriptions,
}
return render(request, 'core/admin_dashboard.html', context)
else:
return redirect('/')
@login_required
def truck_register(request):
if request.user.profile.role != 'TRUCK_OWNER':
return redirect('dashboard')
if request.method == 'POST':
form = TruckForm(request.POST, request.FILES)
if form.is_valid():
truck = form.save(commit=False)
truck.owner = request.user
truck.is_approved = False
truck.save()
messages.success(request, _("Truck registered successfully! It will be visible after admin approval."))
return redirect('dashboard')
else:
messages.error(request, _("There was an error in your registration. Please check the form."))
else:
form = TruckForm()
return render(request, 'core/truck_register.html', {'form': form})
@login_required
def edit_truck(request, truck_id):
truck = get_object_or_404(Truck, id=truck_id, owner=request.user)
if request.method == 'POST':
form = TruckForm(request.POST, request.FILES, instance=truck)
if form.is_valid():
truck = form.save(commit=False)
truck.is_approved = False
truck.save()
messages.success(request, _("Truck data updated successfully! It will be reviewed by admin again."))
return redirect('dashboard')
else:
messages.error(request, _("There was an error updating your truck. Please check the form."))
else:
form = TruckForm(instance=truck)
return render(request, 'core/truck_register.html', {'form': form, 'edit_mode': True, 'truck': truck})
@login_required
def approve_truck(request, truck_id):
if not (request.user.profile.role == 'ADMIN' or request.user.is_superuser):
return redirect('dashboard')
truck = get_object_or_404(Truck, id=truck_id)
truck.is_approved = True
truck.save()
owner_phone = getattr(truck.owner.profile, 'full_phone_number', None)
if owner_phone:
msg = _("Your truck (%(plate)s) has been approved! You can now receive offers for shipments.") % {"plate": truck.plate_no}
send_whatsapp_message(owner_phone, msg)
messages.success(request, _("Truck approved successfully!"))
return redirect('dashboard')
@login_required
def suspend_truck(request, truck_id):
if not (request.user.profile.role == 'ADMIN' or request.user.is_superuser):
return redirect('dashboard')
truck = get_object_or_404(Truck, id=truck_id)
truck.is_approved = False
truck.save()
messages.warning(request, _("Truck has been suspended."))
return redirect('dashboard')
@login_required
def post_shipment(request):
"""Note: This is used as the 'Add A Bid' / 'Add Post' action for Shippers."""
if request.user.profile.role != 'SHIPPER':
return redirect('dashboard')
if request.method == 'POST':
form = ShipmentForm(request.POST)
if form.is_valid():
shipment = form.save(commit=False)
shipment.shipper = request.user
shipment.save()
messages.success(request, _("Shipment posted successfully! It is now open for bids or you can browse trucks to send it as an offer."))
return redirect('dashboard')
else:
logger.error(f"Post Shipment Form Errors: {form.errors}")
messages.error(request, _("Please correct the errors in the form."))
else:
form = ShipmentForm()
return render(request, 'core/post_shipment.html', {'form': form})
@login_required
def marketplace(request):
"""Shippers browse available trucks here."""
if request.user.profile.role != 'SHIPPER':
return redirect('dashboard')
trucks = Truck.objects.filter(is_approved=True).order_by('-created_at')
return render(request, 'core/marketplace.html', {'trucks': trucks})
@login_required
def place_bid(request, truck_id):
"""Shipper makes an offer to a specific truck."""
truck = get_object_or_404(Truck, id=truck_id, is_approved=True)
if request.user.profile.role != 'SHIPPER':
return redirect('dashboard')
if request.method == 'POST':
form = ShipperOfferForm(request.POST)
if form.is_valid():
# Create Shipment
shipment = Shipment.objects.create(
shipper=request.user,
description=form.cleaned_data['description'],
required_truck_type_link=form.cleaned_data["required_truck_type_link"],
weight=form.cleaned_data['weight'],
origin_country=form.cleaned_data['origin_country'],
origin_city=form.cleaned_data['origin_city'],
destination_country=form.cleaned_data['destination_country'],
destination_city=form.cleaned_data['destination_city'],
delivery_date=form.cleaned_data['delivery_date'],
status='OPEN'
)
# Create Bid (Offer)
bid = Bid.objects.create(
shipment=shipment,
truck_owner=truck.owner,
truck=truck,
amount=form.cleaned_data['amount'],
comments=form.cleaned_data.get('comments', ''),
status='PENDING'
)
# Notify Truck Owner via WhatsApp
owner_phone = getattr(truck.owner.profile, 'full_phone_number', None)
if owner_phone:
msg = _("New offer received for your truck (%(plate)s)! Route: %(origin)s to %(dest)s. Amount: %(amount)s") % {"plate": truck.plate_no, "origin": shipment.display_origin, "dest": shipment.display_destination, "amount": bid.amount}
send_whatsapp_message(owner_phone, msg)
messages.success(request, _("Offer sent successfully!"))
return redirect('dashboard')
else:
logger.error(f"Place Bid Form Errors: {form.errors}")
messages.error(request, _("Error sending offer. Please check the form."))
else:
form = ShipperOfferForm()
return render(request, 'core/place_bid.html', {'form': form, 'truck': truck})
@login_required
def shipment_detail(request, shipment_id):
shipment = get_object_or_404(Shipment, id=shipment_id)
# Security: check if user is shipper, truck owner of a bid, or admin
is_involved = Bid.objects.filter(shipment=shipment, truck_owner=request.user).exists() or shipment.shipper == request.user
if not is_involved and not (request.user.profile.role == 'ADMIN' or request.user.is_superuser):
return redirect('dashboard')
bids = shipment.bids.all()
return render(request, 'core/shipment_detail.html', {'shipment': shipment, 'bids': bids})
@login_required
def accept_bid(request, bid_id):
"""Truck owner accepts an offer from a shipper."""
bid = get_object_or_404(Bid, id=bid_id)
if bid.truck_owner != request.user:
messages.error(request, _("You are not authorized to accept this offer."))
return redirect('dashboard')
# Accept this bid
bid.status = 'ACCEPTED'
bid.save()
# Update shipment
bid.shipment.status = 'IN_PROGRESS'
bid.shipment.assigned_truck = bid.truck
bid.shipment.save()
# Notify Shipper via WhatsApp
shipper_phone = getattr(bid.shipment.shipper.profile, 'full_phone_number', None)
if shipper_phone:
msg = _("Your offer for truck %(plate)s (%(origin)s to %(dest)s) has been accepted!") % {"plate": bid.truck.plate_no, "origin": bid.shipment.display_origin, "dest": bid.shipment.display_destination}
send_whatsapp_message(shipper_phone, msg)
messages.success(request, _("Offer accepted! Shipment is now in progress."))
return redirect('dashboard')
@login_required
def reject_bid(request, bid_id):
"""Truck owner rejects an offer."""
bid = get_object_or_404(Bid, id=bid_id)
if bid.truck_owner != request.user:
return redirect('dashboard')
bid.status = 'REJECTED'
bid.save()
messages.info(request, _("Offer rejected."))
return redirect('dashboard')
def privacy_policy(request):
app_settings = AppSetting.objects.first()
context = {
'article': {
'title': _('Privacy Policy'),
'content': app_settings.privacy_policy if app_settings else _("Privacy policy is coming soon.")
}
}
return render(request, 'core/article_detail.html', context)
def terms_of_service(request):
app_settings = AppSetting.objects.first()
context = {
'article': {
'title': _('Terms of Service'),
'content': app_settings.terms_of_service if app_settings else _("Terms of service are soon.")
}
}
return render(request, 'core/article_detail.html', context)
@login_required
def subscription_expired(request):
profile = request.user.profile
if not profile.is_expired():
return redirect('dashboard')
app_settings = AppSetting.objects.first()
form = RenewSubscriptionForm()
# Simplified fees dictionary for JS
fees = {
'SHIPPER': {
'MONTHLY': str(app_settings.shipper_monthly_fee) if app_settings else "0.00",
'ANNUAL': str(app_settings.shipper_annual_fee) if app_settings else "0.00",
},
'TRUCK_OWNER': {
'MONTHLY': str(app_settings.truck_owner_monthly_fee) if app_settings else "0.00",
'ANNUAL': str(app_settings.truck_owner_annual_fee) if app_settings else "0.00",
}
}
return render(request, 'core/subscription_expired.html', {
'profile': profile,
'app_settings': app_settings,
'form': form,
'fees_json': json.dumps(fees)
})
@login_required
def renew_subscription(request):
if request.method == 'POST':
form = RenewSubscriptionForm(request.POST)
if form.is_valid():
plan = form.cleaned_data['subscription_plan']
return thawani_checkout(request, plan)
return redirect('subscription_expired')
@login_required
def thawani_checkout(request, plan):
profile = request.user.profile
app_settings = AppSetting.objects.first()
if app_settings and not app_settings.thawani_enabled:
messages.error(request, _("Online payment is currently disabled. Please contact support."))
return redirect("dashboard")
amount = 0
if profile.role == 'SHIPPER':
amount = app_settings.shipper_monthly_fee if plan == 'MONTHLY' else app_settings.shipper_annual_fee
elif profile.role == 'TRUCK_OWNER':
amount = app_settings.truck_owner_monthly_fee if plan == 'MONTHLY' else app_settings.truck_owner_annual_fee
# Thawani expects amount in baisa (1 OMR = 1000 baisa)
amount_in_baisa = int(amount * 1000)
client = ThawaniClient()
# Generate a unique reference
transaction = Transaction.objects.create(
user=request.user,
amount=amount,
transaction_type='PAYMENT',
status='PENDING',
description=f"Subscription: {plan}",
payment_method="Thawani"
)
payload = {
"client_reference_id": transaction.receipt_number,
"products": [
{
"name": f"MASAR CARGO {plan} Subscription",
"unit_amount": amount_in_baisa,
"quantity": 1
}
],
"success_url": request.build_absolute_uri(reverse('thawani_success')),
"cancel_url": request.build_absolute_uri(reverse('thawani_cancel')),
"metadata": {
"plan": plan,
"user_id": request.user.id,
"transaction_id": transaction.id
}
}
session = client.create_checkout_session(payload)
if session and session.get('success'):
session_id = session['data']['session_id']
transaction.session_id = session_id
transaction.save()
return redirect(client.get_payment_url(session_id))
else:
messages.error(request, _("Failed to initiate payment. Please try again later."))
return redirect('dashboard')
def _activate_subscription_and_notify(transaction, plan, request=None):
"""
Helper to activate subscription, send WhatsApp/Email, and handle receipt link.
"""
# Activate Subscription
profile = transaction.user.profile
profile.subscription_plan = plan
profile.is_subscription_active = True
if plan == 'MONTHLY':
profile.subscription_expiry = timezone.now().date() + timedelta(days=30)
elif plan == 'ANNUAL':
profile.subscription_expiry = timezone.now().date() + timedelta(days=365)
profile.save()
# Get receipt URL
if request:
receipt_url = request.build_absolute_uri(reverse('transaction_receipt', args=[transaction.receipt_number]))
else:
# Fallback for webhook or when request is missing
host = os.getenv('HOST_FQDN', 'masarcargo.com')
receipt_url = f"https://{host}{reverse('transaction_receipt', args=[transaction.receipt_number])}"
# Notifications
expiry_date = profile.subscription_expiry.strftime('%Y-%m-%d')
msg = _("Your subscription for MASAR CARGO has been successfully renewed! Your new expiry date is %(date)s. You can view your receipt here: %(url)s") % {
"date": expiry_date,
"url": receipt_url
}
if profile.full_phone_number:
send_whatsapp_message(profile.full_phone_number, msg)
if transaction.user.email:
send_mail(
_("Subscription Activated - MASAR CARGO"),
msg,
settings.DEFAULT_FROM_EMAIL,
[transaction.user.email],
fail_silently=True,
)
return receipt_url
@login_required
def thawani_success(request):
session_id = request.GET.get('session_id')
if not session_id:
transaction = Transaction.objects.filter(user=request.user, status='PENDING', payment_method='Thawani').first()
else:
transaction = get_object_or_404(Transaction, session_id=session_id, user=request.user)
client = ThawaniClient()
session_data = client.get_checkout_session(transaction.session_id)
if session_data and session_data.get('success'):
payment_status = session_data['data']['payment_status']
transaction.payment_status = payment_status
if payment_status == 'paid':
transaction.status = 'COMPLETED'
transaction.save()
plan = session_data['data']['metadata'].get('plan', transaction.user.profile.subscription_plan)
_activate_subscription_and_notify(transaction, plan, request)
messages.success(request, _("Payment successful! Your subscription is now active."))
# Redirect directly to the receipt for "Automated Invoice" feel
return redirect('transaction_receipt', receipt_number=transaction.receipt_number)
else:
transaction.status = 'FAILED'
transaction.save()
messages.error(request, _("Payment was not successful. Status: %(status)s") % {'status': payment_status})
else:
messages.error(request, _("Failed to verify payment status."))
return redirect('dashboard')
@login_required
def thawani_cancel(request):
messages.warning(request, _("Payment was cancelled."))
return redirect('dashboard')
@csrf_exempt
def thawani_webhook(request):
if request.method == 'POST':
try:
data = json.loads(request.body)
event_type = data.get('event_type')
if event_type == 'checkout.completed':
session_id = data['data']['session_id']
payment_status = data['data']['payment_status']
transaction = Transaction.objects.filter(session_id=session_id).first()
if transaction and transaction.status == 'PENDING':
transaction.payment_status = payment_status
if payment_status == 'paid':
transaction.status = 'COMPLETED'
transaction.save()
plan = data['data']['metadata'].get('plan', transaction.user.profile.subscription_plan)
_activate_subscription_and_notify(transaction, plan, request)
else:
transaction.status = 'FAILED'
transaction.save()
return HttpResponse(status=200)
except Exception as e:
return HttpResponse(status=400)
return HttpResponse(status=405)
@login_required
def financial_history(request):
transactions = Transaction.objects.filter(user=request.user)
return render(request, 'core/financial_history.html', {'transactions': transactions})
@login_required
def transaction_receipt(request, receipt_number):
transaction = get_object_or_404(Transaction, receipt_number=receipt_number, user=request.user)
app_settings = AppSetting.objects.first()
return render(request, 'core/receipt.html', {
'transaction': transaction,
'app_settings': app_settings
})
@login_required
def admin_financials(request):
if request.user.profile.role != 'ADMIN':
return redirect('dashboard')
transactions = Transaction.objects.all()
total_revenue = sum(t.amount for t in transactions if t.transaction_type == 'PAYMENT' and t.status == 'COMPLETED')
return render(request, 'core/admin_financials.html', {
'transactions': transactions,
'total_revenue': total_revenue
})
@login_required
def issue_refund(request, receipt_number):
if request.user.profile.role != 'ADMIN':
return redirect('dashboard')
transaction = get_object_or_404(Transaction, receipt_number=receipt_number)
if transaction.transaction_type == 'REFUND':
messages.error(request, _("This is already a refund transaction."))
return redirect('admin_financials')
# Create a refund transaction
refund = Transaction.objects.create(
user=transaction.user,
amount=transaction.amount,
transaction_type='REFUND',
status='COMPLETED',
description=f"Refund for Receipt: {transaction.receipt_number}",
payment_method=transaction.payment_method
)
messages.success(request, _("Refund issued successfully! Receipt: %(receipt)s") % {'receipt': refund.receipt_number})
return redirect('admin_financials')
@login_required
def admin_app_settings(request):
if not (request.user.profile.role == 'ADMIN' or request.user.is_superuser):
return redirect('dashboard')
settings_obj = AppSetting.objects.first()
if request.method == 'POST':
form = AppSettingForm(request.POST, request.FILES, instance=settings_obj)
if form.is_valid():
form.save()
messages.success(request, _("Application settings updated successfully."))
return redirect('admin_app_settings')
else:
form = AppSettingForm(instance=settings_obj)
return render(request, 'core/app_settings.html', {'form': form})
def contact(request):
app_settings = AppSetting.objects.first()
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
form.save()
messages.success(request, _("Your message has been sent successfully! We will get back to you soon."))
return redirect('contact')
else:
messages.error(request, _("There was an error in your form. Please check the fields below."))
else:
form = ContactForm()
if request.user.is_authenticated:
# Pre-fill name and email if user is logged in
form.fields['name'].initial = request.user.get_full_name() or request.user.username
form.fields['email'].initial = request.user.email
return render(request, 'core/contact.html', {
'form': form,
'app_settings': app_settings
})