diff --git a/avisstage/api.py b/avisstage/api.py
index 49b96e4..8a47666 100644
--- a/avisstage/api.py
+++ b/avisstage/api.py
@@ -1,21 +1,27 @@
# coding: utf-8
from tastypie.resources import ModelResource
-from avisstage.models import Lieu
+from avisstage.models import Lieu, Stage, Normalien, StageMatiere
+
+from tastypie.authentication import SessionAuthentication
from django.contrib.gis import geos
+from tastypie import fields, utils
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", "pays", "coord", "type_lieu", "id"]
-
+ authentication = SessionAuthentication()
+
def build_filters(self, filters=None, **kwargs):
if filters is None:
filters = {}
- orm_filters = super(LieuResource, self).build_filters()
+ orm_filters = super(LieuResource, self).build_filters(filters, **kwargs)
if "lng" in filters and "lat" in filters:
lat = float(filters['lat'])
@@ -40,5 +46,43 @@ class LieuResource(ModelResource):
bundle.data['distance'] = self.reference_point.distance(bundle.obj.coord)
bundle.data["pays_nom"] = obj.get_pays_display()
bundle.data["type_lieu_nom"] = obj.get_type_lieu_display()
-
+ bundle.data["num_stages"] = obj.stages.filter(public=True).count()
+
return bundle
+
+class StageResource(ModelResource):
+ class Meta:
+ queryset = Stage.objects.filter(public=True)
+ resource_name = "stage"
+ fields = ["sujet", "date_debut", "date_fin", "matieres", "id"]
+ authentication = SessionAuthentication()
+
+
+ def build_filters(self, filters=None, **kwargs):
+ if filters is None:
+ filters = {}
+
+ orm_filters = super(StageResource, self).build_filters(filters, **kwargs)
+
+ if "lieux" in filters:
+ flieux = map(int, filters['lieux'].split(','))
+ orm_filters['lieux__id__in'] = flieux
+
+ return orm_filters
+
+ def dehydrate(self, bundle):
+ bundle = super(StageResource, self).dehydrate(bundle)
+ obj = bundle.obj
+ 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))
+ return bundle
+
+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"]
+ authentication = SessionAuthentication()
diff --git a/avisstage/forms.py b/avisstage/forms.py
index 3402464..aca828f 100644
--- a/avisstage/forms.py
+++ b/avisstage/forms.py
@@ -82,3 +82,7 @@ class LieuForm(forms.ModelForm):
model = Lieu
fields = ['nom', 'type_lieu', 'ville', 'pays', 'coord']
+class FeedbackForm(forms.Form):
+ objet = forms.CharField(label="Objet", required=True)
+ message = forms.CharField(label="Message", required=True, widget=forms.widgets.Textarea())
+
diff --git a/avisstage/sass/screen.scss b/avisstage/sass/screen.scss
index c34b0c3..cfc1ebb 100644
--- a/avisstage/sass/screen.scss
+++ b/avisstage/sass/screen.scss
@@ -5,8 +5,8 @@
$fond: #8fcc33;
$barre: darken($fond, 10%);
$compl: #f99b20;
-$jaune: #007afc;
-$vert: #09f7b0;
+$jaune: #fff60a;
+$vert: #1a82dd;//09f7b0;
$rouge: #f70978;
$textfont: 'Dosis', sans-serif;
@@ -584,6 +584,9 @@ div.as-results {
.hidden {
display: none;
}
+ .masked {
+ visibility: hidden;
+ }
}
#avis_lieu_vide {
@@ -612,3 +615,15 @@ a.lieu-change {
width:100%;
height: 600px;
}
+
+#feedback-button {
+ position:fixed;
+ left:0;
+ top:30%;
+ color:#fff;
+ z-index:4;
+ background: #000;
+ padding: 14px;
+ transform: rotateZ(90deg);
+ transform-origin: bottom left;
+}
diff --git a/avisstage/static/css/screen.css b/avisstage/static/css/screen.css
index cfa0523..3b14d21 100644
--- a/avisstage/static/css/screen.css
+++ b/avisstage/static/css/screen.css
@@ -217,7 +217,7 @@ header h1 {
/* line 159, ../../sass/screen.scss */
.stagelist li.stage-publie:before {
content: "Publié";
- background: #3af9c0;
+ background: #419be9;
}
/* line 163, ../../sass/screen.scss */
.stagelist li.stage-ajout:before {
@@ -231,7 +231,7 @@ article.stage {
}
/* line 175, ../../sass/screen.scss */
article.stage h2 {
- background: #6ea3db;
+ background: #ddda78;
color: #fff;
padding: 10px 20px;
margin: -20px;
@@ -353,13 +353,13 @@ article.stage section .plusmoins > div > div p {
}
/* line 289, ../../sass/screen.scss */
article.stage section .plusmoins .plus > div {
- background: #07df9f;
+ background: #1775c6;
}
/* line 292, ../../sass/screen.scss */
article.stage section .plusmoins .plus:before {
content: "Les +";
vertical-align: bottom;
- color: #06c78d;
+ color: #1567af;
}
/* line 299, ../../sass/screen.scss */
article.stage section .plusmoins .moins > div {
@@ -381,8 +381,8 @@ article.stage section .plusmoins .moins:before {
}
/* line 318, ../../sass/screen.scss */
.edit-box.public {
- background: #cffdef;
- border: 1px solid #06ad7b;
+ background: #cae3f9;
+ border: 1px solid #125b9b;
}
/* line 323, ../../sass/screen.scss */
.edit-box.prive {
@@ -657,13 +657,17 @@ div.as-results ul li.as-message {
.lieu-ui .hidden {
display: none;
}
+/* line 587, ../../sass/screen.scss */
+.lieu-ui .masked {
+ visibility: hidden;
+}
-/* line 589, ../../sass/screen.scss */
+/* line 592, ../../sass/screen.scss */
#avis_lieu_vide {
display: none;
}
-/* line 593, ../../sass/screen.scss */
+/* line 596, ../../sass/screen.scss */
a.lieu-change {
color: #fff;
background: #f99b20;
@@ -676,14 +680,27 @@ a.lieu-change {
border-radius: 5px;
margin-right: 7px;
}
-/* line 605, ../../sass/screen.scss */
+/* line 608, ../../sass/screen.scss */
a.lieu-change.ajout:before {
content: "+";
margin-right: 5px;
}
-/* line 611, ../../sass/screen.scss */
+/* line 614, ../../sass/screen.scss */
#stages-map {
width: 100%;
height: 600px;
}
+
+/* line 619, ../../sass/screen.scss */
+#feedback-button {
+ position: fixed;
+ left: 0;
+ top: 30%;
+ color: #fff;
+ z-index: 4;
+ background: #000;
+ padding: 14px;
+ transform: rotateZ(90deg);
+ transform-origin: bottom left;
+}
diff --git a/avisstage/static/js/select_lieu.js b/avisstage/static/js/select_lieu.js
index 3ebbb36..45a627c 100644
--- a/avisstage/static/js/select_lieu.js
+++ b/avisstage/static/js/select_lieu.js
@@ -1,5 +1,5 @@
function SelectLieuWidget(STATIC_ROOT, API_LIEU, target, callback) {
- var map, input, autocomplete;
+ var map, input, autocomplete, map_el;
var $el = $(target);
var ui_el = $el.find('.lieu-ui');
var form_el = $el.find('form');
@@ -18,7 +18,7 @@ function SelectLieuWidget(STATIC_ROOT, API_LIEU, target, callback) {
closer.on("click", closeWidget).attr("href", "javascript:void(0);");
$el.find(".window-bg").on("click", closeWidget);
- var map_el = $("
", {class: "map"});
+ map_el = $("
", {class: "map"});
input = $("
",
{type:"text",
placeholder:"Chercher un établissement..."});
@@ -37,12 +37,21 @@ function SelectLieuWidget(STATIC_ROOT, API_LIEU, target, callback) {
autocomplete.addListener('place_changed', handlePlaceSearch);
}
+ function showMessage(message) {
+ content_el.find(".message").text(message);
+ }
+
+ function hideMessage() {
+ showMessage("");
+ }
+
function setLieuOrigine (lieu) {
map.panTo(lieu.coord);
lieuSurCarte(lieu, greenIcon);
}
function handleLieuOrigine(data) {
+ hideMessage();
lieux_db[data.id] = data;
setLieuOrigine(data);
askForSuggestions(data.coord);
@@ -52,16 +61,19 @@ function SelectLieuWidget(STATIC_ROOT, API_LIEU, target, callback) {
$el.addClass("visible").removeClass("ajout");
if(!ui_ready)
initUI();
+ hideMessage();
ui_el.removeClass("hidden");
form_el.detach();
if (lieu_id === undefined) {
$el.find("h3").text("Ajouter un lieu");
+ map_el.addClass("masked");
} else {
lieu_id = lieu_id * 1;
$el.find("h3").text("Modifier le lieu");
if(lieux_db[lieu_id] === undefined) {
$.getJSON(API_LIEU + lieu_id + "/?format=json",
handleLieuOrigine);
+ showMessage("Chargement...");
ui_el.addClass("hidden");
} else {
handleLieuOrigine(lieux_db[lieu_id]);
@@ -150,6 +162,7 @@ function SelectLieuWidget(STATIC_ROOT, API_LIEU, target, callback) {
}
function lieuSurCarte(data, icone) {
+ map_el.removeClass("masked");
// data : des données sur un lieu, sérialisé comme par tastypie
if(data.marqueur !== undefined) {
if(map.hasLayer(data.marqueur))
@@ -219,15 +232,16 @@ function SelectLieuWidget(STATIC_ROOT, API_LIEU, target, callback) {
form_el.serialize(),
onLieuCreated);
form_el.detach();
- content_el.append($("
").text("Envoi en cours..."));
+ showMessage("Envoi en cours...");
return false;
}
function onLieuCreated(data) {
console.log(data);
- if(data.success = false)
+ if(data.success = false) {
+ content_el.find(".message").text("Erreur : "+data.errors);
content_el.append(form_el);
- else {
+ } else {
lieux_db.suggestion.id = data.id;
callback(lieux_db.suggestion);
}
diff --git a/avisstage/templates/avisstage/base.html b/avisstage/templates/avisstage/base.html
index b0bb750..bdbab14 100644
--- a/avisstage/templates/avisstage/base.html
+++ b/avisstage/templates/avisstage/base.html
@@ -1,4 +1,4 @@
-{% load staticfiles %}
+{% load staticfiles avisstage_tags %}
@@ -24,14 +24,14 @@
- {# BLOCK FEEDBACK #}
- {% if request.user.is_authenticated %}
-
-
-
-
Envoyer un avis sur le siteX
-
-
-
-
-
- Feedback
-
+ {% if user.is_authenticated %}
+ {% feedback_widget %}
{% endif %}
- {# ENDBLOCK FEEDBACK #}
-
{% if messages %}
diff --git a/avisstage/templates/avisstage/detail/profil.html b/avisstage/templates/avisstage/detail/profil.html
index c0e7d31..b598c88 100644
--- a/avisstage/templates/avisstage/detail/profil.html
+++ b/avisstage/templates/avisstage/detail/profil.html
@@ -1,6 +1,8 @@
{% extends "avisstage/base.html" %}
{% load staticfiles %}
+{% block title %}Profil de {{ object.nom }} - ExperiENS{% endblock %}
+
{% block content %}
Profil de {{ object.nom }}
{% if object.user == user %}
diff --git a/avisstage/templates/avisstage/detail/stage.html b/avisstage/templates/avisstage/detail/stage.html
index 08a4b06..4ef5f6e 100644
--- a/avisstage/templates/avisstage/detail/stage.html
+++ b/avisstage/templates/avisstage/detail/stage.html
@@ -1,6 +1,8 @@
{% extends "avisstage/base.html" %}
{% load staticfiles %}
+{% block title %}{{ object.sujet }} - ExperiENS{% endblock %}
+
{% block extra_head %}
diff --git a/avisstage/templates/avisstage/formulaires/stage.html b/avisstage/templates/avisstage/formulaires/stage.html
index 246735c..51f033c 100644
--- a/avisstage/templates/avisstage/formulaires/stage.html
+++ b/avisstage/templates/avisstage/formulaires/stage.html
@@ -12,8 +12,11 @@
@@ -34,7 +37,9 @@
var lieux = data.objects;
$.each(lieux, function(i, item) {
var marqueur = L.marker(item.coord, {icon: greenIcon});
- marqueur.bindPopup(""+item.nom+"
");
+ var txt = item.num_stages > 1 ? item.num_stages+" stages ici": "1 stage ici";
+ marqueur.bindPopup(""+item.nom+"
"+
+ ""+txt+"
");
marqueurs.addLayer(marqueur);
});
map.addLayer(marqueurs);
diff --git a/avisstage/templates/avisstage/templatetags/widget_feedback.html b/avisstage/templates/avisstage/templatetags/widget_feedback.html
new file mode 100644
index 0000000..ba1ba5a
--- /dev/null
+++ b/avisstage/templates/avisstage/templatetags/widget_feedback.html
@@ -0,0 +1,60 @@
+{% load staticfiles %}
+
+
+Feedback
diff --git a/avisstage/templates/avisstage/templatetags/widget_lieu.html b/avisstage/templates/avisstage/templatetags/widget_lieu.html
index 2e4ec14..0611734 100644
--- a/avisstage/templates/avisstage/templatetags/widget_lieu.html
+++ b/avisstage/templates/avisstage/templatetags/widget_lieu.html
@@ -5,6 +5,7 @@
Choisir un lieu
+
{% load staticfiles %}
diff --git a/avisstage/templatetags/avisstage_tags.py b/avisstage/templatetags/avisstage_tags.py
index e11f1ab..82c3b10 100644
--- a/avisstage/templatetags/avisstage_tags.py
+++ b/avisstage/templatetags/avisstage_tags.py
@@ -1,6 +1,6 @@
from django import template
-from avisstage.forms import LieuForm
+from avisstage.forms import LieuForm, FeedbackForm
register = template.Library()
@@ -8,3 +8,8 @@ register = template.Library()
def lieu_widget():
form = LieuForm()
return {"form": form}
+
+@register.inclusion_tag('avisstage/templatetags/widget_feedback.html')
+def feedback_widget():
+ form = FeedbackForm()
+ return {"form": form}
diff --git a/avisstage/urls.py b/avisstage/urls.py
index bf4aafa..b479670 100644
--- a/avisstage/urls.py
+++ b/avisstage/urls.py
@@ -4,6 +4,8 @@ from tastypie.api import Api
v1_api = Api(api_name='v1')
v1_api.register(api.LieuResource())
+v1_api.register(api.StageResource())
+v1_api.register(api.AuteurResource())
urlpatterns = [
url(r'^$', views.index, name='index'),
diff --git a/avisstage/views.py b/avisstage/views.py
index 3d65f8d..3a3f97e 100644
--- a/avisstage/views.py
+++ b/avisstage/views.py
@@ -9,9 +9,10 @@ from django.urls import reverse
from django.contrib.auth.decorators import login_required
from braces.views import LoginRequiredMixin
from django.http import JsonResponse, HttpResponseForbidden
+from django.core.mail import send_mail
from avisstage.models import Normalien, Stage, Lieu, AvisLieu, AvisStage
-from avisstage.forms import StageForm, LieuForm, AvisStageForm, AvisLieuForm
+from avisstage.forms import StageForm, LieuForm, AvisStageForm, AvisLieuForm, FeedbackForm
# Page d'accueil
def index(request):
@@ -123,9 +124,34 @@ def publier_stage(request, pk):
stage.public = False
stage.save()
return redirect(reverse("avisstage:stage", kwargs={"pk": pk}))
-
+
+@login_required
def recherche(request):
return render(request, 'avisstage/recherche.html')
+
+# FEEDBACK
+@login_required
def feedback(request):
- return render(request, 'avisstage/feedback.html')
+ if request.method == "POST":
+ form = FeedbackForm(request.POST)
+ if form.is_valid():
+ objet = form.cleaned_data['objet']
+ message = form.cleaned_data['message']
+ send_mail(
+ "[experiENS] "+ objet,
+ message,
+ request.user.username + "@clipper.ens.fr",
+ ['champeno@clipper.ens.fr'],
+ fail_silently=False,
+ )
+ if request.GET.get("format", None) == "json":
+ return JsonResponse({"success": True})
+ return redirect(reverse("avisstage:index"))
+ else:
+ if request.GET.get("format", None) == "json":
+ return JsonResponse({"success": False,
+ "errors": form.errors})
+ else:
+ form = FeedbackForm()
+ return render(request, 'avisstage/formulaire/feedback.html', {"form": form})
diff --git a/experiENS/settings_dev.py b/experiENS/settings_dev.py
index e9abd38..5bea4d0 100644
--- a/experiENS/settings_dev.py
+++ b/experiENS/settings_dev.py
@@ -22,3 +22,5 @@ MIDDLEWARE_CLASSES += (
SPATIALITE_LIBRARY_PATH = 'mod_spatialite'
STATIC_ROOT = "/home/evarin/Bureau/experiENS/static/"
+
+EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'