experiENS/monstage/views.py
2015-09-23 00:03:57 +02:00

339 lines
No EOL
14 KiB
Python

# coding: utf-8
from django.shortcuts import get_object_or_404, render
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseRedirect, HttpResponse, HttpResponseForbidden, HttpResponseNotFound
from django.core.urlresolvers import reverse
from django import forms
from django.conf import settings
from django.contrib.gis.geos import GEOSGeometry
from django.contrib.gis import measure
from django.forms.widgets import HiddenInput
from django.core.mail import send_mail
from monstage.models import *
def addslashes(s):
d = {'"':'\\"', "\0":"\\\0", "\\":"\\\\", '\n':'\\n'}
return ''.join(d.get(c, c) for c in s)
def index(request):
stats = { 'num_stages': Stage.objects.filter(published=True).count() }
return render(request, 'monstage/index.html', {'stats': stats})
def forbidden(request, type):
context = {}
context[type] = True
return render(request, 'monstage/forbidden.html', context)
@login_required
def home(request):
stages = request.user.profil.stages.all()
return render(request, 'monstage/home.html', {"stages" : stages})
#
# Utilisateurs et profils
#
def profil(request, profil_id):
user = get_object_or_404( User, username = profil_id )
profil = user.profil
stages = Stage.objects.filter( profil_user = profil )
return render(request, 'monstage/profil.html', {'profil': profil, 'stages': stages})
@login_required
def profil_edit(request):
if request.POST:
user = request.user
user.first_name = request.POST['first_name']
user.last_name = request.POST['last_name']
user.save()
return HttpResponseRedirect(reverse('monstage:home'))
else:
(profil, _) = Normalien.objects.get_or_create( user = request.user )
return render(request, 'monstage/profil_edit.html', {'normalien': profil})
#
# Stages
#
@login_required
def stage(request, stage_id):
stage = get_object_or_404( Stage, pk = stage_id)
lieux_latlng = []
if not stage.published and not stage.profil_user == request.user.profil:
return forbidden(request, 'unpublished')
for lieu in stage.lieux.all():
# GEOS Format : (longitude, latitude)
lieux_latlng.append("%f, %f" % (lieu.coord.y, lieu.coord.x))
context = {
'stage': stage,
'modifiable': (stage.profil_user == request.user.profil),
'lieux_latlng': lieux_latlng,
'published':stage.published,
}
return render(request, 'monstage/stage.html', context)
class StageForm(forms.ModelForm):
class Meta:
model = Stage
fields = ("type_stage", "start_date", "end_date", "matieres", "sujet", "thematiques", "encadrants")
def __init__(self, *args, **kwargs):
super(StageForm, self).__init__(*args, **kwargs)
self.fields['matieres'].label = "Matières"
self.fields['thematiques'].help_text = "Une liste de tags séparés par des virgules (ou des espaces)"
self.fields['start_date'].widget.attrs['placeholder'] = "JJ/MM/AAAA"
self.fields['end_date'].widget.attrs['placeholder'] = "JJ/MM/AAAA"
@login_required
def stage_add(request):
if request.POST:
form = StageForm(request.POST)
if form.is_valid:
new_stage = form.save(commit = False)
new_stage.profil_user = request.user.profil
new_stage.save()
form.save_m2m()
return HttpResponseRedirect(reverse('monstage:stage_edit_lieu', args=(new_stage.id,)))
else:
form = StageForm()
return render(request, 'monstage/stage_add.html', { 'form': form })
@login_required
def stage_edit_desc(request, stage_id):
stage = get_object_or_404( Stage, pk = stage_id)
if stage.profil_user != request.user.profil:
return forbidden(request, 'notowned')
bullshit = ""
if request.POST:
form = StageForm(request.POST, instance = stage)
if form.is_valid():
form.save()
return HttpResponseRedirect(reverse('monstage:stage', args=(stage.id,)))
else:
form = StageForm(instance = stage)
return render(request, 'monstage/stage_edit_desc.html', { 'stage': stage, 'form':form })
class LieuStageForm(forms.Form):
lieu_id = forms.IntegerField(widget = HiddenInput())
delete = forms.BooleanField(help_text=(u'Supprimer ce lieu'), required = False, label = '')
def is_to_delete(self):
return self.cleaned_data['delete']
class LieuForm(forms.ModelForm):
latitude = forms.DecimalField()
longitude = forms.DecimalField()
delete = forms.BooleanField(help_text=(u'Supprimer ce lieu'), required = False, label = '')
def __init__(self, *args, **kwargs):
super(LieuForm, self).__init__(*args, **kwargs)
self.fields['latitude'].widget = HiddenInput()
self.fields['longitude'].widget = HiddenInput()
lieu = kwargs.pop('instance', None)
if lieu:
# GEOS Format : (longitude, latitude)
self.fields['longitude'].initial = lieu.coord.x
self.fields['latitude'].initial = lieu.coord.y
class Meta:
model = Lieu
fields = ("name", "type_lieu", "ville", "pays")
def is_to_delete(self):
return self.cleaned_data['delete']
def save(self, *args, **kwargs):
lieu = super(LieuForm, self).save(commit=False, *args, **kwargs)
# GEOS Format : (longitude, latitude)
lieu.coord = GEOSGeometry('POINT(%f %f)' % (self.cleaned_data['longitude'], self.cleaned_data['latitude']), srid=4326)
return lieu
def lieux_candidats(request):
if request.GET:
lat = float(request.GET.get('lat', False))
lon = float(request.GET.get('lon', False))
if lat and lon:
# GEOS Format : (longitude, latitude)
coords = GEOSGeometry('POINT(%f %f)' % (lon, lat), srid=4326)
distance = {'km': 0.5}
lieux = Lieu.objects.filter(coord__distance_lte=(coords, measure.D(**distance)))
lieux = lieux.distance(coords).order_by('distance')
retour = [ {'name': addslashes(lieu.name), 'id': lieu.id, 'lat':str(lieu.coord.coords[0]), 'lon':str(lieu.coord.coords[1]), 'distance':lieu.distance } for lieu in lieux.distance(coords) ]
return render(request, 'monstage/lieux_proches.json', { 'lieux':retour }, content_type='text/plain; charset=utf-8')
return HttpResponseNotFound()
def stage_edit_lieu(request, stage_id):
stage = get_object_or_404( Stage, pk = stage_id)
bullshit = ''
if stage.profil_user != request.user.profil:
return forbidden(request, 'notowned')
if request.POST:
valid = True
prevLieuxStage = [k for k in stage.lieustage_set.all()]
lieuforms = []
deleted = []
for i in range(0, int(request.POST['numplaces'])): # Pour chaque lieu
toSave = False
if request.POST.get('%d-name' % i, False): # Lieu à créer
bullshit += str(i) + 'a '
lieuform = LieuForm(request.POST, prefix = str(i))
if not lieuform.is_valid():
valid = False
lieuforms.append(lieuform)
continue
if lieuform.is_to_delete(): # On ne fait rien : le lieu est nouveau donc n'était pas encore en mémoire
pass
else: # On crée un nouveau lieu
lieu = lieuform.save()
lieu.save()
lieuform.save_m2m()
toSave = True
lieuforms.append(LieuStageForm(initial = {'lieu_id': lieu.id}, prefix = str(i)))
elif request.POST.get('%d-lieu_id' % i, False): # Lien vers un lieu déjà existant
bullshit += str(i) + 'b '
lieuform = LieuStageForm(request.POST, prefix = str(i))
if not lieuform.is_valid():
bullshit += 'invalid '
valid = False
lieuforms.append(lieuform)
continue
if lieuform.is_to_delete(): # On transvase de prevLieuxStage vers deleted pour conserver l'assignation des commentaires
if len(prevLieuxStage) > 0:
deleted.append(prevLieuxStage.pop(0))
else: # On récupère le lieu concerné
lieuforms.append(lieuform)
lieu = Lieu.objects.get( pk = lieuform.cleaned_data['lieu_id'] )
toSave = True
if toSave: # Mise à jour des lieuStage
if len(prevLieuxStage) > 0: # On met à jour un lieuStage conservé (même lieu)
lieustage = prevLieuxStage.pop(0)
lieustage.lieu = lieu
lieustage.save()
elif len(deleted) > 0: # On réutilise l'emplacement d'un lieuStage qui a été supprimé (pour éviter de perdre les commentaires)
lieustage = deleted.pop(0)
lieustage.lieu = lieu
lieustage.save()
else: # On en crée un nouveau
LieuStage.objects.create(lieu = lieu, stage = stage)
if valid:
for lieustage in deleted: # On supprime effectivement les lieuStages non réutilisé
lieustage.delete()
return HttpResponseRedirect(reverse('monstage:stage_edit_feedback', args=(stage.id,)))
else:
lieuforms = [(lieu, LieuStageForm(initial={'lieu_id': lieu.id}, prefix=str(counter))) for counter, lieu in enumerate(stage.lieux.all())]
emptyform = LieuForm(prefix='{{ID}}')
emptylieu = LieuStageForm(prefix='{{ID}}')
return render(request, 'monstage/stage_edit_lieu.html', { 'stage': stage, 'debug': bullshit, 'lieuforms': lieuforms, 'emptyform': addslashes(emptyform.as_p()), 'emptylieu': addslashes(emptylieu.as_p()), 'numforms':len(lieuforms) })
class StageFeedbackForm(forms.ModelForm):
class Meta:
model = Stage
fields = ("avis_encadrants", "avis_equipe", "avis_stage", "avis_admin")
class LieuStageFeedbackForm(forms.ModelForm):
class Meta:
model = LieuStage
fields = ("avis_global", "avis_lieudevie", "avis_lieustage", "avis_pratique", "avis_visite", "avis_anecdotes")
def stage_edit_feedback(request, stage_id):
stage = get_object_or_404( Stage, pk = stage_id)
if stage.profil_user != request.user.profil:
return forbidden(request, 'notowned')
if request.POST:
form_gen = StageFeedbackForm(request.POST, instance = stage, prefix = 'gen')
forms_lieux = [(LieuStageFeedbackForm(request.POST, instance = lieustage, prefix = lieustage.id), lieustage.lieu) for lieustage in stage.lieustage_set.all()]
valid = form_gen.is_valid()
for (form, _) in forms_lieux:
if not form.is_valid():
valid = False
if valid:
form_gen.save()
for (form, _) in forms_lieux:
form.save()
return HttpResponseRedirect(reverse('monstage:stage', args=(stage.id,)))
else:
form_gen = StageFeedbackForm(instance = stage, prefix = 'gen')
forms_lieux = [(LieuStageFeedbackForm(instance = lieustage, prefix = lieustage.id), lieustage.lieu) for lieustage in stage.lieustage_set.all()]
return render(request, 'monstage/stage_edit_feedback.html', { 'stage': stage, 'form_gen':form_gen, 'forms_lieux':forms_lieux })
def stage_publish(request, stage_id):
stage = get_object_or_404( Stage, pk = stage_id)
if request.POST:
publishit = request.POST.get('publishit', False)
if publishit == "yes":
stage.published = True
stage.save()
elif publishit == "no":
stage.published = False
stage.save()
return HttpResponseRedirect(reverse('monstage:stage', args=(stage_id,)))
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
return render(request, 'monstage/detail.html', {'question': question})
#
# Recherche de stages
#
from django.db.models import Q
class SearchForm(forms.Form):
matiere = forms.ModelChoiceField(label='Matière :', required=False, queryset = StageMatiere.objects.all(), empty_label="Toute matière")
thematiques = forms.CharField(label='Thématiques :', required=False)
latitude = forms.DecimalField(widget=HiddenInput(), required=False)
longitude = forms.DecimalField(widget=HiddenInput(), required=False)
lieu = forms.CharField(label=u'A proximité de :', required=False)
tolerance = forms.DecimalField(label='Dans un rayon de (en km) :', initial=100, required=False)
@login_required
def search(request):
stages = None
if request.GET:
form = SearchForm(request.GET)
if form.is_valid():
lon = form.cleaned_data['longitude']
lat = form.cleaned_data['latitude']
lieu = form.cleaned_data['lieu']
stages = Stage.objects.filter(published=True)
if lat and lon and lieu:
coords = GEOSGeometry('POINT(%f %f)' % (lon, lat), srid=4326)
distance = {'km': form.cleaned_data['tolerance']}
lieux = Lieu.objects.filter(coord__distance_lte=(coords, measure.D(**distance)))
lieux = lieux.distance(coords).order_by('distance')
stages = stages.filter(lieux__in=lieux)
matiere = form.cleaned_data['matiere']
if matiere:
stages = stages.filter(matieres=matiere)
thematiques = form.cleaned_data['thematiques'].split(',')
if thematiques:
q = Q()
for thematique in thematiques:
q |= Q(thematiques__slug__icontains = thematique)
stages = stages.filter(q).distinct()
stages = stages.all()
else:
form = SearchForm()
return render(request, 'monstage/search.html', {'form':form, 'resultats':stages})
#
# Feedback
#
class FeedbackForm(forms.Form):
message = forms.CharField(label='Commentaire')
@login_required
def send_feedback(request):
redirection = request.GET.get('next', reverse('monstage:index')) if request.GET else reverse('monstage:index')
if request.POST:
form = FeedbackForm(request.POST, prefix="feedback")
if form.is_valid():
dests = [ mail for (nom, mail) in settings.ADMINS ]
send_mail('Commentaire à propos d\'experiENS', form.cleaned_data["message"], ("%s@clipper.ens.fr" % (request.user.username,)), dests)
return HttpResponseRedirect(redirection+"?feedback_sent=1")
return HttpResponseRedirect(redirection+"?feedback_error=1")
return HttpResponseRedirect(redirection)