1
0
mirror of https://gitlab.crans.org/bde/nk20 synced 2025-07-22 08:53:28 +02:00

Compare commits

...

2 Commits

Author SHA1 Message Date
57f43a8700 API 2025-07-18 13:54:37 +02:00
a72572ded6 Optimisation ergonomique de la création de famille et chalenge 2025-07-18 11:51:27 +02:00
5 changed files with 308 additions and 204 deletions

View File

View File

@ -0,0 +1,46 @@
# Copyright (C) 2018-2025 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from rest_framework import serializers
from ..models import Family, FamilyMembership, Challenge, Achievement
class FamilySerializer(serializers.ModelSerializer):
"""
REST API Serializer for Family.
The djangorestframework plugin will analyse the model `Family` and parse all fields in the API.
"""
class Meta:
model = Family
fields = '__all__'
class FamilyMembershipSerializer(serializers.ModelSerializer):
"""
REST API Serializer for FamilyMembership.
The djangorestframework plugin will analyse the model `FamilyMembership` and parse all fields in the API.
"""
class Meta:
model = FamilyMembership
fields = '__all__'
class ChallengeSerializer(serializers.ModelSerializer):
"""
REST API Serializer for Challenge.
The djangorestframework plugin will analyse the model `Challenge` and parse all fields in the API.
"""
class Meta:
model = Challenge
fields = '__all__'
class AchievementSerializer(serializers.ModelSerializer):
"""
REST API Serializer for Achievement.
The djangorestframework plugin will analyse the model `Achievement` and parse all fields in the API.
"""
class Meta:
model = Achievement
fields = '__all__'

14
apps/family/api/urls.py Normal file
View File

@ -0,0 +1,14 @@
# Copyright (C) 2018-2025 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from .views import FamilyViewSet, FamilyMembershipViewSet, ChallengeViewSet, AchievementViewSet
def register_family_urls(router, path):
"""
Configure router for Family REST API
"""
router.register(path + 'family', FamilyViewSet)
router.register(path + 'familymembership', FamilyMembershipViewSet)
router.register(path + 'challenge', ChallengeViewSet)
router.register(path + 'achievement', AchievementViewSet)

61
apps/family/api/views.py Normal file
View File

@ -0,0 +1,61 @@
# Copyright (C) 2018-2025 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
from api.viewsets import ReadProtectedModelViewSet
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter
from .serializers import FamilySerializer, FamilyMembershipSerializer, ChallengeSerializer, AchievementSerializer
from ..models import Family, FamilyMembership, Challenge, Achievement
class FamilyViewSet(ReadProtectedModelViewSet):
"""
REST API View set.
The djangorestframework plugin will get all `Family` objects, serialize it to JSON with the given serializer,
then render it on /api/family/family/
"""
queryset = Family.object.order_by('id')
serializer_class = FamilySerializer
filter_backends = [DjangoFilterBackend, SearchFilter]
filterset_fields = ['name', ]
search_fields = ['§name', ]
class FamilyMembershipViewSet(ReadProtectedModelViewSet):
"""
REST API View set.
The djangorestframework plugin will get all `FamilyMembership` objects, serialize it to JSON with the given serializer,
then render it on /api/family/familymembership/
"""
queryset = FamilyMembership.object.order_by('id')
serializer_class = FamilyMembershipSerializer
filter_backends = [DjangoFilterBackend, SearchFilter]
filterset_fields = ['name', ]
search_fields = ['§name', ]
class ChallengeViewSet(ReadProtectedModelViewSet):
"""
REST API View set.
The djangorestframework plugin will get all `Challenge` objects, serialize it to JSON with the given serializer,
then render it on /api/family/challenge/
"""
queryset = Challenge.object.order_by('id')
serializer_class = ChallengeSerializer
filter_backends = [DjangoFilterBackend, SearchFilter]
filterset_fields = ['name', ]
search_fields = ['§name', ]
class AchievementViewSet(ReadProtectedModelViewSet):
"""
REST API View set.
The djangorestframework plugin will get all `Achievement` objects, serialize it to JSON with the given serializer,
then render it on /api/family/achievement/
"""
queryset = Achievement.object.order_by('id')
serializer_class = AchievementSerializer
filter_backends = [DjangoFilterBackend, SearchFilter]
filterset_fields = ['name', ]
search_fields = ['§name', ]

View File

