From 822853be6643e2a8fac6b987e1a7c84fdf8e5ae3 Mon Sep 17 00:00:00 2001
From: Yohann D'ANELLO <yohann.danello@gmail.com>
Date: Mon, 13 Apr 2020 05:02:16 +0200
Subject: [PATCH] Add a bus

---
 apps/wei/api/serializers.py            | 24 +++++++++++++-
 apps/wei/api/urls.py                   |  6 ++--
 apps/wei/api/views.py                  | 28 ++++++++++++++--
 apps/wei/forms.py                      | 32 +++++++++++++++++-
 apps/wei/tables.py                     | 45 ++++++++++++++++++++++++--
 apps/wei/urls.py                       |  6 ++--
 apps/wei/views.py                      | 33 +++++++++++++++++--
 templates/member/noteowner_detail.html | 10 +++---
 templates/wei/bus_form.html            | 17 ++++++++++
 templates/wei/weiclub_form.html        | 24 ++++++++------
 templates/wei/weiclub_info.html        |  9 ++++--
 templates/wei/weiclub_tables.html      | 13 ++++++++
 12 files changed, 218 insertions(+), 29 deletions(-)
 create mode 100644 templates/wei/bus_form.html

diff --git a/apps/wei/api/serializers.py b/apps/wei/api/serializers.py
index 5b91e2b1..3312c87a 100644
--- a/apps/wei/api/serializers.py
+++ b/apps/wei/api/serializers.py
@@ -3,7 +3,7 @@
 
 from rest_framework import serializers
 
-from ..models import WEIClub
+from ..models import WEIClub, Bus, BusTeam
 
 
 class WEIClubSerializer(serializers.ModelSerializer):
@@ -15,3 +15,25 @@ class WEIClubSerializer(serializers.ModelSerializer):
     class Meta:
         model = WEIClub
         fields = '__all__'
+
+
+class BusSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Bus.
+    The djangorestframework plugin will analyse the model `Bus` and parse all fields in the API.
+    """
+
+    class Meta:
+        model = Bus
+        fields = '__all__'
+
+
+class BusTeamSerializer(serializers.ModelSerializer):
+    """
+    REST API Serializer for Bus teams.
+    The djangorestframework plugin will analyse the model `BusTeam` and parse all fields in the API.
+    """
+
+    class Meta:
+        model = BusTeam
+        fields = '__all__'
diff --git a/apps/wei/api/urls.py b/apps/wei/api/urls.py
index 7d39e8da..74279695 100644
--- a/apps/wei/api/urls.py
+++ b/apps/wei/api/urls.py
@@ -1,11 +1,13 @@
 # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 # SPDX-License-Identifier: GPL-3.0-or-later
 
-from .views import WEIClubViewSet
+from .views import WEIClubViewSet, BusViewSet, BusTeamViewSet
 
 
 def register_wei_urls(router, path):
     """
     Configure router for Member REST API.
     """
-    router.register(path + '/club/', WEIClubViewSet)
+    router.register(path + '/club', WEIClubViewSet)
+    router.register(path + '/bus', BusViewSet)
+    router.register(path + '/team', BusTeamViewSet)
diff --git a/apps/wei/api/views.py b/apps/wei/api/views.py
index c93512e2..9ab3a139 100644
--- a/apps/wei/api/views.py
+++ b/apps/wei/api/views.py
@@ -4,8 +4,8 @@
 from rest_framework.filters import SearchFilter
 from api.viewsets import ReadProtectedModelViewSet
 
-from .serializers import WEIClubSerializer
-from ..models import WEIClub
+from .serializers import WEIClubSerializer, BusSerializer, BusTeamSerializer
+from ..models import WEIClub, Bus, BusTeam
 
 
 class WEIClubViewSet(ReadProtectedModelViewSet):
@@ -18,3 +18,27 @@ class WEIClubViewSet(ReadProtectedModelViewSet):
     serializer_class = WEIClubSerializer
     filter_backends = [SearchFilter]
     search_fields = ['$name', ]
+
+
+class BusViewSet(ReadProtectedModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `Bus` objects, serialize it to JSON with the given serializer,
+    then render it on /api/wei/bus/
+    """
+    queryset = Bus.objects.all()
+    serializer_class = BusSerializer
+    filter_backends = [SearchFilter]
+    search_fields = ['$name', ]
+
+
+class BusTeamViewSet(ReadProtectedModelViewSet):
+    """
+    REST API View set.
+    The djangorestframework plugin will get all `BusTeam` objects, serialize it to JSON with the given serializer,
+    then render it on /api/wei/team/
+    """
+    queryset = BusTeam.objects.all()
+    serializer_class = BusTeamSerializer
+    filter_backends = [SearchFilter]
+    search_fields = ['$name', ]
diff --git a/apps/wei/forms.py b/apps/wei/forms.py
index e8cd39fe..6fb7af04 100644
--- a/apps/wei/forms.py
+++ b/apps/wei/forms.py
@@ -6,7 +6,7 @@ from django.contrib.auth.models import User
 from django.utils.translation import ugettext_lazy as _
 from note_kfet.inputs import AmountInput, DatePickerInput, Autocomplete
 
