From ba8173f9d892900f39e319ea146f11f7c537349f Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Fri, 23 Jan 2026 09:55:56 +0000 Subject: [PATCH] demo2 --- config/__pycache__/settings.cpython-311.pyc | Bin 5983 -> 6272 bytes config/settings.py | 10 ++ core/__pycache__/forms.cpython-311.pyc | Bin 0 -> 4131 bytes core/__pycache__/views.cpython-311.pyc | Bin 10290 -> 10299 bytes core/forms.py | 52 ++++++++++ core/templates/core/admin_dashboard.html | 104 ++++++++++++++++++++ core/templates/core/place_bid.html | 24 +++-- core/templates/core/post_shipment.html | 25 +++-- core/templates/core/truck_register.html | 40 +++++--- core/views.py | 81 +++++++-------- 10 files changed, 267 insertions(+), 69 deletions(-) create mode 100644 core/__pycache__/forms.cpython-311.pyc create mode 100644 core/forms.py create mode 100644 core/templates/core/admin_dashboard.html diff --git a/config/__pycache__/settings.cpython-311.pyc b/config/__pycache__/settings.cpython-311.pyc index e97298ad74aaa27897e8468f467840464b859dba..c5d401324e17d71f8ad9887f9cb04558c41ce13c 100644 GIT binary patch delta 393 zcmcbw*I>xEoR^o20SIQf6lYe6P2`hc?AWMo#2U?*;*(>ZYY}D1$dGE8#S2mb0x7;g zo)v@*Lo#Tb#-HdBr7(c_qcS zIEzz(oRq|(%3Ca%d1?8#*o#Y(lT(X}Z?Tsr7UgB;rQc#pNz6-6Ez-2#TqRJ&RDVl6 zB?~B!uLsmuQk0pbmkU&#n4Vf(uLA4vS-u*uC&Da}c>D{2OE8G*RCmW6@g z12f}hIbjPH_XiA?7f{gy7M>Qr3Enq=lfvbTFtPlV$FBL-o diff --git a/config/settings.py b/config/settings.py index 066e1f2..1c26d7f 100644 --- a/config/settings.py +++ b/config/settings.py @@ -196,3 +196,13 @@ LOCALE_PATHS = [ MEDIA_URL = 'media/' MEDIA_ROOT = BASE_DIR / 'media' + +from django.contrib.messages import constants as messages +MESSAGE_TAGS = { + messages.DEBUG: 'secondary', + messages.INFO: 'info', + messages.SUCCESS: 'success', + messages.WARNING: 'warning', + messages.ERROR: 'danger', +} + diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ba213a642bba489fcad29fd789be8c4653b1a26b GIT binary patch literal 4131 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 diff --git a/core/forms.py b/core/forms.py new file mode 100644 index 0000000..a294740 --- /dev/null +++ b/core/forms.py @@ -0,0 +1,52 @@ +from django import forms +from .models import Truck, Shipment, Bid +from django.utils.translation import gettext_lazy as _ + +class TruckForm(forms.ModelForm): + class Meta: + model = Truck + fields = [ + 'truck_type', 'model', 'year', 'plate_no', + 'load_capacity', 'color', 'truck_picture', + 'registration_front', 'registration_back', 'driver_license' + ] + widgets = { + 'truck_type': forms.TextInput(attrs={'class': 'form-control', 'placeholder': _('e.g. Flatbed, Trailer')}), + 'model': forms.TextInput(attrs={'class': 'form-control'}), + 'year': forms.NumberInput(attrs={'class': 'form-control'}), + 'plate_no': forms.TextInput(attrs={'class': 'form-control'}), + 'load_capacity': forms.TextInput(attrs={'class': 'form-control'}), + 'color': forms.TextInput(attrs={'class': 'form-control'}), + 'truck_picture': forms.FileInput(attrs={'class': 'form-control'}), + 'registration_front': forms.FileInput(attrs={'class': 'form-control'}), + 'registration_back': forms.FileInput(attrs={'class': 'form-control'}), + 'driver_license': forms.FileInput(attrs={'class': 'form-control'}), + } + +class ShipmentForm(forms.ModelForm): + class Meta: + model = Shipment + fields = ['description', 'weight', 'origin', 'destination', 'delivery_date'] + widgets = { + 'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}), + 'weight': forms.TextInput(attrs={'class': 'form-control'}), + 'origin': forms.TextInput(attrs={'class': 'form-control'}), + 'destination': forms.TextInput(attrs={'class': 'form-control'}), + 'delivery_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}), + } + +class BidForm(forms.ModelForm): + class Meta: + model = Bid + fields = ['truck', 'amount', 'comments'] + widgets = { + 'truck': forms.Select(attrs={'class': 'form-select'}), + 'amount': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01'}), + 'comments': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}), + } + + def __init__(self, *args, **kwargs): + user = kwargs.pop('user', None) + super().__init__(*args, **kwargs) + if user: + self.fields['truck'].queryset = Truck.objects.filter(owner=user) \ No newline at end of file diff --git a/core/templates/core/admin_dashboard.html b/core/templates/core/admin_dashboard.html new file mode 100644 index 0000000..dd8715d --- /dev/null +++ b/core/templates/core/admin_dashboard.html @@ -0,0 +1,104 @@ +{% extends 'base.html' %} +{% load i18n %} + +{% block title %}{% trans "Admin Dashboard" %} - MASAR CARGO{% endblock %} + +{% block content %} +
+
+
+

{% trans "Administrator Dashboard" %}

+

{% trans "System overview and management" %}

+
+ +
+ +
+
+
+
+

{{ total_users }}

+

{% trans "Total Users" %}

+
+
+
+
+
+

{{ total_trucks }}

+

{% trans "Registered Trucks" %}

+
+
+
+
+
+

{{ total_shipments }}

+

{% trans "Total Shipments" %}

+
+
+
+
+
+

{{ total_bids }}

+

{% trans "Active Bids" %}

+
+
+
+ + +
+ + +{% endblock %} diff --git a/core/templates/core/place_bid.html b/core/templates/core/place_bid.html index 8a4e79e..ea68a77 100644 --- a/core/templates/core/place_bid.html +++ b/core/templates/core/place_bid.html @@ -13,27 +13,33 @@ {% trans "Goods:" %} {{ shipment.description }} - {% if trucks %} + {% if form.errors %} +
+ {% trans "Please correct the errors below." %} + {{ form.non_field_errors }} +
+ {% endif %} + + {% if form.fields.truck.queryset.exists %}
{% csrf_token %}
- + {{ form.truck }} + {{ form.truck.errors }}
$ - + {{ form.amount }}
+ {{ form.amount.errors }}
- + {{ form.comments }} + {{ form.comments.errors }}
@@ -48,4 +54,4 @@ -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/core/templates/core/post_shipment.html b/core/templates/core/post_shipment.html index 4a3303e..4e89f1e 100644 --- a/core/templates/core/post_shipment.html +++ b/core/templates/core/post_shipment.html @@ -8,29 +8,42 @@

{% trans "Post a New Shipment" %}

+ + {% if form.errors %} +
+ {% trans "Please correct the errors below." %} + {{ form.non_field_errors }} +
+ {% endif %} +
{% csrf_token %}
- + {{ form.description }} + {{ form.description.errors }}
- + {{ form.weight }} + {{ form.weight.errors }}
- + {{ form.origin }} + {{ form.origin.errors }}
- + {{ form.destination }} + {{ form.destination.errors }}
- + {{ form.delivery_date }} + {{ form.delivery_date.errors }}
@@ -39,4 +52,4 @@
-{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/core/templates/core/truck_register.html b/core/templates/core/truck_register.html index c3ac686..832064c 100644 --- a/core/templates/core/truck_register.html +++ b/core/templates/core/truck_register.html @@ -8,35 +8,49 @@

{% trans "Register a Truck" %}

+ + {% if form.errors %} +
+ {% trans "Please correct the errors below." %} + {{ form.non_field_errors }} +
+ {% endif %} +
{% csrf_token %}
- + {{ form.truck_type }} + {{ form.truck_type.errors }}
- + {{ form.model }} + {{ form.model.errors }}
- + {{ form.year }} + {{ form.year.errors }}
- + {{ form.plate_no }} + {{ form.plate_no.errors }}
- + {{ form.color }} + {{ form.color.errors }}
- + {{ form.load_capacity }} + {{ form.load_capacity.errors }}

@@ -45,21 +59,25 @@
- + {{ form.truck_picture }} + {{ form.truck_picture.errors }}
- + {{ form.driver_license }} + {{ form.driver_license.errors }}
- + {{ form.registration_front }} + {{ form.registration_front.errors }}
- + {{ form.registration_back }} + {{ form.registration_back.errors }}
@@ -70,4 +88,4 @@
-{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/core/views.py b/core/views.py index e03d3f5..32e746d 100644 --- a/core/views.py +++ b/core/views.py @@ -4,14 +4,14 @@ from django.contrib.auth import login, authenticate from django.contrib.auth.forms import UserCreationForm from django.utils import timezone from .models import Profile, Truck, Shipment, Bid, Message +from .forms import TruckForm, ShipmentForm, BidForm 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 def home(request): """Render the landing screen for MASAR CARGO.""" - if request.user.is_authenticated: - return redirect('dashboard') context = { "deployment_timestamp": timezone.now().timestamp(), } @@ -47,8 +47,17 @@ def dashboard(request): 'trucks': my_trucks, 'bids': my_bids }) + elif profile.role == 'ADMIN' or request.user.is_superuser: + context = { + 'total_users': User.objects.count(), + 'total_trucks': Truck.objects.count(), + 'total_shipments': Shipment.objects.count(), + 'total_bids': Bid.objects.count(), + } + return render(request, 'core/admin_dashboard.html', context) else: - return redirect('/admin/') + # Fallback for undefined roles + return redirect('/') @login_required def truck_register(request): @@ -56,30 +65,19 @@ def truck_register(request): return redirect('dashboard') if request.method == 'POST': - truck_type = request.POST.get('truck_type') - model = request.POST.get('model') - year = request.POST.get('year') - plate_no = request.POST.get('plate_no') - load_capacity = request.POST.get('load_capacity') - color = request.POST.get('color') - - truck = Truck.objects.create( - owner=request.user, - truck_type=truck_type, - model=model, - year=year, - plate_no=plate_no, - load_capacity=load_capacity, - color=color, - truck_picture=request.FILES.get('truck_picture'), - registration_front=request.FILES.get('registration_front'), - registration_back=request.FILES.get('registration_back'), - driver_license=request.FILES.get('driver_license') - ) - messages.success(request, _("Truck registered successfully!")) - return redirect('dashboard') + form = TruckForm(request.POST, request.FILES) + if form.is_valid(): + truck = form.save(commit=False) + truck.owner = request.user + truck.save() + messages.success(request, _("Truck registered successfully!")) + 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') + return render(request, 'core/truck_register.html', {'form': form}) @login_required def post_shipment(request): @@ -120,31 +118,28 @@ def place_bid(request, shipment_id): if request.user.profile.role != 'TRUCK_OWNER': return redirect('dashboard') - my_trucks = Truck.objects.filter(owner=request.user) if request.method == 'POST': - truck_id = request.POST.get('truck') - amount = request.POST.get('amount') - comments = request.POST.get('comments') - - truck = get_object_or_404(Truck, id=truck_id, owner=request.user) - Bid.objects.create( - shipment=shipment, - truck_owner=request.user, - truck=truck, - amount=amount, - comments=comments - ) - messages.success(request, _("Bid placed successfully!")) - return redirect('marketplace') + form = BidForm(request.POST, user=request.user) + if form.is_valid(): + bid = form.save(commit=False) + bid.truck_owner = request.user + bid.shipment = shipment + bid.save() + messages.success(request, _("Bid placed successfully!")) + return redirect('marketplace') + else: + messages.error(request, _("Error placing bid. Please check the form.")) + else: + form = BidForm(user=request.user) - return render(request, 'core/place_bid.html', {'shipment': shipment, 'trucks': my_trucks}) + return render(request, 'core/place_bid.html', {'form': form, 'shipment': shipment}) @login_required def shipment_detail(request, shipment_id): shipment = get_object_or_404(Shipment, id=shipment_id) # Security: check if user is shipper or a truck owner who bid if shipment.shipper != request.user and not Bid.objects.filter(shipment=shipment, truck_owner=request.user).exists(): - if request.user.profile.role != 'ADMIN': + if request.user.profile.role != 'ADMIN' and not request.user.is_superuser: return redirect('dashboard') bids = shipment.bids.all()