diff --git a/config/__pycache__/settings.cpython-311.pyc b/config/__pycache__/settings.cpython-311.pyc index e97298a..c5d4013 100644 Binary files a/config/__pycache__/settings.cpython-311.pyc and b/config/__pycache__/settings.cpython-311.pyc differ 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 0000000..ba213a6 Binary files /dev/null and b/core/__pycache__/forms.cpython-311.pyc differ diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index e5c3557..00c55ae 100644 Binary files a/core/__pycache__/views.cpython-311.pyc and b/core/__pycache__/views.cpython-311.pyc differ 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" %}

+
+
+
+ +
+

{% trans "Quick Actions" %}

+ +
+
+ + +{% 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()