-from .models import WEIClub, WEIRegistration
+from .models import WEIClub, WEIRegistration, Bus
 
 
 class WEIForm(forms.ModelForm):
@@ -43,3 +43,33 @@ class WEIRegistrationForm(forms.ModelForm):
             ),
             "birth_date": DatePickerInput(),
         }
+
+
+class BusForm(forms.ModelForm):
+    class Meta:
+        model = Bus
+        fields = '__all__'
+        widgets = {
+            "wei": Autocomplete(
+                WEIClub,
+                attrs={
+                    'api_url': '/api/wei/club/',
+                    'placeholder': 'WEI ...',
+                },
+            ),
+        }
+
+
+class BusTeamForm(forms.ModelForm):
+    class Meta:
+        model = Bus
+        fields = '__all__'
+        widgets = {
+            "bus": Autocomplete(
+                Bus,
+                attrs={
+                    'api_url': '/api/wei/bus/',
+                    'placeholder': 'Bus ...',
+                },
+            ),
+        }
diff --git a/apps/wei/tables.py b/apps/wei/tables.py
index f0541cd0..e0e40d0d 100644
--- a/apps/wei/tables.py
+++ b/apps/wei/tables.py
@@ -6,7 +6,7 @@ from django.urls import reverse_lazy
 from django.utils.translation import gettext_lazy as _
 from django_tables2 import A
 
-from .models import WEIClub, WEIRegistration
+from .models import WEIClub, WEIRegistration, Bus, BusTeam
 
 
 class WEITable(tables.Table):
@@ -71,13 +71,54 @@ class WEIRegistrationTable(tables.Table):
         },
     )
 
+    def render_is_first_year(self, value):
+        return _("yes") if value else _("no")
+
     class Meta:
         attrs = {
             'class': 'table table-condensed table-striped table-hover'
         }
         model = WEIRegistration
         template_name = 'django_tables2/bootstrap4.html'
