| @@ -51,16 +51,16 @@ keys = console | |||||
| keys = generic | keys = generic | ||||
| [logger_root] | [logger_root] | ||||
| level = INFO | |||||
| level = WARN | |||||
| handlers = console | handlers = console | ||||
| [logger_jm2l] | [logger_jm2l] | ||||
| level = DEBUG | |||||
| level = WARN | |||||
| handlers = | handlers = | ||||
| qualname = jm2l | qualname = jm2l | ||||
| [logger_sqlalchemy] | [logger_sqlalchemy] | ||||
| level = DEBUG | |||||
| level = WARN | |||||
| handlers = | handlers = | ||||
| qualname = sqlalchemy.engine | qualname = sqlalchemy.engine | ||||
| # "level = INFO" logs SQL queries. | # "level = INFO" logs SQL queries. | ||||
| @@ -1,3 +1,4 @@ | |||||
| # -*- coding: utf8 -*- | |||||
| from pyramid.authentication import AuthTktAuthenticationPolicy | from pyramid.authentication import AuthTktAuthenticationPolicy | ||||
| from pyramid.authorization import ACLAuthorizationPolicy | from pyramid.authorization import ACLAuthorizationPolicy | ||||
| from pyramid.config import Configurator | from pyramid.config import Configurator | ||||
| @@ -9,14 +10,52 @@ from pyramid.renderers import render_to_response | |||||
| from .models import DBSession, get_user, get_sponsors, get_exposants | from .models import DBSession, get_user, get_sponsors, get_exposants | ||||
| from .security import EntryFactory, groupfinder | from .security import EntryFactory, groupfinder | ||||
| from pyramid_mailer import mailer_factory_from_settings | from pyramid_mailer import mailer_factory_from_settings | ||||
| from pyramid_mailer.message import Attachment, Message | |||||
| import locale | import locale | ||||
| from .helpers import Sejour_helpers | from .helpers import Sejour_helpers | ||||
| from apscheduler.schedulers.background import BackgroundScheduler | |||||
| # Database access imports | |||||
| from pyramid.request import Request | |||||
| from mako.template import Template | |||||
| from .models import User | |||||
| import logging | |||||
| def add_renderer_globals(event): | def add_renderer_globals(event): | ||||
| event['mytrip'] = Sejour_helpers(event) | event['mytrip'] = Sejour_helpers(event) | ||||
| #@sched.scheduled_job('cron', day_of_week='sun', hour=22, minute=07) | |||||
| def mailer_tasks(config): | |||||
| # Send the Welcome Mail | |||||
| mailer = config.registry['mailer'] | |||||
| Contact = DBSession.query(User).filter(User.uid==1).one() | |||||
| request = Request.blank('/', base_url='http://jm2l.linux-azur.org') | |||||
| request.registry = config.registry | |||||
| for StaffUser in DBSession.query(User).filter(User.Staff == True): | |||||
| # Skip mail to contact | |||||
| if StaffUser==Contact: | |||||
| continue | |||||
| # Skip those that have no task assigned | |||||
| if len(filter(lambda k:not k.closed, StaffUser.task_assoc))==0: | |||||
| continue | |||||
| # Prepare Plain Text Message : | |||||
| Mail_template = Template(filename='jm2l/templates/mail_plain.mako') | |||||
| mail_plain = Mail_template.render(request=request, User=StaffUser, Contact=Contact, action="Tasks") | |||||
| print mail_plain | |||||
| # Prepare HTML Message : | |||||
| Mail_template = Template(filename='jm2l/templates/mail_html.mako') | |||||
| mail_html = Mail_template.render(request=request, User=StaffUser, Contact=Contact, action="Tasks") | |||||
| print mail_html | |||||
| # Prepare Message | |||||
| message = Message(subject="[JM2L] Rappel des Tâches pour les JM2L", | |||||
| sender="contact@jm2l.linux-azur.org", | |||||
| recipients=[StaffUser.mail], | |||||
| body=mail_plain, html=mail_html) | |||||
| message.add_bcc("spam@style-python.fr") | |||||
| mailer.send(message) | |||||
| def main(global_config, **settings): | def main(global_config, **settings): | ||||
| """ This function returns a Pyramid WSGI application. | """ This function returns a Pyramid WSGI application. | ||||
| """ | """ | ||||
| @@ -35,8 +74,12 @@ def main(global_config, **settings): | |||||
| authentication_policy=authentication_policy, | authentication_policy=authentication_policy, | ||||
| authorization_policy=authorization_policy | authorization_policy=authorization_policy | ||||
| ) | ) | ||||
| config.add_subscriber(add_renderer_globals, BeforeRender) | |||||
| config.add_subscriber(add_renderer_globals, BeforeRender) | |||||
| config.registry['mailer'] = mailer_factory_from_settings(settings) | config.registry['mailer'] = mailer_factory_from_settings(settings) | ||||
| sched = BackgroundScheduler() | |||||
| #sched.add_job(mailer_tasks, 'interval', minutes=1, args=[ config ]) | |||||
| sched.add_job(mailer_tasks, 'cron', day_of_week='fri', hour=18, args=[ config ]) | |||||
| sched.start() # start the scheduler | |||||
| config.add_renderer('json', JSON(indent=4)) | config.add_renderer('json', JSON(indent=4)) | ||||
| config.add_renderer('jsonp', JSONP(param_name='callback')) | config.add_renderer('jsonp', JSONP(param_name='callback')) | ||||
| config.set_session_factory(my_session_factory) | config.set_session_factory(my_session_factory) | ||||
| @@ -53,7 +96,7 @@ def main(global_config, **settings): | |||||
| # ICal Routes | # ICal Routes | ||||
| config.add_route('progr_iCal', '/{year:\d+}/JM2L.ics') | config.add_route('progr_iCal', '/{year:\d+}/JM2L.ics') | ||||
| # JSON Routes | # JSON Routes | ||||
| config.add_route('users_json', '/json-users') | config.add_route('users_json', '/json-users') | ||||
| config.add_route('tiers_json', '/json-tiers') | config.add_route('tiers_json', '/json-tiers') | ||||
| @@ -79,7 +79,7 @@ | |||||
| <div class="tabbable tabs-left" id="Interventions_tab"> | <div class="tabbable tabs-left" id="Interventions_tab"> | ||||
| <ul class="nav nav-tabs navbar" style="margin-bottom:0;"> | <ul class="nav nav-tabs navbar" style="margin-bottom:0;"> | ||||
| <li class="active"> <a href="#ResumePart" data-toggle="tab">Resumé</a> </li> | |||||
| <li class="active"> <a href="#ResumePart" data-toggle="tab">Resumé</a> </li> | |||||
| <li> <a href="#Conference" data-toggle="tab">Conférence</a> </li> | <li> <a href="#Conference" data-toggle="tab">Conférence</a> </li> | ||||
| <li> <a href="#Stand" data-toggle="tab">Stand</a> </li> | <li> <a href="#Stand" data-toggle="tab">Stand</a> </li> | ||||
| <li> <a href="#Atelier" data-toggle="tab">Atelier</a> </li> | <li> <a href="#Atelier" data-toggle="tab">Atelier</a> </li> | ||||
| @@ -1,4 +1,4 @@ | |||||
| ## -*- coding: utf-8 -*- | |||||
| # -*- coding: utf8 -*- | |||||
| <%def name="Bienvenue(request, User)"> | <%def name="Bienvenue(request, User)"> | ||||
| <H4>JM2L</H4> | <H4>JM2L</H4> | ||||
| Bonjour ${User.prenom},<br> | Bonjour ${User.prenom},<br> | ||||
| @@ -61,8 +61,70 @@ de la connaissance, de la bonne humeur et du soleil ;-) | |||||
| L'équipe des <b>JM2L</b> | L'équipe des <b>JM2L</b> | ||||
| <br> | <br> | ||||
| </%def> \ | </%def> \ | ||||
| <%def name="ShowTasks(request, User, Contact)"> | |||||
| <style> | |||||
| .table { | |||||
| border-collapse: collapse; | |||||
| } | |||||
| .table th, .table td { | |||||
| border: 1px solid #ddd; | |||||
| line-height: 20px; | |||||
| padding: 8px; | |||||
| text-align: left; | |||||
| vertical-align: top; | |||||
| outline: 0 none; | |||||
| margin:0; | |||||
| } | |||||
| </style> | |||||
| Salut ${User.pseudo or User.prenom},<br /> | |||||
| <p> | |||||
| Les JM2L approchent à grand pas, il faut donc avancer sur les tâches d'organisation ! | |||||
| <br/> | |||||
| En se basant sur le travail qu'il reste à faire pour que tout se passe dans les meilleurs | |||||
| conditions lors de l'évenement ... | |||||
| </p> | |||||
| Voici ce qu'il y'a dans la liste des tâches qui te sont assignées: | |||||
| <br/> | |||||
| <H4>Tes actions qui restent à entreprendre pour les JM2L !</H4> | |||||
| <table class="table"> | |||||
| <tr><th>Date</th><th>Pôle</th><th>Tâche</th></tr> | |||||
| % for t in sorted(User.task_assoc, key=lambda k:k.due_date): | |||||
| % if not t.closed: | |||||
| <tr> | |||||
| <td>${t.due_date.strftime('%d %B %Y').decode('utf-8', 'xmlcharrefreplace')}</td><td>${t.area.name}</td> | |||||
| <td><a href="//jm2l.linux-azur.org/Staff/tasks/${t.uid}">${t.name}</a> | |||||
| % endif | |||||
| % endfor | |||||
| </table> | |||||
| <H4>Et il y'a aussi des tâches communes !</H4> | |||||
| <table class="table"> | |||||
| <tr><th>Date</th><th>Pôle</th><th>Tâche</th></tr> | |||||
| % for t in sorted(Contact.task_assoc, key=lambda k:k.due_date): | |||||
| % if not t.closed: | |||||
| <tr> | |||||
| <td>${t.due_date.strftime('%d %B %Y').decode('utf-8', 'xmlcharrefreplace')}</td><td>${t.area.name}</td> | |||||
| <td><a href="//jm2l.linux-azur.org/Staff/tasks/${t.uid}">${t.name}</a> | |||||
| % endif | |||||
| % endfor | |||||
| </table> | |||||
| <br/> | |||||
| Pour accéder à ton espace sur le site, il te suffit de cliquer sur le <a href="${request.route_url('bymail', hash=User.my_hash)}">lien suivant.</a> | |||||
| <br/><br/> | |||||
| % for t in filter(lambda k:k.uid==51, Contact.task_assoc): | |||||
| Nous avons fixé la prochaine réunion JM2L au ${t.due_date.strftime('%d %B').decode('utf-8', 'xmlcharrefreplace')} à 19h30. | |||||
| % endfor | |||||
| <p> | |||||
| Bon courage ! | |||||
| </p> | |||||
| <br/> | |||||
| <small>Ceci est un mail automatisé ;)</small> | |||||
| <br/> | |||||
| <i>Le site de l'équipe des JM2L !</i> | |||||
| </%def> \ | |||||
| % if action=='Welcome': | % if action=='Welcome': | ||||
| ${self.Bienvenue(request, User)} | ${self.Bienvenue(request, User)} | ||||
| % elif action=='Forgot': | % elif action=='Forgot': | ||||
| ${self.Forgot(request, User)} | ${self.Forgot(request, User)} | ||||
| % elif action=='Tasks': | |||||
| ${self.ShowTasks(request, User, Contact)} | |||||
| % endif | % endif | ||||
| @@ -1,4 +1,4 @@ | |||||
| ## -*- coding: utf-8 -*- | |||||
| # -*- coding: utf8 -*- | |||||
| <%def name="Bienvenue(request, User)"> | <%def name="Bienvenue(request, User)"> | ||||
| Bonjour ${User.prenom}, | Bonjour ${User.prenom}, | ||||
| @@ -27,7 +27,7 @@ L'équipe des JM2L | |||||
| </%def> \ | </%def> \ | ||||
| <%def name="Forgot(request, User)"> | <%def name="Forgot(request, User)"> | ||||
| Bonjour ${User.prenom}, | |||||
| Bonjour ${User.pseudo or User.prenom}, | |||||
| Vous venez de demander le renvoi de vos identifiants sur le site des JM2L. | Vous venez de demander le renvoi de vos identifiants sur le site des JM2L. | ||||
| @@ -49,9 +49,56 @@ Nous vous attendons avec impatience le 28 novembre 2015 à Sophia Antipolis pour | |||||
| L'équipe des JM2L | L'équipe des JM2L | ||||
| </%def> \ | |||||
| <%def name="ShowTasks(request, User, Contact)"> | |||||
| Salut ${User.pseudo or User.prenom}, | |||||
| Les JM2L approchent à grand pas, il faut donc avancer sur les tâches d'organisation ! | |||||
| En se basant sur le travail qu'il reste à faire pour que tout se passe dans les meilleurs | |||||
| conditions lors de l'évenement ... | |||||
| Voici ce qu'il y'a dans la liste des tâches qui te sont assignées: | |||||
| % for t in sorted(User.task_assoc, key=lambda k:k.due_date): | |||||
| % if not t.closed: | |||||
| - Pour le ${t.due_date.strftime('%d %B %Y').decode('utf-8', 'xmlcharrefreplace')} - ${t.area.name} tâche ${t.uid} | |||||
| => ${t.name} | |||||
| % endif | |||||
| % endfor | |||||
| Et il y'a aussi des tâches communes ! | |||||
| % for t in sorted(Contact.task_assoc, key=lambda k:k.due_date): | |||||
| % if not t.closed and t.uid!=51: | |||||
| - Pour le ${t.due_date.strftime('%d %B %Y').decode('utf-8', 'xmlcharrefreplace')} - ${t.area.name} tâche ${t.uid} | |||||
| => ${t.name} | |||||
| % endif | |||||
| % endfor | |||||
| Pour accéder à ton espace il te suffit de cliquer sur le lien suivant : | |||||
| ${request.route_url('bymail', hash=User.my_hash)}. | |||||
| % for t in filter(lambda k:k.uid==51, Contact.task_assoc): | |||||
| Nous avons fixé la prochaine réunion JM2L au ${t.due_date.strftime('%d %B').decode('utf-8', 'xmlcharrefreplace')} à 19h30. | |||||
| % endfor | |||||
| Bon courage | |||||
| -- | |||||
| Ceci est un mail automatisé ;) | |||||
| Le site de l'équipe des JM2L ! | |||||
| </%def> \ | </%def> \ | ||||
| % if action=='Welcome': | % if action=='Welcome': | ||||
| ${self.Bienvenue(request, User)} | ${self.Bienvenue(request, User)} | ||||
| % elif action=='Forgot': | % elif action=='Forgot': | ||||
| ${self.Forgot(request, User)} | ${self.Forgot(request, User)} | ||||
| % elif action=='Tasks': | |||||
| ${self.ShowTasks(request, User, Contact)} | |||||
| % endif | % endif | ||||
| @@ -2,28 +2,23 @@ | |||||
| from pyramid.httpexceptions import HTTPFound, HTTPNotFound, HTTPForbidden | from pyramid.httpexceptions import HTTPFound, HTTPNotFound, HTTPForbidden | ||||
| from pyramid.httpexceptions import HTTPBadRequest, HTTPUnauthorized | from pyramid.httpexceptions import HTTPBadRequest, HTTPUnauthorized | ||||
| from pyramid.renderers import render_to_response | from pyramid.renderers import render_to_response | ||||
| from pyramid.response import Response | |||||
| from pyramid.view import notfound_view_config, forbidden_view_config | from pyramid.view import notfound_view_config, forbidden_view_config | ||||
| from pyramid.view import view_config | from pyramid.view import view_config | ||||
| from pyramid_mailer import get_mailer | |||||
| from mako.template import Template | from mako.template import Template | ||||
| # Import Web Forms | # Import Web Forms | ||||
| from .forms import * | from .forms import * | ||||
| # Database access imports | # Database access imports | ||||
| from .models import * | from .models import * | ||||
| from sqlalchemy.exc import DBAPIError | |||||
| from sqlalchemy import func, or_ | from sqlalchemy import func, or_ | ||||
| # Usefull tools | # Usefull tools | ||||
| from slugify import slugify | from slugify import slugify | ||||
| from icalendar import Calendar | from icalendar import Calendar | ||||
| from pytz import timezone | from pytz import timezone | ||||
| from icalendar import Event as Evt | from icalendar import Event as Evt | ||||
| from pyramid_mailer import get_mailer | |||||
| from pyramid_mailer.message import Attachment, Message | |||||
| from pyramid_mailer.message import Message | |||||
| # Then, standard libs | # Then, standard libs | ||||
| import webhelpers.paginate as paginate | import webhelpers.paginate as paginate | ||||
| import unicodedata | import unicodedata | ||||
| import time | |||||
| import datetime | import datetime | ||||
| import re | import re | ||||
| @@ -754,6 +749,8 @@ def list_users(request): | |||||
| Repas = DBSession.query(Sejour.repas).all() | Repas = DBSession.query(Sejour.repas).all() | ||||
| DicRepas = {"Ven":0, "Midi":0, "Soir":0} | DicRepas = {"Ven":0, "Midi":0, "Soir":0} | ||||
| for r in Repas: | for r in Repas: | ||||
| if r[0] is None: | |||||
| continue | |||||
| if (r[0] & 1 == 1): DicRepas["Ven"]+=1 | if (r[0] & 1 == 1): DicRepas["Ven"]+=1 | ||||
| if (r[0] & 2 == 2): DicRepas["Midi"]+=1 | if (r[0] & 2 == 2): DicRepas["Midi"]+=1 | ||||
| if (r[0] & 4 == 4): DicRepas["Soir"]+=1 | if (r[0] & 4 == 4): DicRepas["Soir"]+=1 | ||||
| @@ -1595,5 +1592,4 @@ def notfound(reason, request): | |||||
| request.response.status = 404 | request.response.status = 404 | ||||
| return render_to_response('jm2l:templates/Errors/404.mako', { "reason":reason }, | return render_to_response('jm2l:templates/Errors/404.mako', { "reason":reason }, | ||||
| request=request) | request=request) | ||||
| @@ -29,7 +29,8 @@ requires = [ | |||||
| 'Pillow', | 'Pillow', | ||||
| 'pyramid_exclog', | 'pyramid_exclog', | ||||
| 'repoze.sendmail==4.1', | 'repoze.sendmail==4.1', | ||||
| 'pyramid_mailer' | |||||
| 'pyramid_mailer', | |||||
| 'apscheduler' | |||||
| ] | ] | ||||
| setup(name='JM2L', | setup(name='JM2L', | ||||