From 67b936ae9895476f55eafb3f7e150e70aa237708 Mon Sep 17 00:00:00 2001 From: Ehouarn Date: Fri, 18 Jul 2025 21:01:15 +0200 Subject: [PATCH] Rank calculation optimized --- apps/family/api/urls.py | 8 +++-- apps/family/api/views.py | 30 ++++++++++++++++ apps/family/models.py | 7 ++-- apps/family/static/family/js/achievements.js | 36 ++++++++++++++------ apps/family/urls.py | 3 +- 5 files changed, 67 insertions(+), 17 deletions(-) diff --git a/apps/family/api/urls.py b/apps/family/api/urls.py index b231ef99..e94776d7 100644 --- a/apps/family/api/urls.py +++ b/apps/family/api/urls.py @@ -1,7 +1,7 @@ # Copyright (C) 2018-2025 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later - -from .views import FamilyViewSet, FamilyMembershipViewSet, ChallengeViewSet, AchievementViewSet +from django.urls import path +from .views import FamilyViewSet, FamilyMembershipViewSet, ChallengeViewSet, AchievementViewSet, BatchAchievementsAPIView def register_family_urls(router, path): @@ -12,3 +12,7 @@ def register_family_urls(router, path): router.register(path + '/familymembership', FamilyMembershipViewSet) router.register(path + '/challenge', ChallengeViewSet) router.register(path + '/achievement', AchievementViewSet) + +urlpatterns = [ + path('achievements/batch/', BatchAchievementsAPIView.as_view(), name='batch_achievements') +] \ No newline at end of file diff --git a/apps/family/api/views.py b/apps/family/api/views.py index f2fe0208..d568c1c6 100644 --- a/apps/family/api/views.py +++ b/apps/family/api/views.py @@ -4,6 +4,14 @@ from api.viewsets import ReadProtectedModelViewSet from django_filters.rest_framework import DjangoFilterBackend from rest_framework.filters import SearchFilter +from rest_framework.views import APIView +from rest_framework.permissions import IsAuthenticated +from rest_framework.response import Response +from rest_framework import status +from django.views.decorators.csrf import csrf_exempt +from django.views.decorators.http import require_POST +from django.http import JsonResponse +import json from .serializers import FamilySerializer, FamilyMembershipSerializer, ChallengeSerializer, AchievementSerializer from ..models import Family, FamilyMembership, Challenge, Achievement @@ -59,3 +67,25 @@ class AchievementViewSet(ReadProtectedModelViewSet): filter_backends = [DjangoFilterBackend, SearchFilter] filterset_fields = ['name', ] search_fields = ['$name', ] + + +class BatchAchievementsAPIView(APIView): + permission_classes = [IsAuthenticated] + def post(self, request, format=None): + print("POST de la view spéciale") + family_ids = request.data.get('families', []) + challenge_ids = request.data.get('challenges', []) + + families = Family.objects.filter(id__in=family_ids) + challenges = Challenge.objects.filter(id__in=challenge_ids) + + for family in families: + for challenge in challenges: + a = Achievement(family=family, challenge=challenge) + a.save(update_score=False) + + for family in families: + family.update_score() + Family.update_ranking() + + return Response({'status': 'ok'}, status=status.HTTP_201_CREATED) \ No newline at end of file diff --git a/apps/family/models.py b/apps/family/models.py index 1d2d0d34..1acc9ba8 100644 --- a/apps/family/models.py +++ b/apps/family/models.py @@ -165,7 +165,7 @@ class Achievement(models.Model): return _('Challenge {challenge} carried out by Family {family}').format(challenge=self.challenge.name, family=self.family.name, ) @transaction.atomic - def save(self, *args, **kwargs): + def save(self, *args, update_score=True, **kwargs): """ When saving, also grants points to the family """ @@ -175,8 +175,9 @@ class Achievement(models.Model): super().save(*args, **kwargs) - self.family.refresh_from_db() - self.family.update_score() + if update_score: + self.family.refresh_from_db() + self.family.update_score() # Count only when getting a new achievement if is_new: diff --git a/apps/family/static/family/js/achievements.js b/apps/family/static/family/js/achievements.js index dba07f0d..db29923d 100644 --- a/apps/family/static/family/js/achievements.js +++ b/apps/family/static/family/js/achievements.js @@ -113,33 +113,47 @@ function reset () { * Apply all transactions: all notes in `notes` buy each item in `buttons` */ function consumeAll () { - console.log("consumeAll lancée") if (LOCK) { return } - LOCK = true let error = false if (notes_display.length === 0) { - document.getElementById('note').classList.add('is-invalid') - $('#note_list').html(li('', 'Ajoutez des familles.', 'text-danger')) + // ... gestion erreur ... error = true } - if (buttons.length === 0) { - $('#consos_list').html(li('', 'Ajoutez des défis.', 'text-danger')) + // ... gestion erreur ... error = true } - if (error) { LOCK = false return } - notes_display.forEach(function (family) { - buttons.forEach(function (challenge) { - grantAchievement(family, challenge) - }) + // Récupérer les IDs des familles et des challenges + const family_ids = notes_display.map(fam => fam.id) + const challenge_ids = buttons.map(chal => chal.id) + + $.ajax({ + url: '/family/api/family/achievements/batch/', + type: 'POST', + data: JSON.stringify({ + families: family_ids, + challenges: challenge_ids + }), + contentType: 'application/json', + headers: { + 'X-CSRFToken': CSRF_TOKEN + }, + success: function () { + reset() + addMsg("Défis validés pour les familles !", 'success', 5000) + }, + error: function (e) { + reset() + addMsg("Erreur lors de la création des achievements.",'danger',5000) + } }) } diff --git a/apps/family/urls.py b/apps/family/urls.py index 094ed505..ee491ecc 100644 --- a/apps/family/urls.py +++ b/apps/family/urls.py @@ -1,7 +1,7 @@ # Copyright (C) 2018-2025 by BDE ENS Paris-Saclay # SPDX-License-Identifier: GPL-3.0-or-later -from django.urls import path +from django.urls import path, include from . import views @@ -18,4 +18,5 @@ urlpatterns = [ path('challenge/detail//', views.ChallengeDetailView.as_view(), name="challenge_detail"), path('challenge/update//', views.ChallengeUpdateView.as_view(), name="challenge_update"), path('manage/', views.FamilyManageView.as_view(), name="manage"), + path('api/family/', include('family.api.urls')), ]