change27
This commit is contained in:
parent
346ce7c5aa
commit
9964306747
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -4,7 +4,7 @@ from django.shortcuts import render
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.contrib import messages
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from .models import Profile, Truck, Shipment, Bid, Message, WhatsAppConfig, Country, City, TruckType
|
||||
from .models import Profile, Truck, Shipment, Bid, Message, WhatsAppConfig, Country, City, TruckType, AppSetting
|
||||
from .whatsapp import send_whatsapp_message
|
||||
|
||||
@admin.register(Country)
|
||||
@ -86,4 +86,14 @@ class WhatsAppConfigAdmin(admin.ModelAdmin):
|
||||
title=_("Send Test WhatsApp Message"),
|
||||
opts=self.model._meta,
|
||||
)
|
||||
return render(request, "admin/core/whatsapp_test.html", context)
|
||||
return render(request, "admin/core/whatsapp_test.html", context)
|
||||
|
||||
@admin.register(AppSetting)
|
||||
class AppSettingAdmin(admin.ModelAdmin):
|
||||
list_display = ('app_name', 'contact_phone', 'contact_email')
|
||||
|
||||
def has_add_permission(self, request):
|
||||
# Only allow one configuration record
|
||||
if self.model.objects.exists():
|
||||
return False
|
||||
return super().has_add_permission(request)
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
import os
|
||||
import time
|
||||
from .models import AppSetting
|
||||
|
||||
def project_context(request):
|
||||
"""
|
||||
Adds project-specific environment variables to the template context globally.
|
||||
Adds project-specific environment variables and app settings to the template context globally.
|
||||
"""
|
||||
app_settings = AppSetting.objects.first()
|
||||
return {
|
||||
"project_description": os.getenv("PROJECT_DESCRIPTION", ""),
|
||||
"project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
|
||||
# Used for cache-busting static assets
|
||||
"deployment_timestamp": int(time.time()),
|
||||
}
|
||||
"app_settings": app_settings,
|
||||
}
|
||||
33
core/migrations/0014_appsetting.py
Normal file
33
core/migrations/0014_appsetting.py
Normal file
@ -0,0 +1,33 @@
|
||||
# Generated by Django 5.2.7 on 2026-01-23 17:11
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0013_alter_truck_registration_back_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='AppSetting',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('app_name', models.CharField(max_length=100, verbose_name='App Name')),
|
||||
('logo', models.ImageField(blank=True, null=True, upload_to='app/', verbose_name='Logo')),
|
||||
('slogan', models.CharField(blank=True, max_length=255, verbose_name='Slogan')),
|
||||
('registration_number', models.CharField(blank=True, max_length=100, verbose_name='Registration Number')),
|
||||
('tax_number', models.CharField(blank=True, max_length=100, verbose_name='Tax Number')),
|
||||
('contact_phone', models.CharField(blank=True, max_length=20, verbose_name='Contact Phone')),
|
||||
('contact_email', models.EmailField(blank=True, max_length=254, verbose_name='Contact Email')),
|
||||
('contact_address', models.TextField(blank=True, verbose_name='Contact Address')),
|
||||
('terms_of_service', models.TextField(blank=True, verbose_name='Terms of Service')),
|
||||
('privacy_policy', models.TextField(blank=True, verbose_name='Privacy Policy')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'App Setting',
|
||||
'verbose_name_plural': 'App Settings',
|
||||
},
|
||||
),
|
||||
]
|
||||
BIN
core/migrations/__pycache__/0014_appsetting.cpython-311.pyc
Normal file
BIN
core/migrations/__pycache__/0014_appsetting.cpython-311.pyc
Normal file
Binary file not shown.
@ -229,6 +229,25 @@ class WhatsAppConfig(models.Model):
|
||||
def __str__(self):
|
||||
return str(_("WhatsApp Configuration"))
|
||||
|
||||
class AppSetting(models.Model):
|
||||
app_name = models.CharField(_('App Name'), max_length=100)
|
||||
logo = models.ImageField(_('Logo'), upload_to='app/', blank=True, null=True)
|
||||
slogan = models.CharField(_('Slogan'), max_length=255, blank=True)
|
||||
registration_number = models.CharField(_('Registration Number'), max_length=100, blank=True)
|
||||
tax_number = models.CharField(_('Tax Number'), max_length=100, blank=True)
|
||||
contact_phone = models.CharField(_('Contact Phone'), max_length=20, blank=True)
|
||||
contact_email = models.EmailField(_('Contact Email'), blank=True)
|
||||
contact_address = models.TextField(_('Contact Address'), blank=True)
|
||||
terms_of_service = models.TextField(_('Terms of Service'), blank=True)
|
||||
privacy_policy = models.TextField(_('Privacy Policy'), blank=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('App Setting')
|
||||
verbose_name_plural = _('App Settings')
|
||||
|
||||
def __str__(self):
|
||||
return self.app_name
|
||||
|
||||
@receiver(post_save, sender=User)
|
||||
def create_user_profile(sender, instance, created, **kwargs):
|
||||
if created:
|
||||
@ -257,4 +276,4 @@ def sync_user_groups(sender, instance, **kwargs):
|
||||
instance.user.groups.remove(*other_groups)
|
||||
|
||||
# Add user to the correct group
|
||||
instance.user.groups.add(group)
|
||||
instance.user.groups.add(group)
|
||||
@ -6,7 +6,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}MASAR CARGO{% endblock %}</title>
|
||||
<title>{% block title %}{{ app_settings.app_name|default:"MASAR CARGO" }}{% endblock %}</title>
|
||||
{% if project_description %}
|
||||
<meta name="description" content="{{ project_description }}">
|
||||
{% endif %}
|
||||
@ -37,8 +37,13 @@
|
||||
<body>
|
||||
<nav class="navbar navbar-expand-lg navbar-dark sticky-top">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="/">
|
||||
<i class="fa-solid fa-truck-fast me-2 text-info"></i> MASAR CARGO
|
||||
<a class="navbar-brand d-flex align-items-center" href="/">
|
||||
{% if app_settings.logo %}
|
||||
<img src="{{ app_settings.logo.url }}" alt="{{ app_settings.app_name }}" height="40" class="me-2">
|
||||
{% else %}
|
||||
<i class="fa-solid fa-truck-fast me-2 text-info"></i>
|
||||
{% endif %}
|
||||
<span>{{ app_settings.app_name|default:"MASAR CARGO" }}</span>
|
||||
</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
@ -86,6 +91,11 @@
|
||||
<i class="fa-solid fa-user-circle me-1"></i> {{ user.username }}
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
{% if user.is_staff %}
|
||||
<li>
|
||||
<a class="dropdown-item" href="{% url 'admin:index' %}">{% trans "Admin Panel" %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
<li>
|
||||
<form action="{% url 'logout' %}" method="post">
|
||||
{% csrf_token %}
|
||||
@ -126,27 +136,41 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-md-4 mb-4">
|
||||
<h4 class="fw-bold">MASAR CARGO</h4>
|
||||
<p class="text-white-50">{% trans "Empowering logistics with smart technology. Locally and abroad." %}</p>
|
||||
<h4 class="fw-bold">{{ app_settings.app_name|default:"MASAR CARGO" }}</h4>
|
||||
{% if app_settings.slogan %}
|
||||
<p class="text-white-50">{{ app_settings.slogan }}</p>
|
||||
{% else %}
|
||||
<p class="text-white-50">{% trans "Empowering logistics with smart technology. Locally and abroad." %}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="col-md-4 mb-4">
|
||||
<h5 class="fw-bold">{% trans "Quick Links" %}</h5>
|
||||
<ul class="list-unstyled">
|
||||
<li><a href="#" class="text-white-50 text-decoration-none">{% trans "Privacy Policy" %}</a></li>
|
||||
<li><a href="#" class="text-white-50 text-decoration-none">{% trans "Terms of Service" %}</a></li>
|
||||
<li><a href="{% url 'privacy_policy' %}" class="text-white-50 text-decoration-none">{% trans "Privacy Policy" %}</a></li>
|
||||
<li><a href="{% url 'terms_of_service' %}" class="text-white-50 text-decoration-none">{% trans "Terms of Service" %}</a></li>
|
||||
<li><a href="#" class="text-white-50 text-decoration-none">{% trans "Contact Us" %}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-md-4 mb-4">
|
||||
<h5 class="fw-bold">{% trans "Contact" %}</h5>
|
||||
<p class="text-white-50">
|
||||
<i class="fa-brands fa-whatsapp me-2"></i> +123 456 7890<br>
|
||||
<i class="fa-solid fa-envelope me-2"></i> info@masarcargo.com
|
||||
{% if app_settings.contact_phone %}
|
||||
<i class="fa-solid fa-phone me-2"></i> {{ app_settings.contact_phone }}<br>
|
||||
{% endif %}
|
||||
{% if app_settings.contact_email %}
|
||||
<i class="fa-solid fa-envelope me-2"></i> {{ app_settings.contact_email }}
|
||||
{% endif %}
|
||||
</p>
|
||||
{% if app_settings.registration_number %}
|
||||
<p class="text-white-50 small mb-1">{% trans "CR No:" %} {{ app_settings.registration_number }}</p>
|
||||
{% endif %}
|
||||
{% if app_settings.tax_number %}
|
||||
<p class="text-white-50 small mb-0">{% trans "VAT No:" %} {{ app_settings.tax_number }}</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<hr class="bg-white-50">
|
||||
<p class="text-center text-white-50 mb-0">© 2026 MASAR CARGO. All rights reserved.</p>
|
||||
<p class="text-center text-white-50 mb-0">© 2026 {{ app_settings.app_name|default:"MASAR CARGO" }}. All rights reserved.</p>
|
||||
</div>
|
||||
</footer>
|
||||
<div class="container text-center text-muted small py-2">Debug: Lang={{ CURRENT_LANG }}, Cookie={{ request.COOKIES.django_language }}</div>
|
||||
|
||||
@ -20,4 +20,6 @@ urlpatterns = [
|
||||
path("truck/<int:truck_id>/offer/", views.place_bid, name="place_bid"),
|
||||
path("bid/<int:bid_id>/accept/", views.accept_bid, name="accept_bid"),
|
||||
path("bid/<int:bid_id>/reject/", views.reject_bid, name="reject_bid"),
|
||||
]
|
||||
path("privacy-policy/", views.privacy_policy, name="privacy_policy"),
|
||||
path("terms-of-service/", views.terms_of_service, name="terms_of_service"),
|
||||
]
|
||||
|
||||
@ -2,7 +2,7 @@ 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 .models import Profile, Truck, Shipment, Bid, Message, OTPCode, Country, City
|
||||
from .models import Profile, Truck, Shipment, Bid, Message, OTPCode, Country, City, AppSetting
|
||||
from .forms import TruckForm, ShipmentForm, BidForm, UserRegistrationForm, OTPVerifyForm, ShipperOfferForm
|
||||
from django.contrib import messages
|
||||
from django.utils.translation import gettext as _
|
||||
@ -377,4 +377,24 @@ def reject_bid(request, bid_id):
|
||||
bid.status = 'REJECTED'
|
||||
bid.save()
|
||||
messages.info(request, _("Offer rejected."))
|
||||
return redirect('dashboard')
|
||||
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 coming soon.")
|
||||
}
|
||||
}
|
||||
return render(request, 'core/article_detail.html', context)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user