mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-04-04 01:51:28 +00:00
feat: Securisation du Backend
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.1.3 on 2025-11-30 11:02
|
||||
# Generated by Django 5.1.3 on 2026-03-14 13:23
|
||||
|
||||
import django.contrib.postgres.fields
|
||||
import django.db.models.deletion
|
||||
|
||||
@ -1,3 +1,286 @@
|
||||
from django.test import TestCase
|
||||
"""
|
||||
Tests unitaires pour le module School.
|
||||
Vérifie que tous les endpoints (Speciality, Teacher, SchoolClass, Planning,
|
||||
Fee, Discount, PaymentPlan, PaymentMode, Competency, EstablishmentCompetency)
|
||||
requièrent une authentification JWT.
|
||||
"""
|
||||
|
||||
# Create your tests here.
|
||||
from django.test import TestCase, override_settings
|
||||
from django.urls import reverse
|
||||
from rest_framework import status
|
||||
from rest_framework.test import APIClient
|
||||
from rest_framework_simplejwt.tokens import RefreshToken
|
||||
|
||||
from Auth.models import Profile
|
||||
|
||||
|
||||
def create_user(email="school_test@example.com", password="testpassword123"):
|
||||
return Profile.objects.create_user(username=email, email=email, password=password)
|
||||
|
||||
|
||||
def get_jwt_token(user):
|
||||
refresh = RefreshToken.for_user(user)
|
||||
return str(refresh.access_token)
|
||||
|
||||
|
||||
TEST_REST_FRAMEWORK = {
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||
'rest_framework_simplejwt.authentication.JWTAuthentication',
|
||||
),
|
||||
'DEFAULT_PERMISSION_CLASSES': (
|
||||
'rest_framework.permissions.IsAuthenticated',
|
||||
),
|
||||
}
|
||||
|
||||
TEST_CACHES = {'default': {'BACKEND': 'django.core.cache.backends.locmem.LocMemCache'}}
|
||||
|
||||
OVERRIDE_SETTINGS = dict(
|
||||
CACHES=TEST_CACHES,
|
||||
SESSION_ENGINE='django.contrib.sessions.backends.db',
|
||||
REST_FRAMEWORK=TEST_REST_FRAMEWORK,
|
||||
)
|
||||
|
||||
|
||||
def _assert_endpoint_requires_auth(test_case, method, url, payload=None):
|
||||
"""Utilitaire : vérifie qu'un endpoint retourne 401 sans authentification."""
|
||||
client = APIClient()
|
||||
call = getattr(client, method)
|
||||
kwargs = {}
|
||||
if payload is not None:
|
||||
import json
|
||||
kwargs = {"data": json.dumps(payload), "content_type": "application/json"}
|
||||
response = call(url, **kwargs)
|
||||
test_case.assertEqual(
|
||||
response.status_code,
|
||||
status.HTTP_401_UNAUTHORIZED,
|
||||
msg=f"{method.upper()} {url} devrait retourner 401 sans auth, reçu {response.status_code}",
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Speciality
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@override_settings(**OVERRIDE_SETTINGS)
|
||||
class SpecialityEndpointAuthTest(TestCase):
|
||||
"""Tests d'authentification sur les endpoints Speciality."""
|
||||
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
self.list_url = reverse("School:speciality_list_create")
|
||||
self.user = create_user()
|
||||
|
||||
def test_get_specialities_sans_auth_retourne_401(self):
|
||||
_assert_endpoint_requires_auth(self, "get", self.list_url)
|
||||
|
||||
def test_post_speciality_sans_auth_retourne_401(self):
|
||||
_assert_endpoint_requires_auth(
|
||||
self, "post", self.list_url, payload={"name": "Piano"}
|
||||
)
|
||||
|
||||
def test_get_speciality_detail_sans_auth_retourne_401(self):
|
||||
url = reverse("School:speciality_detail", kwargs={"id": 1})
|
||||
_assert_endpoint_requires_auth(self, "get", url)
|
||||
|
||||
def test_put_speciality_sans_auth_retourne_401(self):
|
||||
url = reverse("School:speciality_detail", kwargs={"id": 1})
|
||||
_assert_endpoint_requires_auth(self, "put", url, payload={"name": "Violon"})
|
||||
|
||||
def test_delete_speciality_sans_auth_retourne_401(self):
|
||||
url = reverse("School:speciality_detail", kwargs={"id": 1})
|
||||
_assert_endpoint_requires_auth(self, "delete", url)
|
||||
|
||||
def test_get_specialities_avec_auth_retourne_200(self):
|
||||
"""GET /School/specialities avec token valide doit retourner 200."""
|
||||
token = get_jwt_token(self.user)
|
||||
self.client.credentials(HTTP_AUTHORIZATION=f"Bearer {token}")
|
||||
response = self.client.get(self.list_url, {"establishment_id": 1})
|
||||
self.assertIn(response.status_code, [status.HTTP_200_OK, status.HTTP_400_BAD_REQUEST])
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Teacher
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@override_settings(**OVERRIDE_SETTINGS)
|
||||
class TeacherEndpointAuthTest(TestCase):
|
||||
"""Tests d'authentification sur les endpoints Teacher."""
|
||||
|
||||
def setUp(self):
|
||||
self.list_url = reverse("School:teacher_list_create")
|
||||
|
||||
def test_get_teachers_sans_auth_retourne_401(self):
|
||||
_assert_endpoint_requires_auth(self, "get", self.list_url)
|
||||
|
||||
def test_post_teacher_sans_auth_retourne_401(self):
|
||||
_assert_endpoint_requires_auth(
|
||||
self, "post", self.list_url, payload={"first_name": "Jean"}
|
||||
)
|
||||
|
||||
def test_get_teacher_detail_sans_auth_retourne_401(self):
|
||||
url = reverse("School:teacher_detail", kwargs={"id": 1})
|
||||
_assert_endpoint_requires_auth(self, "get", url)
|
||||
|
||||
def test_put_teacher_sans_auth_retourne_401(self):
|
||||
url = reverse("School:teacher_detail", kwargs={"id": 1})
|
||||
_assert_endpoint_requires_auth(self, "put", url, payload={"first_name": "Pierre"})
|
||||
|
||||
def test_delete_teacher_sans_auth_retourne_401(self):
|
||||
url = reverse("School:teacher_detail", kwargs={"id": 1})
|
||||
_assert_endpoint_requires_auth(self, "delete", url)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# SchoolClass
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@override_settings(**OVERRIDE_SETTINGS)
|
||||
class SchoolClassEndpointAuthTest(TestCase):
|
||||
"""Tests d'authentification sur les endpoints SchoolClass."""
|
||||
|
||||
def setUp(self):
|
||||
self.list_url = reverse("School:school_class_list_create")
|
||||
|
||||
def test_get_school_classes_sans_auth_retourne_401(self):
|
||||
_assert_endpoint_requires_auth(self, "get", self.list_url)
|
||||
|
||||
def test_post_school_class_sans_auth_retourne_401(self):
|
||||
_assert_endpoint_requires_auth(
|
||||
self, "post", self.list_url, payload={"name": "Classe A"}
|
||||
)
|
||||
|
||||
def test_get_school_class_detail_sans_auth_retourne_401(self):
|
||||
url = reverse("School:school_class_detail", kwargs={"id": 1})
|
||||
_assert_endpoint_requires_auth(self, "get", url)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Fee
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@override_settings(**OVERRIDE_SETTINGS)
|
||||
class FeeEndpointAuthTest(TestCase):
|
||||
"""Tests d'authentification sur les endpoints Fee."""
|
||||
|
||||
def setUp(self):
|
||||
self.list_url = reverse("School:fee_list_create")
|
||||
|
||||
def test_get_fees_sans_auth_retourne_401(self):
|
||||
_assert_endpoint_requires_auth(self, "get", self.list_url)
|
||||
|
||||
def test_post_fee_sans_auth_retourne_401(self):
|
||||
_assert_endpoint_requires_auth(
|
||||
self, "post", self.list_url, payload={"amount": 100}
|
||||
)
|
||||
|
||||
def test_get_fee_detail_sans_auth_retourne_401(self):
|
||||
url = reverse("School:fee_detail", kwargs={"id": 1})
|
||||
_assert_endpoint_requires_auth(self, "get", url)
|
||||
|
||||
def test_put_fee_sans_auth_retourne_401(self):
|
||||
url = reverse("School:fee_detail", kwargs={"id": 1})
|
||||
_assert_endpoint_requires_auth(self, "put", url, payload={"amount": 200})
|
||||
|
||||
def test_delete_fee_sans_auth_retourne_401(self):
|
||||
url = reverse("School:fee_detail", kwargs={"id": 1})
|
||||
_assert_endpoint_requires_auth(self, "delete", url)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Discount
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@override_settings(**OVERRIDE_SETTINGS)
|
||||
class DiscountEndpointAuthTest(TestCase):
|
||||
"""Tests d'authentification sur les endpoints Discount."""
|
||||
|
||||
def setUp(self):
|
||||
self.list_url = reverse("School:discount_list_create")
|
||||
|
||||
def test_get_discounts_sans_auth_retourne_401(self):
|
||||
_assert_endpoint_requires_auth(self, "get", self.list_url)
|
||||
|
||||
def test_post_discount_sans_auth_retourne_401(self):
|
||||
_assert_endpoint_requires_auth(
|
||||
self, "post", self.list_url, payload={"rate": 10}
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# PaymentPlan
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@override_settings(**OVERRIDE_SETTINGS)
|
||||
class PaymentPlanEndpointAuthTest(TestCase):
|
||||
"""Tests d'authentification sur les endpoints PaymentPlan."""
|
||||
|
||||
def setUp(self):
|
||||
self.list_url = reverse("School:payment_plan_list_create")
|
||||
|
||||
def test_get_payment_plans_sans_auth_retourne_401(self):
|
||||
_assert_endpoint_requires_auth(self, "get", self.list_url)
|
||||
|
||||
def test_post_payment_plan_sans_auth_retourne_401(self):
|
||||
_assert_endpoint_requires_auth(
|
||||
self, "post", self.list_url, payload={"name": "Plan A"}
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# PaymentMode
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@override_settings(**OVERRIDE_SETTINGS)
|
||||
class PaymentModeEndpointAuthTest(TestCase):
|
||||
"""Tests d'authentification sur les endpoints PaymentMode."""
|
||||
|
||||
def setUp(self):
|
||||
self.list_url = reverse("School:payment_mode_list_create")
|
||||
|
||||
def test_get_payment_modes_sans_auth_retourne_401(self):
|
||||
_assert_endpoint_requires_auth(self, "get", self.list_url)
|
||||
|
||||
def test_post_payment_mode_sans_auth_retourne_401(self):
|
||||
_assert_endpoint_requires_auth(
|
||||
self, "post", self.list_url, payload={"name": "Virement"}
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Competency
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@override_settings(**OVERRIDE_SETTINGS)
|
||||
class CompetencyEndpointAuthTest(TestCase):
|
||||
"""Tests d'authentification sur les endpoints Competency."""
|
||||
|
||||
def setUp(self):
|
||||
self.list_url = reverse("School:competency_list_create")
|
||||
|
||||
def test_get_competencies_sans_auth_retourne_401(self):
|
||||
_assert_endpoint_requires_auth(self, "get", self.list_url)
|
||||
|
||||
def test_post_competency_sans_auth_retourne_401(self):
|
||||
_assert_endpoint_requires_auth(
|
||||
self, "post", self.list_url, payload={"name": "Lecture"}
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# EstablishmentCompetency
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@override_settings(**OVERRIDE_SETTINGS)
|
||||
class EstablishmentCompetencyEndpointAuthTest(TestCase):
|
||||
"""Tests d'authentification sur les endpoints EstablishmentCompetency."""
|
||||
|
||||
def setUp(self):
|
||||
self.list_url = reverse("School:establishment_competency_list_create")
|
||||
|
||||
def test_get_establishment_competencies_sans_auth_retourne_401(self):
|
||||
_assert_endpoint_requires_auth(self, "get", self.list_url)
|
||||
|
||||
def test_post_establishment_competency_sans_auth_retourne_401(self):
|
||||
_assert_endpoint_requires_auth(
|
||||
self, "post", self.list_url, payload={"competency": 1}
|
||||
)
|
||||
|
||||
@ -4,6 +4,7 @@ from django.utils.decorators import method_decorator
|
||||
from rest_framework.parsers import JSONParser
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework import status
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from .models import (
|
||||
Teacher,
|
||||
Speciality,
|
||||
@ -42,6 +43,8 @@ logger = logging.getLogger(__name__)
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class SpecialityListCreateView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request):
|
||||
establishment_id = request.GET.get('establishment_id', None)
|
||||
if establishment_id is None:
|
||||
@ -66,6 +69,8 @@ class SpecialityListCreateView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class SpecialityDetailView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request, id):
|
||||
speciality = getObject(_objectName=Speciality, _columnName='id', _value=id)
|
||||
speciality_serializer=SpecialitySerializer(speciality)
|
||||
@ -87,6 +92,8 @@ class SpecialityDetailView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class TeacherListCreateView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request):
|
||||
establishment_id = request.GET.get('establishment_id', None)
|
||||
if establishment_id is None:
|
||||
@ -121,6 +128,8 @@ class TeacherListCreateView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class TeacherDetailView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get (self, request, id):
|
||||
teacher = getObject(_objectName=Teacher, _columnName='id', _value=id)
|
||||
teacher_serializer=TeacherSerializer(teacher)
|
||||
@ -169,6 +178,8 @@ class TeacherDetailView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class SchoolClassListCreateView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request):
|
||||
establishment_id = request.GET.get('establishment_id', None)
|
||||
if establishment_id is None:
|
||||
@ -193,6 +204,8 @@ class SchoolClassListCreateView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class SchoolClassDetailView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get (self, request, id):
|
||||
schoolClass = getObject(_objectName=SchoolClass, _columnName='id', _value=id)
|
||||
classe_serializer=SchoolClassSerializer(schoolClass)
|
||||
@ -215,6 +228,8 @@ class SchoolClassDetailView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class PlanningListCreateView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request):
|
||||
schedulesList=getAllObjects(Planning)
|
||||
schedules_serializer=PlanningSerializer(schedulesList, many=True)
|
||||
@ -233,6 +248,8 @@ class PlanningListCreateView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class PlanningDetailView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get (self, request, id):
|
||||
planning = getObject(_objectName=Planning, _columnName='classe_id', _value=id)
|
||||
planning_serializer=PlanningSerializer(planning)
|
||||
@ -263,6 +280,8 @@ class PlanningDetailView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class FeeListCreateView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
establishment_id = request.GET.get('establishment_id', None)
|
||||
if establishment_id is None:
|
||||
@ -287,6 +306,8 @@ class FeeListCreateView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class FeeDetailView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request, id):
|
||||
try:
|
||||
fee = Fee.objects.get(id=id)
|
||||
@ -313,6 +334,8 @@ class FeeDetailView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class DiscountListCreateView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
establishment_id = request.GET.get('establishment_id', None)
|
||||
if establishment_id is None:
|
||||
@ -337,6 +360,8 @@ class DiscountListCreateView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class DiscountDetailView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request, id):
|
||||
try:
|
||||
discount = Discount.objects.get(id=id)
|
||||
@ -363,6 +388,8 @@ class DiscountDetailView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class PaymentPlanListCreateView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
establishment_id = request.GET.get('establishment_id', None)
|
||||
if establishment_id is None:
|
||||
@ -387,6 +414,8 @@ class PaymentPlanListCreateView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class PaymentPlanDetailView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request, id):
|
||||
try:
|
||||
payment_plan = PaymentPlan.objects.get(id=id)
|
||||
@ -413,6 +442,8 @@ class PaymentPlanDetailView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class PaymentModeListCreateView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request):
|
||||
establishment_id = request.GET.get('establishment_id', None)
|
||||
if establishment_id is None:
|
||||
@ -437,6 +468,8 @@ class PaymentModeListCreateView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class PaymentModeDetailView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request, id):
|
||||
try:
|
||||
payment_mode = PaymentMode.objects.get(id=id)
|
||||
@ -463,11 +496,13 @@ class PaymentModeDetailView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class CompetencyListCreateView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request):
|
||||
cycle = request.GET.get('cycle')
|
||||
if cycle is None:
|
||||
return JsonResponse({'error': 'cycle est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
|
||||
competencies_list = getAllObjects(Competency)
|
||||
competencies_list = competencies_list.filter(
|
||||
category__domain__cycle=cycle
|
||||
@ -486,6 +521,8 @@ class CompetencyListCreateView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class CompetencyDetailView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request, id):
|
||||
try:
|
||||
competency = Competency.objects.get(id=id)
|
||||
@ -517,6 +554,8 @@ class CompetencyDetailView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class EstablishmentCompetencyListCreateView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request):
|
||||
establishment_id = request.GET.get('establishment_id')
|
||||
cycle = request.GET.get('cycle')
|
||||
@ -593,10 +632,10 @@ class EstablishmentCompetencyListCreateView(APIView):
|
||||
"data": result
|
||||
}, safe=False)
|
||||
|
||||
def post(self, request):
|
||||
def post(self, request):
|
||||
"""
|
||||
Crée une ou plusieurs compétences custom pour un établissement (is_required=False)
|
||||
Attendu dans le body :
|
||||
Attendu dans le body :
|
||||
[
|
||||
{ "establishment_id": ..., "category_id": ..., "nom": ... },
|
||||
...
|
||||
@ -710,6 +749,8 @@ class EstablishmentCompetencyListCreateView(APIView):
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
class EstablishmentCompetencyDetailView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request, id):
|
||||
try:
|
||||
ec = EstablishmentCompetency.objects.get(id=id)
|
||||
|
||||
Reference in New Issue
Block a user