mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-07-19 23:51:25 +02:00
Achievement delete
This commit is contained in:
@ -1,6 +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
|
||||||
|
|
||||||
from .views import FamilyViewSet, FamilyMembershipViewSet, ChallengeViewSet, AchievementViewSet, BatchAchievementsAPIView
|
from .views import FamilyViewSet, FamilyMembershipViewSet, ChallengeViewSet, AchievementViewSet, BatchAchievementsAPIView
|
||||||
|
|
||||||
|
|
||||||
@ -13,6 +14,7 @@ def register_family_urls(router, path):
|
|||||||
router.register(path + '/challenge', ChallengeViewSet)
|
router.register(path + '/challenge', ChallengeViewSet)
|
||||||
router.register(path + '/achievement', AchievementViewSet)
|
router.register(path + '/achievement', AchievementViewSet)
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('achievements/batch/', BatchAchievementsAPIView.as_view(), name='batch_achievements')
|
path('achievements/batch/', BatchAchievementsAPIView.as_view(), name='batch_achievements')
|
||||||
]
|
]
|
||||||
|
@ -8,10 +8,6 @@ from rest_framework.views import APIView
|
|||||||
from rest_framework.permissions import IsAuthenticated
|
from rest_framework.permissions import IsAuthenticated
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework import status
|
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
|
||||||
@ -71,6 +67,7 @@ class AchievementViewSet(ReadProtectedModelViewSet):
|
|||||||
|
|
||||||
class BatchAchievementsAPIView(APIView):
|
class BatchAchievementsAPIView(APIView):
|
||||||
permission_classes = [IsAuthenticated]
|
permission_classes = [IsAuthenticated]
|
||||||
|
|
||||||
def post(self, request, format=None):
|
def post(self, request, format=None):
|
||||||
print("POST de la view spéciale")
|
print("POST de la view spéciale")
|
||||||
family_ids = request.data.get('families', [])
|
family_ids = request.data.get('families', [])
|
||||||
@ -88,4 +85,4 @@ class BatchAchievementsAPIView(APIView):
|
|||||||
family.update_score()
|
family.update_score()
|
||||||
Family.update_ranking()
|
Family.update_ranking()
|
||||||
|
|
||||||
return Response({'status': 'ok'}, status=status.HTTP_201_CREATED)
|
return Response({'status': 'ok'}, status=status.HTTP_201_CREATED)
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
import django_tables2 as tables
|
import django_tables2 as tables
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django_tables2 import A
|
||||||
|
|
||||||
from .models import Family, Challenge, FamilyMembership, Achievement
|
from .models import Family, Challenge, FamilyMembership, Achievement
|
||||||
|
|
||||||
@ -63,11 +65,28 @@ class AchievementTable(tables.Table):
|
|||||||
"""
|
"""
|
||||||
List recent achievements.
|
List recent achievements.
|
||||||
"""
|
"""
|
||||||
|
delete = tables.LinkColumn(
|
||||||
|
'family:achievement_delete',
|
||||||
|
args=[A('id')],
|
||||||
|
verbose_name=_("Delete"),
|
||||||
|
text=_("Delete"),
|
||||||
|
orderable=False,
|
||||||
|
attrs={
|
||||||
|
'th': {
|
||||||
|
'id': 'delete-membership-header'
|
||||||
|
},
|
||||||
|
'a': {
|
||||||
|
'class': 'btn btn-danger',
|
||||||
|
'data-type': 'delete-membership'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
attrs = {
|
attrs = {
|
||||||
'class': 'table table-condensed table-striped table-hover'
|
'class': 'table table-condensed table-striped table-hover'
|
||||||
}
|
}
|
||||||
model = Achievement
|
model = Achievement
|
||||||
fields = ('family', 'challenge', 'obtained_at', )
|
fields = ('family', 'challenge', 'challenge__points', 'obtained_at', )
|
||||||
template_name = 'django_tables2/bootstrap4.html'
|
template_name = 'django_tables2/bootstrap4.html'
|
||||||
orderable = False
|
order_by = ('-obtained_at',)
|
||||||
|
27
apps/family/templates/family/achievement_confirm_delete.html
Normal file
27
apps/family/templates/family/achievement_confirm_delete.html
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% comment %}
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
{% endcomment %}
|
||||||
|
{% load i18n crispy_forms_tags %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="card bg-light">
|
||||||
|
<div class="card-header text-center">
|
||||||
|
<h4>{% trans "Delete achievement" %}</h4>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
{% blocktrans %}Are you sure you want to delete this achievement? This action can't be undone.{% endblocktrans %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="card-footer text-center">
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<a class="btn btn-primary" href="{% url 'family:achievement_list' %}">{% trans "Return to achievements list" %}</a>
|
||||||
|
{% if not object.locked %}
|
||||||
|
<button class="btn btn-danger" type="submit">{% trans "Delete" %}</button>
|
||||||
|
{% endif %}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
22
apps/family/templates/family/achievement_list.html
Normal file
22
apps/family/templates/family/achievement_list.html
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% comment %}
|
||||||
|
Copyright (C) 2018-2025 by BDE ENS Paris-Saclay
|
||||||
|
SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
{% endcomment %}
|
||||||
|
{% load i18n django_tables2 %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="card mb-4" id="history">
|
||||||
|
<div class="card-header">
|
||||||
|
<p class="card-text font-weight-bold">
|
||||||
|
{% trans "Recent achievements history" %}
|
||||||
|
</p>
|
||||||
|
<a class="btn btn-sm btn-primary mx-2" href="{% url "family:manage" %}">
|
||||||
|
{% trans "Return to management page" %}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
{% render_table table %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -143,24 +143,21 @@ SPDX-License-Identifier: GPL-3.0-or-later
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# Mode switch #}
|
|
||||||
<div class="card-footer border-primary">
|
|
||||||
<a class="btn btn-sm btn-secondary float-left" href="{% url 'note:template_list' %}">
|
|
||||||
<i class="fa fa-edit"></i> {% trans "Edit" %}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{# transaction history #}
|
{# transaction history #}
|
||||||
<div class="card mb-4" id="history">
|
<div class="card">
|
||||||
<div class="card-header">
|
<div class="card-header position-relative" id="historyListHeading">
|
||||||
<p class="card-text font-weight-bold">
|
<a class="stretched-link font-weight-bold"
|
||||||
|
href="{% url 'family:achievement_list' %}" >
|
||||||
{% trans "Recent achievements history" %}
|
{% trans "Recent achievements history" %}
|
||||||
</p>
|
</a>
|
||||||
|
</div>
|
||||||
|
<div id="history_list">
|
||||||
|
{% render_table table %}
|
||||||
</div>
|
</div>
|
||||||
{% render_table table %}
|
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
@ -18,5 +18,7 @@ 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('achievements/', views.AchievementsView.as_view(), name="achievement_list"),
|
||||||
|
path('achievement/delete/<int:pk>/', views.AchievementDeleteView.as_view(), name="achievement_delete"),
|
||||||
path('api/family/', include('family.api.urls')),
|
path('api/family/', include('family.api.urls')),
|
||||||
]
|
]
|
||||||
|
@ -7,6 +7,7 @@ from django.conf import settings
|
|||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.views.generic import DetailView, UpdateView
|
from django.views.generic import DetailView, UpdateView
|
||||||
|
from django.views.generic.edit import DeleteView
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django_tables2 import SingleTableView
|
from django_tables2 import SingleTableView
|
||||||
from permission.backends import PermissionBackend
|
from permission.backends import PermissionBackend
|
||||||
@ -195,7 +196,7 @@ class ChallengeCreateView(ProtectQuerysetMixin, ProtectedCreateView):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse_lazy('family:challenge_list')
|
return reverse_lazy('family:manage')
|
||||||
|
|
||||||
|
|
||||||
class ChallengeListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
|
class ChallengeListView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
|
||||||
@ -264,7 +265,7 @@ class FamilyManageView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView
|
|||||||
# retrieves only Transaction that user has the right to see.
|
# retrieves only Transaction that user has the right to see.
|
||||||
return Achievement.objects.filter(
|
return Achievement.objects.filter(
|
||||||
PermissionBackend.filter_queryset(self.request, Achievement, "view")
|
PermissionBackend.filter_queryset(self.request, Achievement, "view")
|
||||||
).order_by("-obtained_at").all()[:20]
|
).order_by("-obtained_at").all()
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
@ -277,3 +278,33 @@ class FamilyManageView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView
|
|||||||
context["can_add_challenge"] = PermissionBackend.check_perm(self.request, "family.add_challenge")
|
context["can_add_challenge"] = PermissionBackend.check_perm(self.request, "family.add_challenge")
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
def get_table(self, **kwargs):
|
||||||
|
table = super().get_table(**kwargs)
|
||||||
|
table.exclude = ('delete',)
|
||||||
|
table.orderable = False
|
||||||
|
return table
|
||||||
|
|
||||||
|
|
||||||
|
class AchievementsView(ProtectQuerysetMixin, LoginRequiredMixin, SingleTableView):
|
||||||
|
"""
|
||||||
|
List all achievements
|
||||||
|
"""
|
||||||
|
model = Achievement
|
||||||
|
table_class = AchievementTable
|
||||||
|
extra_context = {'title': _('Achievement list')}
|
||||||
|
|
||||||
|
def get_table(self, **kwargs):
|
||||||
|
table = super().get_table(**kwargs)
|
||||||
|
table.orderable = True
|
||||||
|
return table
|
||||||
|
|
||||||
|
|
||||||
|
class AchievementDeleteView(ProtectQuerysetMixin, LoginRequiredMixin, DeleteView):
|
||||||
|
"""
|
||||||
|
Delete an Achievement
|
||||||
|
"""
|
||||||
|
model = Achievement
|
||||||
|
|
||||||
|
def get_success_url(self):
|
||||||
|
return reverse_lazy('family:achievement_list')
|
||||||
|
@ -168,7 +168,7 @@ class InvoiceUpdateView(ProtectQuerysetMixin, LoginRequiredMixin, UpdateView):
|
|||||||
|
|
||||||
class InvoiceDeleteView(ProtectQuerysetMixin, LoginRequiredMixin, DeleteView):
|
class InvoiceDeleteView(ProtectQuerysetMixin, LoginRequiredMixin, DeleteView):
|
||||||
"""
|
"""
|
||||||
Delete a non-validated WEI registration
|
Delete a non-locked Invoice
|
||||||
"""
|
"""
|
||||||
model = Invoice
|
model = Invoice
|
||||||
extra_context = {"title": _("Delete invoice")}
|
extra_context = {"title": _("Delete invoice")}
|
||||||
|
Reference in New Issue
Block a user