scripts/wiki/action/inscription.py
Antoine Durand-Gasselin 81299a838f [inscription.py] ça avance, fout les inscriptions correctes dans des fichiers dans /v/l/w/d/p/
Ignore-this: d2ebe9614a2ca38aa97310480efa143
reste à faire:
 * masquer le mdp
 * empêcher les multi-insciption (ou pas ?)
 * faire plus de tests (ou pas?)
 * coder plus de js (ou pas?)
 * créer un script qui permette au câbleur de câbler plus rapidement (ou pas?)

darcs-hash:20090720172333-bd074-a398864703f09b3048b273eeb437686cc93f7d2d.gz
2009-07-20 19:23:33 +02:00

429 lines
16 KiB
Python

# -*- coding: iso-8859-1 -*-
u"""
_vi
<Ii _aa.
:I> aZ2^
v` .we^
. . .. + _2~
._auqXZZX ._auqXZZZ` ...._... ~ ._|ii~
.aXZZY""^~~ vX#Z?""~~~._=ii|+++++++ii=, _=|+~-
JXXX` )XXX' _|i+~ .__..._. +l= -~-
SXXo )XZX: |i> ._%i>~~+|ii| .i| ._s_ass,,. ._a%ssssssss
-SXZ6,,. )XZX: =l> _li+~` iii| .ii _uZZXX??YZ#Za, uXUX*?!!!!!!!
"!XZ#ZZZZZXZXZ` <i> =i: .|ii| .l|.dZXr 4XXo.XXXs,.
-~^^^^^^^` -||, +i|=. |ii| :i>:ZXZ( ]XZX.-"SXZUZUXoa,,
+l|, ~~|++|++i|||+~:ZXZ( ]ZZX ---~"?Z#m
.__;=- ~+l|=____.___, :ZXZ( ]ZXX_________auXX2
._||>+~- . -~+~++~~~- :ZXZ( ]ZXZZ#######UX*!"
-+-- .>` _
.<}` 3;
.<l> .Zc
.ii^ )Xo
]XX
MoinMoin - Formulaire d'inscription
Un formulaire de préinscription au Crans
Copyright 2009 Antoine Durand-Gasselin <adg@crans.org>
Licence: GPLv3
"""
import os, re, locale, base64, sys, unicodedata, random
from commands import getstatusoutput as gso
sys.path.append("/usr/scripts/gestion")
from iptools import AddrInNet
from MoinMoin import wikiutil
from MoinMoin.widget import html
from MoinMoin.Page import Page
from MoinMoin.PageEditor import PageEditor
from MoinMoin.formatter.text_html import Formatter
PREINSCRIPTION_DIR = '/var/local/wiki/data/preinscription/'
ETABLISSEMENTS = [ ("ENS", u"ENS Cachan"),
("IUT Cachan", u"IUT Cachan"),
("Maximilien Sorre", u"Maximilien Sorre"),
("Gustave Eiffel", u"Gustave Eiffel"),
("P1", u"Paris I"),
("P2", u"Paris II"),
("P3", u"Paris III"),
("P4", u"Paris IV"),
("P5", u"Paris V"),
("P6", u"Paris VI"),
("P7", u"Paris VII"),
("P8", u"Paris VIII"),
("P9", u"Paris IX"),
("P10", u"Paris X"),
("P11", u"Paris XI"),
("P12", u"Paris XII"),
("P13", u"Paris XIII"),
("IUFM", u"IUFM"),
("other", u"Autre...") ]
LABOS = [ ("CMLA", u"CMLA - Centre de Mathématiques et de Leurs Applications"),
("GAPP", u"GAPP - Groupe d'Analyse des Politiques Publiques"),
("IDHE", u"IDHE - Institutions et Dynamiques Historiques de l'Economie"),
("LBPA", u"LBPA - Laboratoire de Biotechnologies et Pharmacologie génétique Appliquées"),
("LMT", u"LMT - Laboratoire de Mécanique et Technologie"),
("LPQM", u"LPQM - Laboratoire de Photonique Quantique et Moléculaire"),
("LSV", u"LSV - Laboratoire de Spécification et Vérification"),
("LURPA", u"LURPA - Laboratoire Universitaire de Recherche en Production Automatisée"),
("PPSM", u"PPSM - Laboratoire de Photophysique et Photochimie Supramoléculaires et Macromoléculaires"),
("SATIE", u"SATIE - Systèmes et Applications des Technologies de l\'Information et de l'Energie"),
("STEF", u"STEF - Sciences Techniques Education Formation") ]
ANNEE_ENS = [ ("1", u"1A (licence)"), ("2", u"2A (master 1)"),
("3", u"3A (agrégation)"), ("4", u"4A (master 2)"),
("5", u"5A (thèse 1)"), ("6", u"6A (thèse 2)"),
("7", u"7A (thèse 3)"), ("8", u"8A+") ]
ANNEE_ETUDE = [ ("-2", u"Seconde"), ("-1", u"Première"), ("0", u"Terminale"),
("1", u"BAC+1 (L1)"), ("2", u"BAC+2 (L2)"), ("3", u"BAC+3 (L3)"),
("4", u"BAC+4 (M1)"), ("5", u"BAC+5 (M2)"), ("6", u"BAC+6 (thèse 1)"),
("7", u"BAC+7 (thèse 2)"), ("8", u"BAC+8 (thèse 3)"), ("9", "Autre") ]
SECTIONS_ENS = [ ("A0", u"A0 - Informatique"),
("A1", u"A1 - Mathématiques"),
("A2", u"A2 - Physique fondamentale"),
("A'2", u"A'2 - Physique appliquée"),
("A''2", u"A''2 - Chimie"),
("A3", u"A3 - Biochimie"),
("EEA", u"EEA"),
("B123", u"B123 - Technologie mécanique"),
("B1", u"B1 - Mécanique"),
("B2", u"B2 - Génie civil"),
("B3", u"B3 - Génie mécanique"),
("B1", u"B1 - Mécanique"),
("B2", u"B2 - Génie civil"),
("B3", u"B3 - Génie mécanique"),
("B4", u"B4 - Génie électrique"),
("C", u"C - Art et création industrielle"),
("D2", u"D2 - Economie gestion"),
("D3", u"D3 - Sciences sociales"),
("E", u"E - Anglais") ]
class FormElement():
"""Une classe pour représenter un élément d'un formulaire"""
def __init__(self, wikitxt):
self.content = wikitxt
def render(self, request, parser):
return wikiutil.renderText(request, parser, self.content)
class Field():
"""Une classe pour représenter les champs
Attention, elle ne permet que de rendre les champs en html, et
d'effectuer des tests unitaires"""
error_txt=''
error_msg=''
error_field=''
def __init__(self, id, prompt, default = "", input_type = "text",
check=None, CLASS="formulaire_field"):
self.id = id
self.prompt = html.Text(prompt)
self.default = default
self.input_type = input_type
self.CLASS= CLASS
if check != None: self.check_hook = check
else: self.check_hook = (lambda x: True)
def fill(self, post):
self.input = post.get(self.id, [''])[0]
def check(self):
self.error_txt= '' # Devrait pourtant être déjà vide
self.default = self.input
ok = self.check_hook(self)
if ok:
self.content = self.__dict__.get('content', self.input) # des fois qu'on ait oublié de le faire
if self.content != self.default and self.default == self.input:
self.default = self.content
if not self.error_txt and not ok:
self.error_txt = u'Valeur %s incorrecte pour le champ %s.' % (self.input, self.id)
return ok
def render(self, request, parser):
champ = html.UL(CLASS=self.CLASS)
champ.append(html.LI(CLASS="formulaire_id").append(self.prompt))
input = html.INPUT(type=self.input_type,name=self.id,value=self.default)
champ.append(html.LI(CLASS="formulaire_input").append(input))
if self.error_txt:
error = wikiutil.renderText(request, parser, self.error_txt)
champ.append(html.LI(CLASS="formulaire_error").append(error))
if self.error_msg:
request.add_msg(self.error_msg)
return champ
class MenuField(Field):
def __init__(self, id, prompt, fields):
Field.__init__(self, id, prompt)
self.fields = fields
def render(self, request, parser):
champ = html.UL(CLASS="formulaire_field_%s" % self.id)
champ.append(html.LI(CLASS="formulaire_id").append(self.prompt))
menu = html.SELECT(NAME=self.id, onchange='TestEtudes()')
for opt, legend in self.fields:
menu.append(html.OPTION(VALUE=opt).append(legend))
champ.append(menu)
if self.error_txt:
error = wikiutil.renderText(request, parser, self.error_txt)
champ.append(html.LI(CLASS="formulaire_error").append(error))
if self.error_msg:
request.add_msg(self.error_msg)
return champ
class PasswordField(Field):
def fill(self, post):
self.input = post.get(self.id, [''])[0]
self.input2 = post.get(self.id+'2',[''])[0]
def check(self):
self.error_txt= '' # Devrait pourtant être déjà vide
self.default = ''
if self.input == self.input2:
self.content = self.input
return True
else:
self.error_txt = u'Les deux mots de passe diffèrent'
return False
def render(self, request, parser):
champ = html.UL(CLASS="formulaire_field")
champ.append(html.LI(CLASS="formulaire_id").append(self.prompt))
input = html.INPUT(type=self.input_type,onchange="testPassword()", name=self.id)
champ.append(html.LI(CLASS="formulaire_input").append(input))
champ.append(html.LI().append('<img name="verdict" />'))
champ2 = html.UL(CLASS="formulaire_field")
champ2.append(html.LI(CLASS="formulaire_id").append('Retapez le mot de passe'))
input = html.INPUT(type=self.input_type, name=self.id+'2')
champ2.append(html.LI(CLASS="formulaire_input").append(input))
if self.error_txt:
error = wikiutil.renderText(request, parser, self.error_txt)
champ2.append(html.LI(CLASS="formulaire_error").append(error))
return u'%s\n%s\n' % (champ, champ2)
def is_name(self):
"""Vérifie que le champ input de l'objet passé en argument est un nom valide."""
analysed_content = unicodedata.normalize('NFKD', self.input)
try: stripped_content = analysed_content.encode('ASCII', 'ignore')
except UnicodeEncodeError: stripped_content = '<ugly utf-8>'
if re.match('[a-z][-a-z _]*', stripped_content.lower()):
return True
else:
self.error_txt = u"""Valeur %s incorrecte pour le champ %s.
Seules les lettres (éventuellement accentuées),
l'espace et le tiret '-' sont acceptés.""" % (self.input, self.id)
return False
def is_chbre(self):
if re.match('[abcghijp][0-9]{1,3}[gd]?', self.input.lower()):
return True
else:
self.error_txt = u"""Valeur %s incorrecte pour votre chambre, celle-ci doit être de la forme Bxxx, Bxxxg ou Bxxxd, avec B la première lettre de votre batiment (P pour le Pavillon des Jardins), xxx le numéro de votre chambre et g ou d si vous êtes dans un T1 bis selon que vous soyiez à gauche ou à droite"""
return False
def is_phonenumber(self):
chiffres = self.input.replace('.', '')
if re.match('(0|\+[0-9][0-9])[0-9]{9}', chiffres):
return True
else:
self.content = ''
return True
def is_dns(self):
dns = self.input.lower()
if re.match('[a-z][-a-z0-9_]*', dns):
return True
else:
return False
def get_mac(ip):
"Récupère la mac"
mac= 'XX' + ':XX'*5
if AddrInNet(ip, '138.231.136.0/21'):
status, mac = gso("/usr/sbin/arp %s | perl -nle '{print $& if /00(:[0-9a-f]{2}){5}/}'" % ip) # gruik, gruik, grUUIIIk !
mac= mac.strip()
return mac
def is_valid_mac(self):
mac = self.input.lower()
if re.search("00((:|-|)[a-f0-9][a-f0-9]){5}", mac):
return True
else:
self.default = get_mac(self.ip)
return False
class Formulaire():
"""Une classe qui représente un formulaire.
Elle contient un champs ``champs'', qui contient une liste de
Fields, qui est la liste des champs qui doivent être demandés (dans
le bon ordre l'ordre).
"""
def __init__(self, champs):
self.champs = champs
def render(self, request, parser):
url = request.page.url(request)
ret = html.FORM(action=url, NAME="preinscription")
ret.append(html.INPUT(type='hidden', name='action', value='inscription'))
f = html.UL(CLASS="formulaire_preinscription")
for field in self.champs:
champ = field.render(request, parser)
f.append(html.LI().append(champ))
ret.append(f)
ret.append(html.HR(CLASS= "invisiblesep"))
ret.append(html.INPUT(type="submit", name="inscrire", value=u"Me préinscrire"))
return unicode(ret)
def check(self, post):
u"""Vérifie les paramètres postés par l'utilisateur.
Vérifie que toutes les entrées du formulaire (formulaire.fields)
sont présentes et bien valides, (en appelant check() pour chaque
champs).
"""
errors = []
for field in self.champs:
field.fill(post)
for field in self.champs:
if not field.check():
errors.append(field.id)
# est-ce que les test unitaires passent ?
return errors
def _create_inscription_form(request):
"""Renvoie les champs du formulaire inscription pour créer un Formulaire."""
ip = request.remote_addr
mac_field = Field("mac", u"Adresse physique de votre carte réseau", check=is_valid_mac, default=get_mac(ip))
mac_field.ip = ip
return [
# informations personnelles
Field("nom", "Nom", check=is_name),
Field("prenom", u"Prénom", check=is_name),
Field("chbre", u"Chambre", check=is_chbre),
MenuField('etablissement', u"Établissement d'études", ETABLISSEMENTS),
Field("etablissement_autre", u"Précisez votre établissement d'études",
CLASS='formulaire_field_etablissement_autre'),
MenuField('annee_ens', u"Année scolaire à l'ENS", ANNEE_ENS),
MenuField('annee', u"Choisissez votre année scolaire", ANNEE_ETUDE),
MenuField('section_ens', u"Section", SECTIONS_ENS),
MenuField('labo', u"Laboratoire", LABOS),
Field("section", u"Précisez votre section", CLASS="formulaire_field_section"),
Field("tel", u"Numéro de téléphone", check=is_phonenumber),
# compte crans
PasswordField("pass", u"Mot de passe", input_type='password'),
# Votre machine
Field("dns", u"Nom de votre ordinateur", check=is_dns),
mac_field
]
def _perform_inscription(request, formulaire):
rand=random.Random()
rand.seed()
for i in range(1000):
numero = rand.randint(100000, 999999)
if not os.path.exists( os.path.join( PREINSCRIPTION_DIR, str( numero ) ) ):
break
else: # JAMAIS JAMAIS exécuté
request.theme.add_msg(u"Erreur côté serveur, merci de réessayer", "error")
return request.page.send_page()
print "ok"
fichier = open (os.path.join( PREINSCRIPTION_DIR, str( numero ) ), 'w')
for field in formulaire.champs:
# if type(field) == Field:
content = field.content.split('\n')[0]
fichier.write(u'%s: %s\n' % (field.id, content))
fichier.close()
print "ok 2"
# tests of redundancy
request.theme.add_msg(u"Votre préinscription est réalisée, elle a le numero %d" % numero)
return Page(request, "VieCrans/PreinscriptionOk").send_page()
# form = {}
# for field in formulaire.champs:
# if type(field) == Field:
# form[field.id] = field.content
# adh = {}
# adh['nom'] = form['nom']
# adh['prenom'] = form['prenom']
# adh['chbre'] = form['chbre']
# adh['tel'] = form['tel']
# if form['etablissement'] == 'ENS':
# if int(form['annee_ens']) > 4:
# adh['etudes'] = "ENS\n%(annee_ens)s\n%(labo)s" % form
# else:
# adh['etudes'] = "ENS\n%(annee_ens)s\n%(section_ens)s" % form
# else:
# adh['etudes'] = "%(etablissement)s\n%(annee)s\n%(secion)s" %form
#
# machine = {}
# machine['macAdress'] = form['mac']
# machine['host'] = form['dns']
def execute(pagename, request):
request.page = Page(request, pagename)
request.formatter.setPage(request.page)
request.loadTheme('crans-www')
formulaire = Formulaire(_create_inscription_form(request))
post = request.form
parser = wikiutil.searchAndImportPlugin(request.cfg, "parser", request.page.pi['format'])
if not request.dicts.has_member("GroupeAdmin", request.user.name) and not request.user == 'AntoineDurandGasselin':
request.theme.add_msg(u"Non, car tu es méchant", "error")
return(request.page.send_page())
if post.has_key('inscrire'):
if formulaire.check(post) == []:
return(_perform_inscription(request, formulaire))
else:
request.theme.add_msg(u'des erreurs', 'error')
request.emit_http_headers()
request.theme.send_title(u"Formulaire de préinscription", pagename=pagename, html_head='<script type="text/javascript" src="/wiki/crans-www/js/passwd.js"></script>')
request.write(request.formatter.startContent("content"))
form = formulaire.render(request, parser)
# THIS IS A BIG HACK. IT NEEDS TO BE CLEANED UP
request.write(form)
request.write(request.formatter.endContent())
request.theme.send_footer(pagename)
request.theme.send_closing_html()