@@ -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', | ||||