-        fields = ('user',)
+        fields = ('user', 'is_first_year',)
+        row_attrs = {
+            'class': 'table-row',
+            'id': lambda record: "row-" + str(record.pk),
+            'data-href': lambda record: record.pk
+        }
+
+
+class BusTable(tables.Table):
+    class Meta:
+        attrs = {
+            'class': 'table table-condensed table-striped table-hover'
+        }
+        model = Bus
+        template_name = 'django_tables2/bootstrap4.html'
+        fields = ('name', 'teams',)
+        row_attrs = {
+            'class': 'table-row',
+            'id': lambda record: "row-" + str(record.pk),
+            'data-href': lambda record: record.pk
+        }
+
+
+class BusTeamTable(tables.Table):
+    color = tables.Column(
+        attrs={
+            "td": {
+                "style": lambda record: "background-color: #" + "".format(record.color) + ";"
+            }
+        }
+    )
+
+    class Meta:
+        attrs = {
+            'class': 'table table-condensed table-striped table-hover'
+        }
+        model = BusTeam
+        template_name = 'django_tables2/bootstrap4.html'
+        fields = ('name', 'color', 'team',)
         row_attrs = {
             'class': 'table-row',
             'id': lambda record: "row-" + str(record.pk),
diff --git a/apps/wei/urls.py b/apps/wei/urls.py
index 3d3be0f0..331cb4db 100644
--- a/apps/wei/urls.py
+++ b/apps/wei/urls.py
@@ -3,7 +3,8 @@
 
 from django.urls import path
 
-from .views import WEIListView, WEICreateView, WEIDetailView, WEIUpdateView, WEIRegisterView, WEIUpdateRegistrationView
+from .views import WEIListView, WEICreateView, WEIDetailView, WEIUpdateView, BusCreateView,\
+    WEIRegisterView, WEIUpdateRegistrationView
 
 
 app_name = 'wei'
@@ -12,6 +13,7 @@ urlpatterns = [
     path('create/', WEICreateView.as_view(), name="wei_create"),
     path('detail/<int:pk>/', WEIDetailView.as_view(), name="wei_detail"),
     path('update/<int:pk>/', WEIUpdateView.as_view(), name="wei_update"),
+    path('add-bus/<int:pk>/', BusCreateView.as_view(), name="add_bus"),
     path('register/<int:wei_pk>/', WEIRegisterView.as_view(), name="wei_register"),
-    path('edit_registration/<int:pk>/', WEIUpdateRegistrationView.as_view(), name="wei_update_registration"),
+    path('edit-registration/<int:pk>/', WEIUpdateRegistrationView.as_view(), name="wei_update_registration"),
 ]
diff --git a/apps/wei/views.py b/apps/wei/views.py
index 60f0a164..cf7c9ca8 100644
--- a/apps/wei/views.py
+++ b/apps/wei/views.py
@@ -16,9 +16,9 @@ from note.tables import HistoryTable
 from permission.backends import PermissionBackend
 from permission.views import ProtectQuerysetMixin
 
-from .models import WEIClub, WEIRegistration, WEIMembership
-from .forms import WEIForm, WEIRegistrationForm
-from .tables import WEITable, WEIRegistrationTable
+from .models import WEIClub, WEIRegistration, WEIMembership, Bus
+from .forms import WEIForm, WEIRegistrationForm, BusForm
+from .tables import WEITable, WEIRegistrationTable, BusTable
 
 
 class WEIListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
@@ -91,6 +91,11 @@ class WEIDetailView(ProtectQuerysetMixin, LoginRequiredMixin, DetailView):
         pre_registrations_table.paginate(per_page=20, page=self.request.GET.get('membership-page', 1))
         context['pre_registrations'] = pre_registrations_table
 
+        buses = Bus.objects.filter(PermissionBackend.filter_queryset(self.request.user, Bus, "view"))\
+            .filter(wei=self.object)
+        bus_table = BusTable(data=buses, prefix="bus-")
+        context['buses'] = bus_table
+
         # Check if the user has the right to create a membership, to display the button.
         empty_membership = Membership(
             club=club,
@@ -117,6 +122,28 @@ class WEIUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
         return reverse_lazy("wei:wei_detail", kwargs={"pk": self.object.pk})
 
 
+class BusCreateView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
+    """
+    Create Bus
+    """
+    model = Bus
+    form_class = BusForm
+
+    def get_context_data(self, **kwargs):
+        context = super().get_context_data(**kwargs)
+        context["club"] = WEIClub.objects.get(pk=self.kwargs["pk"])
+        return context
+
+    def get_form(self, form_class=None):
+        form = super().get_form(form_class)
+        form.fields["wei"].initial = WEIClub.objects.get(pk=self.kwargs["pk"])
+        return form
+
+    def get_success_url(self):
+        self.object.refresh_from_db()
+        return reverse_lazy("wei:wei_detail", kwargs={"pk": self.object.wei.pk})
+
+
 class WEIRegisterView(ProtectQuerysetMixin, LoginRequiredMixin, CreateView):
     """
     Register to the WEI
diff --git a/templates/member/noteowner_detail.html b/templates/member/noteowner_detail.html
index 2a377140..93ba19ef 100644
--- a/templates/member/noteowner_detail.html
+++ b/templates/member/noteowner_detail.html
@@ -19,9 +19,11 @@
 
 {% block extrajavascript %}
     <script>
-    function refreshHistory() {
-        $("#history_list").load("{% url 'member:user_detail' pk=object.pk %} #history_list");
-        $("#profile_infos").load("{% url 'member:user_detail' pk=object.pk %} #profile_infos");
-    }
+        {% if object %}
+            function refreshHistory() {
+                $("#history_list").load("{% url 'member:user_detail' pk=object.pk %} #history_list");
+                $("#profile_infos").load("{% url 'member:user_detail' pk=object.pk %} #profile_infos");
+            }
+        {% endif %}
     </script>
 {% endblock %}
diff --git a/templates/wei/bus_form.html b/templates/wei/bus_form.html
new file mode 100644
index 00000000..7fa2b01c
--- /dev/null
+++ b/templates/wei/bus_form.html
@@ -0,0 +1,17 @@
+{% extends "member/noteowner_detail.html" %}
+{% load crispy_forms_tags %}
+{% load i18n %}
+
+{% block profile_info %}
+    {% if club %}
+        {% include "wei/weiclub_info.html" %}
+    {% endif %}
+{% endblock %}
+
+{% block profile_content %}
+<form method="post">
+{% csrf_token %}
+{{ form|crispy }}
+<button class="btn btn-primary" type="submit">{% trans "Submit" %}</button>
+</form>
+{% endblock %}
diff --git a/templates/wei/weiclub_form.html b/templates/wei/weiclub_form.html
index ea29d966..64edf798 100644
--- a/templates/wei/weiclub_form.html
+++ b/templates/wei/weiclub_form.html
@@ -1,11 +1,17 @@
-{% extends "base.html" %}
-{% load static %}
-{% load i18n %}
+{% extends "member/noteowner_detail.html" %}
 {% load crispy_forms_tags %}
-{% block content %}
-<form method="post">
-{% csrf_token %}
-{{ form|crispy }}
-<button class="btn btn-primary" type="submit">{% trans "Submit" %}</button>
-</form>
+{% load i18n %}
+
+{% block profile_info %}
+    {% if club %}
+        {% include "wei/weiclub_info.html" %}
+    {% endif %}
+{% endblock %}
+
+{% block profile_content %}
+    <form method="post">
+        {% csrf_token %}
+        {{ form|crispy }}
+        <button class="btn btn-primary" type="submit">{% trans "Submit" %}</button>
+    </form>
 {% endblock %}
diff --git a/templates/wei/weiclub_info.html b/templates/wei/weiclub_info.html
index 16f2527d..5e62fe29 100644
--- a/templates/wei/weiclub_info.html
+++ b/templates/wei/weiclub_info.html
@@ -37,12 +37,12 @@
 
             {% if "note.view_note"|has_perm:club.note %}
                 <dt class="col-xl-6">{% trans 'balance'|capfirst %}</dt>
-                <dd class="col-xl-6">{{ object.note.balance | pretty_money }}</dd>
+                <dd class="col-xl-6">{{ club.note.balance | pretty_money }}</dd>
             {% endif %}
 
             {% if "note.change_alias"|has_perm:club.note.alias_set.first %}
                 <dt class="col-xl-4"><a href="{% url 'member:club_alias' club.pk %}">{% trans 'aliases'|capfirst %}</a></dt>
-                <dd class="col-xl-8 text-truncate">{{ object.note.alias_set.all|join:", " }}</dd>
+                <dd class="col-xl-8 text-truncate">{{ club.note.alias_set.all|join:", " }}</dd>
             {% endif %}
 
             <dt class="col-xl-4">{% trans 'email'|capfirst %}</dt>
@@ -56,9 +56,12 @@
         {% if ".change_"|has_perm:club %}
             <a class="btn btn-primary btn-sm my-1" href="{% url 'wei:wei_update' pk=club.pk %}"> {% trans "Edit" %}</a>
         {% endif %}
+        {% if True %}
+            <a class="btn btn-primary btn-sm my-1" href="{% url 'wei:add_bus' pk=club.pk %}"> {% trans "Add bus" %}</a>
+        {% endif %}
         {% url 'wei:wei_detail' club.pk as club_detail_url %}
         {%if request.path_info != club_detail_url %}
-        <a class="btn btn-primary btn-sm my-1" href="{{ club_detail_url }}">{% trans 'View WEI' %}</a>
+            <a class="btn btn-primary btn-sm my-1" href="{{ club_detail_url }}">{% trans 'View WEI' %}</a>
         {% endif %}
     </div>
 </div>
diff --git a/templates/wei/weiclub_tables.html b/templates/wei/weiclub_tables.html
index b1e54c7c..50fb1a81 100644
--- a/templates/wei/weiclub_tables.html
+++ b/templates/wei/weiclub_tables.html
@@ -59,6 +59,19 @@
 
 <hr>
 
+{% if buses.data or True %}
+    <div class="card">
+        <div class="card-header position-relative" id="clubListHeading">
+            <a class="btn btn-link stretched-link font-weight-bold">
+                <i class="fa fa-bus"></i> {% trans "Buses" %}
+            </a>
+        </div>
+        {% render_table buses %}
+    </div>
+
+    <hr>
+{% endif %}
+
 {% if member_list.data %}
     <div class="card">
         <div class="card-header position-relative" id="clubListHeading">
-- 
GitLab