# -*- coding: utf8 -*- import re from pyramid.response import Response,FileResponse from pyramid.renderers import render, get_renderer from pyramid.view import ( view_config, forbidden_view_config, ) from pyramid.security import ( remember, forget, ) from pyramid.httpexceptions import ( HTTPFound, ) from ..security import groupfinder from pyramid_mailer import get_mailer from pyramid_mailer.message import Message, Attachment from datetime import * from dateutil.relativedelta import relativedelta from email.utils import formataddr from docutils.core import publish_parts from time import strftime from user_agents import parse from markdown2 import Markdown import math import os.path import subprocess import pkg_resources import tempfile import transaction import hashlib import hmac import json from PIL import Image import shutil import locale from datetime import datetime import magic from ..models.default import * from ..models.reservation import * def to_age(dob, type): today = date.today() age = relativedelta(today, dob) if type == '>': if age.years >= 0: a = '%s ans %s mois' % (age.years, age.months) else: a = '???' else: if age.years < 0 or age.years < 0: if age.years <= -1: a = '%sa %sm' % (age.years, age.months) else: a = '%sm' % (age.months) else: a = '' return a.replace('-', '') def to_decimal(x): import decimal return decimal.Decimal(str(x)) def to_sha1(message): return hashlib.sha1(message.encode('utf-8')).hexdigest() def to_int(x): try: number = int(x.replace(',', '.')) return number except ValueError: return 0 def to_euro(x): """Takes a float and returns 12 345,67 €""" locale.setlocale(locale.LC_ALL, '') return locale.currency(x, True, True) def to_euroz(x): """Takes a float and returns 12 345,67 € if non zero""" if x == 0: return "" else: return to_euro(x) def to_percent(x): """Takes a float and returns a string""" return (u"%.2f " % x).replace('.', ',') + "%" def to_date(date_text): try: madate = datetime.strptime(date_text, '%d/%m/%Y') if madate.year >= 1900: return madate else: return False except ValueError: return False def to_time(date_text): try: madate = datetime.strptime(date_text, '%H:%M') return madate except ValueError: return False def isMinor(dob): today = date.today() age = relativedelta(today, dob) if age.years < 18: minor = True else: minor = False return minor def toSemaine(strDate): chaine = strDate.replace(' Feb', ' Fév') chaine = chaine.replace(' Mar', ' Mars') chaine = chaine.replace(' Apr', ' Avr') chaine = chaine.replace(' May', ' Mai') chaine = chaine.replace(' Jun', ' Juin') chaine = chaine.replace(' Jul', ' Juil') chaine = chaine.replace(' Aug', ' Août') chaine = chaine.replace(' Dec', ' Déc') chaine = chaine.replace('Mon', 'Lun') chaine = chaine.replace('Tue', 'Mar') chaine = chaine.replace('Wed', 'Mer') chaine = chaine.replace('Thu', 'Jeu') chaine = chaine.replace('Fri', 'Ven') chaine = chaine.replace('Sat', 'Sam') chaine = chaine.replace('Sun', 'Dim') return chaine # - - - - - - - - - - - - - - - - - - - - - - - - - - def envoyerMail(request, destinataires, objet, corps): # lire l'adresse email de l'agence logged_in = request.authenticated_userid if logged_in is None: # user anonyme agence_email = request.registry.settings['monaem.admin_email'] else: # user connecté, lire son numéro d'agence agence = get_eleve_agence(request, logged_in) agence_email = agence.email if agence else request.registry.settings['monaem.admin_email'] message = Message(subject=u"[MARIETTON] %s" % objet, sender=agence_email, recipients=destinataires, html=corps) mailer = get_mailer(request) mailer.send_immediately(message, fail_silently=True) @view_config(route_name='affiche_message', renderer='../templates/default/affiche_message.pt') def affiche_message(request): login = request.matchdict['login'] messages = request.session.pop_flash() return { 'page_title': "Demande effectuée", 'login': login, 'messages': messages, 'url_identification': request.route_url('login_as', login=login) } @view_config(route_name='agence', renderer='../templates/default/agence.pt', permission='view') def agence(request): """Mon agence""" logged_in = request.authenticated_userid # get agence item = get_eleve_agence(request, logged_in) return { 'page_title': "Mon agence MARIETTON", 'item': item, } @view_config(route_name='change_details', renderer='../templates/default/change_details.pt', permission='view') def change_details(request): url = request.route_url('change_details') logged_in = request.authenticated_userid member = get_eleves_by_code(request, logged_in) if 'form.submitted' in request.params: new_values = {} for param, db_value in member.items(): if param in request.params and request.params[param] != db_value: new_values[param] = request.params[param] if new_values: update_details(request, logged_in, new_values) request.session.flash(u"Vos coordonnées ont été mises à jour avec succès.", 'success') # si élève appartient à une agence if member.AGENCE > 0: # envoyer un message à la secrétaire body = getMessageText(request, 'changeCoord', member.NOMPREN, logged_in, '', '', '') agence_email = get_eleve_agence(request, logged_in).email destinataires = [agence_email] envoyerMail(request, destinataires, "Changement de coordonnées", body) return HTTPFound(location=request.route_url('home')) return { 'page_title': "Changer mes coordonnées", 'url': url, 'member': member, } @view_config(route_name='change_password', renderer='../templates/default/change_password.pt', permission='view') def change_password(request): url = request.route_url('change_password') logged_in = request.authenticated_userid message = '' member = get_eleves_by_code(request, logged_in) if 'form.submitted' in request.params: old_password = request.params['old_password'] new_password = request.params['new_password1'] new_password2 = request.params['new_password2'] if len(new_password) >= 8 and len(new_password) <= 20: if re.match(r'^(?=.*\d)(?=.*[!@#$%^&*\_\-\.\+,;\:\\/§à\]\[\?\{\}])(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z!@#$%^&*\_\-\.\+,;\:\\/§à\]\[\?\{\}]{8,}$',new_password): if new_password == new_password2 : if member.mdp_hash == to_sha1(old_password): update_password(request, logged_in, new_password) request.session.flash(u"Votre mot de passe a été mis à jour avec succès.", 'success') return HTTPFound(location=request.route_url('home')) else: message = "Le mot de passe fourni est incorrect." else: message = "Le mot de passe et sa confirmation ne sont pas identiques." else: message = "Le mot de passe doit contenir au minimum une lettre, un nombre,un majuscule, un minuscle, et un caractère speciaux." else: message = "La longueur du mot de passe n'est pas respectée, minimum 8, maximum 20." return { 'page_title': "Changer mon mot de passe", 'url': url, 'member': member, 'message': message, } @view_config(route_name='date_examen', renderer='../templates/default/date_examen.pt', permission='view') def date_examen(request): """ Date examen view """ logged_in = request.authenticated_userid item = get_date_examen(request, logged_in) return { 'page_title': "Prochaine date d'examen", 'item': item, } @view_config(route_name='email_password', renderer='../templates/default/email_password.pt') def email_password(request): url = request.route_url('email_password') message = '' login = '' date_naissance = '' if 'form.submitted' in request.params: login = request.params['login'] date_naissance = request.params['date_naissance'] member = get_eleves_by_date_nais(request, login, date_naissance) if member: if member.email: lien = update_membre_mdp_oublie(request, login) # Fabrication du corps du Message body = getMessageText(request, 'emailPassword', member.NOMPREN, lien, '', '', '') destinataires = [member.email] envoyerMail(request, destinataires, "Oubli de mot de passe", body) request.session.flash( u"Le lien permettant de redéfinir votre mot de passe vous a été envoyé à l'adresse : %s." % member.email, 'success') return HTTPFound(location=request.route_url('affiche_message', login=login)) else: message = "L'adresse e-mail de cet élève n'est pas renseignée. Contactez votre agence." else: message = "Aucun élève trouvé avec ce code et cette date de naissance. Veuillez réessayer." return { 'page_title': "Mot de passe oublié ?", 'url': url, 'message': message, 'login': login, 'date_naissance': date_naissance, } @view_config(route_name='email_code', renderer='../templates/default/email_code.pt') def email_code(request): url = request.route_url('email_code') message = '' if 'form.submitted' in request.params: name = request.params['name'] forname = request.params['forname'] birthday = request.params['birthday'] member = get_eleves_by_name_date_nais(request, name, forname, birthday) if not member: message = "Aucun utilisateur trouvé avec ce nom, prenom et cette date de naissance. Veuillez réessayer." else: # a member has been found if member.email: # Fabrication du corps du Message body = getMessageText(request, 'emailCode', member.NOMPREN, member.CD_CLI, '', '', '') destinataires = [member.email] envoyerMail(request, destinataires, "Oubli de code élève", body) request.session.flash(u"Votre code élève vous a été envoyé à l'adresse : %s." % member.email) return HTTPFound(location=request.route_url('affiche_message', login=member.CD_CLI)) else: message = "L'adresse e-mail de ce compte n'est pas renseignée. Veuillez contacter votre agence." return { 'page_title': "Code élève oublié ?", 'url': url, 'message': message, } @view_config(route_name='stages_reservation', renderer='../templates/default/stages_reservation.pt', permission='view') def stages_reservation(request): std = { 'POINT' : { 'title' : "RECUPERATION DE POINTS", 'link' : 2763 }, 'PEM125' : { 'title' : "PRISE EN MAIN 125", 'link' : 2765 }, 'PASSERELLE' : { 'title' : 'PASSERELLE A2 à A', 'link' : 2766 }, 'B96' : { 'title':'B96', 'link' : 2786 } } logged_in = request.authenticated_userid url = request.route_url('stages_reservation') eleve = get_eleves_by_code(request, logged_in) permis = eleve.PERMIS_DEMANDE stages = get_stages_by_type(request, eleve.FORMULE,None,15) if 'form.submitted' in request.params: params = dict(request.params) cd_cli = logged_in new_stage = get_stage_by_id(request, params['stage_id']) if new_stage.dispo <= 0: request.session.flash(u"Ce stage n’est plus disponible", 'danger') return HTTPFound(location=request.route_url('stages_reserves')) else: debut_stage = ins_stage_eleve(request, eleve.FORMULE, new_stage.stage_id, cd_cli, eleve.NOM, eleve.PRENOM) if debut_stage != None: # si déjà inscrit, retourne aux dispo request.session.flash(u"Vous êtes déjà inscrit(e) au stage du %s." % debut_stage.strftime("%d-%m-%Y"), 'danger') else: nompren = "%s %s %s" % (eleve.CIVILITE, eleve.NOM, eleve.PRENOM) body = getConfirmText(request, eleve.FORMULE, nompren, cd_cli, '%s au %s à %s' % (new_stage.debut.strftime("%d-%m-%Y"), new_stage.fin.strftime("%d-%m-%Y"), new_stage.debut.strftime("%Hh%M")), new_stage.lieu1, new_stage.lieu2) # envoyer un message à l'élève et la secrétaire agence_email = get_eleve_agence(request, cd_cli).email destinataires = [eleve.email, agence_email,] envoyerMail(request, destinataires, "Votre réservation pour le stage de %s" %std[eleve.FORMULE]['title'], body) request.session.flash(u"Vous avez réservé votre date de stage le %s à %s " % (new_stage.debut.date().strftime("%d-%m-%Y"), new_stage.fin.strftime("%d-%m-%Y")), 'success') return HTTPFound(location=request.route_url('home')) return { 'eleve': eleve, 'message': "", 'link': std[eleve.FORMULE]['link'], 'stages': stages, 'url': url, 'page_title': "Mon espace", } @view_config(route_name='stages_dates', renderer='../templates/default/stages_dates.pt', permission='view') def stages_dates(request): logged_in = request.authenticated_userid url = request.route_url('stages_dates') eleve = get_eleves_by_code(request, logged_in) items = get_eleve_stage(request, logged_in) permis = eleve.PERMIS_DEMANDE std = { 'POINT' : { 'title' : "RECUPERATION DE POINTS", 'link' : 2763 }, 'PEM125' : { 'title' : "PRISE EN MAIN 125", 'link' : 2765 }, 'PASSERELLE' : { 'title' : 'PASSERELLE A2 à A', 'link' : 2766 }, 'B96' : { 'title':'B96', 'link' : 2786 } } diff = False nbdaysbefore_stage = 15 stages = [] if items: stage = items[0] debut_en_clair = 'Il commence le %s.' % stage.debut_en_clair lieu_stage = 'VAUGNERAY' if permis[:1] == 'A': # and stage.date_debut < datetime(2016,11,20): debut_en_clair = '' if eleve.FORMULE == 'POINT': if stage.groupe == 'A': lieu_stage = 'CHARPENNES' stage_startdate = datetime.strptime(str(stage.stage_debut), '%d-%m-%Y').date() datenow = datetime.now().date() nbdaysbefore_stage = stage_startdate - datenow if stage.debut_en_clair: diff = nbdaysbefore_stage.days > 1 and eleve.FORMULE in ['B96', 'PEM125', 'PASSERELLE', 'POINT'] else: stage = items debut_en_clair = '' lieu_stage = '' stages = get_stages_by_type(request, eleve.FORMULE,stage_startdate.strftime('%Y-%m-%d'),nbdaysbefore_stage.days) if 'form.submitted' in request.params: params = dict(request.params) cd_cli = logged_in new_stage = get_stage_by_id(request, params['stage_id']) if items: stage = items[0] else: stage = items diffdate = new_stage.debut.date() - datetime.strptime(str(stage.stage_debut), '%d-%m-%Y').date() if diffdate.days == 0: request.session.flash(u"Vous êtes déjà inscrit(e) au stage du %s." % stage.stage_debut, 'danger') return HTTPFound(location=request.route_url('stages_dates')) else: stage_ligne = dict(get_stage_ligne_by_cd_cli(request, cd_cli, stage.groupe)) # Delete stage_ligne query = """ CALL spDel_PLA_STAGE_LIGNES(:type,:semaine,:groupe,:cd_cli)""" request.dbsession.execute(query, {'type': stage_ligne['TYPE'], 'semaine': stage_ligne['SEMAINE'], 'groupe': stage_ligne['GROUPE'], "cd_cli": stage_ligne['CD_CLI']}) debut_stage = ins_stage_eleve(request, eleve.FORMULE, new_stage.stage_id, cd_cli, eleve.NOM, eleve.PRENOM) if debut_stage != None: # si déjà inscrit, retourne aux dispo request.session.flash(u"Vous êtes déjà inscrit(e) au stage du %s." % debut_stage.strftime("%d-%m-%Y"), 'danger') else: nompren = "%s %s %s" % (eleve.CIVILITE, eleve.NOM, eleve.PRENOM) body = getConfirmText(request, eleve.FORMULE, nompren, cd_cli, '%s au %s à %s' % (new_stage.debut.strftime("%d-%m-%Y"), new_stage.fin.strftime("%d-%m-%Y"), new_stage.debut.strftime("%Hh%M")), new_stage.lieu1, new_stage.lieu2) # envoyer un message à l'élève et la secrétaire agence_email = get_eleve_agence(request, cd_cli).email destinataires = [eleve.email, agence_email,] envoyerMail(request, destinataires, "Votre réservation pour le stage de %s" %std[eleve.FORMULE]['title'], body) request.session.flash(u"Vous avez modifié votre date de stage le %s à %s " % (new_stage.debut.date().strftime("%d-%m-%Y"), new_stage.fin.strftime("%d-%m-%Y")), 'success') return HTTPFound(location=request.route_url('home')) return { 'eleve': eleve, 'message': "", 'debut_en_clair': debut_en_clair, 'stage': stage, 'lieu_stage': lieu_stage, 'link': std[eleve.FORMULE]['link'], 'stages': stages, 'url': url, 'diff': diff, 'page_title': "Mon espace", } @view_config(route_name='home', renderer='../templates/default/home.pt', permission='view') def home(request): """Home view""" logged_in = request.authenticated_userid url = request.route_url('home') eleve = get_eleves_by_code(request, logged_in) permis = eleve.PERMIS_DEMANDE suivi_list = ['B', 'B78', 'A1', 'A2', 'POINT', 'AL', 'A','AM'] if permis in suivi_list: hasSuivi = True else: hasSuivi = False # lire le carnet de rendez-vous nb_rdv = len(get_rdv_by_code(request, logged_in)) # lire les justifs justifs = get_eleve_docs(request, logged_in, 'JUST') docs = get_eleve_docs(request, logged_in, 'DOC') diff = False items = get_eleve_stage(request, logged_in) if items: stage = items[0] debut_en_clair = 'Il commence le %s.' % stage.debut_en_clair lieu_stage = 'VAUGNERAY' if permis[:1] == 'A': # and stage.date_debut < datetime(2016,11,20): debut_en_clair = '' if eleve.FORMULE == 'POINT': if stage.groupe == 'A': lieu_stage = 'CHARPENNES' if stage['type'] == 'B': if stage['groupe'] == 'J': lieu_stage = 'VAISE' elif stage['groupe'] == 'K' : lieu_stage = 'CHARPENNES' elif stage['groupe'] == 'L' : lieu_stage = "PRESQU’ILE" if stage.debut_en_clair: startedDateStage = datetime.strptime(str(stage.stage_debut), '%d-%m-%Y').date() dateNow = datetime.now().date() diffDate = startedDateStage - dateNow diff = diffDate.days > 1 and eleve.FORMULE in ['B96', 'PEM125', 'PASSERELLE', 'POINT'] else: stage = items debut_en_clair = '' lieu_stage = '' examen = get_date_examen(request, logged_in) # lire le compte items = get_eleve_cpt_extrait(request, logged_in) # calculer le solde de l'élève sum_to_pay = 0 sum_paid = 0 for item in items: sum_to_pay += float(item.DEBIT) sum_paid += float(item.CREDIT) solde = sum_to_pay - eleve.encours_societe - sum_paid # get date de fin code dates = get_dates_fin_validite(request, logged_in) if dates: date_fin_code = dates[0].date_fin_code date_fin_vm = dates[0].date_fin_vm else: date_fin_code = None date_fin_vm = None # Lire toutes les FAQS sauf les 'INTERNE' faqs = get_faqs(request, -1) # calcul des clés élève d = date.today() # calculer le jour de l'année d'auj yearday = (d - date(d.year, 1, 1)).days + 1 keyE = int(yearday * d.year / d.day * eleve.CD_CLI) param_suivi = 'codeE=%s&key=%s&En=%s&MnR=%s&filiere=%s&agence=%s&permis=%s&formule=%s' % ( str(eleve.CD_CLI), keyE, eleve.NOMPREN, eleve.CD_MON, eleve.filiere, eleve.AGENCE, eleve.PERMIS_DEMANDE, eleve.FORMULE) suivi_pedago_list = ['CE', 'C', 'D', 'DE', 'BE', 'BEPCA', 'C1', 'D1', 'GL', 'B96'] if permis in suivi_pedago_list: hasOutilPedago = True else: hasOutilPedago = False return { 'page_title': "Mon espace", 'nb_rdv': nb_rdv, 'stage': stage, 'examen': examen, 'faqs': faqs, 'eleve': eleve, 'reservation' : eleve.FORMULE in ['B96', 'PEM125', 'PASSERELLE', 'POINT'], 'today': strftime("%d/%m/%Y"), 'solde': solde, 'remain_to_pay': to_euro(solde * -1), 'date_fin_code': date_fin_code, 'date_fin_vm': date_fin_vm, 'has_email': bool(eleve.email), 'debut_en_clair': debut_en_clair, 'lieu_stage': lieu_stage, 'hasSuivi': hasSuivi, 'justifs': justifs, 'docs': docs, 'param_suivi': param_suivi, 'hasOutilPedago': hasOutilPedago, 'diff': diff, 'logged_in': str(logged_in) } @view_config(route_name='fiche_inscription', renderer='../templates/default/fiche_inscription.pt', permission='view') def fiche_inscription(request): """ Fiche inscription view """ logged_in = request.authenticated_userid eleve = get_eleves_by_code(request, logged_in) return { 'page_title': "Fiche d'inscription", 'item': eleve, } @view_config(route_name='login', renderer='../templates/default/login.pt', permission='view') @view_config(route_name='login_as', renderer='../templates/default/login.pt', permission='view') @forbidden_view_config(renderer='../templates/default/login.pt') def login(request): current_route_path = request.current_route_path() if 'login_as' in current_route_path: login = request.matchdict['login'] login_url = request.route_url('login_as', login=login) else: login = '' login_url = request.route_url('login') referrer = request.url if referrer == login_url: referrer = '/' # never use the login form itself as came_from came_from = request.params.get('came_from', referrer) message = '' password = '' if 'form.submitted' in request.params: login = request.params['login'] password = request.params['password'] record = get_eleves_by_code(request, login) if record: # controler que la fiche n'est pas cloturee if record.STATUT < 10: # On encode le password pour ne plus avoir de plantage avec les "é" if (record.mdp_hash == to_sha1(password)): # get user agent string from request ua_string = request.user_agent user_agent = parse(ua_string) device = str(user_agent).split('/') update_last_connection(request, login, device[0]) # force le commit car il ne se fait pas automatiquement après l'update transaction.commit() headers = remember(request, login) return HTTPFound(location=came_from, headers=headers) else: message = "Le code élève ou le mot de passe est incorrect. Identification échouée." else: message = "Votre espace client a été clôturé. Accès refusé." else: message = "Le code élève ou le mot de passe est incorrect. Identification échouée." return { 'page_title': "Se connecter", 'message': message, 'url': login_url, 'came_from': came_from, 'login': login, 'password': password, } @view_config(route_name='logout') def logout(request): headers = forget(request) request.session.flash(u"Vous avez bien été déconnecté.", 'success') return HTTPFound(location=request.route_url('login', login=''), headers=headers) @view_config(route_name='connecter_a', permission='manage') def connecter_a(request): # paramètre fourni ? login = request.matchdict["login"] if len(login) > 0: request.session.invalidate() headers = forget(request) headers = remember(request, login) return HTTPFound(location="/", headers=headers) else: return HTTPFound(location="/") @view_config(route_name='redefinir_mdp', renderer='..//templates/default/redefinir_mdp.pt') def redefinir_mdp(request): lien = request.matchdict["lien"] # tester si le champ "motdepasse_oublie" est encore valide message = '' if is_lien_mdp_oublie(request, lien) == True: membre = get_mdp_oublie_infos(request, lien) if 'form.submitted' in request.params: new_password = request.params['new_password1'] if len(new_password) >= 8 and len(new_password) <= 20: if re.match(r'^(?=.*\d)(?=.*[!@#$%^&*\_\-\.\+,;\:\\/§à\]\[\?\{\}])(?=.*[a-z])(?=.*[A-Z])[0-9a-zA-Z!@#$%^&*\_\-\.\+,;\:\\/§à\]\[\?\{\}]{8,}$',new_password): new_password2 = request.params['new_password2'] if new_password == new_password2 : update_password(request, membre.CD_CLI, new_password) request.session.flash(u"Votre mot de passe a été mis à jour avec succès.", 'success') return HTTPFound(location=request.route_url('login')) else: message = "Le mot de passe et sa confirmation ne sont pas identiques." else: message = "Le mot de passe doit contenir au minimum une lettre, un nombre,un majuscule, un minuscle, et un caractère speciaux." else: message = "La longueur du mot de passe n'est pas respectée, minimum 8, maximum 20." else: return HTTPFound(location=request.route_url('login')) return { 'page_title': "Redéfinir le mot de passe", 'message': message, } @view_config(route_name='show_iframe', renderer='../templates/default/show_iframe.pt', permission='view') def show_iframe(request): param = request.matchdict['param'] logged_in = request.authenticated_userid eleve = get_eleves_by_code(request, logged_in) if param == 'suivi': # calcul des clés élève d = date.today() # calculer le jour de l'année d'auj yearday = (d - date(d.year, 1, 1)).days + 1 keyE = int(yearday * d.year / d.day * eleve.CD_CLI) param = 'codeE=%s&key=%s&En=%s&MnR=%s&filiere=%s&agence=%s&permis=%s&formule=%s' % ( str(eleve.CD_CLI), keyE, eleve.NOMPREN, eleve.CD_MON, eleve.filiere, eleve.AGENCE, eleve.PERMIS_DEMANDE, eleve.FORMULE) iframe_src = "https://www.suivi-eleve.marietton.com/suivi.php?%s" % param else: # videos pédagogiques param = 'codeE=%s&filiere=%s&agence=%s' % (str(eleve.CD_CLI), eleve.filiere, eleve.AGENCE) iframe_src = "https://suivi-eleve.marietton.com/contenu-pedago/index.php?%s" % param return { 'page_title': "", 'iframe_src': iframe_src, } @view_config(route_name='faq_view', renderer='../templates/default/faq_view.pt') def faq_view(request): faq_id = request.matchdict['faq_id'] faq = get_faqs(request, faq_id) intitule = faq.intitule # insèrer le path de static/img img_path = 'image:: %s/static/img/' % request.application_url texte = faq.texte.replace('image:: static/img/', img_path) # convertir reST en HTML texte = publish_parts(texte, writer_name='html')['html_body'] return { 'page_title': intitule, 'texte': texte, 'faq_id': faq_id, } @view_config(route_name='member_search', renderer='../templates/default/member_search.pt', permission='manage') def member_search(request): url = request.route_url('member_search') message = '' members = [] name = '' if 'form.submitted' in request.params: name = request.params['name'] members = get_eleves_by_name(request, name) if len(members) == 0: message = "Elève non trouvé : %s" % name return { 'page_title': "Rechercher un élève", 'url': url, 'message': message, 'members': members, 'name': name, } @view_config(route_name='ajax_dept_nais') def ajax_dept_nais(request): recherche = request.GET['recherche'] # lire les departements commencant par items = get_departements(request, recherche) liste = [] for row in items: d = row.libelle + " | " + row.code liste.append(d) return Response(json.dumps(liste)) @view_config(route_name='ajax_codepostal') def ajax_codepostal(request): recherche = request.GET['recherche'] # lire les codes postaux commencant par items = get_codespostaux(request, recherche) liste = [] for row in items: d = row.code_postal + " - " + row.libelle liste.append(d) return Response(json.dumps(liste)) def getMessageText(request, ref, nomEleve, codeEleve, dateRDV, Lieu1RDV, Lieu2RDV): if ref == 'emailPassword': body = """

