Suppression des vieilleries

This commit is contained in:
Evarin 2017-04-25 22:02:59 +02:00
parent b77a45a56a
commit d1243280d8
38 changed files with 0 additions and 2204 deletions

View file

@ -1,110 +0,0 @@
"""
Django settings for experiENS project.
For more information on this file, see
https://docs.djangoproject.com/en/1.7/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.7/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '9+h+8jp2jphi4@m==cggy75^ghm_l**%4@y957k_*u)t4o%)*u'
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
TEMPLATE_DEBUG = True
ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = (
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.gis',
'monstage',
'taggit',
)
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
)
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend',
'django_cas.backends.CASBackend',
)
ROOT_URLCONF = 'experiENS.urls'
WSGI_APPLICATION = 'experiENS.wsgi.application'
CAS_SERVER_URL = "https://cas.eleves.ens.fr/" #SPI CAS
CAS_VERIFY_URL = "https://cas.eleves.ens.fr/"
CAS_IGNORE_REFERER = True
CAS_REDIRECT_URL = '/home/'
CAS_EMAIL_FORMAT = "%s@clipper.ens.fr"
LOGIN_URL = '/login/'
LOGOUT_URL = '/logout/'
from django.conf.global_settings import TEMPLATE_CONTEXT_PROCESSORS as TCP
TEMPLATE_CONTEXT_PROCESSORS = TCP + (
'django.core.context_processors.request',
)
# Database
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.contrib.gis.db.backends.postgis',
# 'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'experiens',
'USER': 'experiens',
'PASSWORD': 'experiens',
'HOST': 'localhost',
}
}
# Internationalization
# https://docs.djangoproject.com/en/1.7/topics/i18n/
LANGUAGE_CODE = 'fr-fr'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.7/howto/static-files/
STATIC_URL = '/static/'

View file

@ -1,9 +0,0 @@
from django.conf.urls import patterns, include, url
from django.contrib import admin
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'^login/$', 'django_cas.views.login', name = "login"),
url(r'^logout/$', 'django_cas.views.logout', name = "logout"),
url(r'^', include('monstage.urls', namespace="monstage")),
)

View file

@ -1,14 +0,0 @@
"""
WSGI config for experiENS project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
"""
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "experiENS.settings")
from django.core.wsgi import get_wsgi_application
application = get_wsgi_application()

View file

@ -1,10 +0,0 @@
#!/usr/bin/env python
import os
import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "experiENS.settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)

View file

@ -1,26 +0,0 @@
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from monstage.models import *
class NormalienInline(admin.StackedInline):
model = Normalien
inline_classes = ("collapse open",)
class UserAdmin(UserAdmin):
inlines = (NormalienInline, )
class LieuStageInline(admin.StackedInline):
model = LieuStage
inline_classes = ("collapse open",)
extra = 0
class StageAdmin(admin.ModelAdmin):
inlines = (LieuStageInline, )
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
admin.site.register(Lieu)
admin.site.register(StageMatiere)
admin.site.register(Stage, StageAdmin)

View file

@ -1,245 +0,0 @@
# coding: utf-8
PAYS_CHOICES = (
("AF", u"Afghanistan"),
("AL", u"Albanie"),
("AQ", u"Antarctique"),
("DZ", u"Algérie"),
("AS", u"Samoa Américaines"),
("AD", u"Andorre"),
("AO", u"Angola"),
("AG", u"Antigua-et-Barbuda"),
("AZ", u"Azerbaïdjan"),
("AR", u"Argentine"),
("AU", u"Australie"),
("AT", u"Autriche"),
("BS", u"Bahamas"),
("BH", u"Bahreïn"),
("BD", u"Bangladesh"),
("AM", u"Arménie"),
("BB", u"Barbade"),
("BE", u"Belgique"),
("BM", u"Bermudes"),
("BT", u"Bhoutan"),
("BO", u"Bolivie"),
("BA", u"Bosnie-Herzégovine"),
("BW", u"Botswana"),
("BV", u"Île Bouvet"),
("BR", u"Brésil"),
("BZ", u"Belize"),
("IO", u"Territoire Britannique de l'Océan Indien"),
("SB", u"Îles Salomon"),
("VG", u"Îles Vierges Britanniques"),
("BN", u"Brunéi Darussalam"),
("BG", u"Bulgarie"),
("MM", u"Myanmar"),
("BI", u"Burundi"),
("BY", u"Bélarus"),
("KH", u"Cambodge"),
("CM", u"Cameroun"),
("CA", u"Canada"),
("CV", u"Cap-vert"),
("KY", u"Îles Caïmanes"),
("CF", u"République Centrafricaine"),
("LK", u"Sri Lanka"),
("TD", u"Tchad"),
("CL", u"Chili"),
("CN", u"Chine"),
("TW", u"Taïwan"),
("CX", u"Île Christmas"),
("CC", u"Îles Cocos (Keeling)"),
("CO", u"Colombie"),
("KM", u"Comores"),
("YT", u"Mayotte"),
("CG", u"République du Congo"),
("CD", u"République Démocratique du Congo"),
("CK", u"Îles Cook"),
("CR", u"Costa Rica"),
("HR", u"Croatie"),
("CU", u"Cuba"),
("CY", u"Chypre"),
("CZ", u"République Tchèque"),
("BJ", u"Bénin"),
("DK", u"Danemark"),
("DM", u"Dominique"),
("DO", u"République Dominicaine"),
("EC", u"Équateur"),
("SV", u"El Salvador"),
("GQ", u"Guinée Équatoriale"),
("ET", u"Éthiopie"),
("ER", u"Érythrée"),
("EE", u"Estonie"),
("FO", u"Îles Féroé"),
("FK", u"Îles (malvinas) Falkland"),
("GS", u"Géorgie du Sud et les Îles Sandwich du Sud"),
("FJ", u"Fidji"),
("FI", u"Finlande"),
("AX", u"Îles Åland"),
("FR", u"France"),
("GF", u"Guyane Française"),
("PF", u"Polynésie Française"),
("TF", u"Terres Australes Françaises"),
("DJ", u"Djibouti"),
("GA", u"Gabon"),
("GE", u"Géorgie"),
("GM", u"Gambie"),
("PS", u"Territoire Palestinien Occupé"),
("DE", u"Allemagne"),
("GH", u"Ghana"),
("GI", u"Gibraltar"),
("KI", u"Kiribati"),
("GR", u"Grèce"),
("GL", u"Groenland"),
("GD", u"Grenade"),
("GP", u"Guadeloupe"),
("GU", u"Guam"),
("GT", u"Guatemala"),
("GN", u"Guinée"),
("GY", u"Guyana"),
("HT", u"Haïti"),
("HM", u"Îles Heard et Mcdonald"),
("VA", u"Saint-Siège (état de la Cité du Vatican)"),
("HN", u"Honduras"),
("HK", u"Hong-Kong"),
("HU", u"Hongrie"),
("IS", u"Islande"),
("IN", u"Inde"),
("ID", u"Indonésie"),
("IR", u"République Islamique d'Iran"),
("IQ", u"Iraq"),
("IE", u"Irlande"),
("IL", u"Israël"),
("IT", u"Italie"),
("CI", u"Côte d'Ivoire"),
("JM", u"Jamaïque"),
("JP", u"Japon"),
("KZ", u"Kazakhstan"),
("JO", u"Jordanie"),
("KE", u"Kenya"),
("KP", u"République Populaire Démocratique de Corée"),
("KR", u"République de Corée"),
("KW", u"Koweït"),
("KG", u"Kirghizistan"),
("LA", u"République Démocratique Populaire Lao"),
("LB", u"Liban"),
("LS", u"Lesotho"),
("LV", u"Lettonie"),
("LR", u"Libéria"),
("LY", u"Jamahiriya Arabe Libyenne"),
("LI", u"Liechtenstein"),
("LT", u"Lituanie"),
("LU", u"Luxembourg"),
("MO", u"Macao"),
("MG", u"Madagascar"),
("MW", u"Malawi"),
("MY", u"Malaisie"),
("MV", u"Maldives"),
("ML", u"Mali"),
("MT", u"Malte"),
("MQ", u"Martinique"),
("MR", u"Mauritanie"),
("MU", u"Maurice"),
("MX", u"Mexique"),
("MC", u"Monaco"),
("MN", u"Mongolie"),
("MD", u"République de Moldova"),
("MS", u"Montserrat"),
("MA", u"Maroc"),
("MZ", u"Mozambique"),
("OM", u"Oman"),
("NA", u"Namibie"),
("NR", u"Nauru"),
("NP", u"Népal"),
("NL", u"Pays-Bas"),
("AN", u"Antilles Néerlandaises"),
("AW", u"Aruba"),
("NC", u"Nouvelle-Calédonie"),
("VU", u"Vanuatu"),
("NZ", u"Nouvelle-Zélande"),
("NI", u"Nicaragua"),
("NE", u"Niger"),
("NG", u"Nigéria"),
("NU", u"Niué"),
("NF", u"Île Norfolk"),
("NO", u"Norvège"),
("MP", u"Îles Mariannes du Nord"),
("UM", u"Îles Mineures Éloignées des États-Unis"),
("FM", u"États Fédérés de Micronésie"),
("MH", u"Îles Marshall"),
("PW", u"Palaos"),
("PK", u"Pakistan"),
("PA", u"Panama"),
("PG", u"Papouasie-Nouvelle-Guinée"),
("PY", u"Paraguay"),
("PE", u"Pérou"),
("PH", u"Philippines"),
("PN", u"Pitcairn"),
("PL", u"Pologne"),
("PT", u"Portugal"),
("GW", u"Guinée-Bissau"),
("TL", u"Timor-Leste"),
("PR", u"Porto Rico"),
("QA", u"Qatar"),
("RE", u"Réunion"),
("RO", u"Roumanie"),
("RU", u"Fédération de Russie"),
("RW", u"Rwanda"),
("SH", u"Sainte-Hélène"),
("KN", u"Saint-Kitts-et-Nevis"),
("AI", u"Anguilla"),
("LC", u"Sainte-Lucie"),
("PM", u"Saint-Pierre-et-Miquelon"),
("VC", u"Saint-Vincent-et-les Grenadines"),
("SM", u"Saint-Marin"),
("ST", u"Sao Tomé-et-Principe"),
("SA", u"Arabie Saoudite"),
("SN", u"Sénégal"),
("SC", u"Seychelles"),
("SL", u"Sierra Leone"),
("SG", u"Singapour"),
("SK", u"Slovaquie"),
("VN", u"Viet Nam"),
("SI", u"Slovénie"),
("SO", u"Somalie"),
("ZA", u"Afrique du Sud"),
("ZW", u"Zimbabwe"),
("ES", u"Espagne"),
("EH", u"Sahara Occidental"),
("SD", u"Soudan"),
("SR", u"Suriname"),
("SJ", u"Svalbard etÎle Jan Mayen"),
("SZ", u"Swaziland"),
("SE", u"Suède"),
("CH", u"Suisse"),
("SY", u"République Arabe Syrienne"),
("TJ", u"Tadjikistan"),
("TH", u"Thaïlande"),
("TG", u"Togo"),
("TK", u"Tokelau"),
("TO", u"Tonga"),
("TT", u"Trinité-et-Tobago"),
("AE", u"Émirats Arabes Unis"),
("TN", u"Tunisie"),
("TR", u"Turquie"),
("TM", u"Turkménistan"),
("TC", u"Îles Turks et Caïques"),
("TV", u"Tuvalu"),
("UG", u"Ouganda"),
("UA", u"Ukraine"),
("MK", u"L'ex-République Yougoslave de Macédoine"),
("EG", u"Égypte"),
("GB", u"Royaume-Uni"),
("IM", u"Île de Man"),
("TZ", u"République-Unie de Tanzanie"),
("US", u"États-Unis"),
("VI", u"Îles Vierges des États-Unis"),
("BF", u"Burkina Faso"),
("UY", u"Uruguay"),
("UZ", u"Ouzbékistan"),
("VE", u"Venezuela"),
("WF", u"Wallis et Futuna"),
("WS", u"Samoa"),
("YE", u"Yémen"),
("CS", u"Serbie-et-Monténégro"),
("ZM", u"Zambie"),
)

View file

@ -1,98 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
from django.conf import settings
import django.contrib.gis.db.models.fields
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Lieu',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=250, verbose_name="Nom de l'institution d'accueil")),
('ville', models.CharField(max_length=200, verbose_name='Ville, Pays')),
('coord', django.contrib.gis.db.models.fields.PointField(srid=4326, verbose_name='Coordonn\xe9es', geography=True)),
('type_lieu', models.CharField(default=b'universite', max_length=15, verbose_name="Type de structure d'accueil", choices=[(b'universite', 'Universit\xe9'), (b'entreprise', 'Entreprise'), (b'centrerecherche', 'Centre de recherche'), (b'administration', 'Administration'), (b'autre', 'Autre')])),
],
options={
},
bases=(models.Model,),
),
migrations.CreateModel(
name='LieuStage',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('avis_global', models.TextField(verbose_name='Ressenti global', blank=True)),
('avis_lieudevie', models.TextField(verbose_name='Mon lieu de vie', blank=True)),
('avis_lieustage', models.TextField(verbose_name='Le lieu du stage', blank=True)),
('avis_pratique', models.TextField(verbose_name="S'installer / Conseils pratiques", blank=True)),
('avis_visite', models.TextField(verbose_name='Que voir / que faire', blank=True)),
('avis_anecdotes', models.TextField(verbose_name='Anecdotes', blank=True)),
('lieu', models.ForeignKey(to='monstage.Lieu')),
],
options={
},
bases=(models.Model,),
),
migrations.CreateModel(
name='Normalien',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('permanent_mail', models.CharField(max_length=200, verbose_name=b'Adresse e-mail permanente', blank=True)),
('user', models.OneToOneField(related_name='profil', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'Profil \xe9l\xe8ve',
'verbose_name_plural': 'Profils \xe9l\xe8ves',
},
bases=(models.Model,),
),
migrations.CreateModel(
name='Stage',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('published', models.BooleanField(default=False, verbose_name='Visible publiquement')),
('type_stage', models.CharField(default=b'stage', max_length=5, verbose_name='Type', choices=[(b'stage', 'Stage')])),
('start_date', models.DateField(null=True, verbose_name='Date de d\xe9but')),
('end_date', models.DateField(null=True, verbose_name='Date de fin')),
('sujet', models.CharField(max_length=500, verbose_name='Sujet')),
('encadrants', models.CharField(max_length=500, verbose_name='Encadrants', blank=True)),
('avis_encadrants', models.TextField(verbose_name='Avis sur les encadrants', blank=True)),
('avis_equipe', models.TextField(verbose_name="Avis sur l'\xe9quipe", blank=True)),
('avis_stage', models.TextField(verbose_name='Int\xe9r\xeat du stage', blank=True)),
('avis_admin', models.TextField(verbose_name='Visa et administratif', blank=True)),
('lieux', models.ManyToManyField(related_name='stages', through='monstage.LieuStage', to='monstage.Lieu')),
('user', models.ForeignKey(related_name='stages', to='monstage.Normalien')),
],
options={
},
bases=(models.Model,),
),
migrations.CreateModel(
name='StageMatiere',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=30, verbose_name='Mati\xe8re')),
('users', models.ManyToManyField(related_name='matieres', to='monstage.Stage')),
],
options={
'verbose_name': 'Mati\xe8re des stages',
'verbose_name_plural': 'Mati\xe8res des stages',
},
bases=(models.Model,),
),
migrations.AddField(
model_name='lieustage',
name='stage',
field=models.ForeignKey(to='monstage.Stage'),
preserve_default=True,
),
]

View file

@ -1,41 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('monstage', '0001_initial'),
]
operations = [
migrations.AlterModelOptions(
name='lieu',
options={'verbose_name': 'Lieu', 'verbose_name_plural': 'Lieux'},
),
migrations.AlterModelOptions(
name='lieustage',
options={'verbose_name': 'Avis sur un lieu de stage', 'verbose_name_plural': 'Avis sur un lieu de stage'},
),
migrations.AlterModelOptions(
name='stage',
options={'verbose_name': 'Stage', 'verbose_name_plural': 'Stages'},
),
migrations.RenameField(
model_name='stage',
old_name='user',
new_name='profil_user',
),
migrations.RemoveField(
model_name='stagematiere',
name='users',
),
migrations.AddField(
model_name='stage',
name='matieres',
field=models.ManyToManyField(related_name='stages', to='monstage.StageMatiere'),
preserve_default=True,
),
]

View file

@ -1,26 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('monstage', '0002_auto_20150612_2003'),
]
operations = [
migrations.AddField(
model_name='lieu',
name='pays',
field=models.CharField(default='', max_length=200, verbose_name='Pays'),
preserve_default=False,
),
migrations.AlterField(
model_name='lieu',
name='ville',
field=models.CharField(max_length=200, verbose_name='Ville'),
preserve_default=True,
),
]

File diff suppressed because one or more lines are too long

View file

@ -1,22 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
import taggit.managers
class Migration(migrations.Migration):
dependencies = [
('taggit', '0001_initial'),
('monstage', '0004_auto_20150614_1517'),
]
operations = [
migrations.AddField(
model_name='stage',
name='thematiques',
field=taggit.managers.TaggableManager(to='taggit.Tag', through='taggit.TaggedItem', blank=True, help_text='A comma-separated list of tags.', verbose_name='Th\xe9matiques'),
preserve_default=True,
),
]

View file

@ -1,136 +0,0 @@
# coding: utf-8
from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
from django.contrib.gis.db import models as geomodels
from django.db.models.signals import post_save
from taggit.managers import TaggableManager
from monstage.listepays import PAYS_CHOICES
import ldap
TYPE_STAGE_CHOICES = (
('stage', _(u"Stage")),
)
TYPE_LIEU_CHOICES = (
('universite', _(u"Université")),
('entreprise', _(u"Entreprise")),
('centrerecherche', _(u"Centre de recherche")),
('administration', _(u"Administration")),
('autre', _(u"Autre")),
)
def choices_length (choices):
return reduce (lambda m, choice: max (m, len (choice[0])), choices, 0)
class Normalien(models.Model):
user = models.OneToOneField(User, related_name = "profil")
permanent_mail = models.CharField("Adresse e-mail permanente", max_length = 200, blank = True)
class Meta:
verbose_name = u"Profil élève"
verbose_name_plural = u"Profils élèves"
def __unicode__(self):
if self.user.first_name:
return unicode(self.user.first_name + " " + self.user.last_name)
return unicode(self.user)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Normalien.objects.get_or_create(user = instance)
try:
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
l = ldap.initialize("ldaps://ldap.spi.ens.fr:636")
l.set_option(ldap.OPT_REFERRALS, 0)
l.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
l.set_option(ldap.OPT_X_TLS,ldap.OPT_X_TLS_DEMAND)
l.set_option( ldap.OPT_X_TLS_DEMAND, True )
l.set_option( ldap.OPT_DEBUG_LEVEL, 255 )
info = l.search_s('dc=spi,dc=ens,dc=fr',ldap.SCOPE_SUBTREE,'(uid=%s)' % (instance.username,),['cn','mail'])
if len(info) > 0:
noms = info[0][1]['cn'][0].split(" ")
instance.first_name = noms[0]
instance.last_name = ' '.join(noms[1:])
instance.save()
except ldap.LDAPError:
pass
post_save.connect(create_user_profile, sender = User)
class Lieu(models.Model):
name = models.CharField(_(u"Nom de l'institution d'accueil"), max_length = 250)
ville = models.CharField(_(u"Ville"), max_length = 200)
pays = models.CharField(_(u"Pays"),
choices = PAYS_CHOICES,
max_length = choices_length (TYPE_STAGE_CHOICES))
coord = geomodels.PointField(_(u"Coordonnées"), geography = True)
objects = geomodels.GeoManager() # Requis par GeoDjango
type_lieu = models.CharField( _(u"Type de structure d'accueil"),
default = "universite",
choices = TYPE_LIEU_CHOICES,
max_length = choices_length (TYPE_LIEU_CHOICES))
def __unicode__(self):
return u"%s (%s)" % (self.name, self.ville)
class Meta:
verbose_name = "Lieu"
verbose_name_plural = "Lieux"
class StageMatiere(models.Model):
name = models.CharField(_(u"Matière"), max_length = 30)
class Meta:
verbose_name = "Matière des stages"
verbose_name_plural = "Matières des stages"
def __unicode__(self):
return self.name
class Stage(models.Model):
profil_user = models.ForeignKey(Normalien, related_name = "stages")
published = models.BooleanField(_("Visible publiquement"), default = False)
type_stage = models.CharField (_(u"Type"),
default = "stage",
choices = TYPE_STAGE_CHOICES,
max_length = choices_length (TYPE_STAGE_CHOICES))
start_date = models.DateField(_(u"Date de début"), null = True)
end_date = models.DateField(_(u"Date de fin"), null = True)
sujet = models.CharField(_(u"Sujet"), max_length = 500)
thematiques = TaggableManager(_(u"Thématiques"), blank = True)
encadrants = models.CharField(_(u"Encadrants"), max_length = 500, blank = True)
lieux = models.ManyToManyField(Lieu, related_name = "stages", through = "LieuStage")
matieres = models.ManyToManyField(StageMatiere, related_name = "stages")
# Avis
avis_encadrants = models.TextField(_(u"Avis sur les encadrants"), blank = True)
avis_equipe = models.TextField(_(u"Avis sur l'équipe"), blank = True)
avis_stage = models.TextField(_(u"Intérêt du stage"), blank = True)
avis_admin = models.TextField(_(u"Visa et administratif"), blank = True)
def __unicode__(self):
return u"%s : %s" % (self.profil_user.user.username, self.sujet)
class Meta:
verbose_name = "Stage"
verbose_name_plural = "Stages"
class LieuStage(models.Model):
stage = models.ForeignKey(Stage)
lieu = models.ForeignKey(Lieu)
# Avis
avis_global = models.TextField(_(u"Ressenti global"), blank = True)
avis_lieudevie = models.TextField(_(u"Mon lieu de vie"), blank = True)
avis_lieustage = models.TextField(_(u"Le lieu du stage"), blank = True)
avis_pratique = models.TextField(_(u"S'installer / Conseils pratiques"), blank = True)
avis_visite = models.TextField(_(u"Que voir / que faire"), blank = True)
avis_anecdotes = models.TextField(_(u"Anecdotes"), blank = True)
class Meta:
verbose_name = "Avis sur un lieu de stage"
verbose_name_plural = "Avis sur un lieu de stage"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

View file

@ -1,62 +0,0 @@
@charset "utf-8";
.entrer {
text-align:center;
}
.entrer a, a.btn {
display:inline-block;
background:#FFA41E;
color:#fff;
font-size:1.5em;
padding:8px;
border-radius:5px;
}
a.btn {
display:inline-block;
background:#FFA41E;
color:#fff;
font-size:1.2em;
padding:10px;
margin-top:12px;
border-radius:5px;
}
.explications {
background:#348d68;
display:table-row;
}
.explications img, .explications p {
display:table-cell;
vertical-align:middle;
}
.explications p {
color:#fff;
padding:20px;
font-size:1.1em;
text-align:center;
}
.homeh1 p {
float:right;
}
.homeh1 h1 {
display:inline-block;
margin-bottom:3px;
}
.homeh1 {
border-bottom:1px solid #888;
overflow:hidden;
margin-bottom:15px;
}
.betacadre {
background:#bbb;
padding:20px;
margin:20px 0;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,415 +0,0 @@
@charset "utf-8";
@import url(http://fonts.googleapis.com/css?family=Lato:300,700,300italic);
body {
font: 18px 'Lato', sans-serif;
background:#4FB088;
padding:0;
margin:0;
}
a {
font-weight:bold;
color:#4FB088;
text-decoration:none;
}
h1 {
margin-top:0;
}
.beta {
font-size:0.5em;
display:inline-block;
transform:rotate(-20deg);
color:#aaa;
}
header {
background:#166142;
padding:10px;
margin:0;
overflow:hidden;
color:#fff;
}
header li {
display:inline-block;
text-align:center;
vertical-align:middle;
}
header h1 {
float:left;
color:#fff;
margin:20px;
}
header h1 a {
color:#fff;
text-decoration:none;
}
header li a {
display:inline-block;
padding:20px 20px;
margin:0 5px;
}
header li a:hover {
background:#4FB088;
color:#166142;
}
header ul {
float:right;
padding:0;
margin:0;
}
header .username {
color:#fff;
font-weight:normal;
}
.footer {
clear:both;
font-size:14px;
color:#555;
text-align:right;
margin-top:25px;
}
#content {
width:80%;
max-width:700px;
padding:30px;
margin:20px auto;
background:#eee;
}
/* formulaires */
label {
display:inline-block;
font-weight:bold;
padding:10px;
}
form {
overflow:hidden;
}
form p {
padding:10px;
overflow:hidden;
margin:0;
}
form p:nth-child(2n) {
background:#fff;
}
form p:nth-child(2n+1) {
background:#ddd;
}
form textarea, form input, form select {
display:block;
font:16px 'Lato', sans-serif;
margin:10px;
float:right;
}
form textarea {
resize:vertical;
}
form textarea {
width:90%;
}
.helptext {
display:block;
font-size:0.8em;
color:#333;
text-align:right;
margin-top:10px;
width:100%;
clear:both;
}
/* lieux */
#map_addlieu {
width:100%;
height:300px;
}
input#addlieu {
font-size:20px;
padding:15px;
width:70%;
margin:0 auto;
float:none;
}
div.lieuform {
display:block;
border:1px solid #337359;
padding:10px;
margin-bottom:20px;
}
div.lieuform h3 {
margin:0px;
margin-bottom:5px;
}
div.lieuform p {
background:none;
padding:0;
}
div#candidats ul {
list-style:none;
padding:10px;
margin:0;
}
div#candidats li{
list-style:none;
display:block;
overflow:hidden;
padding:0;
border:2px #fff;
}
div#candidats li a, div#candidats #addcandidat {
display:block;
background:#5AC99C;
padding:10px;
color:#000;
}
div#candidats li a .choice_btn {
float:right;
background:none;
text-decoration:underline;
border:none;
}
div#candidats #addcandidat {
width:90%;
margin:15px auto;
}
div#candidats input {
float:none;
}
div#candidats #addcandidat {
font-size:20px;
}
#addlieu_win .win_content{
max-width:600px;
}
.btn_like {
display:block;
background:#5AC99C;
padding:10px;
color:#000;
}
#addlieu_btn {
text-align:center;
font-size:1.5em;
padding:30px;
}
#addlieu_btn:before {
content:"+";
margin-right:12px;
}
/* stages */
#stage_present {
display:table;
background: #fff;
border-spacing:20px;
width:100%;
}
#stage_misc {
display:table-cell;
min-width:300px;
}
#stage_map {
display:table-cell;
min-width:300px;
}
#stage_published.published {
background:#9f9;
}
#stage_published.unpublished {
background:#f99;
}
#stage_published input {
display:inline;
margin:0;
}
#stage_published p {
background:none;
}
ul.bigger {
display:block;
padding:0;
}
ul.bigger li {
display:table-row;
list-style:none;
}
ul.bigger li:hover{
background:#ccc;
}
.stagestatus {
display:table-cell;
width:100px;
text-align:right;
padding-right:20px;
}
.stagelink {
display:table-cell;
padding:10px;
}
.stagestatus.draft {
color:#f00;
}
.changestage {
color:#B8741A;
}
/* Fenêtre */
.win_bg {
display:none;
position:fixed;
width:100%;
height:100%;
background:rgba(0,0,0,0.6);
z-index:300;
top:0;
left:0;
}
.win_centrer {
display:table-cell;
vertical-align:middle;
text-align:center;
overflow-y:auto;
}
.win_close {
float:right;
}
.win_content {
text-align:left;
display:inline-block;
padding:0;
max-width:500px;
width:90%;
background:#fff;
}
.win_content h2 {
background:#000;
color:#fff;
padding:20px;
margin-top:0;
}
.win_content textarea {
min-height:150px;
}
/* Fenêtres spéciales */
#feedback_btn {
position:fixed;
top:65%;
left:0;
z-index:40;
background:#000;
color:#fff;
padding:20px;
transform:rotate(-90deg);
font-weight:bold;
transform-origin:top left;
}
.success {
background:#9f9;
padding:5px;
}
.failure {
padding:5px;
background:#f99;
}
/* Recherche */
form.recherche p {
background:none;
}
form.recherche {
background:#ddd;
padding:5px;
}
form.recherche .criteria {
display:table;
width:100%;
}
form.recherche .criteria p {
display:table-cell;
}
form.recherche .lieu {
display:table;
}
form.recherche .lieu div {
display:table-cell;
}
#map_searchlieu {
width:50%;
}
.stagefound {
background:#fff;
padding:10px;
margin:10px 0;
}
.stagefound h3 {
margin-top:0;
}
.stagefound p {
margin-bottom:0px;
}

View file

@ -1,15 +0,0 @@
{% extends "skeleton.html" %}
{% load staticfiles %}
{% block extra_head %}
<link type="text/css" href="{% static 'index.css' %}" rel="stylesheet" />
{% endblock %}
{% block content %}
<h1>Accès interdit</h1>
{% if unpublished %}<p>Le stage n'est pas encore publié</p>
{% elif notowned %}<p>Ce stage ne vous appartient pas, vous ne pouvez pas le modifier</p>
{% else %}<p>L'accès à ce contenu est interdit</p>
{% endif %}
{% endblock %}

View file

@ -1,22 +0,0 @@
{% extends "skeleton.html" %}
{% block content %}
{% if user.first_name %}
<h1>Bonjour {{ user.first_name }} !</h1>
<p><a href="{% url 'monstage:profil_edit' %}" class="changestage">Modifier mon profil</a></p>
{% else %}
<h1>Bonjour {{ user.username }} !</h1>
<p>Je ne connais pas votre prénom. Pensez à le <a href="{% url 'monstage:profil_edit' %}" class="changestage">renseigner ici</a> !</p>
{% endif %}
<h2>Mes stages</h2>
<ul class="bigger">
{% for stage in stages %}
<li>
<span class="stagestatus {{ stage.published|yesno:'published,draft' }}">{{ stage.published|yesno:"Publié,Brouillon" }}</span>
<a href="{% url 'monstage:stage' stage.id %}" class="stagelink">{{ stage.sujet }}</a></li>
{% endfor %}
<li><span class="stagestatus">+</span><a href="{% url 'monstage:stage_add' %}" class="stagelink changestage">Ajouter un stage</a></li>
</ul>
{% endblock %}

View file

@ -1,34 +0,0 @@
{% extends "skeleton.html" %}
{% load staticfiles %}
{% block extra_head %}
<link type="text/css" href="{% static 'index.css' %}" rel="stylesheet" />
{% endblock %}
{% block content %}
<div class="homeh1">
<h1>ExperiENS<span class="beta">beta</span></h1>
<p>Partagez vos expériences de stages !</p>
</div>
<div class="betacadre">
Ce site est en cours de développement, et fait l'objet de mises à jours régulières. N'hésitez pas cependant à remplir une fiche pour vos stages, utiliser la recherche, et donner votre avis en utilisant le bouton "feedback".
</div>
{% if not user.username %}
<div class="entrer">
<p><a href="{% url 'login' %}">Connexion</a></p>
<p class="helptext">Connexion via le serveur central d'authentification ENS (identifiants clipper)</p>
</div>
{% endif %}
<div class="explications">
<p>Ne partez plus en stage en terre inconnue : nourrissez-vous de l'expérience de {{ stats.num_stages }} stages effectués par la communauté normalienne, repérez les bons plans, et ne faites pas les mêmes erreurs&nbsp;!
{% if user.username %}<br /><a href="{% url 'monstage:search' %}" class="btn">Rechercher des stages</a>{% endif %}</p>
<img src="{% static 'home2.jpg' %}" width="350"/>
</div>
<div class="explications">
<img src="{% static 'home1.jpg' %}" width="350"/>
<p>Vous revenez du bout du monde (ou de la rue d'à côté)&nbsp;? N'attendez plus, rédigez un avis sur votre stage pour que votre expérience profite à d'autres&nbsp;!
{% if user.username %}<br /><a href="{% url 'monstage:home' %}" class="btn">Partager ses stages</a>{% endif %}</p>
</div>
<div class="footer">Propulsé par Django, <a href="http://evarin.fr" target="_blank">Evarin</a> et Damien</div>
{% endblock %}

View file

@ -1,5 +0,0 @@
{
"lieux": [ {% for lieu in lieux %} {% if not forloop.first %},{% endif %}
{ "name": "{{ lieu.name }}", "id": "{{ lieu.id }}", "lat": {{ lieu.lat }}, "lon": {{ lieu.lon }}, "distance": "{{ lieu.distance }}" }
{% endfor %} ]
}

View file

@ -1,16 +0,0 @@
{% extends "skeleton.html" %}
{% block content %}
<h1>{{ profil }}</h1>
<h2>Ses stages</h2>
{% if stages %}
<ul class="bigger">
{% for stage in stages %}
<li><a href="{% url 'monstage:stage' stage.id %}" class="stagelink">{{ stage.sujet }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>Aucun stage pour le moment</p>
{% endif %}
{% endblock %}

View file

@ -1,14 +0,0 @@
{% extends "skeleton.html" %}
{% block content %}
<h1>Modifier son profil</h1>
<p><a href="{% url 'monstage:home' %}">Retour</a></p>
<form action="{% url 'monstage:profil_edit' %}" method="post">
{% csrf_token %}
<p><label for="first_name">Prénom : </label><input type="text" name="first_name" id="first_name" value="{{ user.first_name }}" /> </p>
<p><label for="last_name">Nom : </label><input type="text" name="last_name" id="last_name" value="{{ user.last_name }}" /> </p>
<input type="submit" value="Enregistrer" />
</form>
{% endblock %}

View file

@ -1,98 +0,0 @@
{% extends "skeleton.html" %}
{% load staticfiles %}
{% block extra_head %}
<script src="http://maps.googleapis.com/maps/api/js?sensor=false&libraries=places" type="text/javascript"></script>
<script src="{% static 'script/jquery-1.11.1.min.js' %}" type="text/javascript"></script>
<script src="{% static 'script/jquery.geocomplete.min.js' %}" type="text/javascript"></script>
{% endblock %}
{% block content %}
<h1>Rechercher des stages</h1>
<div id="searchbox">
<form action="{% url 'monstage:search' %}" method="get" class="recherche">
<p>Critères :</p>
<div class="criteria">
<p>
{{ form.matiere.errors }}
{{ form.matiere.label_tag }}
{{ form.matiere }}
</p>
<p>
{{ form.thematiques.errors }}
{{ form.thematiques.label_tag }}
{{ form.thematiques }}
</p>
</div>
{{ form.latitude }}
{{ form.longitude }}
<div class="lieu">
<div class="champs">
<p>
{{ form.lieu.errors }}
{{ form.lieu.label_tag }}
{{ form.lieu }}
</p>
<p id="search_tolerance" style="display:none">
{{ form.tolerance.errors }}
{{ form.tolerance.label_tag }}
{{ form.tolerance }}
</p>
</div>
<div id="map_searchlieu"></div>
</div>
<script>
$(function(){
$("#id_lieu").attr("placeholder", "(N'importe où)").geocomplete({
map: "#map_searchlieu",
types: ["geocode", "establishment"],
}).on("geocode:result", function(event, result){
$("#map_searchlieu").css("display", "table-cell");
digere(result);
console.log(result);
if($("#id_latitude").val() != "") {
$("#search_tolerance").css("display", "block");
}
});
if($("#id_latitude").val() != "") {
$("#search_tolerance").css("display", "block");
}
});
var predata;
function digere (gdata) {
var data = {};
for (var i in gdata.address_components) {
var obj = gdata.address_components[i];
for (var j in obj.types) {
switch(obj.types[j]) {
case "locality":
data["ville"] = obj.long_name;
break;
case "country":
data["pays"] = obj.short_name;
break;
}
}
}
data["name"] = gdata.name;
data["longitude"] = gdata.geometry.location.lng();
data["latitude"] = gdata.geometry.location.lat();
$("#id_longitude").val(data["longitude"]);
$("#id_latitude").val(data["latitude"]);
}
</script>
<input type="submit" action="submit" value="Rechercher" />
</form>
</div>
{% if resultats != None %}
<p><a name="resultats"></a>{{ resultats|length }} stage(s) trouvé(s)</p>
{% for stage in resultats %}
<div class="stagefound">
<h3><a href="{% url 'monstage:stage' stage.id %}">{{ stage.sujet }}</a></h3>
<p>Par <a href="{% url 'monstage:profil' stage.profil_user.user.username %}">{{ stage.profil_user }}</a> à {% for lieu in stage.lieux.all %}{% if not forloop.first %}{% if forloop.last %} et {% else %}, {% endif %}{% endif %}{{ lieu.name }} ({{ lieu.ville }}){% endfor %}, en {{ stage.end_date|date:'Y' }}.</p>
</div>
{% endfor %}
{% endif %}
{% endblock %}

View file

@ -1,102 +0,0 @@
{% extends "skeleton.html" %}
{% block extra_head %}
<script src="http://maps.googleapis.com/maps/api/js"></script>
<script>
function initialize() {
var lieux = [ {% for coords in lieux_latlng %}
new google.maps.LatLng({{ coords }}) {% if not forloop.last %},{% endif %}
{% endfor %} ];
var mapProp = {
center:new google.maps.LatLng({{ lieux_latlng.0 }}),
zoom:7,
mapTypeId:google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById("stage_map"),mapProp);
for (var i in lieux) {
var marker = new google.maps.Marker({
position:lieux[i],
});
marker.setMap(map);
}
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
{% endblock %}
{% block content %}
<p><a href="{% url 'monstage:home' %}">Retour</a></p>
<h1>{{ stage.sujet }}</h1>
{% if modifiable %}
<form action="{% url 'monstage:stage_publish' stage.id %}" method="post">
{% csrf_token %}
<div id="stage_published" class="{{ published|yesno:'published,unpublished' }}">
<input type="hidden" name="publishit" value="{{ published|yesno:'no,yes' }}" />
{% if published %}
<p>Ce stage est publié et visible des autres utilisateurs <input type="submit" value="Masquer" /></p>
{% else %}
<p>Ce stage est un brouillon invisible des autres utilisateurs <input type="submit" value="Publier" /></p>
{% endif %}
</div>
</form>
{% endif %}
<div id="stage_present">
{% if stage.lieux.all %}
<div id="stage_map"></div>
{% endif %}
<div id="stage_misc">
{% if modifiable %}<p><a href="{% url 'monstage:stage_edit_desc' stage.id %}" class="changestage">Modifier la description du stage (sujet, ...)</a></p>{% endif %}
<p><a href="{% url 'monstage:profil' stage.profil_user.user.username %}">{{ stage.profil_user.user.first_name }} {{ stage.profil_user.user.last_name }}</a> a fait ce stage du {{ stage.start_date }} au {{ stage.end_date }}{% if stage.encadrants %}, supervisé par {{ stage.encadrants }}{% endif %}.</p>
<p>Matières : {% for matiere in stage.matieres.all %}{% if not forloop.first %}, {% endif %}{{ matiere.name }}{% endfor %}</p>
<p>Thématiques : {% for tag in stage.thematiques.names %}{% if not forloop.first %}, {% endif %}{{ tag }}{% endfor %}</p>
{% if stage.lieux.all %}<p>À {% for lieu in stage.lieux.all %}{% if not forloop.first %}{% if forloop.last %} et {% else %}, {% endif %}{% endif %}{{ lieu.name }} ({{ lieu.ville }}){% endfor %}</p>{% endif %}
{% if modifiable %}<p><a href="{% url 'monstage:stage_edit_lieu' stage.id %}" class="changestage">Modifier les lieux du stage</a></p>{% endif %}
</div>
</div>
{% if modifiable %}<p><a href="{% url 'monstage:stage_edit_feedback' stage.id %}" class="changestage">Modifier les avis sur le stage</a></p>{% endif %}
<h2>Ressenti sur le stage</h2>
{% if stage.avis_encadrants %}
<h3>Les encadrants : {{ stage.encadrants }}</h3>
{{ stage.avis_encadrants|linebreaks }}
{% endif %}
{% if stage.avis_equipe %}
<h3>L'équipe</h3>
{{ stage.avis_equipe|linebreaks }}
{% endif %}
{% if stage.avis_stage %}
<h3>Le stage en général</h3>
{{ stage.avis_stage|linebreaks }}
{% endif %}
{% if stage.avis_admin %}
<h3>L'administratif et le visa</h3>
{{ stage.avis_admin|linebreaks }}
{% endif %}
{% for lieustage in stage.lieustage_set.all %}
<h2>La vie à {{ lieustage.lieu.ville }}, {{ lieustage.lieu.get_pays_display }}</h2>
{% if lieustage.avis_global %}
<h3>Ressenti global du séjour</h3>
{{ lieustage.avis_global|linebreaks }}
{% endif %}
{% if lieustage.avis_lieudevie %}
<h3>Mon lieu de vie</h3>
{{ lieustage.avis_lieudevie|linebreaks }}
{% endif %}
{% if lieustage.avis_lieustage %}
<h3>Le lieu du stage : {{ lieustage.lieu.name }}</h3>
{{ lieustage.avis_lieustage|linebreaks }}
{% endif %}
{% if lieustage.avis_pratique %}
<h3>S'installer / conseils pratiques</h3>
{{ lieustage.avis_pratique|linebreaks }}
{% endif %}
{% if lieustage.avis_visite %}
<h3>A voir, à faire aux alentours de {{ lieustage.lieu.ville }}</h3>
{{ lieustage.avis_visite|linebreaks }}
{% endif %}
{% if lieustage.avis_anecdotes %}
<h3>Anecdotes</h3>
{{ lieustage.avis_anecdotes|linebreaks }}
{% endif %}
{% endfor %}
{% endblock %}

View file

@ -1,12 +0,0 @@
{% extends "skeleton.html" %}
{% block content %}
<h1>Ajouter un stage</h1>
<p><a href="{% url 'monstage:index' %}">Retour</a></p>
<form action="{% url 'monstage:stage_add' %}" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Etape suivante" />
</form>
{% endblock %}

View file

@ -1,10 +0,0 @@
{% extends "skeleton.html" %}
{% block content %}
<h1>Editer le stage {{ stage.sujet }}</h1>
<p><a href="{% url 'monstage:stage' stage.id %}">Retour</a></p>
<p><a href="{% url 'monstage:stage_edit_desc' stage.id %}">Modifier la description du stage (sujet, ...)</a></p>
<p><a href="{% url 'monstage:stage_edit_lieu' stage.id %}">Modifier les lieux du stage</a></p>
<p><a href="{% url 'monstage:stage_edit_feedback' stage.id %}">Modifier son avis sur le stage</a></p>
{% endblock %}

View file

@ -1,12 +0,0 @@
{% extends "skeleton.html" %}
{% block content %}
<h1>Modifier la description du stage "{{ stage.sujet }}"</h1>
<p><a href="{% url 'monstage:stage' stage.id %}">Retour</a></p>
<form action="{% url 'monstage:stage_edit_desc' stage.id %}" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Enregistrer" />
</form>
{% endblock %}

View file

@ -1,23 +0,0 @@
{% extends "skeleton.html" %}
{% load staticfiles %}
{% block content %}
<h1>Avis sur le stage "{{ stage.sujet }}"</h1>
<p><a href="{% url 'monstage:stage' stage.id %}">Retour</a></p>
<p>{{ debug }}</p>
<form action="{% url 'monstage:stage_edit_feedback' stage.id %}" method="post">
{% csrf_token %}
<div class="avis_gen">
<h2>Le déroulement du stage</h2>
{{ form_gen.as_p }}
</div>
{% for obj in forms_lieux %}
<div class="avis_lieux">
<h2>Avis sur le lieu "{{ obj.1.name }}"</h2>
{{ obj.0.as_p }}
</div>
{% endfor %}
<input type="submit" value="Enregistrer" />
</form>
{% endblock %}

View file

@ -1,172 +0,0 @@
{% extends "skeleton.html" %}
{% load staticfiles %}
{% block extra_head %}
<script src="http://maps.googleapis.com/maps/api/js?sensor=false&libraries=places" type="text/javascript"></script>
<script src="{% static 'script/jquery-1.11.1.min.js' %}" type="text/javascript"></script>
<script src="{% static 'script/jquery.geocomplete.min.js' %}" type="text/javascript"></script>
{% endblock %}
{% block content %}
<h1>Lieux du stage "{{ stage.sujet }}"</h1>
<p><a href="{% url 'monstage:stage' stage.id %}">Retour</a></p>
<form action="{% url 'monstage:stage_edit_lieu' stage.id %}" method="post">
{% csrf_token %}
<input type="hidden" id="numplaces" name="numplaces" value="{{ numforms }}" />
<div id="places">
<h2>Liste des lieux de ce stage</h2>
{% for lieuform in lieuforms %}
<div class="lieuform">
<h3>{{ lieuform.0.name }}</h3>
<p>{{ lieuform.0.ville }}, {{ lieuform.0.get_pays_display }}</p>
{{ lieuform.1.as_p }}
</div>
{% endfor %}
</div>
<a id="addlieu_btn" class="btn_like" href="javascript:showAddLieu(true);">Ajouter un lieu</a>
<div id="addlieu_win" class="win_bg">
<div class="win_centrer">
<div class="win_content">
<h2>Ajouter un autre lieu<a class="win_close" href="javascript:showAddLieu(false)">X</a></h2>
<p><input id="addlieu" type="text" placeholder="Chercher un établissement" /></p>
<div id="map_addlieu"></div>
<div id="candidats"></div>
</div>
</div>
</div>
<input type="submit" value="Enregistrer" onclick="return checkForm();"/>
</form>
<script>
var emptyform = "{{ emptyform |safe }}";
var emptylieu = "{{ emptylieu |safe }}";
$(function(){
$("#addlieu").geocomplete({
map: "#map_addlieu",
types: ["geocode", "establishment"],
}).on("geocode:result", function(event, result){ digere(result); console.log(result); });
});
var fieldcount = {{ numforms }};
var places = $("#places");
function addNewPlace (data) {
if (data == undefined) return;
var t = $("<div>", {class:"lieuform"})
t.html(emptyform.replace(/\{\{ID\}\}/gi, fieldcount));
places.append(t);
document.getElementById('id_'+fieldcount+'-name').value = data.name;
document.getElementById('id_'+fieldcount+'-ville').value = data.ville;
document.getElementById('id_'+fieldcount+'-pays').value = data.pays;
document.getElementById('id_'+fieldcount+'-latitude').value = data.latitude;
document.getElementById('id_'+fieldcount+'-longitude').value = data.longitude;
fieldcount++;
document.getElementById('numplaces').value = fieldcount;
predata = undefined;
showAddLieu(false);
clearCandidats();
}
function addKnownPlace(data) {
if (data == undefined) return;
var t = $("<div>", {class:"lieuform"})
t.html(emptylieu.replace(/\{\{ID\}\}/gi, fieldcount));
t.prepend($("<h3>", {html:data.name}));
places.append(t);
document.getElementById('id_'+fieldcount+'-lieu_id').value = data.id;
fieldcount++;
document.getElementById('numplaces').value = fieldcount;
predata = undefined;
showAddLieu(false);
clearCandidats();
$("#map_addlieu").css("display", "none");
}
var predata;
function digere (gdata) {
var data = {};
for (var i in gdata.address_components) {
var obj = gdata.address_components[i];
for (var j in obj.types) {
switch(obj.types[j]) {
case "locality":
data["ville"] = obj.long_name;
break;
case "country":
data["pays"] = obj.short_name;
break;
}
}
}
data["name"] = gdata.name;
data["longitude"] = gdata.geometry.location.lng();
data["latitude"] = gdata.geometry.location.lat();
predata = data;
getCandidats(data);
}
function getCandidats (data) {
$.getJSON("{% url 'monstage:lieux_candidats' %}", {lat:data.latitude, lon:data.longitude}, showCandidats);
clearCandidats();
$("#candidats").append($("<p>", {text:"Recherche des lieux connus..."}));
}
function showCandidats (candidats) {
var liste = $("<ul>");
for (var i in candidats.lieux) {
lieu = candidats.lieux[i];
console.log(lieu)
liste.append($("<li>", {html: "<a class=\"choose_lieu\" href=\"javascript:void(0);\"> "+lieu.name + " ("+lieu.distance+") <span class=\"choice_btn\">Choisir cet établissement</span></a>"}).prop("data", lieu).click(clickCandidat));
}
var candi = $("#candidats");
clearCandidats();
if (candidats.lieux.length == 0) {
candi.append($("<h3>", {text:"(Aucun établissement déjà référencé à proximité)"}));
candi.append($("<input>", {id:"addcandidat", type:"button", class:"btn_like", value:"Enregistrer une nouvelle institution"})
.click(function(){addNewPlace(predata)}) );
} else {
candi.append($("<h3>", {text:"Choisir parmi les lieux déjà référencés :"}));
candi.append(liste);
candi.append($("<input>", {id:"addcandidat", type:"button", class:"btn_like", value:"Ou bien créer une nouvelle institution"})
.click(function(){addNewPlace(predata)}) );
}
hackForGMaps();
}
function clearCandidats () {
var candi = $("#candidats");
$.each(candi.children(), function(i, item){$(item).remove()});
}
function clickCandidat () {
addKnownPlace(this.data);
clearCandidats();
}
function checkForm () {
for(var i=0; i<fieldcount; i++){
if (!document.getElementById('id_'+i+'-delete').checked)
return true;
}
if(confirm("Vous n'avez aucun lieu de précisé, vous ne pourrez pas donner d'avis complet sur votre stage !\nÊtes-vous sûr de vouloir continuer ?")) {
return true;
}else
return false;
}
function showAddLieu(show) {
document.getElementById("addlieu_win").style.display=show?"table":"none";
}
function hackForGMaps() { // le widget google maps ne s'affiche pas correctement. un event resize le fait s'afficher normalement, don't ask why
var v = document.createEvent("UIEvent");
v.initUIEvent('resize', true, false, window, 0);
window.dispatchEvent(v);
}
</script>
{% endblock %}

View file

@ -1,57 +0,0 @@
{% load staticfiles %}
<!doctype html>
<html>
<head>
<title>{% block title %}ExperiENS{% endblock %}</title>
<link type="text/css" rel="stylesheet" href="{% static 'style.css' %}" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script type="text/javascript">function showFeedback(show){document.getElementById("feedback_win").style.display=show?"table":"none";}</script>
{% block extra_head %}{% endblock %}
</head>
<body>
<header>
<h1><a href="{% url 'monstage:index' %}">ExperiENS<span class='beta'>beta</span></a></h1>
<nav>
<ul id="menu">
<li><a href="{% url 'monstage:index' %}">Accueil</a></li>
{% if user.username %}
<li><a href="{% url 'monstage:home' %}">Mon expérience</a></li>
<li><a href="{% url 'monstage:search' %}">Recherche</a></li>
{% endif %}
{% if user.is_staff %}
<li><a href="{% url 'admin:index' %}">Administration</a></li>
{% endif %}
{% if user.username %}<li><a href="{% url 'logout' %}"><span class="username">{{ user.username }}</span><br/> Déconnexion</a></li>
{% else %}<li><a href="{% url 'login' %}">Connexion</a></li>{% endif %}
</ul>
</nav>
</header>
{% if user.username %}
<div id="feedback_win" class="win_bg">
<div class="win_centrer">
<div class="win_content">
<h2>Envoyer un avis sur le site<a class="win_close" href="javascript:showFeedback(false)">X</a></h2>
<form method="POST" action="{% url 'monstage:send_feedback' %}?next={{ request.path|urlencode }}">
{% csrf_token %}
<p>Connecté en tant que {{ user.profil }}</p>
<p><label for="id_feedback-message">Commentaire :</label><textarea name="feedback-message" id="id_feedback-message"></textarea></p>
<input type="submit" />
</form>
</div>
</div>
</div>
<a id="feedback_btn" href="javascript:showFeedback(true)">
Feedback
</a>
{% endif %}
<div id="content">
{% if request.GET.feedback_sent %}<p class="success">Merci pour votre message !</p>{% endif %}
{% if request.GET.feedback_error %}<p class="failure">Erreur lors de l'envoi du message.</p>{% endif %}
{% block content %}{% endblock %}
</div>
</body>
</html>

View file

@ -1,3 +0,0 @@
from django.test import TestCase
# Create your tests here.

View file

@ -1,19 +0,0 @@
from django.conf.urls import patterns, url
from monstage import views
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
url(r'^home/$', views.home, name='home'),
url(r'^profil/show/(?P<profil_id>\w+)/$', views.profil, name='profil'),
url(r'^profil/edit/$', views.profil_edit, name='profil_edit'),
url(r'^api/lieux/candidats/$', views.lieux_candidats, name='lieux_candidats'),
url(r'^stage/(?P<stage_id>\d+)/$', views.stage, name='stage'),
url(r'^stage/new/$', views.stage_add, name='stage_add'),
url(r'^stage/(?P<stage_id>\d+)/edit/description/$', views.stage_edit_desc, name='stage_edit_desc'),
url(r'^stage/(?P<stage_id>\d+)/edit/lieu/$', views.stage_edit_lieu, name='stage_edit_lieu'),
url(r'^stage/(?P<stage_id>\d+)/edit/avis/$', views.stage_edit_feedback, name='stage_edit_feedback'),
url(r'^stage/(?P<stage_id>\d+)/edit/publish/$', views.stage_publish, name='stage_publish'),
url(r'^recherche/$', views.search, name='search'),
url(r'^feedback/send/$', views.send_feedback, name='send_feedback'),
)

View file

@ -1,340 +0,0 @@
# 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 django.template.defaultfilters import slugify
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__contains = slugify(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)