Le repo des sources pour le site web des JM2L
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 
 

2038 righe
90 KiB

  1. # -*- coding: utf8 -*-
  2. from pyramid.httpexceptions import HTTPFound, HTTPNotFound, HTTPForbidden
  3. from pyramid.httpexceptions import HTTPBadRequest, HTTPUnauthorized
  4. from pyramid.renderers import render_to_response
  5. from pyramid.view import notfound_view_config, forbidden_view_config
  6. from pyramid.view import view_config
  7. from pyramid.response import Response
  8. from mako.template import Template
  9. from pyramid_mailer.message import Message
  10. from .upload import IMAGEPATH
  11. # Import Web Forms
  12. from .forms import *
  13. # Database access imports
  14. from .models import *
  15. from .helpers import Orga_helpers
  16. from sqlalchemy import func, or_, text, and_
  17. from sqlalchemy.orm import aliased
  18. from os import path, makedirs, listdir
  19. # Usefull tools
  20. from slugify import slugify
  21. from icalendar import Calendar
  22. from pytz import timezone
  23. from icalendar import Event as Evt
  24. from pyramid_mailer.message import Message
  25. # Then, standard libs
  26. import csv
  27. import cStringIO as StringIO
  28. import webhelpers.paginate as paginate
  29. import unicodedata
  30. import datetime
  31. import re
  32. import shutil
  33. import glob
  34. from jm2l.const import CurrentYear
  35. ## =-=- Here, We keep some usefull function -=-=
  36. def remove_accents(input_str):
  37. """ This function is intended to remove all accent from input unicode string """
  38. nkfd_form = unicodedata.normalize('NFKD', input_str)
  39. only_ascii = nkfd_form.encode('ASCII', 'ignore')
  40. return only_ascii
  41. def embeed_video(mime_type, link):
  42. Container = "<video controls='controls' preload='metadata' style='width:60%'>"
  43. Container += "<source type='%s' " % mime_type
  44. Container += "src='%s' />" % link
  45. Container += "</video>"
  46. return Container
  47. @view_config(route_name='Live', renderer="jm2l:templates/Live.mako")
  48. def Live(request):
  49. year = int(request.matchdict.get('year', CurrentYear))
  50. tz = timezone('Europe/Paris')
  51. curtime = datetime.datetime.now().replace(tzinfo=tz, day=28) #, hour=10, minute=00 )
  52. Events = DBSession.query(Event)\
  53. .filter(Event.for_year == year)\
  54. .filter(Event.event_type != 'Stand')\
  55. .filter(and_(Event.start_time <= curtime, Event.end_time >= curtime) )\
  56. .order_by(Event.start_time)
  57. return {'year': year, "DisplayYear": year, 'events':Events, "logged_in":request.authenticated_userid }
  58. ## =-=- Here, We handle ICal requests -=-=
  59. @view_config(route_name='progr_iCal', renderer="string")
  60. def ICal_Progamme_Request(request):
  61. year = int(request.matchdict.get('year', CurrentYear))
  62. # Initialization
  63. # Compute days used by all events matching the specified input year
  64. Events = DBSession.query(Event)\
  65. .filter(Event.for_year == year)\
  66. .filter(Event.event_type != 'Stand')\
  67. .order_by(Event.start_time)
  68. cal = Calendar()
  69. cal.add('prodid', '-//Programme %d//jm2l.linux-azur.org//' % year)
  70. cal.add('version', '2.0')
  71. tz = timezone('Europe/Paris')
  72. for ev in Events:
  73. if ev.event_type:
  74. event = Evt()
  75. event['uid'] = "%d/%d" % ( year, ev.uid )
  76. event.add('summary', ev.name )
  77. event.add('dtstart', ev.start_time.replace(tzinfo=tz) )
  78. event.add('dtend', ev.end_time.replace(tzinfo=tz) )
  79. event.add('created', ev.last_change.replace(tzinfo=tz) )
  80. event.add('description', "http://www.linux-azur.org/event/%s/%s" % (ev.for_year, ev.slug) )
  81. event.add('url', "http://www.linux-azur.org/event/%s/%s" % (ev.for_year, ev.slug) )
  82. event.add('priority', 5)
  83. cal.add_component(event)
  84. request.response.content_type = "text/calendar"
  85. return cal.to_ical()
  86. ## =-=- Here, We handle ICal requests -=-=
  87. @view_config(route_name='progr_dyn_iCal', renderer="string")
  88. def ICal_Progamme_Dyn_Request(request):
  89. year = int(request.matchdict.get('year', CurrentYear))
  90. # Initialization
  91. # Compute days used by all events matching the specified input year
  92. Events = DBSession.query(Event)\
  93. .filter(Event.for_year == year)\
  94. .filter(Event.event_type != 'Stand')\
  95. .order_by(Event.start_time)
  96. cal = Calendar()
  97. cal.add('prodid', '-//Programme %d//jm2l.linux-azur.org//' % year)
  98. cal.add('version', '2.0')
  99. today = datetime.datetime.now()
  100. tz = timezone('Europe/Paris')
  101. event = Evt()
  102. event['uid'] = "%d/%d" % ( year, 100 )
  103. event.add('summary', "Les stands JM2L %s" % year )
  104. event.add('dtstart', datetime.datetime.now().replace(tzinfo=tz, hour=10, minute=00 ) )
  105. event.add('dtend', datetime.datetime.now().replace(tzinfo=tz, hour=18, minute=00 ) )
  106. event.add('created', datetime.datetime.now().replace(tzinfo=tz, hour=10, minute=00 ) )
  107. event.add('description', "https://www.youtube.com/watch?v=91X65eEKxvU&t=6s" )
  108. event.add('location', "http://jm2l.linux-azur.org/img/325.gif" )
  109. event.add('url', "http://jm2l.linux-azur.org/%s/le-programme" % CurrentYear)
  110. event.add('priority', 5)
  111. cal.add_component(event)
  112. TabCorr = {
  113. 135:"Koneko",
  114. 131:"cam-jm2l-a",
  115. 132:"cam-jm2l-b",
  116. 115:"cam-jm2l-e",
  117. 114:"cam-jm2l-f",
  118. 116:"cam-jm2l-g",
  119. 139:"cam-jm2l-y"
  120. }
  121. for i, ev in enumerate(Events):
  122. if ev.event_type:
  123. event = Evt()
  124. event['uid'] = "%d/%d" % ( year, ev.uid )
  125. event.add('summary', ev.name )
  126. event.add('dtstart', ev.start_time.replace(tzinfo=tz, day=today.day, month = today.month, hour=(ev.start_time.hour)%24 ) )
  127. event.add('dtend', ev.end_time.replace(tzinfo=tz, day=today.day, month = today.month, hour=(ev.end_time.hour)%24 ) )
  128. event.add('created', ev.last_change.replace(tzinfo=tz) )
  129. event.add('description', "http://jm2l.linux-azur.org:8080/%s.webm" % TabCorr.get(ev.Salle.phy_salle_id, ev.Salle.phy_salle_id) )
  130. event.add('location', "http://jm2l.linux-azur.org/img/%d.gif" % ev.Salle.phy_salle_id )
  131. event.add('url', "http://www.linux-azur.org/event/%s/%s" % (ev.for_year, ev.slug) )
  132. event.add('priority', 5)
  133. cal.add_component(event)
  134. request.response.content_type = "text/calendar"
  135. return cal.to_ical()
  136. ## =-=- Here, We handle Json requests -=-=
  137. @view_config(route_name='users_json', renderer="json")
  138. def JSON_User_Request(request):
  139. """ Build a JSON answer with active users and pagination handling """
  140. # Check arguments consitency
  141. pageSize = request.params.get('pageSize',"8")
  142. current_page = request.params.get('pageNum',"1")
  143. UserQuery = request.params.get('searchTerm', u"")
  144. # Don't answer to users that aren't logged
  145. if not request.user:
  146. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  147. # Check consistancy of parameters
  148. if pageSize.isdigit() and current_page.isdigit():
  149. current_page = int(current_page)
  150. pageSize = int(pageSize)
  151. else:
  152. return HTTPBadRequest('pageSize and pageNum accept only digits.')
  153. # Query database
  154. Users = DBSession.query(User.uid, User.nom, User.prenom)\
  155. .filter(User.slug.contains( remove_accents(UserQuery) ))
  156. page_url = paginate.PageURL_WebOb(request)
  157. records = paginate.Page(Users, current_page, url=page_url, items_per_page=pageSize)
  158. ListMatchUser = map( lambda u:{"id": u.uid, "text":"%s %s" % ( u.prenom, u.nom )}, records )
  159. return { "Results": ListMatchUser, "Total":records.item_count,
  160. "logged_in":request.authenticated_userid }
  161. @view_config(route_name='tiers_json', renderer="json")
  162. def JSON_Tiers_Request(request):
  163. """ Build a JSON answer with active users and pagination handling """
  164. # Check arguments consitency
  165. pageSize = request.params.get('pageSize',"8")
  166. current_page = request.params.get('pageNum',"1")
  167. TiersQuery = request.params.get('searchTerm', u"")
  168. # Don't answer to users that aren't logged
  169. if not request.user:
  170. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  171. # Check consistancy of parameters
  172. if pageSize.isdigit() and current_page.isdigit():
  173. current_page = int(current_page)
  174. pageSize = int(pageSize)
  175. else:
  176. return HTTPBadRequest('pageSize and pageNum accept only digits.')
  177. # Query database
  178. JTiers = DBSession.query(Tiers.uid, Tiers.name)\
  179. .filter(Tiers.slug.contains( remove_accents(TiersQuery) ))
  180. page_url = paginate.PageURL_WebOb(request)
  181. records = paginate.Page(JTiers, current_page, url=page_url, items_per_page=pageSize)
  182. ListMatchTiers = map( lambda t:{"id": t.uid, "text": t.name }, records )
  183. return { "Results": ListMatchTiers, "Total":records.item_count,
  184. "logged_in":request.authenticated_userid }
  185. @view_config(route_name='progr_json', renderer="json")
  186. def JSON_Progamme_Request(request):
  187. year = int(request.matchdict.get('year', CurrentYear))
  188. # Initialization
  189. DicResult = dict()
  190. # Query database
  191. # Compute days used by all events matching the specified input year
  192. Days = DBSession.query( func.strftime('%d', Event.start_time).label('day') )\
  193. .filter(Event.for_year == year)\
  194. .filter(Event.event_type != None)\
  195. .group_by(func.strftime('%d', Event.start_time)).all()
  196. for Day in Days:
  197. Events = DBSession.query(Event)\
  198. .filter(Event.for_year == year)\
  199. .filter(Event.event_type != 'Stand')\
  200. .filter(text("strftime('%d', start_time) = :dow")).params(dow=Day.day)\
  201. .order_by(Event.start_time)
  202. ListEv = []
  203. for ev in Events:
  204. if ev.event_type:
  205. ListEv.append( {
  206. "uid":"%d/%d" % ( year, ev.uid ),
  207. "desc":ev.name,
  208. "startDate":ev.start_time.strftime('%Y-%m-%dT%H:%M:%S+01:00'),
  209. "endDate":ev.end_time.strftime('%Y-%m-%dT%H:%M:%S+01:00'),
  210. "placeName":ev.Salle and (ev.Salle.name or "unk") ,
  211. "status":ev.event_type
  212. } )
  213. DicResult[Day.day] = ListEv
  214. return { 'all':DicResult }
  215. @view_config(route_name='timeline_json', renderer="json")
  216. def JSON_TimeLine_Request(request):
  217. year = int(request.matchdict.get('year', CurrentYear))
  218. # Initialization
  219. DicResult = dict()
  220. # Query database
  221. # Compute days used by all events matching the specified input year
  222. Days = DBSession.query( func.strftime('%d', Event.start_time).label('day') )\
  223. .filter(Event.for_year == year)\
  224. .filter(Event.event_type != None)\
  225. .group_by(func.strftime('%d', Event.start_time)).all()
  226. ListEv = []
  227. for Day in Days:
  228. Events = DBSession.query(Event)\
  229. .filter(Event.for_year == year)\
  230. .filter(Event.event_type != 'Stand')\
  231. .filter(text("strftime('%d', start_time) = :dow")).params(dow=Day.day)\
  232. .order_by(Event.start_time)
  233. #ListEv = []
  234. for ev in Events:
  235. if ev.event_type:
  236. CurMedia = ev.video.first() or ""
  237. if CurMedia:
  238. Container = "<video controls='controls' preload='metadata' style='width:60%'>"
  239. Container += "<source type='%s' " % CurMedia.mime_type
  240. Container += "src='%s' />" % CurMedia.get_path
  241. Container += "</video>"
  242. else:
  243. Container = ""
  244. ListEv.append( {
  245. #"uid":"%d/%d" % ( year, ev.uid ),
  246. "headline":'<a href="/event/%s/%s">%s</a>' % (ev.for_year, ev.slug, ev.name),
  247. "startDate":ev.start_time.strftime('%Y,%m,%d,%H,%M'),
  248. "endDate":ev.end_time.strftime('%Y,%m,%d,%H,%M'),
  249. "text": ev.Salle and (ev.Salle.name or "unk"),
  250. #"text":ev.description[:100],
  251. "tags":ev.Salle and (ev.Salle.salle_id or "unk") ,
  252. #"status":ev.event_type,
  253. "asset": {
  254. "media": Container,
  255. "credit": ",".join(["%s %s" % (i.prenom, i.nom) for i in ev.intervenants]),
  256. "caption":"" }
  257. } )
  258. if year==2017:
  259. DicResult = {
  260. "lang":"fr",
  261. "headline":"JM2L 2017",
  262. "type":"default",
  263. "startDate":"2017,11,25,10",
  264. "text":"<i><span class='c1'>10ème Édition</span></i>",
  265. "asset":
  266. {
  267. #"media":"https://www.youtube.com/watch?v=91X65eEKxvU&t=6s",
  268. "media":embeed_video("video/ogg","http://jm2l.linux-azur.org/resources/2015/Video/jm2l_france3-2015.ogv"),
  269. "credit":"Reportage France 3",
  270. "caption":"JM2L 2015"
  271. }
  272. }
  273. elif year==2015:
  274. DicResult = {
  275. "lang":"fr",
  276. "headline":"JM2L 2015",
  277. "type":"default",
  278. "startDate":"2015,11,28,10",
  279. "text":"<i><span class='c1'>9ème Édition</span></i>",
  280. "asset":
  281. {
  282. #"media":"https://www.youtube.com/watch?v=91X65eEKxvU&t=6s",
  283. "media":embeed_video("video/ogg","http://jm2l.linux-azur.org/resources/2015/Video/jm2l_france3-2015.ogv"),
  284. "credit":"Reportage France 3",
  285. "caption":"JM2L 2015"
  286. }
  287. }
  288. elif year==2011:
  289. DicResult = {
  290. "lang":"fr",
  291. "headline":"JM2L 2011",
  292. "type":"default",
  293. "startDate":"2011,11,25,10",
  294. "text":"<i><span class='c1'>6ème Édition</span></i>",
  295. "asset":
  296. {
  297. "media":"https://www.youtube.com/embed/rcaNeXuAEhs",
  298. "credit":"JM2L",
  299. "caption":"Reportage FR3"
  300. },
  301. }
  302. elif year==2010:
  303. DicResult = {
  304. "lang":"fr",
  305. "headline":"JM2L 2010",
  306. "type":"default",
  307. "text":"<i><span class='c1'>5ème Édition</span></i>",
  308. "asset":
  309. {
  310. "media":embeed_video("video/ogg","http://jm2l.linux-azur.org/resources/2010/Video/reportages/JM2L2010-PleinSudTV.ogv"),
  311. "credit":"<a href='http://pleinsudtv.com/index.php/casa/affichage-en-vignettes/93-casa-culture/582-les-jm-du-logiciel-libre-2010'>Le reportage Plein-sud TV</a>",
  312. "caption":"JM2L",
  313. }
  314. }
  315. elif year==2007:
  316. DicResult = {
  317. "lang":"fr",
  318. "headline":"JM2L 2007",
  319. "type":"default",
  320. "text":"<i><span class='c1'>2ème Édition</span></i>",
  321. "asset":
  322. {
  323. "media":embeed_video("video/ogg","http://jm2l.linux-azur.org/resources/2007/Video/20071110-linux.ogv"),
  324. "credit":"<a href='http://pleinsudtv.com/index.php/casa/affichage-en-vignettes/93-casa-culture/245-logiciel-libre-linux-jm2l'>Le reportage Plein-sud TV</a>",
  325. "caption":"JM2L 2007",
  326. }
  327. }
  328. else:
  329. DicResult = {
  330. "lang":"fr",
  331. "headline":"JM2L %d" % year,
  332. "type":"default",
  333. "asset":
  334. {
  335. "media":"",
  336. "credit":"JM2L",
  337. "caption":""
  338. }
  339. }
  340. DicResult["date"] = ListEv
  341. return { 'timeline':DicResult }
  342. ## =-=- Here, We handle HTTP requests - Public Part -=-=
  343. @view_config(route_name='home', renderer="jm2l:templates/NewIndex.mako")
  344. def index_page(request):
  345. year = request.matchdict.get('year')
  346. if year:
  347. year=int(year[:-1])
  348. content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==year).first()
  349. if content:
  350. content = content.description
  351. else:
  352. content = ""
  353. if 2004<year<=CurrentYear:
  354. if year==2006:
  355. return {'year': year, 'content':content, 'edition':u"1<sup>ère</sup>" }
  356. elif year==2015:
  357. return {'year': year, 'content':content, 'edition':u"9<sup>ème</sup>" }
  358. elif year==2017:
  359. return {'year': year, 'content':content, 'edition':u"10<sup>ème</sup>" }
  360. else:
  361. edition = year - 2005
  362. return {'year': year, 'content':content, 'edition':u"%d<sup>ème</sup>" % edition }
  363. else:
  364. raise HTTPNotFound()
  365. else:
  366. content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==CurrentYear).first().description
  367. TargetDir = "jm2l/static/img/%s/Photos" % (year or CurrentYear)
  368. TargetUrl = "/static/img/%s/Photos/" % (year or CurrentYear)
  369. if path.isdir(TargetDir):
  370. ListPhotos = map(lambda x: TargetUrl + x, listdir(TargetDir))
  371. else:
  372. ListPhotos = []
  373. return {'year': CurrentYear, 'content':content, 'edition':u"10<sup>ème</sup>", 'ListPhotos': ListPhotos}
  374. @view_config(route_name='edit_index', renderer="jm2l:templates/Staff/EditIndex.mako")
  375. def edit_index(request):
  376. year = int(request.matchdict.get('year', CurrentYear))
  377. if not request.user.Staff:
  378. # Don't answer to users that aren't logged
  379. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  380. content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==year).first()
  381. form = IndexForm(request.POST, content, meta={'csrf_context': request.session})
  382. if request.method == 'POST' and form.validate():
  383. form.populate_obj(content)
  384. return HTTPFound(location=request.route_url('home', year="%d/" % year))
  385. MainTab = {'home':'active', "logged_in":request.authenticated_userid,
  386. 'form':form, 'DisplayYear':year}
  387. return MainTab
  388. @view_config(route_name='programme', renderer="jm2l:templates/Public/Programme.mako")
  389. def programme(request):
  390. year = int(request.matchdict.get('year'))
  391. if 2006 > year:
  392. return HTTPBadRequest('The first JM2L event was in 2006.')
  393. # Query database about selected Year.
  394. Events = DBSession.query(Event)\
  395. .filter(Event.for_year == year)\
  396. .order_by(Event.start_time)
  397. Days = DBSession.query(func.strftime('%d-%m-%Y', Event.start_time))\
  398. .filter(Event.for_year == year)\
  399. .filter(Event.event_type != None)\
  400. .group_by(func.strftime('%d', Event.start_time)).all()
  401. ListDay = []
  402. for day in Days:
  403. RefDay = datetime.datetime.strptime(day[0],'%d-%m-%Y')
  404. ListDay.append( ( RefDay.strftime('%A %d %b %Y'),
  405. RefDay.strftime('%d') ) )
  406. MainTab = {'programme':'active','DisplayYear':year, \
  407. 'Events':Events, 'Event':Event, 'Days':ListDay, "logged_in":request.authenticated_userid }
  408. return MainTab
  409. @view_config(route_name='presse', renderer="jm2l:templates/Public/Presse.mako")
  410. def static_presse(request):
  411. year = int(request.matchdict.get('year', None))
  412. content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==year).first()
  413. MainTab = {'presse':'active', "logged_in":request.authenticated_userid, 'content':content, 'DisplayYear':year}
  414. return MainTab
  415. @view_config(route_name='edit_presse', renderer="jm2l:templates/Staff/EditPresse.mako")
  416. def edit_presse(request):
  417. year = int(request.matchdict.get('year', None))
  418. if request.user is None:
  419. # Don't answer to users that aren't logged
  420. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  421. if not request.user.Staff:
  422. # Don't answer to users that aren't logged
  423. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  424. content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==year).first()
  425. form = DossPresse(request.POST, content, meta={'csrf_context': request.session})
  426. if request.method == 'POST' and form.validate():
  427. form.populate_obj(content)
  428. MainTab = {'presse':'active', "logged_in":request.authenticated_userid, 'form':form, 'DisplayYear':year}
  429. return MainTab
  430. @view_config(route_name='plan', renderer="jm2l:templates/Public/Plan.mako")
  431. def static_plan(request):
  432. session = request.session
  433. session['year'] = CurrentYear
  434. MainTab = {'plan':'active', "logged_in":request.authenticated_userid }
  435. return MainTab
  436. ## =-=- Here, We handle HTTP requests - Staff Logged Part -=-=
  437. @view_config(route_name='list_task', renderer='jm2l:templates/Staff/list.mako')
  438. def list_view(request):
  439. year = int(request.matchdict.get('year', CurrentYear))
  440. if request.user is None:
  441. # Don't answer to users that aren't logged
  442. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  443. if not request.user.Staff:
  444. # Don't answer to users that aren't logged
  445. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  446. DicTask = {}
  447. taskgroup = DBSession.query( TasksArea ).filter( TasksArea.year_uid == year).all()
  448. for grp in taskgroup:
  449. tasks = DBSession.query( Tasks )\
  450. .filter( Tasks.area_uid==grp.uid ) \
  451. .filter( Tasks.year_uid == year) \
  452. .order_by(Tasks.closed, Tasks.due_date).all()
  453. DicTask[grp] = tasks
  454. return {'tasks': DicTask, 'year':year }
  455. @view_config(route_name='list_expenses', renderer='jm2l:templates/Staff/compta.mako')
  456. def expenses(request):
  457. year = int(request.matchdict.get('year', CurrentYear))
  458. if request.user is None:
  459. # Don't answer to users that aren't logged
  460. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  461. if not request.user.Staff:
  462. # Don't answer to users that aren't logged
  463. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  464. output = []
  465. dic_out = {}
  466. for name in glob.glob('jm2l/upload/images/users/*/RIB/*'):
  467. tab_path = name.split('/')
  468. if tab_path[6]=='thumbnails' or tab_path[6].endswith('.type'):
  469. continue
  470. if dic_out.get(tab_path[4]) is None:
  471. dic_out[tab_path[4]] = {}
  472. if dic_out[tab_path[4]].get('RIB') is None:
  473. dic_out[tab_path[4]]['RIB'] = {'files':[], 'thumb':[]}
  474. u = User.by_slug(tab_path[4])
  475. dic_out[tab_path[4]]['User'] = {
  476. 'uid':u.uid,
  477. 'nom':u.nom,
  478. 'prenom':u.prenom,
  479. 'slug':u.slug
  480. }
  481. dic_out[tab_path[4]]['RIB']['files'].append( name )
  482. dic_out[tab_path[4]]['RIB']['thumb'].append( name + ".jpg" )
  483. for name in glob.glob('jm2l/upload/images/users/*/Justif/*'):
  484. tab_path = name.split('/')
  485. if tab_path[6]=='thumbnails' or tab_path[6].endswith('.type'):
  486. continue
  487. if dic_out.get(tab_path[4]) is None:
  488. dic_out[tab_path[4]] = {}
  489. if dic_out[tab_path[4]].get('Justif') is None:
  490. dic_out[tab_path[4]]['Justif'] = {'files':[], 'thumb':[]}
  491. u = User.by_slug(tab_path[4])
  492. dic_out[tab_path[4]]['User'] = {
  493. 'uid':u.uid,
  494. 'nom':u.nom,
  495. 'prenom':u.prenom,
  496. 'slug':u.slug
  497. }
  498. dic_out[tab_path[4]]['Justif']['files'].append( name )
  499. dic_out[tab_path[4]]['Justif']['thumb'].append( name + ".jpg" )
  500. return dict(found=dic_out, year=year )
  501. @view_config(route_name='handle_task', renderer='jm2l:templates/Staff/tasks.mako')
  502. def tasks(request):
  503. year = int(request.matchdict.get('year', CurrentYear))
  504. if request.user is None:
  505. # Don't answer to users that aren't logged
  506. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  507. if not request.user.Staff:
  508. # Don't answer to users that aren't logged
  509. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  510. task_id = request.matchdict.get('task_id')
  511. # Convert the pole_id GET parameter to int or 0
  512. if request.params.get('pole_id') and request.params.get('pole_id').isdigit():
  513. pole_id = int(request.params.get('pole_id'))
  514. else:
  515. pole_id = None
  516. # Get areas from db
  517. Areas = DBSession.query(TasksArea.uid, TasksArea.name) \
  518. .filter(TasksArea.year_uid == year) \
  519. .order_by('name').all()
  520. # Get users from db
  521. Users = DBSession.query(User)\
  522. .filter(User.Staff==1)\
  523. .order_by('nom').all()
  524. if task_id:
  525. TmpTask = Tasks.by_id(int(task_id))
  526. if not TmpTask:
  527. raise HTTPNotFound()
  528. form = EditStaffTasks(request.POST, TmpTask, meta={'csrf_context': request.session})
  529. else:
  530. TmpTask = Tasks()
  531. # Check if the supplied pole_id is in the Areas' range
  532. form = StaffTasks(request.POST, TmpTask, meta={'csrf_context': request.session})
  533. Area = TasksArea.by_id(pole_id)
  534. if Area:
  535. form.area_uid.data = Area.uid
  536. # Put some areas on form
  537. form.area_uid.choices = Areas
  538. # Put some users on form
  539. form.closed_by.choices = [(u.uid, "%s %s" % (u.nom, u.prenom))
  540. for u in Users]
  541. form.due_date.type = "date"
  542. if request.method=='POST' and form.validate():
  543. form.populate_obj(TmpTask)
  544. TmpTask.closed = False
  545. if not TmpTask.year_uid:
  546. TmpTask.year_uid = year;
  547. if 'uid' in form._fields.keys():
  548. DBSession.merge(TmpTask)
  549. else:
  550. DBSession.add(TmpTask)
  551. DBSession.flush()
  552. return HTTPFound(location=request.route_url('list_task', year=year)+"#"+slugify(TmpTask.area.name))
  553. return {'form':form, 'area':TmpTask.area and slugify(TmpTask.area.name) or '', 'year':year}
  554. @view_config(route_name='handle_pole', renderer='jm2l:templates/Staff/pole.mako')
  555. def tasks_area(request):
  556. year = int(request.matchdict.get('year', CurrentYear))
  557. if request.user is None:
  558. # Don't answer to users that aren't logged
  559. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  560. if not request.user.Staff:
  561. # Don't answer to users that aren't logged
  562. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  563. pole_id = request.matchdict.get('pole_id')
  564. if pole_id:
  565. Pole = TasksArea.by_id(int(pole_id))
  566. if not Pole:
  567. raise HTTPNotFound()
  568. form = EditStaffArea(request.POST, Pole, meta={'csrf_context': request.session})
  569. else:
  570. Pole = TasksArea()
  571. form = StaffArea(request.POST, Pole, meta={'csrf_context': request.session})
  572. if request.method == 'POST' and form.validate():
  573. form.populate_obj(Pole)
  574. if not Pole.year_uid:
  575. Pole.year_uid = year;
  576. if 'uid' in form._fields.keys():
  577. DBSession.merge(Pole)
  578. else:
  579. DBSession.add(Pole)
  580. return HTTPFound(location=request.route_url('list_task', year=year)+"#"+slugify(Pole.name))
  581. return {'form':form, 'year':year }
  582. @view_config(route_name='action_task')
  583. def action_task(request):
  584. year = int(request.matchdict.get('year', CurrentYear))
  585. if request.user is None:
  586. # Don't answer to users that aren't logged
  587. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  588. if not request.user.Staff:
  589. # Don't answer to users that aren't logged
  590. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  591. action = request.matchdict.get('action')
  592. task_id = request.matchdict.get('task_id')
  593. Task = Tasks.by_id(int(task_id))
  594. if action=='close':
  595. Task.closed = True
  596. request.session.flash(('info', u'La tâche a été fermé, Félicitations !'))
  597. DBSession.merge(Task)
  598. if action=='open':
  599. Task.closed = False
  600. request.session.flash(('info', u'La tâche a été ré-ouverte !'))
  601. DBSession.merge(Task)
  602. if action=='delete':
  603. request.session.flash(('info', u'La tâche a été supprimée !'))
  604. DBSession.delete(Task)
  605. return HTTPFound(location=request.route_url('list_task', year=year)+"#"+slugify(Task.area.name))
  606. @view_config(route_name='action_task_area')
  607. def action_task_area(request):
  608. year = int(request.matchdict.get('year', CurrentYear))
  609. if request.user is None:
  610. # Don't answer to users that aren't logged
  611. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  612. if not request.user.Staff:
  613. # Don't answer to users that aren't logged
  614. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  615. action = request.matchdict.get('action')
  616. pole_id = request.matchdict.get('pole_id')
  617. Pole = TasksArea.by_id(int(pole_id))
  618. if not Pole:
  619. raise HTTPNotFound()
  620. if action=='delete':
  621. request.session.flash(('info', u'Le pôle a été supprimé !'))
  622. DBSession.delete(Pole)
  623. return HTTPFound(location=request.route_url('list_task', year=year))
  624. @view_config(route_name='list_salles', renderer='jm2l:templates/Salles/list.mako')
  625. def list_salles(request):
  626. if request.user is None:
  627. # Don't answer to users that aren't logged
  628. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  629. if not request.user.Staff:
  630. # Don't answer to users that aren't logged
  631. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  632. DicSalle = {}
  633. years = DBSession.query( JM2L_Year ).all()
  634. for year in years:
  635. salles = DBSession.query( Salles )\
  636. .filter( Salles.year_uid==year.year_uid )\
  637. .order_by(Salles.name).all()
  638. DicSalle[year] = salles
  639. return {'DicSalle': DicSalle }
  640. @view_config(route_name='handle_salle', renderer='jm2l:templates/Salles/salle.mako')
  641. def handle_salle(request):
  642. if request.user is None:
  643. # Don't answer to users that aren't logged
  644. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  645. if not request.user.Staff:
  646. # Don't answer to users that aren't logged
  647. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  648. salle_id = request.matchdict.get('salle_id')
  649. if salle_id:
  650. Salle = Salles.by_id(int(salle_id))
  651. if not Salle:
  652. raise HTTPNotFound()
  653. form = EditSalleForm(request.POST, Salle, meta={'csrf_context': request.session})
  654. else:
  655. Salle = Salles()
  656. form = SalleForm(request.POST, Salle, meta={'csrf_context': request.session})
  657. form.year_uid.choices = map(tuple, DBSession.query(JM2L_Year.year_uid, JM2L_Year.year_uid).all())
  658. form.phy_salle_id.choices = map(tuple, DBSession.query(SallePhy.uid, SallePhy.name).all())
  659. if request.method == 'POST' and form.validate():
  660. form.populate_obj(Salle)
  661. if 'uid' in form._fields.keys():
  662. DBSession.merge(Salle)
  663. else:
  664. DBSession.add(Salle)
  665. return HTTPFound(location=request.route_url('list_salles'))
  666. return {'form':form }
  667. @view_config(route_name='handle_salle_phy', renderer='jm2l:templates/Salles/salle_phy.mako')
  668. def handle_salle_phy(request):
  669. if request.user is None:
  670. # Don't answer to users that aren't logged
  671. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  672. if not request.user.Staff:
  673. # Don't answer to users that aren't logged
  674. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  675. salle_id = request.matchdict.get('salle_id')
  676. if salle_id:
  677. Salle = SallePhy.by_id(int(salle_id))
  678. if not Salle:
  679. raise HTTPNotFound()
  680. form = EditSallePhyForm(request.POST, Salle, meta={'csrf_context': request.session})
  681. else:
  682. Salle = SallePhy()
  683. form = SallePhyForm(request.POST, Salle, meta={'csrf_context': request.session})
  684. if request.method == 'POST' and form.validate():
  685. form.populate_obj(Salle)
  686. Salle.slug = slugify(Salle.name)
  687. if 'uid' in form._fields.keys():
  688. DBSession.merge(Salle)
  689. else:
  690. DBSession.add(Salle)
  691. return HTTPFound(location=request.route_url('list_salles'))
  692. return {'form':form }
  693. @view_config(route_name='action_salle')
  694. def action_salle(request):
  695. if request.user is None:
  696. # Don't answer to users that aren't logged
  697. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  698. if not request.user.Staff:
  699. # Don't answer to users that aren't logged
  700. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  701. action = request.matchdict.get('action')
  702. salle_id = request.matchdict.get('salle_id')
  703. Salle = Salles.by_id(int(salle_id))
  704. if not Salle:
  705. raise HTTPNotFound()
  706. if action=='delete':
  707. request.session.flash(('info', u'La Salle a été supprimée !'))
  708. DBSession.delete(Salle)
  709. return HTTPFound(location=request.route_url('list_salles'))
  710. ## =-=- Here, We handle HTTP requests - User Logged Part -=-=
  711. @view_config(route_name='exchange', renderer="jm2l:templates/Logistique/Logistique.mako")
  712. def exchange(request):
  713. modtype = request.matchdict.get('modtype', None)
  714. action = request.matchdict.get('action', None)
  715. uid = int(request.matchdict.get('id', -1))
  716. Exch = Exchange.by_id(uid)
  717. if not Exch:
  718. MainTab = {
  719. 'Exchanges':Exchange,
  720. 'Type':modtype[-1:],
  721. 'reload':True,
  722. 'logged_in':request.authenticated_userid
  723. }
  724. return MainTab
  725. if action in ['delete', 'accept', 'refuse', 'deal']:
  726. if action=='delete': # delete exchange
  727. DBSession.delete(Exch)
  728. elif action=='accept': # accept exchange
  729. Exch.exch_done=True
  730. DBSession.merge(Exch)
  731. elif action=='refuse': # refuse exchange
  732. Exch.exch_done=False
  733. if Exch.exch_state=="Ask":
  734. Exch.provider_id = None
  735. elif Exch.exch_state=="Proposal":
  736. Exch.asker_id = None
  737. DBSession.merge(Exch)
  738. elif action=='deal':
  739. # ask to deal the exchange
  740. if Exch.exch_state=="Ask":
  741. Exch.provider_id = request.user.uid
  742. elif Exch.exch_state=="Proposal":
  743. Exch.asker_id = request.user.uid
  744. # Return javascript to parent page
  745. response = render_to_response('jm2l:templates/modals_js.mako',
  746. {'modtype':modtype, 'action':action},
  747. request=request)
  748. response.content_type = 'text/javascript'
  749. return response
  750. else:
  751. MainTab = {
  752. 'Exchanges':Exchange,
  753. 'Type':modtype[-1:],
  754. 'reload':True,
  755. 'logged_in':request.authenticated_userid
  756. }
  757. return MainTab
  758. @view_config(route_name='miam')
  759. def miam(request):
  760. if request.user is None:
  761. # Don't answer to users that aren't logged
  762. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  763. miam_form = MiamForm(request.POST, request.user, meta={'csrf_context': request.session})
  764. if request.method == 'POST' and miam_form.validate():
  765. FicheSejour = Sejour.by_user(request.user.uid, CurrentYear)
  766. if FicheSejour:
  767. Update=True
  768. else:
  769. FicheSejour = Sejour()
  770. FicheSejour.created = datetime.datetime.now()
  771. Update=False
  772. Repas=0
  773. for num, item in enumerate(['RepasVendredi', 'RepasSamediMidi', 'RepasSamediSoir']):
  774. if request.params.get(item)==u"1":
  775. Repas += 2**num
  776. FicheSejour.repas = Repas
  777. FicheSejour.repas_allerg = request.params.get('Allergies')
  778. FicheSejour.repas_contr = request.params.get('Contraintes')
  779. FicheSejour.user_id = request.user.uid
  780. FicheSejour.for_year = CurrentYear
  781. if Update:
  782. DBSession.merge(FicheSejour)
  783. else:
  784. DBSession.add(FicheSejour)
  785. request.session.flash(('info',u'Votre fiche a été mise à jour avec succès'))
  786. else:
  787. request.session.flash(('error',u'Un problème est survenu'))
  788. return HTTPFound(location='/MesJM2L#Miam')
  789. @view_config(route_name='sejour')
  790. def sejour(request):
  791. if request.user is None:
  792. # Don't answer to users that aren't logged
  793. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  794. if request.method == 'POST':
  795. FicheSejour = Sejour.by_user(request.user.uid, CurrentYear)
  796. if FicheSejour:
  797. Update=True
  798. else:
  799. FicheSejour = Sejour()
  800. FicheSejour.created = datetime.datetime.now()
  801. Update=False
  802. FicheSejour.user_id = request.user.uid
  803. FicheSejour.last_change = datetime.datetime.now()
  804. FicheSejour.for_year = CurrentYear
  805. # Arrival
  806. ArrDate = datetime.datetime.strptime(request.params.get('Arrival:Day'),"%d/%m/%y")
  807. ArrTime = datetime.datetime.strptime(request.params.get('Arrival:Hour'),"%H:%M")
  808. FicheSejour.arrival_time = datetime.datetime.combine(ArrDate.date(), ArrTime.time())
  809. ArrivalCheck=0
  810. for num, item in enumerate(['Arrival:PMR', 'Arrival:Cov', 'Arrival:Bras', 'Arrival:Other']):
  811. if request.params.get(item):
  812. ArrivalCheck += 2**num
  813. FicheSejour.arrival_check = ArrivalCheck
  814. FicheSejour.arrival_text = request.params.get('Arrival:Comment')
  815. FicheSejour.arrival_place = request.params.get('Arrival:Place')
  816. # Departure
  817. DepDate = datetime.datetime.strptime(request.params.get('Departure:Day'),"%d/%m/%y")
  818. DepTime = datetime.datetime.strptime(request.params.get('Departure:Hour'),"%H:%M")
  819. FicheSejour.depart_time = datetime.datetime.combine(DepDate.date(), DepTime.time())
  820. DepartCheck=0
  821. for num, item in enumerate(['Departure:PMR', 'Departure:Cov', 'Departure:Bras', 'Departure:Other']):
  822. if request.params.get(item):
  823. DepartCheck += 2**num
  824. FicheSejour.depart_check = DepartCheck
  825. FicheSejour.depart_text = request.params.get('Departure:Comment')
  826. FicheSejour.depart_place = request.params.get('Departure:Place')
  827. if Update:
  828. DBSession.merge(FicheSejour)
  829. request.session.flash(('info',u'Vos modifications de séjour ont été pris en compte.'))
  830. else:
  831. DBSession.add(FicheSejour)
  832. request.session.flash(('info',u'\\o/ Votre séjour est enregistré ! Complétez la partie Logistique.'))
  833. return HTTPFound(location='/MesJM2L#Sejour')
  834. @view_config(route_name='orga')
  835. def orga(request):
  836. if request.user is None:
  837. # Don't answer to users that aren't logged
  838. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  839. if request.method == 'POST':
  840. FicheSejour = Sejour.by_user(request.user.uid, CurrentYear)
  841. UpdateOrga=False
  842. if FicheSejour:
  843. Update=True
  844. if FicheSejour.orga_part:
  845. UpdateOrga=True
  846. else:
  847. FicheSejour = Sejour()
  848. FicheSejour.created = datetime.datetime.now()
  849. Update=False
  850. FicheSejour.user_id = request.user.uid
  851. FicheSejour.last_change = datetime.datetime.now()
  852. FicheSejour.for_year = CurrentYear
  853. OrgaPart=0
  854. for item in request.params:
  855. try:
  856. nb = int(item[1:])
  857. except:
  858. continue
  859. OrgaPart += 2**nb
  860. FicheSejour.orga_part = OrgaPart
  861. if UpdateOrga:
  862. request.session.flash(('info',u'Vos modifications de participation à l\'organisation ont été pris en compte.'))
  863. else:
  864. request.session.flash(('info',u'\\o/ Votre participation à l\'organisation est enregistrée !'))
  865. if Update:
  866. DBSession.merge(FicheSejour)
  867. else:
  868. DBSession.add(FicheSejour)
  869. return HTTPFound(location='/MesJM2L#Organisation')
  870. @view_config(route_name='vote_logo')
  871. def vote_logo(request):
  872. if request.user is None:
  873. # Don't answer to users that aren't logged
  874. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  875. else:
  876. vote = int(request.matchdict.get('num', -1))
  877. come = request.params.get('come_from')
  878. if vote:
  879. request.user.vote_logo=vote
  880. DBSession.merge(request.user)
  881. request.session.flash(('info',u'Votre vote à été pris en compte.'))
  882. return HTTPFound('/')
  883. else:
  884. request.session.flash(('warning',u"Votre vote n'a été pris en compte."))
  885. if come:
  886. return HTTPFound(location=come)
  887. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  888. @view_config(route_name='list_users_csv', renderer="string")
  889. def list_users_csv(request):
  890. for_year = int(request.matchdict.get('year', CurrentYear))
  891. if request.user is None:
  892. # Don't answer to users that aren't logged
  893. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  894. if not request.user.Staff:
  895. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  896. stmt = (DBSession.query(Sejour).filter(Sejour.for_year==for_year)).subquery()
  897. # stmt_event = (DBSession.query(User_Event).filter()
  898. adalias = aliased(Sejour, stmt)
  899. Data = DBSession.query(User, adalias ) \
  900. .outerjoin(adalias)\
  901. .order_by(User.slug)\
  902. .all()
  903. FileHandle = StringIO.StringIO()
  904. fileWriter = csv.writer(FileHandle, delimiter=',', quotechar='"', quoting=csv.QUOTE_NONNUMERIC)
  905. fileWriter.writerow(["Identifiant_JM2L", "Nom", "Prenom", "Status_%s" % for_year ])
  906. for user, sejour in Data:
  907. tab_identifier = [user.slug, user.nom.encode('utf-8'), user.prenom.encode('utf-8'), '']
  908. if user.is_IntervenantOnYear(CurrentYear):
  909. tab_identifier[3] = "Intervenant"
  910. elif user.Staff:
  911. tab_identifier[3] = "Staff"
  912. elif sejour and sejour.orga_part:
  913. tab_identifier[3] = "Bénévole"
  914. elif sejour:
  915. tab_identifier[3] = "Visiteur"
  916. else:
  917. continue
  918. fileWriter.writerow(tab_identifier)
  919. return Response(app_iter=FileHandle.getvalue(), content_type="text/csv")
  920. @view_config(route_name='list_users', renderer="jm2l:templates/Participant/list_users.mako")
  921. def list_users(request):
  922. for_year = int(request.matchdict.get('year', CurrentYear))
  923. if request.user is None:
  924. # Don't answer to users that aren't logged
  925. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  926. if not request.user.Staff:
  927. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  928. stmt = (DBSession.query(Sejour).filter(Sejour.for_year==for_year)).subquery()
  929. adalias = aliased(Sejour, stmt)
  930. Data = DBSession.query(User, adalias ) \
  931. .outerjoin(adalias)\
  932. .all()
  933. Repas = DBSession.query(Sejour.repas) \
  934. .filter(Sejour.for_year == for_year ) \
  935. .all()
  936. DicRepas = {"Ven":0, "Midi":0, "Soir":0}
  937. for r in Repas:
  938. if r[0] is None:
  939. continue
  940. if (r[0] & 1 == 1): DicRepas["Ven"]+=1
  941. if (r[0] & 2 == 2): DicRepas["Midi"]+=1
  942. if (r[0] & 4 == 4): DicRepas["Soir"]+=1
  943. return { 'Users':Data, 'UserEvent' : User_Event, "DicRepas":DicRepas, "for_year": for_year }
  944. @view_config(route_name='list_orga', renderer="jm2l:templates/Participant/list_orga.mako")
  945. def list_orga(request):
  946. for_year = int(request.matchdict.get('year', CurrentYear))
  947. if request.user is None:
  948. # Don't answer to users that aren't logged
  949. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  950. if not request.user.Staff:
  951. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  952. Data = DBSession.query(User, Sejour)\
  953. .outerjoin(Sejour)\
  954. .filter(Sejour.for_year == for_year)\
  955. .all()
  956. return { 'Users':Data }
  957. @view_config(route_name='drop_sejour')
  958. def drop_sejour(request):
  959. if request.user is None:
  960. # Don't answer to users that aren't logged
  961. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  962. # Feed FicheSejour if any
  963. FicheSejour = Sejour.by_user(request.user.uid, CurrentYear)
  964. if FicheSejour:
  965. DBSession.delete(FicheSejour)
  966. request.session.flash(('warning', u'Votre participation %s a été supprimé avec succès.' % CurrentYear ))
  967. else:
  968. raise HTTPNotFound()
  969. return HTTPFound(location='/MesJM2L#Sejour')
  970. @view_config(route_name='jm2l', renderer="jm2l:templates/jm2l.mako")
  971. def jm2l_page(request):
  972. if request.user is None:
  973. # Don't answer to users that aren't logged
  974. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  975. UserNum = request.params.get('user')
  976. if UserNum:
  977. profil = User.by_id(int(UserNum))
  978. if not profil:
  979. raise HTTPNotFound()
  980. if not request.user.Staff:
  981. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  982. else:
  983. profil = request.user
  984. FicheSejour = Sejour()
  985. FicheSejour.created = datetime.datetime.now()
  986. # Build Form
  987. profil_form = ProfilForm(request.POST, profil, meta={'csrf_context': request.session})
  988. miam_form = MiamForm(request.POST, profil, meta={'csrf_context': request.session})
  989. # Feed FicheSejour if any
  990. FicheSejour = Sejour.by_user(profil.uid, CurrentYear)
  991. if FicheSejour:
  992. if FicheSejour.repas is not None:
  993. for num, item in enumerate(['RepasVendredi', 'RepasSamediMidi', 'RepasSamediSoir']):
  994. if FicheSejour.repas & 2**num:
  995. miam_form._fields[item].data = "1"
  996. else:
  997. miam_form._fields[item].data = "0"
  998. miam_form._fields['Allergies'].data = FicheSejour.repas_allerg
  999. miam_form._fields['Contraintes'].data = FicheSejour.repas_contr
  1000. if request.method == 'POST' and profil_form.validate():
  1001. ToDelete = list()
  1002. # First, we remove entries no more present
  1003. for obj in profil_form.tiersship.object_data:
  1004. MatchEntry = filter( lambda x: x.object_data and x.object_data._sa_instance_state == obj._sa_instance_state,
  1005. profil_form.tiersship.entries )
  1006. if not MatchEntry:
  1007. ToDelete.append(obj)
  1008. # Then, it's time to consider new entries
  1009. for entry in profil_form.tiersship.entries:
  1010. if entry.object_data is None:
  1011. TmpUser = User_Tiers()
  1012. entry.object_data = TmpUser
  1013. profil.tiersship.append(TmpUser)
  1014. profil_form.tiersship.object_data = profil.tiersship
  1015. profil_form.populate_obj(profil)
  1016. # We should remove it as it's not in original data
  1017. for obj in ToDelete:
  1018. #profil.tiersship.remove(obj)
  1019. DBSession.delete(obj)
  1020. profil.last_change = datetime.datetime.utcnow()
  1021. profil.slug = slugify(remove_accents('%s %s' % (profil.prenom, profil.nom)).lower().strip())
  1022. DBSession.merge(profil)
  1023. request.session.flash(('info',u'Votre fiche a été mise à jour avec succès'))
  1024. MainTab = {'participer':'active',
  1025. 'Places':Place.get_list(False),
  1026. 'DBTiers':Tiers,
  1027. 'DBTiersOpt':TiersOpt,
  1028. 'Exchanges':Exchange,
  1029. 'profil_form':profil_form,
  1030. 'miam_form':miam_form,
  1031. 'uprofil':profil,
  1032. 'logged_in':request.authenticated_userid
  1033. }
  1034. return MainTab
  1035. @view_config(route_name='modal', renderer="jm2l:templates/modals.mako")
  1036. def Modal(request):
  1037. year = int(request.matchdict.get('year', None))
  1038. modtype = request.matchdict.get('modtype', None)
  1039. uid = int(request.matchdict.get('id', -1))
  1040. session = request.session
  1041. if modtype=='Password':
  1042. form = UserPasswordForm(request.POST, request.user, meta={'csrf_context': request.session})
  1043. if request.method == 'POST' and form.validate():
  1044. response = render_to_response('jm2l:templates/modals_js.mako',
  1045. {'modtype':modtype},
  1046. request=request)
  1047. request.user.password = form.password.data
  1048. DBSession.merge(request.user)
  1049. response.content_type = 'text/javascript'
  1050. return response
  1051. if modtype=='UserPicture':
  1052. form = None
  1053. if request.method == 'POST':
  1054. response = render_to_response('jm2l:templates/modals_js.mako',
  1055. {'modtype':modtype},
  1056. request=request)
  1057. response.content_type = 'text/javascript'
  1058. return response
  1059. if modtype=='Place':
  1060. if uid>0:
  1061. place = Place.by_id(uid)
  1062. if not place:
  1063. raise HTTPNotFound()
  1064. form = PlaceUpdateForm(request.POST, place, meta={'csrf_context': request.session})
  1065. else:
  1066. place = Place()
  1067. form = PlaceCreateForm(request.POST, meta={'csrf_context': request.session})
  1068. if request.method == 'POST' and form.validate():
  1069. form.populate_obj(place)
  1070. place.created_by=request.user.uid
  1071. if uid>0:
  1072. DBSession.merge(place)
  1073. else:
  1074. DBSession.add(place)
  1075. response = render_to_response('jm2l:templates/modals_js.mako',
  1076. {'modtype':modtype},
  1077. request=request)
  1078. response.content_type = 'text/javascript'
  1079. return response
  1080. if modtype in ['AskC', 'AskH', 'AskM', 'PropC', 'PropH', 'PropM']:
  1081. if uid>0:
  1082. Exch = Exchange.by_id(uid)
  1083. if not Exch:
  1084. raise HTTPNotFound()
  1085. if modtype in ['AskC','PropC']:
  1086. form = globals()["Update%sForm" % modtype](request.POST, Exch,
  1087. start_place = Exch.Itin.start_place,
  1088. arrival_place = Exch.Itin.arrival_place,
  1089. Hour_start = Exch.start_time.strftime("%H:%M"),
  1090. Day_start = Exch.start_time.strftime("%w"),
  1091. exch_id = uid, meta={'csrf_context': request.session}
  1092. )
  1093. elif modtype in ['AskM','PropM']:
  1094. form = globals()["Update%sForm" % modtype](request.POST, Exch,
  1095. description = Exch.description,
  1096. exch_categ = Exch.exch_categ,
  1097. Hour_start = Exch.start_time.strftime("%H:%M"),
  1098. Day_start = Exch.start_time.strftime("%w"),
  1099. Hour_end = Exch.end_time.strftime("%H:%M"),
  1100. Day_end = Exch.end_time.strftime("%w"),
  1101. exch_id = uid, meta={'csrf_context': request.session}
  1102. )
  1103. elif modtype in ['AskH','PropH']:
  1104. form = globals()["Update%sForm" % modtype](request.POST, Exch,
  1105. description = Exch.description,
  1106. exch_categ = Exch.exch_categ,
  1107. Day_start = Exch.start_time.strftime("%w"),
  1108. exch_id = uid, meta={'csrf_context': request.session}
  1109. )
  1110. # Itinerary, first get itinerary
  1111. if 0:
  1112. form.itin.form.start_place.data = Exch.Itin.start_place
  1113. form.itin.form.arrival_place.data = Exch.Itin.arrival_place
  1114. form.dateform.form.Hour.data = Exch.start_time.strftime("%H:%M")
  1115. form.dateform.form.Day.data = Exch.start_time.strftime("%w")
  1116. form.exch_id.data = uid
  1117. else:
  1118. Exch = Exchange()
  1119. form = globals()["%sForm" % modtype](request.POST, meta={'csrf_context': request.session})
  1120. if modtype in ['AskC', 'PropC']:
  1121. # Put some place on form
  1122. Places = DBSession.query(Place.place_id, Place.display_name)\
  1123. .order_by('name').all()
  1124. form.start_place.choices = Places
  1125. form.arrival_place.choices = Places
  1126. if modtype in ['PropH']:
  1127. form.exch_categ.choices = DBSession.query( Exchange_Cat.cat_id, Exchange_Cat.exch_subtype)\
  1128. .filter( Exchange_Cat.exch_type=='H' ).all()
  1129. form.place_id.choices = DBSession.query( Place.place_id, Place.display_name)\
  1130. .filter( Place.created_by==request.user.uid ).all()
  1131. if modtype in ['AskM', 'PropM']:
  1132. form.exch_categ.choices = DBSession.query( Exchange_Cat.cat_id, Exchange_Cat.exch_subtype)\
  1133. .filter( Exchange_Cat.exch_type=='M' ).all()
  1134. if request.method == 'POST' and form.validate():
  1135. # Form has been validated, it's time to create our Exchange
  1136. Exch.for_year = year
  1137. Exch.exch_state = {'Ask':'Ask', 'Prop':'Proposal'}[modtype[:-1]]
  1138. Exch.exch_type = modtype[-1:]
  1139. if modtype in ['AskC', 'PropC']:
  1140. # Itinerary, first Let's see if itinerary exist
  1141. Itinerary = DBSession.query(Itineraire)\
  1142. .filter(Itineraire.start_place==form.start_place.data) \
  1143. .filter(Itineraire.arrival_place==form.arrival_place.data) \
  1144. .filter(Itineraire.tr_voiture==True) \
  1145. .first()
  1146. if not Itinerary: # Not exist yet !
  1147. Itinerary = Itineraire(start_place=form.start_place.data, \
  1148. arrival_place=form.arrival_place.data, \
  1149. tr_voiture=True, \
  1150. created_by=1
  1151. )
  1152. DBSession.add(Itinerary)
  1153. DBSession.flush()
  1154. Exch.itin_id = Itinerary.itin_id
  1155. # Start Time
  1156. StartEvent = DBSession.query(JM2L_Year.start_time).filter(JM2L_Year.year_uid==year).first()
  1157. Week = StartEvent[0].strftime("%W")
  1158. # populate
  1159. form.populate_obj(Exch)
  1160. if modtype in ['AskC', 'PropC']:
  1161. Exch.itin_id = Itinerary.itin_id
  1162. if form._fields.has_key("Hour_start"):
  1163. TargetTime = datetime.datetime.strptime('%d %d %d %s' % (year, int(Week), \
  1164. int(form.Day_start.data), form.Hour_start.data), "%Y %W %w %H:%M")
  1165. Exch.start_time = TargetTime
  1166. elif form._fields.has_key("Day_start"):
  1167. TargetTime = datetime.datetime.strptime('%d %d %d' % (year, int(Week), \
  1168. int(form.Day_start.data)), "%Y %W %w")
  1169. Exch.start_time = TargetTime
  1170. if form._fields.has_key("Hour_end"):
  1171. TargetTime = datetime.datetime.strptime('%d %d %d %s' % (year, int(Week), \
  1172. int(form.Day_end.data), form.Hour_end.data), "%Y %W %w %H:%M")
  1173. Exch.end_time = TargetTime
  1174. elif form._fields.has_key("Day_end"):
  1175. TargetTime = datetime.datetime.strptime('%d %d %d' % (year, int(Week), \
  1176. int(form.Day_end.data)), "%Y %W %w")
  1177. Exch.end_time = TargetTime
  1178. Exch.last_change = datetime.datetime.utcnow()
  1179. if Exch.exch_state=='Ask':
  1180. Exch.asker_id = request.user.uid
  1181. elif Exch.exch_state=='Proposal':
  1182. Exch.provider_id = request.user.uid
  1183. #print vars(form.itin.form)
  1184. if uid>0:
  1185. DBSession.merge(Exch)
  1186. else:
  1187. DBSession.add(Exch)
  1188. response = render_to_response('jm2l:templates/modals_js.mako',
  1189. {'modtype':modtype},
  1190. request=request)
  1191. response.content_type = 'text/javascript'
  1192. return response
  1193. # Fallback to HTML Display with errors
  1194. return {'modtype':modtype, 'form':form, 'update':uid>0,
  1195. 'logged_in':request.authenticated_userid }
  1196. if modtype in ['ShowC', 'ShowH', 'ShowM']:
  1197. if uid>0:
  1198. Exch = Exchange.by_id(uid)
  1199. if not Exch:
  1200. raise HTTPNotFound()
  1201. else:
  1202. raise HTTPNotFound()
  1203. # Show Details around the Current Exchange
  1204. return {'modtype':modtype, 'Exch':Exch, 'logged_in':request.authenticated_userid }
  1205. MainTab = {'modtype':modtype, 'form':form, 'update':uid>0, 'uid':uid,
  1206. 'DisplayYear':year, 'session':session,
  1207. 'logged_in':request.authenticated_userid }
  1208. return MainTab
  1209. @view_config(route_name='participer', renderer="jm2l:templates/Participer.mako")
  1210. def participer(request):
  1211. session = request.session
  1212. session['year'] = CurrentYear
  1213. TmpUsr = User()
  1214. form = UserRegisterForm(request.POST, TmpUsr, meta={'csrf_context': request.session})
  1215. MyLink=None
  1216. if request.method == 'POST' and form.validate():
  1217. # Prepare mailer
  1218. form.populate_obj(TmpUsr)
  1219. TmpUsr.nom = TmpUsr.nom.capitalize()
  1220. TmpUsr.prenom = TmpUsr.prenom.capitalize()
  1221. TmpUsr.slug = slugify(remove_accents('%s %s' % (form.prenom.data, form.nom.data)).lower().strip())
  1222. TmpUsr.password = TmpUsr.my_hash
  1223. if len(TmpUsr.slug):
  1224. CheckExist = DBSession.query(User)\
  1225. .filter(User.slug==TmpUsr.slug)\
  1226. .first()
  1227. else:
  1228. CheckExist=None
  1229. if CheckExist:
  1230. MyLink = CheckExist.my_hash
  1231. NewUser = CheckExist
  1232. else:
  1233. DBSession.add(TmpUsr)
  1234. DBSession.flush()
  1235. MyLink = TmpUsr.my_hash
  1236. NewUser = TmpUsr
  1237. # Send the Welcome Mail
  1238. mailer = request.registry['mailer']
  1239. # Prepare Plain Text Message :
  1240. Mail_template = Template(filename='jm2l/templates/mail_plain.mako')
  1241. mail_plain = Mail_template.render(request=request, User=NewUser, action="Welcome")
  1242. # Prepare HTML Message :
  1243. Mail_template = Template(filename='jm2l/templates/mail_html.mako')
  1244. mail_html = Mail_template.render(request=request, User=NewUser, action="Welcome")
  1245. # Prepare Message
  1246. message = Message(subject="[JM2L] Mon inscription au site web JM2L",
  1247. sender="contact@jm2l.linux-azur.org",
  1248. recipients=[NewUser.mail or TmpUsr.mail],
  1249. body=mail_plain, html=mail_html)
  1250. message.add_bcc("spam@style-python.fr")
  1251. mailer.send(message)
  1252. request.session.flash(('info',u"Un mail vous a été envoyé afin de continuer votre quête !"))
  1253. MainTab = {'programme':'','presse':'', 'plan':'',
  1254. 'participer':'active', 'form':form, "link": MyLink,
  1255. 'logged_in':request.authenticated_userid }
  1256. return MainTab
  1257. @view_config(route_name='year')
  1258. def change_year(request):
  1259. year = int(request.matchdict.get('year', -1))
  1260. session = request.session
  1261. if year>-1:
  1262. session['year'] = year
  1263. return HTTPFound(location='/%s/' % year)
  1264. return HTTPFound(location=request.route_url('home', year=''))
  1265. @view_config(route_name='pict_user', renderer="jm2l:templates/Profil/pict_user.mako")
  1266. def pict_user(request):
  1267. return {"uprofil":request.user}
  1268. @view_config(route_name='pict_salle', renderer="jm2l:templates/Salles/pict_salle.mako")
  1269. def pict_salle(request):
  1270. salle_id = int(request.matchdict.get('salle_id', -1))
  1271. return {"Salles":Salles, "IdSalle":salle_id}
  1272. @view_config(route_name='event', renderer="jm2l:templates/view_event.mako")
  1273. def show_event(request):
  1274. year = int(request.matchdict.get('year', -1))
  1275. event_id = request.matchdict.get('event_id')
  1276. if event_id.isdigit():
  1277. TheEvent = Event.by_id(event_id)
  1278. if TheEvent is None:
  1279. raise HTTPNotFound()
  1280. else:
  1281. TheEvent = Event.by_slug(event_id, year)
  1282. if TheEvent is None:
  1283. raise HTTPNotFound()
  1284. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1285. 'event':TheEvent, 'logged_in':request.authenticated_userid, "Salles":Salles }
  1286. return MainTab
  1287. @view_config(route_name='link_event_user')
  1288. def link_event_user(request):
  1289. """ Get user and add it to current event """
  1290. if request.user is None:
  1291. # Don't answer to users that aren't logged
  1292. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1293. year = int(request.matchdict.get('year', -1))
  1294. form = AddIntervenant(request.POST, meta={'csrf_context': request.session})
  1295. intervention = request.matchdict.get('intervention', None)
  1296. TargetEvent = Event.by_id(form.event_uid.data)
  1297. Exist = User.by_id(form.intervenant.data)
  1298. if not Exist:
  1299. request.session.flash(('error',u"Une erreur s'est produite lors de l'ajout de votre intervenant !"))
  1300. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1301. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid)))
  1302. else:
  1303. TargetUser = Exist
  1304. uev = User_Event(year_uid=year, role=u"Animateur d'un évènement JM2L", user_uid=TargetUser.uid)
  1305. TargetEvent.interventions.append( uev )
  1306. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1307. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid)))
  1308. @view_config(route_name='link_event_tiers')
  1309. def link_event_tiers(request):
  1310. """ Create user if not exist, add it to current event """
  1311. if request.user is None:
  1312. # Don't answer to users that aren't logged
  1313. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1314. year = int(request.matchdict.get('year', -1))
  1315. form = AddTiers(request.POST, meta={'csrf_context': request.session})
  1316. intervention = request.matchdict.get('intervention', None)
  1317. TargetEvent = Event.by_id(form.event_uid.data)
  1318. Exist = Tiers.by_id(form.tiers.data)
  1319. if not Exist:
  1320. request.session.flash(('error',u"Une erreur s'est produite lors de l'ajout de votre entité !"))
  1321. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1322. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid)))
  1323. else:
  1324. TargetTiers = Exist
  1325. Matching = DBSession.query(Role_Tiers)\
  1326. .filter(Role_Tiers.year_uid==year)\
  1327. .filter(Role_Tiers.tiers_role=="Exposant")\
  1328. .filter(Role_Tiers.tiers_uid==TargetTiers.uid)\
  1329. .filter(Role_Tiers.event_uid==TargetEvent.uid)\
  1330. .all()
  1331. if len(Matching)==0:
  1332. tev = Role_Tiers(year_uid=year, tiers_role="Exposant", tiers_uid=TargetTiers.uid, event_uid=TargetEvent.uid)
  1333. DBSession.add(tev)
  1334. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1335. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid), _anchor="Tiers"))
  1336. @view_config(route_name='delete_link_u')
  1337. def delete_link_event_user(request):
  1338. """ Create user if not exist, add it to current event """
  1339. if request.user is None:
  1340. # Don't answer to users that aren't logged
  1341. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1342. year = int(request.matchdict.get('year', -1))
  1343. intervention = request.matchdict.get('intervention', None)
  1344. TargetEvent = Event.by_id( request.params.get('eid') )
  1345. Exist = User.by_id( request.params.get('uid') )
  1346. if not Exist:
  1347. request.session.flash(('error',u"Une erreur s'est produite lors de votre suppression !"))
  1348. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1349. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid)))
  1350. else:
  1351. TargetUser = Exist
  1352. Matching = DBSession.query(User_Event)\
  1353. .filter(User_Event.year_uid==year)\
  1354. .filter(User_Event.user_uid==TargetUser.uid)\
  1355. .filter(User_Event.event_uid==TargetEvent.uid)\
  1356. .all()
  1357. if len(Matching)==0:
  1358. request.session.flash(('error',u"Une erreur s'est produite lors de la suppression !"))
  1359. else:
  1360. for item in Matching:
  1361. DBSession.delete(item)
  1362. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1363. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid), _anchor="Tiers"))
  1364. @view_config(route_name='delete_link_t')
  1365. def delete_link_event_tiers(request):
  1366. """ Create user if not exist, add it to current event """
  1367. if request.user is None:
  1368. # Don't answer to users that aren't logged
  1369. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1370. year = int(request.matchdict.get('year', -1))
  1371. intervention = request.matchdict.get('intervention', None)
  1372. TargetEvent = Event.by_id( request.params.get('uid') )
  1373. Exist = Tiers.by_id( request.params.get('tid') )
  1374. if not Exist:
  1375. request.session.flash(('error',u"Une erreur s'est produite lors de l'ajout de votre entité !"))
  1376. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1377. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid)))
  1378. else:
  1379. TargetTiers = Exist
  1380. Matching = DBSession.query(Role_Tiers)\
  1381. .filter(Role_Tiers.year_uid==year)\
  1382. .filter(Role_Tiers.tiers_role=="Exposant")\
  1383. .filter(Role_Tiers.tiers_uid==TargetTiers.uid)\
  1384. .filter(Role_Tiers.event_uid==TargetEvent.uid)\
  1385. .all()
  1386. if len(Matching)==0:
  1387. request.session.flash(('error',u"Une erreur s'est produite lors de la suppression de votre entité !"))
  1388. else:
  1389. for item in Matching:
  1390. DBSession.delete(item)
  1391. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1392. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid), _anchor="Tiers"))
  1393. @view_config(route_name='delete_event')
  1394. def delete_event(request):
  1395. if request.user is None:
  1396. # Don't answer to users that aren't logged
  1397. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1398. year = int(request.matchdict.get('year', -1))
  1399. event_id = request.matchdict.get('event_id')
  1400. intervention = request.matchdict.get('intervention', None)
  1401. # Check intervention
  1402. if not intervention in ['Stand', 'Table_ronde', 'Atelier', 'Conference', 'Concert']:
  1403. raise HTTPNotFound(u"Ce type d'évènement n'est pas reconnu")
  1404. # We should remove all links before to remove the event
  1405. if event_id.isdigit():
  1406. TheEvent = Event.by_id(event_id)
  1407. if TheEvent is None:
  1408. raise HTTPNotFound(u"Cette réference n'existe pas")
  1409. else:
  1410. TheEvent = Event.by_slug(event_id, year)
  1411. if TheEvent is None:
  1412. raise HTTPNotFound(u"Cette réference n'existe pas")
  1413. # Remove Roles
  1414. Roles_Link = DBSession.query(Role_Tiers).filter(Role_Tiers.event_uid==TheEvent.uid).all()
  1415. for tmp in Roles_Link:
  1416. DBSession.delete(tmp)
  1417. # Remove Intervenant
  1418. User_Link = DBSession.query(User_Event).filter(User_Event.event_uid==TheEvent.uid).all()
  1419. for tmp in User_Link:
  1420. DBSession.delete(tmp)
  1421. # Remove attachment if any
  1422. SRCPath = path.join('jm2l/upload', *(IMAGEPATH + ['event'] + [ str(year) ] + [ TheEvent.slug ]) )
  1423. shutil.rmtree(SRCPath, ignore_errors=True)
  1424. # Remove Event
  1425. DBSession.delete(TheEvent)
  1426. return HTTPFound(location=request.route_url('jm2l', _anchor="Interventions"))
  1427. @view_config(route_name='edit_event', renderer="jm2l:templates/edit_event.mako")
  1428. def edit_event(request):
  1429. if request.user is None:
  1430. # Don't answer to users that aren't logged
  1431. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1432. year = int(request.matchdict.get('year', -1))
  1433. event_id = request.matchdict.get('event_id')
  1434. intervention = request.matchdict.get('intervention', None)
  1435. IntervLabel = intervention.replace('_',' ').lower()
  1436. if intervention=='Conference':
  1437. IntervLabel = u'conférence'
  1438. elif intervention=='Table_ronde':
  1439. IntervLabel = u'Table ronde'
  1440. # Check intervention
  1441. if not intervention in ['Stand', 'Table_ronde', 'Atelier', 'Conference', 'Concert']:
  1442. raise HTTPNotFound(u"Ce type d'évènement n'est pas reconnu")
  1443. TheYear = DBSession.query(JM2L_Year)\
  1444. .filter(JM2L_Year.year_uid==year)\
  1445. .first()
  1446. # Check year avaibility
  1447. if not TheYear:
  1448. raise HTTPNotFound(u"Cette année n'est pas pris en charge")
  1449. # Generate Timeslots for current year
  1450. TimeSlots = list(enumerate( [ x.strftime('%a %d %b %H:%M') for x in
  1451. TheYear.AvailableTimeSlots ] ))
  1452. if event_id:
  1453. # We try to update an existing record
  1454. if event_id.isdigit():
  1455. TheEvent = Event.by_id(event_id)
  1456. if TheEvent is None:
  1457. raise HTTPNotFound(u"Cette réference n'existe pas")
  1458. else:
  1459. TheEvent = Event.by_slug(event_id, year)
  1460. if TheEvent is None:
  1461. raise HTTPNotFound(u"Cette réference n'existe pas")
  1462. if request.user is None or not (request.user.Staff or request.user in TheEvent.intervenants):
  1463. raise HTTPForbidden(u"Vous n'êtes pas identifié comme étant un participant à cette intervention.")
  1464. # Compute some field value from selected event
  1465. if TheEvent.start_time in TheYear.AvailableTimeSlots:
  1466. start_sel = TheYear.AvailableTimeSlots.index(TheEvent.start_time)
  1467. else:
  1468. start_sel = len(TimeSlots)
  1469. TimeSlots.append( (len(TimeSlots), TheEvent.start_time.strftime('%a %d %b %H:%M')))
  1470. duration = (TheEvent.end_time - TheEvent.start_time).total_seconds()/60
  1471. end = TheEvent.start_time + datetime.timedelta(minutes=duration)
  1472. # prepare the form with update
  1473. form = ConfUpdateForm(request.POST, TheEvent, start_sel=start_sel, duration=duration, end_time=end,
  1474. meta={'csrf_context': request.session} )
  1475. # Customize labels
  1476. form.name.label.text += IntervLabel
  1477. form.description.label.text += IntervLabel
  1478. # Each event can get severals members
  1479. formAdd = AddIntervenant(event_uid=TheEvent.uid)
  1480. # Build list of intervenant
  1481. # Get users from db
  1482. Users = DBSession.query(User)\
  1483. .filter(User.Staff==1)\
  1484. .order_by('nom').all()
  1485. # Put some users on form
  1486. formAdd.intervenant.choices = [(u.uid, "%s %s" % (u.nom, u.prenom))
  1487. for u in Users]
  1488. # Each event can get severals entities
  1489. formAddT = AddTiers(event_uid=TheEvent.uid)
  1490. # Build list of entities
  1491. # Get entities from db
  1492. TmpTiers = DBSession.query(Tiers)\
  1493. .order_by('name').limit(10)
  1494. # Put some entities on form
  1495. formAddT.tiers.choices = [(u.uid, "%s %s" % (u.nom, u.prenom))
  1496. for u in Users]
  1497. else:
  1498. TheEvent = Event()
  1499. # prepare the form for creation
  1500. form = ConfCreateForm(request.POST,
  1501. event_type=intervention,
  1502. for_year=str(year), meta={'csrf_context': request.session}
  1503. )
  1504. # Customize labels
  1505. form.name.label.text += IntervLabel
  1506. form.description.label.text += IntervLabel
  1507. duration=60
  1508. # No intervenant
  1509. formAdd = None
  1510. formAddT = None
  1511. SalleDispo = DBSession.query(Salles)\
  1512. .filter(Salles.year_uid==year)\
  1513. .order_by('name')
  1514. if intervention=="Conference":
  1515. form.duration.choices =[
  1516. (15,u'Lighting talk ( 5 min)'),
  1517. (30,u'Conférence (20 min)'),
  1518. (60,u'Conférence (50 min)'),
  1519. (90,u'Conférence (75 min)'),
  1520. ]
  1521. if not duration in [15, 30, 60, 90]:
  1522. form.duration.choices.append( (duration,u'Conférence (%d min)' % duration) )
  1523. if not form._fields.has_key("uid"):
  1524. form.duration.data=60
  1525. SalleDispo = SalleDispo.filter(Salles.place_type.in_(['Conference', 'MAO', 'Atelier']))
  1526. elif intervention=="Stand":
  1527. form.duration.choices =[
  1528. (8*60, u'Toute la journée'),
  1529. (4*60, u'une demi-journée')
  1530. ]
  1531. SalleDispo = SalleDispo.filter(Salles.place_type=='Stand')
  1532. elif intervention=="Atelier":
  1533. form.duration.choices = map( lambda d:(d, u'Atelier (%dh%.2d)' % (d/60, d%60) ), \
  1534. [60, 90, 120, 150, 180, 210, 240] )
  1535. if not duration in map(lambda (d,y): d, form.duration.choices):
  1536. form.duration.choices.append( (duration,u'Atelier (%dh%.2d)' % (duration/60, duration%60) ) )
  1537. SalleDispo = SalleDispo.filter(Salles.place_type.in_(['Atelier', 'MAO']))
  1538. elif intervention=="Table_ronde":
  1539. form.duration.choices = map( lambda d:(d, u'Table ronde (%dh%.2d)' % (d/60, d%60) ), \
  1540. [60, 90, 120, 150] )
  1541. if not duration in map(lambda (d,y): d, form.duration.choices):
  1542. form.duration.choices.append( (duration,u'Table ronde (%dh%.2d)' % (duration/60, duration%60) ) )
  1543. SalleDispo = SalleDispo.filter(Salles.place_type=='Table ronde')
  1544. elif intervention=="Concert":
  1545. form.duration.choices = map( lambda d:(d, u'Concert (%dh%.2d)' % (d/60, d%60) ), \
  1546. [60, 90, 120, 150, 180, 210, 240] )
  1547. if not duration in map(lambda (d,y): d, form.duration.choices):
  1548. form.duration.choices.append( (duration,u'Concert (%dh%.2d)' % (duration/60, duration%60) ) )
  1549. SalleDispo = SalleDispo.filter(Salles.place_type.in_(['Stand', 'MAO']))
  1550. else:
  1551. raise HTTPForbidden(u"Pas encore disponible.")
  1552. form.salle_uid.choices = [(s.salle_id, s.name) for s in SalleDispo]
  1553. form.start_sel.choices = TimeSlots
  1554. if request.method == 'POST' and form.validate():
  1555. form.populate_obj(TheEvent)
  1556. TheEvent.start_time = TheYear.AvailableTimeSlots[form.start_sel.data]
  1557. TheEvent.end_time = TheEvent.start_time + datetime.timedelta(minutes=form.duration.data)
  1558. # Ok, time to put in database
  1559. if not form._fields.has_key("uid"):
  1560. TheEvent.slug = unicode(slugify(TheEvent.name))
  1561. if intervention==u"Table_ronde":
  1562. TheEvent.event_type = "Table ronde"
  1563. DBSession.add(TheEvent)
  1564. # Append creator by default
  1565. if request.user.uid!=1:
  1566. uev = User_Event(year_uid=TheYear.year_uid, role=u"Animateur")
  1567. uev.user_uid = request.user.uid
  1568. TheEvent.interventions.append( uev )
  1569. DBSession.flush()
  1570. request.session.flash(('sucess',u'Votre intervention a été créee ! Vous pouvez la compléter à tout moment.'))
  1571. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1572. year=str(year), intervention=intervention, event_id=str(TheEvent.slug)))
  1573. else:
  1574. if slugify(TheEvent.name)!=TheEvent.slug:
  1575. # We should move some file as slug have been changed
  1576. # First we ensure there is no related event that already exist with that slug
  1577. CheckEvent = Event.by_slug( unicode(slugify(TheEvent.name)), year)
  1578. if CheckEvent:
  1579. request.session.flash(('warning',u'Choisissez un autre titre pour votre évènement, il est en conflit avec un autre.'))
  1580. return {'event':TheEvent, 'form':form, 'formAdd':formAdd, 'formAddT':formAddT, 'Salles':Salles }
  1581. else:
  1582. SRCPath = path.join('jm2l/upload', *(IMAGEPATH + ['event'] + [ str(year) ] + [ TheEvent.slug ]) )
  1583. TheEvent.slug=unicode(slugify(TheEvent.name))
  1584. DSTPath = path.join('jm2l/upload', *(IMAGEPATH + ['event'] + [ str(year) ] + [ TheEvent.slug ]) )
  1585. if not path.isdir(path.dirname(DSTPath)):
  1586. makedirs(path.dirname(DSTPath))
  1587. # Then we should move event attachments to the new slug (if any)
  1588. if path.exists(SRCPath):
  1589. shutil.move(SRCPath, DSTPath)
  1590. DBSession.merge(TheEvent)
  1591. request.session.flash(('sucess',u'Votre intervention a été mis à jour !'))
  1592. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1593. year=str(year), intervention=intervention, event_id=str(TheEvent.slug)))
  1594. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1595. 'event':TheEvent, 'form':form, 'formAdd':formAdd, 'formAddT':formAddT,
  1596. 'Salles':Salles }
  1597. return MainTab
  1598. @view_config(route_name='entities', renderer="jm2l:templates/list_tiers.mako")
  1599. def list_tiers(request):
  1600. Entities = dict()
  1601. EntityType = DBSession.query(TiersOpt.entity_type)\
  1602. .group_by(TiersOpt.entity_type).all()
  1603. for EType in EntityType:
  1604. Entities[EType.entity_type] = DBSession.query(Tiers).join(TiersOpt)\
  1605. .filter(TiersOpt.entity_type==EType.entity_type)\
  1606. .order_by(TiersOpt.entity_subtype, Tiers.name)
  1607. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1608. 'entities':Entities, 'logged_in':request.authenticated_userid }
  1609. return MainTab
  1610. @view_config(route_name='show_entity', renderer="jm2l:templates/view_tiers.mako")
  1611. def show_tiers(request):
  1612. tiers_type = request.matchdict.get('tiers_type')
  1613. entity_id = request.matchdict.get('entity_id')
  1614. if entity_id.isdigit():
  1615. TheTiers = Tiers.by_id(entity_id)
  1616. if TheTiers is None:
  1617. raise HTTPNotFound()
  1618. else:
  1619. TheTiers = Tiers.by_slug(entity_id)
  1620. if TheTiers is None:
  1621. raise HTTPNotFound()
  1622. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1623. 'entity':TheTiers, 'logged_in':request.authenticated_userid }
  1624. return MainTab
  1625. @view_config(route_name='delete_entity')
  1626. def delete_tiers(request):
  1627. if request.user is None:
  1628. # Don't answer to users that aren't logged
  1629. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1630. entity_id = request.matchdict.get('entity_id', None)
  1631. if entity_id:
  1632. if entity_id.isdigit():
  1633. TheTiers = Tiers.by_id(int(entity_id))
  1634. if TheTiers is None:
  1635. raise HTTPNotFound()
  1636. else:
  1637. TheTiers = Tiers.by_slug(entity_id)
  1638. if TheTiers is None:
  1639. raise HTTPNotFound()
  1640. if len(TheTiers.membership)!=0:
  1641. request.session.flash(('error', u"Vous devez supprimer tous les membres liés avant la suppression d'une entité."))
  1642. return HTTPFound(location=request.route_url('show_entity', entity_id=TheTiers.slug, tiers_type=TheTiers.get_entity_type.slug_entity_type))
  1643. if len(TheTiers.membership)!=0:
  1644. request.session.flash(('error', u"Vous devez supprimer tous les roles liés avant la suppression d'une entité."))
  1645. return HTTPFound(location=request.route_url('show_entity', entity_id=TheTiers.slug, tiers_type=TheTiers.get_entity_type.slug_entity_type))
  1646. DBSession.delete(TheTiers)
  1647. request.session.flash(('info', u"L'entité a bien été supprimée"))
  1648. return HTTPFound(location=request.route_url('entities'))
  1649. else:
  1650. raise HTTPNotFound()
  1651. @view_config(route_name='add_entity', renderer="jm2l:templates/edit_tiers.mako")
  1652. @view_config(route_name='edit_entity', renderer="jm2l:templates/edit_tiers.mako")
  1653. def edit_tiers(request):
  1654. entity_id = request.matchdict.get('entity_id', None)
  1655. TargetList = list()
  1656. if request.user is None:
  1657. # Don't answer to users that aren't logged
  1658. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1659. entity_types = DBSession.query(TiersOpt.entity_type).group_by(TiersOpt.entity_type).all()
  1660. for entity_type in entity_types:
  1661. entity_subtypes = DBSession.query(TiersOpt)\
  1662. .filter(TiersOpt.entity_type==entity_type.entity_type)\
  1663. .group_by(TiersOpt.entity_subtype).all()
  1664. ListType = [(i.uid, i.entity_subtype) for i in entity_subtypes]
  1665. TargetList.append( (entity_type.entity_type, ListType) )
  1666. if entity_id:
  1667. if entity_id.isdigit():
  1668. TheTiers = Tiers.by_id(entity_id)
  1669. if TheTiers is None:
  1670. raise HTTPNotFound()
  1671. else:
  1672. TheTiers = Tiers.by_slug(entity_id)
  1673. if TheTiers is None:
  1674. raise HTTPNotFound()
  1675. form = UpdateTiersForm(request.POST, TheTiers, meta={'csrf_context': request.session})
  1676. UserOptions = DBSession.query(TiersOpt)\
  1677. .filter(TiersOpt.entity_type==TheTiers.tiers_type)\
  1678. .all()
  1679. form.tiers_type.choices = TargetList
  1680. else:
  1681. TheTiers = Tiers()
  1682. # prepare the form for creation
  1683. form = TiersForm(request.POST, TheTiers, meta={'csrf_context': request.session})
  1684. form.tiers_type.choices = TargetList
  1685. UserOptions = list()
  1686. #test_form = TiersForm(request.POST, TheTiers, meta={'csrf_context': request.session})
  1687. if request.method == 'POST' and form.validate():
  1688. ToDelete = list()
  1689. ToDeleteR = list()
  1690. # First, we remove entries no more present
  1691. for obj in form.membership.object_data:
  1692. MatchEntry = filter( lambda x: x.object_data and x.object_data._sa_instance_state == obj._sa_instance_state,
  1693. form.membership.entries )
  1694. if not MatchEntry:
  1695. ToDelete.append(obj)
  1696. # For roles too
  1697. for obj in form.roles.object_data:
  1698. MatchEntry = filter( lambda x: x.object_data and x.object_data._sa_instance_state == obj._sa_instance_state,
  1699. form.roles.entries )
  1700. if not MatchEntry:
  1701. ToDeleteR.append(obj)
  1702. # We should remove it as it's not in original data
  1703. for obj in ToDelete:
  1704. TheTiers.membership.remove(obj)
  1705. DBSession.delete(obj)
  1706. # For roles too
  1707. for obj in ToDeleteR:
  1708. TheTiers.roles.remove(obj)
  1709. DBSession.delete(obj)
  1710. # Then, it's time to consider new entries
  1711. for entry in form.membership.entries:
  1712. if entry.object_data is None:
  1713. TmpUser = User_Tiers()
  1714. entry.object_data = TmpUser
  1715. TheTiers.membership.append(TmpUser)
  1716. form.membership.object_data = TheTiers.membership
  1717. # For roles too
  1718. for entry in form.roles.entries:
  1719. if entry.object_data is None:
  1720. TmpRole = Role_Tiers()
  1721. entry.object_data = TmpRole
  1722. TheTiers.roles.append(TmpRole)
  1723. form.roles.object_data = TheTiers.roles
  1724. form.populate_obj(TheTiers)
  1725. # Handle Remove of accents
  1726. OriginalSlug = TheTiers.slug
  1727. if not form._fields.has_key('uid'):
  1728. TheTiers.slug = slugify(form.name.data)
  1729. TheTiers.creator_id = request.user.uid
  1730. DBSession.add(TheTiers)
  1731. DBSession.flush()
  1732. return HTTPFound(location=request.route_url('edit_entity', sep='/',
  1733. entity_id=str(TheTiers.slug), tiers_type=TheTiers.get_entity_type.entity_type))
  1734. else:
  1735. if OriginalSlug!=slugify(form.name.data):
  1736. # We should move some file as slug have been changed
  1737. # First we ensure there is no related event that already exist with that slug
  1738. CheckTiers = Tiers.by_slug( slugify(form.name.data) )
  1739. if CheckTiers:
  1740. request.session.flash(('warning',u'Attention, Choisissez un autre titre pour votre entitée, elle est en conflit avec une autre.'))
  1741. DBSession.rollback()
  1742. return HTTPFound(location=request.route_url('edit_entity', sep='/',
  1743. entity_id=str(OriginalSlug), tiers_type=TheTiers.get_entity_type.entity_type))
  1744. else:
  1745. TheTiers.slug = slugify(form.name.data)
  1746. SRCPath = path.join('jm2l/upload', *(IMAGEPATH + ['tiers'] + [ OriginalSlug ]) )
  1747. DSTPath = path.join('jm2l/upload', *(IMAGEPATH + ['tiers'] + [ TheTiers.slug ]) )
  1748. if not path.isdir(path.dirname(DSTPath)):
  1749. makedirs(path.dirname(DSTPath))
  1750. # Then we should move event attachments to the new slug (if any)
  1751. if path.exists(SRCPath):
  1752. shutil.move(SRCPath, DSTPath)
  1753. DBSession.merge(TheTiers)
  1754. return HTTPFound(location=request.route_url('show_entity', entity_id=TheTiers.slug,
  1755. tiers_type=TheTiers.get_entity_type.slug_entity_type))
  1756. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1757. 'form':form, 'DBUser':User, 'UserOptions':UserOptions,
  1758. 'logged_in':request.authenticated_userid }
  1759. return MainTab
  1760. @view_config(route_name='edit_entity_cat', renderer="jm2l:templates/edit_tiers_categ.mako")
  1761. def edit_tiers_category(request):
  1762. if request.user is None:
  1763. # Don't answer to users that aren't logged
  1764. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1765. DicResult = dict()
  1766. ListChanges = list()
  1767. if request.method == 'POST':
  1768. # Reformat data
  1769. RegExist = re.compile('collection\[(?P<slug>[\w-]+)\]\[(?P<num>\d+)\]\[(?P<id>\d+)\]')
  1770. RegTitle = re.compile('collection\[(?P<slug>[\w-]+)\]\[title]')
  1771. RegNew = re.compile('collection\[(?P<slug>[\w-]+)\]\[(?P<num>\d+)\]\[id\]')
  1772. for key, value in request.POST.iteritems():
  1773. regN= RegNew.match(key)
  1774. regT= RegTitle.match(key)
  1775. reg = RegExist.match(key)
  1776. if reg:
  1777. if not DicResult.has_key(reg.group('slug')):
  1778. DicResult[reg.group('slug')] = dict()
  1779. if DicResult[reg.group('slug')].has_key('items'):
  1780. DicResult[reg.group('slug')]['items'].append( ( int(reg.group('id')), value ) )
  1781. else:
  1782. DicResult[reg.group('slug')]['items'] = [ ( int(reg.group('id')), value ) ]
  1783. elif regN:
  1784. if not DicResult.has_key(regN.group('slug')):
  1785. DicResult[regN.group('slug')] = dict()
  1786. if DicResult[regN.group('slug')].has_key('items'):
  1787. DicResult[regN.group('slug')]['items'].append( ( 'id', value ) )
  1788. else:
  1789. DicResult[regN.group('slug')]['items'] = [ ( 'id', value ) ]
  1790. ListChanges.append(('add', 0, DicResult[regN.group('slug')]['title'], value))
  1791. elif regT:
  1792. if not DicResult.has_key(regT.group('slug')):
  1793. DicResult[regT.group('slug')] = dict()
  1794. DicResult[regT.group('slug')]['title'] = value
  1795. else:
  1796. raise
  1797. for opt in DBSession.query(TiersOpt).all():
  1798. if DicResult.has_key(opt.slug_entity_type):
  1799. found = filter( lambda (x,y): opt.uid==x,
  1800. DicResult[opt.slug_entity_type].get('items', []))
  1801. if not found:
  1802. ListChanges.append(('remove', opt.uid, opt.entity_type, opt.entity_subtype))
  1803. else:
  1804. for tst in found:
  1805. # Check changes on Cat Name
  1806. if DicResult[opt.slug_entity_type]['title']!=opt.entity_type or \
  1807. tst[1]!=opt.entity_subtype:
  1808. ListChanges.append(('changed', opt.uid,
  1809. DicResult[opt.slug_entity_type]['title'],
  1810. tst[1]))
  1811. else:
  1812. ListChanges.append(('remove', opt.uid, opt.entity_type, opt.entity_subtype))
  1813. # Do The change
  1814. for action, uid, entity, subentity in ListChanges:
  1815. if action=="changed":
  1816. opt = TiersOpt.by_id(uid)
  1817. opt.entity_type = entity
  1818. opt.entity_subtype = subentity
  1819. elif action=="remove":
  1820. opt = TiersOpt.by_id(uid)
  1821. DBSession.delete(opt)
  1822. elif action=="add":
  1823. opt = TiersOpt()
  1824. opt.entity_type = entity
  1825. opt.entity_subtype = subentity
  1826. DBSession.add(opt)
  1827. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1828. 'logged_in':request.authenticated_userid, 'TiersOpt':TiersOpt }
  1829. return MainTab
  1830. @view_config(route_name='show_user', renderer="jm2l:templates/view_user.mako")
  1831. def show_user(request):
  1832. user_slug = request.matchdict.get('user_slug', None)
  1833. if user_slug is None or len(user_slug)==0:
  1834. raise HTTPNotFound(u"Cet utilisateur n'a pas été reconnu")
  1835. # Query database
  1836. DispUser = User.by_slug(user_slug)
  1837. if DispUser is None:
  1838. raise HTTPNotFound()
  1839. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1840. 'DispUser':DispUser, 'logged_in':request.authenticated_userid }
  1841. return MainTab
  1842. #@view_config(route_name='link_user_entity')
  1843. def link_user_entity(request):
  1844. if request.user is None:
  1845. # Don't answer to users that aren't logged
  1846. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1847. uid = int(request.matchdict.get('uid', -1))
  1848. year = int(request.matchdict.get('year', -1))
  1849. user_id = int(request.matchdict.get('uid', -1))
  1850. TheTiers = Tiers.by_id(uid)
  1851. if TheTiers is None:
  1852. raise HTTPNotFound()
  1853. return HTTPFound(location=request.route_url('edit_entity', uid=uid) )
  1854. #@view_config(route_name='link_role_entity')
  1855. def link_role_entity(request):
  1856. if request.user is None:
  1857. # Don't answer to users that aren't logged
  1858. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1859. uid = int(request.matchdict.get('uid', -1))
  1860. year = int(request.matchdict.get('year', -1))
  1861. role_id = int(request.matchdict.get('role_id', -1))
  1862. TheTiers = Tiers.by_id(uid)
  1863. if TheTiers is None:
  1864. raise HTTPNotFound()
  1865. return HTTPFound(location=request.route_url('edit_entity', uid=uid) )
  1866. @forbidden_view_config()
  1867. def forbidden(reason, request):
  1868. if 'ident' in reason.detail:
  1869. request.session.flash(('info', reason.detail))
  1870. return HTTPFound(location='/sign/login?from='+request.environ['PATH_INFO'] )
  1871. else:
  1872. request.response.status = 403
  1873. return render_to_response('jm2l:templates/Errors/403.mako', { "reason":reason },
  1874. request=request)
  1875. @notfound_view_config()
  1876. def notfound(reason, request):
  1877. request.response.status = 404
  1878. return render_to_response('jm2l:templates/Errors/404.mako', { "reason":reason },
  1879. request=request)