1
0
mirror of https://gitlab.crans.org/bde/nk20 synced 2025-07-19 23:51:25 +02:00

Rank calculation optimized

This commit is contained in:
Ehouarn
2025-07-18 21:01:15 +02:00
parent ac56700705
commit 67b936ae98
5 changed files with 67 additions and 17 deletions

View File

@ -1,7 +1,7 @@
# Copyright (C) 2018-2025 by BDE ENS Paris-Saclay # Copyright (C) 2018-2025 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from django.urls import path
from .views import FamilyViewSet, FamilyMembershipViewSet, ChallengeViewSet, AchievementViewSet from .views import FamilyViewSet, FamilyMembershipViewSet, ChallengeViewSet, AchievementViewSet, BatchAchievementsAPIView
def register_family_urls(router, path): def register_family_urls(router, path):
@ -12,3 +12,7 @@ def register_family_urls(router, path):
router.register(path + '/familymembership', FamilyMembershipViewSet) router.register(path + '/familymembership', FamilyMembershipViewSet)
router.register(path + '/challenge', ChallengeViewSet) router.register(path + '/challenge', ChallengeViewSet)
router.register(path + '/achievement', AchievementViewSet) router.register(path + '/achievement', AchievementViewSet)
urlpatterns = [
path('achievements/batch/', BatchAchievementsAPIView.as_view(), name='batch_achievements')
]

View File

@ -4,6 +4,14 @@
from api.viewsets import ReadProtectedModelViewSet from api.viewsets import ReadProtectedModelViewSet
from django_filters.rest_framework import DjangoFilterBackend from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter 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 .serializers import FamilySerializer, FamilyMembershipSerializer, ChallengeSerializer, AchievementSerializer
from ..models import Family, FamilyMembership, Challenge, Achievement from ..models import Family, FamilyMembership, Challenge, Achievement
@ -59,3 +67,25 @@ class AchievementViewSet(ReadProtectedModelViewSet):
filter_backends = [DjangoFilterBackend, SearchFilter] filter_backends = [DjangoFilterBackend, SearchFilter]
filterset_fields = ['name', ] filterset_fields = ['name', ]
search_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)

View File

@ -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, ) return _('Challenge {challenge} carried out by Family {family}').format(challenge=self.challenge.name, family=self.family.name, )
@transaction.atomic @transaction.atomic
def save(self, *args, **kwargs): def save(self, *args, update_score=True, **kwargs):
""" """
When saving, also grants points to the family When saving, also grants points to the family
""" """
@ -175,8 +175,9 @@ class Achievement(models.Model):
super().save(*args, **kwargs) super().save(*args, **kwargs)
self.family.refresh_from_db() if update_score:
self.family.update_score() self.family.refresh_from_db()
self.family.update_score()
# Count only when getting a new achievement # Count only when getting a new achievement
if is_new: if is_new:

View File

@ -113,33 +113,47 @@ function reset () {
* Apply all transactions: all notes in `notes` buy each item in `buttons` * Apply all transactions: all notes in `notes` buy each item in `buttons`
*/ */
function consumeAll () { function consumeAll () {
console.log("consumeAll lancée")
if (LOCK) { return } if (LOCK) { return }
LOCK = true LOCK = true
let error = false let error = false
if (notes_display.length === 0) { if (notes_display.length === 0) {
document.getElementById('note').classList.add('is-invalid') // ... gestion erreur ...
$('#note_list').html(li('', '<strong>Ajoutez des familles.</strong>', 'text-danger'))
error = true error = true
} }
if (buttons.length === 0) { if (buttons.length === 0) {
$('#consos_list').html(li('', '<strong>Ajoutez des défis.</strong>', 'text-danger')) // ... gestion erreur ...
error = true error = true
} }
if (error) { if (error) {
LOCK = false LOCK = false
return return
} }
notes_display.forEach(function (family) { // Récupérer les IDs des familles et des challenges
buttons.forEach(function (challenge) { const family_ids = notes_display.map(fam => fam.id)
grantAchievement(family, challenge) 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)
}
}) })
} }

View File

@ -1,7 +1,7 @@
# Copyright (C) 2018-2025 by BDE ENS Paris-Saclay # Copyright (C) 2018-2025 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
from django.urls import path from django.urls import path, include
from . import views from . import views
@ -18,4 +18,5 @@ urlpatterns = [
path('challenge/detail/<int:pk>/', views.ChallengeDetailView.as_view(), name="challenge_detail"), path('challenge/detail/<int:pk>/', views.ChallengeDetailView.as_view(), name="challenge_detail"),
path('challenge/update/<int:pk>/', views.ChallengeUpdateView.as_view(), name="challenge_update"), path('challenge/update/<int:pk>/', views.ChallengeUpdateView.as_view(), name="challenge_update"),
path('manage/', views.FamilyManageView.as_view(), name="manage"), path('manage/', views.FamilyManageView.as_view(), name="manage"),
path('api/family/', include('family.api.urls')),
] ]