This commit is contained in:
Yohann D'ANELLO 2020-04-11 23:02:12 +02:00
parent a186ccbb26
commit 31d2224b8f
15 changed files with 257 additions and 7 deletions

View File

@ -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'

0
apps/wei/api/__init__.py Normal file
View File

View File

@ -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__'

11
apps/wei/api/urls.py Normal file
View File

@ -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)

20
apps/wei/api/views.py Normal file
View File

@ -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', ]

View File

@ -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
}
}
]

View File

@ -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"),
)

25
apps/wei/tables.py Normal file
View File

@ -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,))
}

View File

@ -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"),
]

View File

@ -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

View File

@ -312,7 +312,7 @@ function in_validate(id, validated) {
else
invalidity_reason = null;
$("#validate_" + id).html("<strong style=\"font-size: 16pt;\">⟳ ...</strong>");
$("#validate_" + id).html("<i class='fa fa-spinner'></i>");
// Perform a PATCH request to the API in order to update the transaction
// If the user has insuffisent rights, an error message will appear

View File

@ -108,9 +108,12 @@ SPDX-License-Identifier: GPL-3.0-or-later
{% endif %}
{% if "treasury.invoice"|not_empty_model_change_list %}
<li class="nav-item active">
<a class="nav-link" href="{% url 'treasury:invoice_list' %}"><i class="fa fa-money"></i>{% trans 'Treasury' %} </a>
<a class="nav-link" href="{% url 'treasury:invoice_list' %}"><i class="fa fa-money"></i> {% trans 'Treasury' %}</a>
</li>
{% endif %}
<li class="nav-item active">
<a class="nav-link" href="{% url 'wei:wei_list' %}"><i class="fa fa-bus"></i> {% trans 'WEI' %}</a>
</li>
</ul>
<ul class="navbar-nav ml-auto">
{% if user.is_authenticated %}

View File

@ -43,8 +43,8 @@
<dt class="col-xl-6"><a href="{% url 'member:club_alias' club.pk %}">{% trans 'aliases'|capfirst %}</a></dt>
<dd class="col-xl-6 text-truncate">{{ object.note.alias_set.all|join:", " }}</dd>
<dt class="col-xl-3">{% trans 'email'|capfirst %}</dt>
<dd class="col-xl-9"><a href="mailto:{{ club.email }}">{{ club.email }}</a></dd>
<dt class="col-xl-4">{% trans 'email'|capfirst %}</dt>
<dd class="col-xl-8"><a href="mailto:{{ club.email }}">{{ club.email }}</a></dd>
</dl>
</div>
<div class="card-footer text-center">

View File

@ -0,0 +1,70 @@
{% extends "base.html" %}
{% load render_table from django_tables2 %}
{% load i18n %}
{% block content %}
<div class="row justify-content-center mb-4">
<div class="col-md-10 text-center">
<h4>
{% trans "search WEI" %}
</h4>
<input class="form-control mx-auto w-25" type="text" onkeyup="search_field_moved()" id="search_field"/>
<hr>
<a class="btn btn-primary text-center my-4" href="{% url 'member:club_create' %}">{% trans "Create WEI" %}</a>
</div>
</div>
<div class="row justify-content-center">
<div class="col-md-10">
<div class="card card-border shadow">
<div class="card-header text-center">
<h5> {% trans "WEI listing "%}</h5>
</div>
<div class="card-body px-0 py-0" id="club_table">
{% render_table table %}
</div>
</div>
</div>
</div>
{% endblock %}
{% block extrajavascript %}
<script type="text/javascript">
function getInfo() {
var asked = $("#search_field").val();
/* on ne fait la requête que si on a au moins un caractère pour chercher */
var sel = $(".table-row");
if (asked.length >= 1) {
$.getJSON("/api/wei/club/?format=json&search="+asked, function(buttons){
let selected_id = buttons.results.map((a => "#row-"+a.id));
$(".table-row,"+selected_id.join()).show();
$(".table-row").not(selected_id.join()).hide();
});
}else{
// show everything
$('table tr').show();
}
}
var timer;
var timer_on;
/* Fontion appelée quand le texte change (délenche le timer) */
function search_field_moved(secondfield) {
if (timer_on) { // Si le timer a déjà été lancé, on réinitialise le compteur.
clearTimeout(timer);
timer = setTimeout("getInfo(" + secondfield + ")", 300);
}
else { // Sinon, on le lance et on enregistre le fait qu'il tourne.
timer = setTimeout("getInfo(" + secondfield + ")", 300);
timer_on = true;
}
}
// clickable row
$(document).ready(function($) {
$(".table-row").click(function() {
window.document.location = $(this).data("href");
});
});
</script>
{% endblock %}

View File

@ -30,7 +30,7 @@ deps =
pep8-naming
pyflakes
commands =
flake8 apps/activity apps/api apps/logs apps/member apps/note apps/permission apps/treasury
flake8 apps/activity apps/api apps/logs apps/member apps/note apps/permission apps/treasury apps/wei
[flake8]
# Ignore too many errors, should be reduced in the future