diff --git a/requirements.txt b/requirements.txt index 1ae518cf3..404c46abf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,4 +4,5 @@ flake8-quotes==3.3.1 flake8-variables-names==0.0.5 pep8-naming==0.13.2 django-debug-toolbar==3.2.4 -django-crispy-forms==1.14.0 \ No newline at end of file +django-crispy-forms==1.14.0 +crispy_bootstrap4 \ No newline at end of file diff --git a/taxi/forms.py b/taxi/forms.py new file mode 100644 index 000000000..0b180cb6d --- /dev/null +++ b/taxi/forms.py @@ -0,0 +1,52 @@ +from django import forms +from .models import Driver, Car +import re +from django.contrib.auth.forms import UserCreationForm + + +class DriverLicenseUpdateForm(forms.ModelForm): + class Meta: + model = Driver + fields = ('license_number',) + + def clean_license_number(self): + license_number = self.cleaned_data.get('license_number') + + if len(license_number) != 8: + raise forms.ValidationError("license_number must have 8 characters") + + if not re.match(r'^[A-Z]{3}\d{5}$', license_number): + raise forms.ValidationError("license_number must begin with 3 Uppercase letters and then 5 digits") + + return license_number + + +class DriverCreationForm(UserCreationForm): + license_number = forms.CharField(max_length=255) + + class Meta: + model = Driver + fields = UserCreationForm.Meta.fields + + def clean_license_number(self): + license_number = self.cleaned_data.get('license_number') + + if len(license_number) != 8: + raise forms.ValidationError("license_number must have 8 characters") + + if not re.match(r'^[A-Z]{3}\d{5}$', license_number): + raise forms.ValidationError("license_number must begin with 3 Uppercase letters and then 5 digits") + + return license_number + + +class CarCreateForm(forms.ModelForm): + drivers = forms.ModelMultipleChoiceField( + queryset=Driver.objects.all(), + widget=forms.CheckboxSelectMultiple, + required=False + ) + + class Meta: + model = Car + fields = '__all__' diff --git a/taxi/urls.py b/taxi/urls.py index 4f017a999..43b3ade84 100644 --- a/taxi/urls.py +++ b/taxi/urls.py @@ -13,6 +13,12 @@ ManufacturerCreateView, ManufacturerUpdateView, ManufacturerDeleteView, + DriverCreateView, + DriverDeleteView, + DriverLicenseUpdateView, + AssignMeToCarView, + RemoveMeFromCarView, + DriverUpdateView, ) urlpatterns = [ @@ -46,6 +52,13 @@ path( "drivers//", DriverDetailView.as_view(), name="driver-detail" ), + path('driver/create/', DriverCreateView.as_view(), name='driver-create'), + path('driver//delete/', DriverDeleteView.as_view(), name='driver-delete'), + path('driver//update_license/', DriverLicenseUpdateView.as_view(), name='driver-license-update'), + path("car//assign-me/", AssignMeToCarView.as_view(), name="assign-me-to-car"), + path("car//remove-me/", RemoveMeFromCarView.as_view(), name="remove-me-from-car"), + path('driver//update/', DriverUpdateView.as_view(), name='driver-update'), + ] app_name = "taxi" diff --git a/taxi/views.py b/taxi/views.py index 0789d616e..19e872ee4 100644 --- a/taxi/views.py +++ b/taxi/views.py @@ -3,8 +3,10 @@ from django.urls import reverse_lazy from django.views import generic from django.contrib.auth.mixins import LoginRequiredMixin - +from .forms import DriverLicenseUpdateForm, DriverCreationForm, CarCreateForm from .models import Driver, Car, Manufacturer +from django.shortcuts import get_object_or_404 +from django.shortcuts import redirect @login_required @@ -64,13 +66,14 @@ class CarDetailView(LoginRequiredMixin, generic.DetailView): class CarCreateView(LoginRequiredMixin, generic.CreateView): model = Car - fields = "__all__" + form_class = CarCreateForm + template_name = 'taxi/car_create.html' success_url = reverse_lazy("taxi:car-list") class CarUpdateView(LoginRequiredMixin, generic.UpdateView): model = Car - fields = "__all__" + form_class = CarCreateForm success_url = reverse_lazy("taxi:car-list") @@ -87,3 +90,61 @@ class DriverListView(LoginRequiredMixin, generic.ListView): class DriverDetailView(LoginRequiredMixin, generic.DetailView): model = Driver queryset = Driver.objects.all().prefetch_related("cars__manufacturer") + + +class DriverCreateView(LoginRequiredMixin, generic.CreateView): + model = Driver + form_class = DriverCreationForm + template_name = 'taxi/driver_create.html' + success_url = reverse_lazy("taxi:driver-list") + + def form_valid(self, form): + return super().form_valid(form) + + def form_invalid(self, form): + return super().form_invalid(form) + + +class DriverDeleteView(LoginRequiredMixin, generic.DeleteView): + model = Driver + template_name = 'taxi/driver_confirm_delete.html' + success_url = reverse_lazy("taxi:driver-list") + + +class DriverLicenseUpdateView(LoginRequiredMixin, generic.UpdateView): + model = Driver + form_class = DriverLicenseUpdateForm + template_name = 'taxi/driver_license_update.html' + success_url = reverse_lazy('taxi:driver-list') + + def get_success_url(self): + return reverse_lazy('taxi:driver-detail', kwargs={'pk': self.object.pk}) + + def form_valid(self, form): + messages.success(self.request, "license updated successfully.") + return super().form_valid(form) + + +class AssignMeToCarView(LoginRequiredMixin, generic.View): + def post(self, request, pk): + car = get_object_or_404(Car, pk=pk) + car.drivers.add(request.user) + return redirect(reverse("taxi:car-detail", kwargs={"pk": pk})) + + +class RemoveMeFromCarView(LoginRequiredMixin, generic.View): + def post(self, request, pk): + car = get_object_or_404(Car, pk=pk) + car.drivers.remove(request.user) + return redirect(reverse("taxi:car-detail", kwargs={"pk": pk})) + + +class DriverUpdateView(LoginRequiredMixin, generic.UpdateView): + model = Driver + form_class = DriverCreationForm + template_name = 'taxi/driver_update.html' + success_url = reverse_lazy("taxi:driver-list") + + def form_valid(self, form): + messages.success(self.request, "Driver information updated successfully.") + return super().form_valid(form) \ No newline at end of file diff --git a/taxi_service/settings.py b/taxi_service/settings.py index 8f98f33e6..6e2d5e1ee 100644 --- a/taxi_service/settings.py +++ b/taxi_service/settings.py @@ -43,6 +43,7 @@ "django.contrib.messages", "django.contrib.staticfiles", "debug_toolbar", + "crispy_bootstrap4", "crispy_forms", "taxi", ] diff --git a/templates/taxi/car_create.html b/templates/taxi/car_create.html new file mode 100644 index 000000000..1f3ccfc3a --- /dev/null +++ b/templates/taxi/car_create.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} + +{% block content %} +