Bonjour %s,

Vous avez oublié votre mot de passe. Par mesure de sécurité, nous vous demandons de bien vouloir le réinitialiser en cliquant sur ce lien :

%s

Ce lien ne sera valable que pendant 48 heures.

""" % (nomEleve, request.route_url('redefinir_mdp', lien=codeEleve)) elif ref == 'emailCode': body = """

Bonjour %s,

Pour faire suite à votre demande, voici le code élève de votre compte MARIETTON : %s

Merci de bien vouloir le mémoriser pour une connexion ultérieure.

""" % (nomEleve, codeEleve) elif ref == 'annuleRDV': body = """

Bonjour,

L'élève : %s (%s),

vient d'annuler son rendez-vous %s du planning %s.

%s

""" % (nomEleve, codeEleve, dateRDV, Lieu1RDV, Lieu2RDV) elif ref == 'envoiPassRousseau': body = """

Bonjour %s,

L’équipe Marietton vous remercie pour votre inscription.

Vos identifiants de connexion au site [https://www.marietton.com/salle-de-code-acces.php](https://www.marietton.com/salle-de-code-acces.php) sont les suivants :

votre identifiant : %s

votre mot de passe : %s

Nous vous souhaitons à présent une agréable formation.

""" % (nomEleve, codeEleve, Lieu1RDV, Lieu2RDV) elif ref == 'dispoPassRousseau': body = """

Bonjour %s,

L’équipe Marietton vous remercie pour votre inscription.

Nous vous invitons à contacter communication@marietton.com sur la disponibilité des PASS Rousseau.

""" % ( nomEleve) else: # message changeCoord body = """

Bonjour,

L'élève : %s (%s),

vient de changer ses coordonnées via son espace élève.

""" % (nomEleve, codeEleve) # ajouter salutation corps = """ %s

Cordialement,
Espace Client MARIETTON

""" % body return corps def getConfirmText(request, ref, nomEleve, codeEleve, dateRDV, lieu1RDV, lieu2RDV): # lire le message selon la référence du tarif body = get_messageConformation(request, ref) # convertir confirmation de mardown en HTML if body: markdowner = Markdown() body = markdowner.convert(body) # remplacer les mots clés body = body.replace("!civNomPrenom!", nomEleve) body = body.replace("!codeClient!", str(codeEleve)) body = body.replace("!dateRDV!", dateRDV) body = body.replace("!lieu1RDV!", lieu1RDV) body = body.replace("!lieu2RDV!", lieu2RDV) else: body = 'Texte de confirmation non trouvé pour %s' % ref return body @view_config(route_name='justifs_list', renderer='../templates/default/justifs_list.pt', permission='view') def justifs_list(request): logged_in = request.authenticated_userid # initialiser la liste des justifs à télécharger init_eleve_justifs(request, logged_in) justifs = get_eleve_docs(request, logged_in, 'JUST') justifs_manquant = get_eleve_justifs_manquant(request, logged_in) return { 'page_title': "Justificatifs à télécharger", 'justifs': justifs, 'justifs_manquant': justifs_manquant, 'code_add': '', 'cd_cli' : logged_in } def downloadFile2Temp(input_file, input_name, ext_allowed): # récupère son extension input_extension = input_name.split('.')[-1] mime = magic.from_buffer(input_file.read(), mime=True) # extensions autorisées ? if mime not in ext_allowed: return "ERREUR: Le format du fichier n'est pas valide. Téléchargement impossible." # Finally write the data to a temporary file temp_file_path = os.path.join('/tmp/', input_name) # supprimer le fichier s'il existe déjà if os.path.exists(temp_file_path): os.remove(temp_file_path) input_file.seek(0) with open(temp_file_path, 'wb') as output_file: shutil.copyfileobj(input_file, output_file) # controler la taille du fichier < 4 Mo filesize = round(os.path.getsize(temp_file_path) / 1024) if filesize > 4096: os.remove(temp_file_path) return "ERREUR: La taille du fichier dépasse la limite autorisée. Téléchargement impossible." if input_extension in ['jpeg', 'jpg', 'png']: # using the Python Image Library (PIL) to resize an image resize_photos(temp_file_path) return temp_file_path def tempFile2Dossier(request, no_ligne, cd_cli, temp_file, filename, logged_in): # créer le répertoire du chantier path = '%s/%s' % (request.registry.settings['monaem.justifs_dir'], cd_cli) os.makedirs(path, exist_ok=True) filepath = os.path.join('%s/%s' % (path, filename)) # supprimer le fichier s'il existe déjà if os.path.exists(filepath): os.remove(filepath) # Finally move the temporary file to folder shutil.move(temp_file, filepath) filesize = round(os.path.getsize(filepath) / 1024) new_values = {} new_values['nom_fic'] = filename new_values['taille_fic'] = filesize new_values['cd_uti'] = 'WEB' update_eleve_justif(request, no_ligne, new_values) def resize_photos(image_file): # using the Python Image Library (PIL) to resize an image img_org = Image.open(image_file) # get the size of the original image width_org, height_org = img_org.size # set the resizing factor so the aspect ratio can be retained # factor > 1.0 increases size # factor < 1.0 decreases size factor = 0.75 width = int(width_org * factor) height = int(height_org * factor) # best down-sizing filter img_anti = img_org.resize((width, height), Image.ANTIALIAS) # split image filename into name and extension name, ext = os.path.splitext(image_file) # create a new file name for saving the result img_anti.save(image_file) return @view_config(route_name='doc_upload', renderer='../templates/default/doc_upload.pt', permission='view') def doc_upload(request): logged_in = request.authenticated_userid.upper() no_ligne = request.matchdict['no_ligne'] cd_cli = request.matchdict['cd_cli'] url = request.route_url("doc_upload", no_ligne=no_ligne, cd_cli=cd_cli) message = "" # lire le document à uploader justif = get_eleve_justifs_byligne(request, no_ligne) if justif is None: request.session.flash(u"Le justif %s est introuvable" % (noligne), 'danger') return HTTPFound(location=request.route_url("home", cd_cli=cd_cli)) url_retour = request.route_url('justifs_list') if 'form.submitted' in request.params: libelle_fic = None if 'libelle_fic' in request.params: new_values = {} new_values['libelle_fic'] = request.params['libelle_fic'] new_values['cd_uti'] = 'WEB' if 'nom_fic' in request.params: new_values['nom_fic'] = request.params['nom_fic'] update_eleve_justif(request, no_ligne, new_values) request.session.flash('Le e-photo est enregistré avec succès.', 'success') if request.POST['uploadfile'] != b'': # récupère le fichier download dans le dossier /tmp input_file = request.POST['uploadfile'].file input_name = request.POST['uploadfile'].filename input_parts = input_name.split('.') input_ext = input_parts[len(input_parts) - 1] ext_allowed = ['image/jpeg', 'image/jpg', 'image/png', 'application/pdf'] temp_file = downloadFile2Temp(input_file, input_name, ext_allowed) if temp_file[:8] == 'ERREUR: ': request.session.flash(temp_file, 'danger') return HTTPFound(location=url) # fabriquer le nom du document TODAY = date.today().strftime('%Y-%m-%d') filename = '%s_%s_%s_%s.%s' % (cd_cli, justif.type, justif.code, TODAY, input_ext) tempFile2Dossier(request, no_ligne, cd_cli, temp_file, filename, logged_in) request.session.flash('%s : Ce fichier est téléchargé avec succès.' % input_name, 'success') return HTTPFound(location=url_retour) return { 'page_title': "Télécharger un document", 'url': url, 'url_retour': url_retour, 'justif': justif, } @view_config(route_name='doc_edit', renderer='../templates/default/doc_edit.pt', permission='view') def doc_edit(request): logged_in = request.authenticated_userid.upper() no_ligne = request.matchdict['no_ligne'] cd_cli = request.matchdict['cd_cli'] url = request.route_url("doc_edit", no_ligne=no_ligne, cd_cli=cd_cli) message = "" # lire le document à uploader justif = get_eleve_justifs_byligne(request, no_ligne) if justif is None: request.session.flash(u"Le justif %s est introuvable" % (no_ligne), 'danger') return HTTPFound(location=request.route_url("fiche_eleve", cd_cli=cd_cli)) url_retour = request.route_url('justifs_list') if 'form.submitted' in request.params: new_values = {} new_values['cd_uti'] = 'WEB' if 'libelle_fic' in request.params: new_values['libelle_fic'] = request.params['libelle_fic'] update_eleve_justif(request, no_ligne, new_values) request.session.flash('Le fichier est validé avec succès.', 'success') return HTTPFound(location=url_retour) if 'form.erased' in request.params: new_values = {} new_values['cd_uti'] = 'WEB' new_values['nom_fic'] = '' new_values['libelle_fic'] = '' new_values['taille_fic'] = 0 # supprimer le fichier de la pièce file_path = '%s/%s/%s' % (request.registry.settings['monaem.justifs_dir'], cd_cli, justif.nom_fic) if os.path.exists(file_path): os.remove(file_path) update_eleve_justif(request, no_ligne, new_values) request.session.flash('Le fichier est effacé avec succès.', 'success') return HTTPFound(location=url_retour) if 'form.deleted' in request.params: # supprimer le fichier de la pièce file_path = '%s/%s/%s' % (request.registry.settings['monaem.justifs_dir'], cd_cli, justif.nom_fic) if os.path.exists(file_path): os.remove(file_path) delete_eleve_justif(request, no_ligne) request.session.flash('Le fichier est supprimé avec succès.', 'success') return HTTPFound(location=url_retour) return { 'page_title': "Modifier un document", 'url': url, 'url_retour': url_retour, 'justif': justif, } @view_config(route_name='download', renderer='', permission='view') def download(request): filename = request.matchdict['filename'] cd_cli = request.matchdict['cd_cli'] logged_in = request.authenticated_userid file_path = '%s/%s/%s' % (request.registry.settings['monaem.justifs_dir'], cd_cli, filename) if str(logged_in) != str(cd_cli) or not os.path.exists(file_path): return Response(status=404) else: #there is no overwrite response = FileResponse(file_path) response.headers['Content-Disposition'] = ("inline; filename=%s"%(filename)) return response