mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-04-05 20:51:26 +00:00
183 lines
6.9 KiB
Python
183 lines
6.9 KiB
Python
import os
|
|
import mimetypes
|
|
|
|
from django.conf import settings
|
|
from django.http import FileResponse
|
|
from django.http.response import JsonResponse
|
|
from django.views.decorators.csrf import ensure_csrf_cookie, csrf_protect
|
|
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 (
|
|
Domain,
|
|
Category
|
|
)
|
|
from .serializers import (
|
|
DomainSerializer,
|
|
CategorySerializer
|
|
)
|
|
|
|
@method_decorator(csrf_protect, name='dispatch')
|
|
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
|
class DomainListCreateView(APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
def get(self, request):
|
|
domains = Domain.objects.all()
|
|
serializer = DomainSerializer(domains, many=True)
|
|
return JsonResponse(serializer.data, safe=False)
|
|
|
|
def post(self, request):
|
|
data = JSONParser().parse(request)
|
|
serializer = DomainSerializer(data=data)
|
|
if serializer.is_valid():
|
|
serializer.save()
|
|
return JsonResponse(serializer.data, safe=False, status=status.HTTP_201_CREATED)
|
|
return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
@method_decorator(csrf_protect, name='dispatch')
|
|
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
|
class DomainDetailView(APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
def get(self, request, id):
|
|
try:
|
|
domain = Domain.objects.get(id=id)
|
|
serializer = DomainSerializer(domain)
|
|
return JsonResponse(serializer.data, safe=False)
|
|
except Domain.DoesNotExist:
|
|
return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
def put(self, request, id):
|
|
try:
|
|
domain = Domain.objects.get(id=id)
|
|
except Domain.DoesNotExist:
|
|
return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
|
|
data = JSONParser().parse(request)
|
|
serializer = DomainSerializer(domain, data=data, partial=True)
|
|
if serializer.is_valid():
|
|
serializer.save()
|
|
return JsonResponse(serializer.data, safe=False)
|
|
return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
def delete(self, request, id):
|
|
try:
|
|
domain = Domain.objects.get(id=id)
|
|
domain.delete()
|
|
return JsonResponse({'message': 'Deleted'}, safe=False)
|
|
except Domain.DoesNotExist:
|
|
return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
# Répète la même logique pour Category, Competency, EstablishmentCompetency
|
|
|
|
@method_decorator(csrf_protect, name='dispatch')
|
|
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
|
class CategoryListCreateView(APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
def get(self, request):
|
|
categories = Category.objects.all()
|
|
serializer = CategorySerializer(categories, many=True)
|
|
return JsonResponse(serializer.data, safe=False)
|
|
|
|
def post(self, request):
|
|
data = JSONParser().parse(request)
|
|
serializer = CategorySerializer(data=data)
|
|
if serializer.is_valid():
|
|
serializer.save()
|
|
return JsonResponse(serializer.data, safe=False, status=status.HTTP_201_CREATED)
|
|
return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
@method_decorator(csrf_protect, name='dispatch')
|
|
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
|
class CategoryDetailView(APIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
def get(self, request, id):
|
|
try:
|
|
category = Category.objects.get(id=id)
|
|
serializer = CategorySerializer(category)
|
|
return JsonResponse(serializer.data, safe=False)
|
|
except Category.DoesNotExist:
|
|
return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
def put(self, request, id):
|
|
try:
|
|
category = Category.objects.get(id=id)
|
|
except Category.DoesNotExist:
|
|
return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
|
|
data = JSONParser().parse(request)
|
|
serializer = CategorySerializer(category, data=data, partial=True)
|
|
if serializer.is_valid():
|
|
serializer.save()
|
|
return JsonResponse(serializer.data, safe=False)
|
|
return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
def delete(self, request, id):
|
|
try:
|
|
category = Category.objects.get(id=id)
|
|
category.delete()
|
|
return JsonResponse({'message': 'Deleted'}, safe=False)
|
|
except Category.DoesNotExist:
|
|
return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
|
|
class ServeFileView(APIView):
|
|
"""Sert les fichiers media de manière sécurisée avec authentification JWT."""
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
def get(self, request):
|
|
file_path = request.query_params.get('path', '')
|
|
|
|
if not file_path:
|
|
return JsonResponse(
|
|
{'error': 'Le paramètre "path" est requis'},
|
|
status=status.HTTP_400_BAD_REQUEST,
|
|
)
|
|
|
|
# Nettoyer les prefixes media usuels si presents
|
|
if file_path.startswith('/media/'):
|
|
file_path = file_path[len('/media/'):]
|
|
elif file_path.startswith('media/'):
|
|
file_path = file_path[len('media/'):]
|
|
|
|
# Nettoyer le préfixe /data/ si présent
|
|
if file_path.startswith('/data/'):
|
|
file_path = file_path[len('/data/'):]
|
|
elif file_path.startswith('data/'):
|
|
file_path = file_path[len('data/'):]
|
|
|
|
# Construire le chemin absolu et le résoudre pour éliminer les traversals
|
|
absolute_path = os.path.realpath(
|
|
os.path.join(settings.MEDIA_ROOT, file_path)
|
|
)
|
|
|
|
# Protection contre le path traversal
|
|
media_root = os.path.realpath(settings.MEDIA_ROOT)
|
|
if not absolute_path.startswith(media_root + os.sep) and absolute_path != media_root:
|
|
return JsonResponse(
|
|
{'error': 'Accès non autorisé'},
|
|
status=status.HTTP_403_FORBIDDEN,
|
|
)
|
|
|
|
if not os.path.isfile(absolute_path):
|
|
return JsonResponse(
|
|
{'error': 'Fichier introuvable'},
|
|
status=status.HTTP_404_NOT_FOUND,
|
|
)
|
|
|
|
content_type, _ = mimetypes.guess_type(absolute_path)
|
|
if content_type is None:
|
|
content_type = 'application/octet-stream'
|
|
|
|
response = FileResponse(
|
|
open(absolute_path, 'rb'),
|
|
content_type=content_type,
|
|
)
|
|
response['Content-Disposition'] = (
|
|
f'inline; filename="{os.path.basename(absolute_path)}"'
|
|
)
|
|
return response
|