@ -25,14 +25,13 @@ SPDX-License-Identifier: GPL-3.0-or-later
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<div class='col-sm-5 col-xl-6' id="infos_div"> <div class="col-sm-5 col-xl-6" id="infos_div">
<div class="row justify-content-center justify-content-md-end"> <div class="row justify-content-center justify-content-md-end">
{# User details column #} {# User details column #}
<div class="col picture-col"> <div class="col picture-col">
<div class="card bg-light mb-4 text-center"> <div class="card bg-light mb-4 text-center">
<a id="profile_pic_link" href="#"> <a id="profile_pic_link" href="#">
<img src="{% static "member/img/default_picture.png" %}" <img src="{% static "member/img/default_picture.png" %}" id="profile_pic" alt="" class="card-img-top d-none d-sm-block">
id="profile_pic" alt="" class="card-img-top d-none d-sm-block">
</a> </a>
<div class="card-body text-center text-break p-2"> <div class="card-body text-center text-break p-2">
<span id="user_note"><i class="small">{% trans "Please select a family" %}</i></span> <span id="user_note"><i class="small">{% trans "Please select a family" %}</i></span>
@ -49,14 +48,11 @@ SPDX-License-Identifier: GPL-3.0-or-later
</p> </p>
</div> </div>
<div class="card-body p-0" style="min-height:125px;"> <div class="card-body p-0" style="min-height:125px;">
<ul class="list-group list-group-flush" id="note_list"> <ul class="list-group list-group-flush" id="note_list"></ul>
</ul>
</div> </div>
{# User search with autocompletion #} {# User search with autocompletion #}
<div class="card-footer"> <div class="card-footer">
<input class="form-control mx-auto d-block" <input class="form-control mx-auto d-block" placeholder="{% trans "Name" %}" type="text" id="note" autofocus />
placeholder="{% trans "Name" %}" type="text" id="note" autofocus />
</div> </div>
</div> </div>
</div> </div>
@ -70,8 +66,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
</p> </p>
</div> </div>
<div class="card-body p-0" style="min-height:125px;"> <div class="card-body p-0" style="min-height:125px;">
<ul class="list-group list-group-flush" id="consos_list"> <ul class="list-group list-group-flush" id="consos_list"></ul>
</ul>
</div> </div>
<div class="card-footer text-center"> <div class="card-footer text-center">
<span id="consume_all" class="btn btn-primary"> <span id="consume_all" class="btn btn-primary">
@ -81,21 +76,20 @@ SPDX-License-Identifier: GPL-3.0-or-later
</div> </div>
</div> </div>
</div> </div>
{# Create family/challenge buttons #} {# Create family/challenge buttons #}
<div class="card bg-light border-success mb-4"> <div class="card bg-light border-success mb-4">
<h3 class="card-header"> <h3 class="card-header font-weight-bold text-center">
<p class="card-text font-weight-bold">
{% trans "Create a family or challenge" %} {% trans "Create a family or challenge" %}
</p>
</h3> </h3>
<div class="card-body"> <div class="card-body text-center">
{% if can_add_family %} {% if can_add_family %}
<a class="btn btn-sm btn-primary" href="{% url "family:add_family" %}"> <a class="btn btn-sm btn-primary mx-2" href="{% url 'family:add_family' %}">
{% trans "Add a family" %} {% trans "Add a family" %}
</a> </a>
{% endif %} {% endif %}
{% if can_add_challenge %} {% if can_add_challenge %}
<a class="btn btn-sm btn-primary" href="{% url "family:add_challenge" %}"> <a class="btn btn-sm btn-primary mx-2" href="{% url 'family:add_challenge' %}">
{% trans "Add a challenge" %} {% trans "Add a challenge" %}
</a> </a>
{% endif %} {% endif %}
@ -103,11 +97,8 @@ SPDX-License-Identifier: GPL-3.0-or-later
</div> </div>
</div> </div>
{# Buttons column #} {# Buttons column #}
<div class="col"> <div class="col">
{# Regroup buttons under categories #}
<div class="card bg-light border-primary text-center mb-4"> <div class="card bg-light border-primary text-center mb-4">
{# Tabs for list and search #} {# Tabs for list and search #}
<div class="card-header"> <div class="card-header">
@ -139,8 +130,7 @@ SPDX-License-Identifier: GPL-3.0-or-later
</div> </div>
</div> </div>
<div class="tab-pane" id="search"> <div class="tab-pane" id="search">
<input class="form-control mx-auto d-block mb-3" <input class="form-control mx-auto d-block mb-3" placeholder="{% trans "Search challenge..." %}" type="search" id="search-input"/>
placeholder="{% trans "Search challenge..." %}" type="search" id="search-input"/>
<div class="d-inline-flex flex-wrap justify-content-center" id="search-results"> <div class="d-inline-flex flex-wrap justify-content-center" id="search-results">
{% for challenge in all_challenges %} {% for challenge in all_challenges %}
<button class="btn btn-outline-dark rounded-0 flex-fill" hidden <button class="btn btn-outline-dark rounded-0 flex-fill" hidden
@ -158,29 +148,22 @@ SPDX-License-Identifier: GPL-3.0-or-later
<a class="btn btn-sm btn-secondary float-left" href="{% url 'note:template_list' %}"> <a class="btn btn-sm btn-secondary float-left" href="{% url 'note:template_list' %}">
<i class="fa fa-edit"></i> {% trans "Edit" %} <i class="fa fa-edit"></i> {% trans "Edit" %}
</a> </a>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{# transaction history #} {# transaction history #}
<div class="card mb-4" id="history"> <div class="card mb-4" id="history">
<div class="card-header"> <div class="card-header">
<p class="card-text font-weight-bold"> <p class="card-text font-weight-bold">
{% trans "Recent achievements history" %} {% trans "Recent achievements history" %}
</p> </p>
</div> </div>
{% render_table table %} {% render_table table %}
</div> </div>
{% endblock %} {% endblock %}
{% block extrajavascript %} {% block extrajavascript %}
<script type="text/javascript" src="{% static "family/js/consos.js" %}"></script> <script type="text/javascript" src="{% static "family/js/consos.js" %}"></script>
<script type="text/javascript"> <script type="text/javascript">