Create a New Car

+ +
+ {% csrf_token %} + {{ form.as_p }} + + +
+{% endblock %} diff --git a/templates/taxi/car_detail.html b/templates/taxi/car_detail.html index 78197443a..c8314cd34 100644 --- a/templates/taxi/car_detail.html +++ b/templates/taxi/car_detail.html @@ -1,22 +1,39 @@ {% extends "base.html" %} {% block content %} -

- {{ car.model }} - - Delete - - - - Update - -

+

MODEL: {{ car.model }}

+

Manufacturer: {{ car.manufacturer.name }}

+

Year: {{ car.year }}

+ + Update + Delete +

Manufacturer: ({{ car.manufacturer.name }}, {{ car.manufacturer.country }})

-

Drivers

-
-
    - {% for driver in car.drivers.all %} -
  • {{ driver.username }} ({{ driver.first_name }} {{ driver.last_name }})
  • - {% endfor %} -
+ +

Drivers

+
    + {% for driver in car.drivers.all %} +
  • +
    Username: {{ driver.username }}
    +
    First Name: {{ driver.first_name }}
    +
    Last Name: {{ driver.last_name }}
    +
    License: {{ driver.license_number }}
    +
  • + {% endfor %} +
+ + + {% if user in car.drivers.all %} +
+ {% csrf_token %} + +
+ {% else %} +
+ {% csrf_token %} + +
+ {% endif %} + {% endblock %} + diff --git a/templates/taxi/driver_confirm_delete.html b/templates/taxi/driver_confirm_delete.html new file mode 100644 index 000000000..630ffac3a --- /dev/null +++ b/templates/taxi/driver_confirm_delete.html @@ -0,0 +1,10 @@ +{% extends "base.html" %} + +{% block content %} +

Are you sure you want to delete {{ driver.name }}?

+
+ {% csrf_token %} + +
+ Cancel +{% endblock %} \ No newline at end of file diff --git a/templates/taxi/driver_create.html b/templates/taxi/driver_create.html new file mode 100644 index 000000000..15d6eba23 --- /dev/null +++ b/templates/taxi/driver_create.html @@ -0,0 +1,12 @@ +{% extends "base.html" %} + +{% block content %} +

Create a New DRIVER

+ +
+ {% csrf_token %} + {{ form.as_p }} + + +
+{% endblock %} diff --git a/templates/taxi/driver_detail.html b/templates/taxi/driver_detail.html index 788084648..968a99e42 100644 --- a/templates/taxi/driver_detail.html +++ b/templates/taxi/driver_detail.html @@ -23,4 +23,9 @@

Cars

No cars!

{% endfor %} + + + Update License + + Delete Driver {% endblock %} diff --git a/templates/taxi/driver_license_update.html b/templates/taxi/driver_license_update.html new file mode 100644 index 000000000..cd452f7f3 --- /dev/null +++ b/templates/taxi/driver_license_update.html @@ -0,0 +1,13 @@ +{% extends 'base.html' %} + +{% block content %} +

Update license

+ +
+ {% csrf_token %} + {{ form.as_p }} + +
+ + Back to driver-list +{% endblock %} diff --git a/templates/taxi/driver_list.html b/templates/taxi/driver_list.html index b740f95ea..ab3668fa5 100644 --- a/templates/taxi/driver_list.html +++ b/templates/taxi/driver_list.html @@ -3,6 +3,7 @@ {% block content %}

Driver List

+ Create NEW Driver {% if driver_list %} diff --git a/templates/taxi/driver_update.html b/templates/taxi/driver_update.html new file mode 100644 index 000000000..a2890c56e --- /dev/null +++ b/templates/taxi/driver_update.html @@ -0,0 +1,10 @@ +{% extends 'base.html' %} + +{% block content %} +

Edit Driver Information

+ + {% csrf_token %} + {{ form.as_p }} + + +{% endblock %} \ No newline at end of file