diff --git a/apps/api/urls.py b/apps/api/urls.py index 67fdba30..03d6bd68 100644 --- a/apps/api/urls.py +++ b/apps/api/urls.py @@ -15,6 +15,7 @@ from note.api.urls import register_note_urls from treasury.api.urls import register_treasury_urls from logs.api.urls import register_logs_urls from permission.api.urls import register_permission_urls +from wei.api.urls import register_wei_urls class UserSerializer(serializers.ModelSerializer): @@ -78,6 +79,7 @@ register_note_urls(router, 'note') register_treasury_urls(router, 'treasury') register_permission_urls(router, 'permission') register_logs_urls(router, 'logs') +register_wei_urls(router, 'wei') app_name = 'api' diff --git a/apps/wei/api/__init__.py b/apps/wei/api/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/wei/api/serializers.py b/apps/wei/api/serializers.py new file mode 100644 index 00000000..5b91e2b1 --- /dev/null +++ b/apps/wei/api/serializers.py @@ -0,0 +1,17 @@ +# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay +# SPDX-License-Identifier: GPL-3.0-or-later + +from rest_framework import serializers + +from ..models import WEIClub + + +class WEIClubSerializer(serializers.ModelSerializer): + """ + REST API Serializer for Clubs. + The djangorestframework plugin will analyse the model `WEIClub` and parse all fields in the API. + """ + + class Meta: + model = WEIClub + fields = '__all__' diff --git a/apps/wei/api/urls.py b/apps/wei/api/urls.py new file mode 100644 index 00000000..f5836b8c --- /dev/null +++ b/apps/wei/api/urls.py @@ -0,0 +1,11 @@ +# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay +# SPDX-License-Identifier: GPL-3.0-or-later + +from .views import WEIClubViewSet + + +def register_wei_urls(router, path): + """ + Configure router for Member REST API. + """ + router.register(path + '/club', WEIClubViewSet) diff --git a/apps/wei/api/views.py b/apps/wei/api/views.py new file mode 100644 index 00000000..c93512e2 --- /dev/null +++ b/apps/wei/api/views.py @@ -0,0 +1,20 @@ +# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay +# SPDX-License-Identifier: GPL-3.0-or-later + +from rest_framework.filters import SearchFilter +from api.viewsets import ReadProtectedModelViewSet + +from .serializers import WEIClubSerializer +from ..models import WEIClub + + +class WEIClubViewSet(ReadProtectedModelViewSet): + """ + REST API View set. + The djangorestframework plugin will get all `WEIClub` objects, serialize it to JSON with the given serializer, + then render it on /api/wei/club/ + """ + queryset = WEIClub.objects.all() + serializer_class = WEIClubSerializer + filter_backends = [SearchFilter] + search_fields = ['$name', ] diff --git a/apps/wei/fixtures/initial.json b/apps/wei/fixtures/initial.json new file mode 100644 index 00000000..db371985 --- /dev/null +++ b/apps/wei/fixtures/initial.json @@ -0,0 +1,76 @@ +[ + { + "model": "member.club", + "pk": 3, + "fields": { + "name": "A[WEI] from Home", + "email": "gc.wei@example.com", + "parent_club": 2, + "require_memberships": true, + "membership_fee_paid": 16500, + "membership_fee_unpaid": 9500, + "membership_duration": 30, + "membership_start": "2019-09-01", + "membership_end": "2019-09-16" + } + }, + { + "model": "wei.weiclub", + "pk": 1, + "fields": { + "club_ptr_id": 3, + "year": 2019, + "date_start": "2019-09-14", + "date_end": "2019-09-16" + } + }, + { + "model": "note.note", + "pk": 7, + "fields": { + "polymorphic_ctype": [ + "note", + "noteclub" + ], + "balance": 0, + "last_negative": null, + "is_active": true, + "display_image": "pic/default.png", + "created_at": "2020-02-20T20:16:14.753Z" + } + }, + { + "model": "note.noteclub", + "pk": 7, + "fields": { + "club": 3 + } + }, + { + "model": "note.alias", + "pk": 7, + "fields": { + "name": "A[WEI] from Home", + "normalized_name": "aweifromhome", + "note": 7 + } + }, + { + "model": "note.alias", + "pk": 8, + "fields": { + "name": "WEI 2019", + "normalized_name": "wei2019", + "note": 7 + } + }, + { + "model": "note.alias", + "pk": 9, + "fields": { + "name": "WEI", + "normalized_name": "wei", + "note": 7 + } + } +] diff --git a/apps/wei/models.py b/apps/wei/models.py index 45834256..08ebbc8c 100644 --- a/apps/wei/models.py +++ b/apps/wei/models.py @@ -1,23 +1,32 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later + import json from django.contrib.auth.models import User from django.db import models from django.utils.translation import gettext_lazy as _ - from member.models import Role, Club, Membership from note.models import NoteSpecial class WEIClub(Club): """ + The WEI is a club. Register to the WEI is equivalent than be member of the club. """ year = models.PositiveIntegerField( unique=True, verbose_name=_("year"), ) + date_start = models.DateField( + verbose_name=_("date start"), + ) + + date_end = models.DateField( + verbose_name=_("date end"), + ) + def update_membership_dates(self): """ We can't join the WEI next years. @@ -84,6 +93,8 @@ class WEIRole(Role): bus = models.ForeignKey( Bus, on_delete=models.CASCADE, + null=True, + default=None, related_name="roles", verbose_name=_("bus"), ) diff --git a/apps/wei/tables.py b/apps/wei/tables.py new file mode 100644 index 00000000..3c1bd3af --- /dev/null +++ b/apps/wei/tables.py @@ -0,0 +1,25 @@ +# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay +# SPDX-License-Identifier: GPL-3.0-or-later + +import django_tables2 as tables +from django.urls import reverse_lazy + +from wei.models import WEIClub + + +class WEITable(tables.Table): + """ + List all clubs. + """ + class Meta: + attrs = { + 'class': 'table table-condensed table-striped table-hover' + } + model = WEIClub + template_name = 'django_tables2/bootstrap4.html' + fields = ('name', 'year', 'date_start', 'date_end',) + row_attrs = { + 'class': 'table-row', + 'id': lambda record: "row-" + str(record.pk), + 'data-href': lambda record: reverse_lazy('member:club_detail', args=(record.pk,)) + } diff --git a/apps/wei/urls.py b/apps/wei/urls.py index afd1c566..9c898139 100644 --- a/apps/wei/urls.py +++ b/apps/wei/urls.py @@ -3,7 +3,10 @@ from django.urls import path +from .views import WEIListView + app_name = 'wei' urlpatterns = [ + path('list/', WEIListView.as_view(), name="wei_list"), ] diff --git a/apps/wei/views.py b/apps/wei/views.py index 8b245779..7d7fc01f 100644 --- a/apps/wei/views.py +++ b/apps/wei/views.py @@ -1,5 +1,17 @@ # Copyright (C) 2018-2020 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later -from django.shortcuts import render +from django.contrib.auth.mixins import LoginRequiredMixin +from django_tables2 import SingleTableView +from permission.views import ProtectQuerysetMixin +from wei.models import WEIClub +from .tables import WEITable + + +class WEIListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView): + """ + List existing WEI + """ + model = WEIClub + table_class = WEITable diff --git a/static/js/base.js b/static/js/base.js index bb73b328..f9f040c1 100644 --- a/static/js/base.js +++ b/static/js/base.js @@ -312,7 +312,7 @@ function in_validate(id, validated) { else invalidity_reason = null; - $("#validate_" + id).html("⟳ ..."); + $("#validate_" + id).html(""); // Perform a PATCH request to the API in order to update the transaction // If the user has insuffisent rights, an error message will appear diff --git a/templates/base.html b/templates/base.html index 3c2c637f..810927f9 100644 --- a/templates/base.html +++ b/templates/base.html @@ -108,9 +108,12 @@ SPDX-License-Identifier: GPL-3.0-or-later {% endif %} {% if "treasury.invoice"|not_empty_model_change_list %} {% endif %} +