experiENS/avisstage/api.py
2021-02-07 00:41:22 +01:00

132 lines
4.3 KiB
Python

# coding: utf-8
from tastypie.resources import ModelResource
from tastypie.authentication import SessionAuthentication
from tastypie import fields, utils
from django.contrib.gis import geos
from django.urls import reverse
from .models import Lieu, Stage, Normalien, StageMatiere
from .utils import approximate_distance
class EnScolariteAuthentication(SessionAuthentication):
def is_authenticated(self, request, **kwargs):
if super().is_authenticated(request, **kwargs):
return request.user.profil.en_scolarite
return False
# API principale pour les lieux
class LieuResource(ModelResource):
# stages = fields.ToManyField("avisstage.api.StageResource",
# "stages", use_in="detail", full=True)
class Meta:
queryset = Lieu.objects.all()
resource_name = "lieu"
fields = ["nom", "ville", "pays", "coord", "type_lieu", "id"]
# login_required
authentication = SessionAuthentication()
# Filtres personnalisés
def build_filters(self, filters=None, **kwargs):
if filters is None:
filters = {}
orm_filters = super(LieuResource, self).build_filters(filters, **kwargs)
# Trouver les lieux à proximités d'un point donné
if "lng" in filters and "lat" in filters:
lat = float(filters["lat"])
lng = float(filters["lng"])
pt = geos.Point((lng, lat), srid=4326)
self.reference_point = pt
orm_filters["coord__distance_lte"] = (pt, 10000)
# Filtrer les lieux qui ont déjà des stages
if "has_stage" in filters:
orm_filters["stages__public"] = True
return orm_filters
# Custom apply filters pour ajouter le "distinct"
def apply_filters(self, request, applicable_filters):
return self.get_object_list(request).filter(**applicable_filters).distinct()
# Ajout d'informations
def dehydrate(self, bundle):
bundle = super(LieuResource, self).dehydrate(bundle)
obj = bundle.obj
bundle.data["coord"] = {"lat": float(obj.coord.y), "lng": float(obj.coord.x)}
# Distance au point recherché
if "lat" in bundle.request.GET and "lng" in bundle.request.GET:
bundle.data["distance"] = approximate_distance(
self.reference_point, bundle.obj.coord
)
# Autres infos utiles
bundle.data["pays_nom"] = obj.get_pays_display()
bundle.data["type_lieu_nom"] = obj.type_lieu_fancy
# TODO use annotate?
bundle.data["num_stages"] = obj.stages.filter(public=True).count()
return bundle
# API sur un stage
class StageResource(ModelResource):
class Meta:
queryset = Stage.objects.filter(public=True)
resource_name = "stage"
fields = ["sujet", "date_debut", "date_fin", "matieres", "id"]
# login_required
authentication = EnScolariteAuthentication()
# Filtres personnalisés
def build_filters(self, filters=None, **kwargs):
if filters is None:
filters = {}
orm_filters = super(StageResource, self).build_filters(filters, **kwargs)
# Récupération des stages à un lieu donné
if "lieux" in filters:
flieux = map(int, filters["lieux"].split(","))
orm_filters["lieux__id__in"] = flieux
return orm_filters
# Informations à ajouter
def dehydrate(self, bundle):
bundle = super(StageResource, self).dehydrate(bundle)
obj = bundle.obj
# Affichage des manytomany en condensé
bundle.data["auteur"] = obj.auteur.nom
bundle.data["thematiques"] = list(
obj.thematiques.all().values_list("name", flat=True)
)
bundle.data["matieres"] = list(obj.matieres.all().values_list("nom", flat=True))
# Adresse de la fiche de stage
bundle.data["url"] = reverse("avisstage:stage", kwargs={"pk": obj.id})
return bundle
# Auteurs des fiches (TODO supprimer ?)
class AuteurResource(ModelResource):
stages = fields.ToManyField(
"avisstage.api.StageResource", "stages", use_in="detail"
)
class Meta:
queryset = Normalien.objects.all()
resource_name = "profil"
fields = ["id", "nom", "stages"]
# login_required
authentication = EnScolariteAuthentication()