Le repo des sources pour le site web des JM2L
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 
 

1406 Zeilen
61 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.response import Response
  6. from pyramid.view import notfound_view_config, forbidden_view_config
  7. from pyramid.view import view_config
  8. from pyramid_mailer import get_mailer
  9. from mako.template import Template
  10. # Import Web Forms
  11. from .forms import *
  12. # Database access imports
  13. from .models import *
  14. from sqlalchemy.exc import DBAPIError
  15. from sqlalchemy import func, or_
  16. # Usefull tools
  17. from slugify import slugify
  18. from icalendar import Calendar
  19. from pytz import timezone
  20. from icalendar import Event as Evt
  21. from pyramid_mailer import get_mailer
  22. from pyramid_mailer.message import Attachment, Message
  23. # Then, standard libs
  24. import webhelpers.paginate as paginate
  25. import unicodedata
  26. import time
  27. import datetime
  28. import re
  29. CurrentYear = 2015
  30. ## =-=- Here, We keep some usefull function -=-=
  31. def remove_accents(input_str):
  32. """ This function is intended to remove all accent from input unicode string """
  33. nkfd_form = unicodedata.normalize('NFKD', input_str)
  34. only_ascii = nkfd_form.encode('ASCII', 'ignore')
  35. return only_ascii
  36. ## =-=- Here, We handle ICal requests -=-=
  37. @view_config(route_name='progr_iCal', renderer="string")
  38. def ICal_Progamme_Request(request):
  39. year = int(request.matchdict.get('year', CurrentYear))
  40. # Initialization
  41. DicResult = dict()
  42. # Query database
  43. # Compute days used by all events matching the specified input year
  44. Events = DBSession.query(Event)\
  45. .filter(Event.for_year == year)\
  46. .filter(Event.event_type != 'Stand')\
  47. .order_by(Event.start_time)
  48. cal = Calendar()
  49. cal.add('prodid', '-//Programme %d//jm2l.linux-azur.org//' % year)
  50. cal.add('version', '2.0')
  51. tz = timezone('Europe/Paris')
  52. for ev in Events:
  53. if ev.event_type:
  54. event = Evt()
  55. event['uid'] = "%d/%d" % ( year, ev.uid )
  56. event.add('summary', ev.name )
  57. event.add('dtstart', ev.start_time.replace(tzinfo=tz) )
  58. event.add('dtend', ev.end_time.replace(tzinfo=tz) )
  59. event.add('created', ev.last_change.replace(tzinfo=tz) )
  60. event.add('description', "http://www.linux-azur.org/event/%s/%s" % (ev.for_year, ev.slug) )
  61. event.add('url', "http://www.linux-azur.org/event/%s/%s" % (ev.for_year, ev.slug) )
  62. event.add('priority', 5)
  63. cal.add_component(event)
  64. return cal.to_ical()
  65. ## =-=- Here, We handle Json requests -=-=
  66. @view_config(route_name='users_json', renderer="json")
  67. def JSON_User_Request(request):
  68. """ Build a JSON answer with active users and pagination handling """
  69. # Check arguments consitency
  70. pageSize = request.params.get('pageSize',"8")
  71. current_page = request.params.get('pageNum',"1")
  72. UserQuery = request.params.get('searchTerm', u"")
  73. # Don't answer to users that aren't logged
  74. if not request.user:
  75. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  76. # Check consistancy of parameters
  77. if pageSize.isdigit() and current_page.isdigit():
  78. current_page = int(current_page)
  79. pageSize = int(pageSize)
  80. else:
  81. return HTTPBadRequest('pageSize and pageNum accept only digits.')
  82. # Query database
  83. Users = DBSession.query(User.uid, User.nom, User.prenom)\
  84. .filter(User.slug.contains( remove_accents(UserQuery) ))
  85. page_url = paginate.PageURL_WebOb(request)
  86. records = paginate.Page(Users, current_page, url=page_url, items_per_page=pageSize)
  87. ListMatchUser = map( lambda u:{"id": u.uid, "text":"%s %s" % ( u.prenom, u.nom )}, records )
  88. return { "Results": ListMatchUser, "Total":records.item_count,
  89. "logged_in":request.authenticated_userid }
  90. @view_config(route_name='tiers_json', renderer="json")
  91. def JSON_Tiers_Request(request):
  92. """ Build a JSON answer with active users and pagination handling """
  93. # Check arguments consitency
  94. pageSize = request.params.get('pageSize',"8")
  95. current_page = request.params.get('pageNum',"1")
  96. TiersQuery = request.params.get('searchTerm', u"")
  97. # Don't answer to users that aren't logged
  98. if not request.user:
  99. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  100. # Check consistancy of parameters
  101. if pageSize.isdigit() and current_page.isdigit():
  102. current_page = int(current_page)
  103. pageSize = int(pageSize)
  104. else:
  105. return HTTPBadRequest('pageSize and pageNum accept only digits.')
  106. # Query database
  107. JTiers = DBSession.query(Tiers.uid, Tiers.name)\
  108. .filter(Tiers.slug.contains( remove_accents(TiersQuery) ))
  109. page_url = paginate.PageURL_WebOb(request)
  110. records = paginate.Page(JTiers, current_page, url=page_url, items_per_page=pageSize)
  111. ListMatchTiers = map( lambda t:{"id": t.uid, "text": t.name }, records )
  112. return { "Results": ListMatchTiers, "Total":records.item_count,
  113. "logged_in":request.authenticated_userid }
  114. @view_config(route_name='progr_json', renderer="json")
  115. def JSON_Progamme_Request(request):
  116. year = int(request.matchdict.get('year', CurrentYear))
  117. # Initialization
  118. DicResult = dict()
  119. # Query database
  120. # Compute days used by all events matching the specified input year
  121. Days = DBSession.query( func.strftime('%d', Event.start_time).label('day') )\
  122. .filter(Event.for_year == year)\
  123. .filter(Event.event_type != None)\
  124. .group_by(func.strftime('%d', Event.start_time)).all()
  125. for Day in Days:
  126. Events = DBSession.query(Event)\
  127. .filter(Event.for_year == year)\
  128. .filter(Event.event_type != 'Stand')\
  129. .filter("strftime('%d', start_time) = :dow").params(dow=Day.day)\
  130. .order_by(Event.start_time)
  131. ListEv = []
  132. for ev in Events:
  133. if ev.event_type:
  134. ListEv.append( {
  135. "uid":"%d/%d" % ( year, ev.uid ),
  136. "desc":ev.name,
  137. "startDate":ev.start_time.strftime('%Y-%m-%dT%H:%M:%S'),
  138. "endDate":ev.end_time.strftime('%Y-%m-%dT%H:%M:%S'),
  139. "placeName":ev.Salle and (ev.Salle.name or "unk") ,
  140. "status":ev.event_type
  141. } )
  142. DicResult[Day.day] = ListEv
  143. return { 'all':DicResult }
  144. @view_config(route_name='timeline_json', renderer="json")
  145. def JSON_TimeLine_Request(request):
  146. year = int(request.matchdict.get('year', CurrentYear))
  147. # Initialization
  148. DicResult = dict()
  149. # Query database
  150. # Compute days used by all events matching the specified input year
  151. Days = DBSession.query( func.strftime('%d', Event.start_time).label('day') )\
  152. .filter(Event.for_year == year)\
  153. .filter(Event.event_type != None)\
  154. .group_by(func.strftime('%d', Event.start_time)).all()
  155. ListEv = []
  156. for Day in Days:
  157. Events = DBSession.query(Event)\
  158. .filter(Event.for_year == year)\
  159. .filter(Event.event_type != 'Stand')\
  160. .filter("strftime('%d', start_time) = :dow").params(dow=Day.day)\
  161. .order_by(Event.start_time)
  162. #ListEv = []
  163. for ev in Events:
  164. if ev.event_type:
  165. CurMedia = ev.video.first() or ""
  166. if CurMedia:
  167. Container = "<video controls='controls' preload='metadata' style='width:60%'>"
  168. Container += "<source type='%s' " % CurMedia.mime_type
  169. Container += "src='%s' />" % CurMedia.get_path
  170. Container += "</video>"
  171. else:
  172. Container = ""
  173. ListEv.append( {
  174. #"uid":"%d/%d" % ( year, ev.uid ),
  175. "headline":ev.name,
  176. "startDate":ev.start_time.strftime('%Y,%m,%d,%H,%M'),
  177. "endDate":ev.end_time.strftime('%Y,%m,%d,%H,%M'),
  178. "text":ev.Salle and (ev.Salle.name or "unk"),
  179. #"text":ev.description[:100],
  180. "tags":ev.Salle and (ev.Salle.salle_id or "unk") ,
  181. #"status":ev.event_type,
  182. "asset": {
  183. "media": Container,
  184. "credit": ",".join(["%s %s" % (i.prenom, i.nom) for i in ev.intervenants]),
  185. "caption":"" }
  186. } )
  187. if year=="2015":
  188. DicResult = {
  189. "lang":"fr",
  190. "headline":"JM2L 2015",
  191. "type":"default",
  192. "startDate":"2015,11,28,10",
  193. "text":"<i><span class='c1'>9ème Édition</span></i>",
  194. "asset":
  195. {
  196. "media":"https://www.youtube.com/watch?v=DnfjrxVoLao",
  197. "credit":"JM2L",
  198. "caption":""
  199. }
  200. }
  201. else:
  202. DicResult = {
  203. "lang":"fr",
  204. "headline":"JM2L %d" % year,
  205. "type":"default",
  206. "asset":
  207. {
  208. "media":"",
  209. "credit":"JM2L",
  210. "caption":""
  211. }
  212. }
  213. DicResult["date"] = ListEv
  214. return { 'timeline':DicResult }
  215. ## =-=- Here, We handle HTTP requests - Public Part -=-=
  216. @view_config(route_name='home', renderer="jm2l:templates/NewIndex.mako")
  217. def index_page(request):
  218. year = request.matchdict.get('year')
  219. if year:
  220. year=int(year[:-1])
  221. content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==year).first()
  222. if content:
  223. content = content.description
  224. else:
  225. content = ""
  226. if 2004<year<=CurrentYear:
  227. if year==2006:
  228. return {'year': year, 'content':content, 'edition':u"1<sup>ère</sup>" }
  229. elif year==2015:
  230. return {'year': year, 'content':content, 'edition':u"9<sup>ème</sup>" }
  231. else:
  232. edition = year - 2005
  233. return {'year': year, 'content':content, 'edition':u"%d<sup>ème</sup>" % edition }
  234. else:
  235. raise HTTPNotFound()
  236. else:
  237. content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==CurrentYear).first().description
  238. return {'year': CurrentYear, 'content':content, 'edition':u"9<sup>ème</sup>"}
  239. @view_config(route_name='edit_index', renderer="jm2l:templates/Staff/EditIndex.mako")
  240. def edit_index(request):
  241. year = int(request.matchdict.get('year', None))
  242. content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==year).first()
  243. form = IndexForm(request.POST, content, meta={'csrf_context': request.session})
  244. if request.method == 'POST' and form.validate():
  245. form.populate_obj(content)
  246. return HTTPFound(location=request.route_url('home', year="%d/" % year))
  247. MainTab = {'home':'active', "logged_in":request.authenticated_userid,
  248. 'form':form, 'DisplayYear':year}
  249. return MainTab
  250. @view_config(route_name='programme', renderer="jm2l:templates/Public/Programme.mako")
  251. def programme(request):
  252. year = int(request.matchdict.get('year'))
  253. if 2006 > year:
  254. return HTTPBadRequest('The first JM2L event was in 2006.')
  255. # Query database about selected Year.
  256. Events = DBSession.query(Event)\
  257. .filter(Event.for_year == year)\
  258. .order_by(Event.start_time)
  259. Days = DBSession.query(func.strftime('%d-%m-%Y', Event.start_time))\
  260. .filter(Event.for_year == year)\
  261. .filter(Event.event_type != None)\
  262. .group_by(func.strftime('%d', Event.start_time)).all()
  263. ListDay = []
  264. for day in Days:
  265. RefDay = datetime.datetime.strptime(day[0],'%d-%m-%Y')
  266. ListDay.append( ( RefDay.strftime('%A %d %b %Y'),
  267. RefDay.strftime('%d') ) )
  268. MainTab = {'programme':'active','DisplayYear':year, \
  269. 'Events':Events, 'Event':Event, 'Days':ListDay, "logged_in":request.authenticated_userid }
  270. return MainTab
  271. @view_config(route_name='presse', renderer="jm2l:templates/Public/Presse.mako")
  272. def static_presse(request):
  273. year = int(request.matchdict.get('year', None))
  274. content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==year).first()
  275. MainTab = {'presse':'active', "logged_in":request.authenticated_userid, 'content':content, 'DisplayYear':year}
  276. return MainTab
  277. @view_config(route_name='edit_presse', renderer="jm2l:templates/Staff/EditPresse.mako")
  278. def edit_presse(request):
  279. year = int(request.matchdict.get('year', None))
  280. content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==year).first()
  281. form = DossPresse(request.POST, content, meta={'csrf_context': request.session})
  282. if request.method == 'POST' and form.validate():
  283. form.populate_obj(content)
  284. MainTab = {'presse':'active', "logged_in":request.authenticated_userid, 'form':form, 'DisplayYear':year}
  285. return MainTab
  286. @view_config(route_name='plan', renderer="jm2l:templates/Public/Plan.mako")
  287. def static_plan(request):
  288. session = request.session
  289. session['year'] = 2015
  290. MainTab = {'plan':'active', "logged_in":request.authenticated_userid }
  291. return MainTab
  292. ## =-=- Here, We handle HTTP requests - Staff Logged Part -=-=
  293. @view_config(route_name='list_task', renderer='jm2l:templates/Staff/list.mako')
  294. def list_view(request):
  295. if request.user is None:
  296. # Don't answer to users that aren't logged
  297. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  298. if not request.user.Staff:
  299. # Don't answer to users that aren't logged
  300. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  301. DicTask = {}
  302. taskgroup = DBSession.query( TasksArea ).all()
  303. for grp in taskgroup:
  304. tasks = DBSession.query( Tasks )\
  305. .filter( Tasks.area_uid==grp.uid )\
  306. .order_by(Tasks.closed, Tasks.due_date).all()
  307. DicTask[grp] = tasks
  308. return {'tasks': DicTask }
  309. @view_config(route_name='handle_task', renderer='jm2l:templates/Staff/tasks.mako')
  310. def tasks(request):
  311. if request.user is None:
  312. # Don't answer to users that aren't logged
  313. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  314. if not request.user.Staff:
  315. # Don't answer to users that aren't logged
  316. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  317. task_id = request.matchdict.get('task_id')
  318. # Convert the pole_id GET parameter to int or 0
  319. try:
  320. pole_id = int(request.params.get('pole_id'))
  321. except (ValueError, TypeError):
  322. pole_id = 0
  323. # Get areas from db
  324. Areas = DBSession.query(TasksArea.uid, TasksArea.name)\
  325. .order_by('name').all()
  326. # Get users from db
  327. Users = DBSession.query(User)\
  328. .filter(User.Staff==1)\
  329. .order_by('nom').all()
  330. if task_id:
  331. Task = Tasks.by_id(int(task_id))
  332. if not Task:
  333. raise HTTPNotFound()
  334. form = EditStaffTasks(request.POST, Task, meta={'csrf_context': request.session})
  335. else:
  336. Task = Tasks()
  337. # Check if the supplied pole_id is in the Areas' range
  338. Task.area_uid = pole_id if 1 < pole_id <= len(Areas) else 1
  339. form = StaffTasks(request.POST, Task, meta={'csrf_context': request.session})
  340. # Put some areas on form
  341. form.area_uid.choices = Areas
  342. # Put some users on form
  343. form.closed_by.choices = [(u.uid, "%s %s" % (u.nom, u.prenom))
  344. for u in Users]
  345. form.due_date.type = "date"
  346. if request.method == 'POST' and form.validate():
  347. form.populate_obj(Task)
  348. Task.closed = False
  349. if 'uid' in form._fields.keys():
  350. DBSession.merge(Task)
  351. else:
  352. DBSession.add(Task)
  353. DBSession.flush()
  354. return HTTPFound(location=request.route_url('list_task')+"#"+slugify(Task.area.name))
  355. return {'form':form, 'area':slugify(Areas[Task.area_uid-1].name)}
  356. @view_config(route_name='handle_pole', renderer='jm2l:templates/Staff/pole.mako')
  357. def tasks_area(request):
  358. if request.user is None:
  359. # Don't answer to users that aren't logged
  360. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  361. if not request.user.Staff:
  362. # Don't answer to users that aren't logged
  363. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  364. pole_id = request.matchdict.get('pole_id')
  365. if pole_id:
  366. Pole = TasksArea.by_id(int(pole_id))
  367. if not Pole:
  368. raise HTTPNotFound()
  369. form = EditStaffArea(request.POST, Pole, meta={'csrf_context': request.session})
  370. else:
  371. Pole = TasksArea()
  372. form = StaffArea(request.POST, Pole, meta={'csrf_context': request.session})
  373. if request.method == 'POST' and form.validate():
  374. form.populate_obj(Pole)
  375. if 'uid' in form._fields.keys():
  376. DBSession.merge(Pole)
  377. else:
  378. DBSession.add(Pole)
  379. return HTTPFound(location=request.route_url('list_task')+"#"+slugify(Pole.name))
  380. return {'form':form }
  381. @view_config(route_name='action_task')
  382. def action_task(request):
  383. if request.user is None:
  384. # Don't answer to users that aren't logged
  385. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  386. if not request.user.Staff:
  387. # Don't answer to users that aren't logged
  388. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  389. action = request.matchdict.get('action')
  390. task_id = request.matchdict.get('task_id')
  391. Task = Tasks.by_id(int(task_id))
  392. if action=='close':
  393. Task.closed = True
  394. request.session.flash(('info', u'La tâche a été fermé, Félicitations !'))
  395. DBSession.merge(Task)
  396. if action=='open':
  397. Task.closed = False
  398. request.session.flash(('info', u'La tâche a été ré-ouverte !'))
  399. DBSession.merge(Task)
  400. if action=='delete':
  401. request.session.flash(('info', u'La tâche a été supprimée !'))
  402. DBSession.delete(Task)
  403. return HTTPFound(location=request.route_url('list_task')+"#"+slugify(Task.area.name))
  404. @view_config(route_name='action_task_area')
  405. def action_task_area(request):
  406. action = request.matchdict.get('action')
  407. pole_id = request.matchdict.get('pole_id')
  408. Pole = TasksArea.by_id(int(pole_id))
  409. if not Pole:
  410. raise HTTPNotFound()
  411. if action=='delete':
  412. request.session.flash(('info', u'Le pôle a été supprimé !'))
  413. DBSession.delete(Pole)
  414. return HTTPFound(location=request.route_url('list_task'))
  415. @view_config(route_name='list_salles', renderer='jm2l:templates/Salles/list.mako')
  416. def list_salles(request):
  417. if request.user is None:
  418. # Don't answer to users that aren't logged
  419. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  420. if not request.user.Staff:
  421. # Don't answer to users that aren't logged
  422. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  423. DicSalle = {}
  424. years = DBSession.query( JM2L_Year ).all()
  425. for year in years:
  426. salles = DBSession.query( Salles )\
  427. .filter( Salles.year_uid==year.year_uid )\
  428. .order_by(Salles.name).all()
  429. DicSalle[year] = salles
  430. return {'DicSalle': DicSalle }
  431. @view_config(route_name='handle_salle', renderer='jm2l:templates/Salles/salle.mako')
  432. def handle_salle(request):
  433. if request.user is None:
  434. # Don't answer to users that aren't logged
  435. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  436. if not request.user.Staff:
  437. # Don't answer to users that aren't logged
  438. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  439. salle_id = request.matchdict.get('salle_id')
  440. if salle_id:
  441. Salle = Salles.by_id(int(salle_id))
  442. if not Salle:
  443. raise HTTPNotFound()
  444. form = EditSalleForm(request.POST, Salle, meta={'csrf_context': request.session})
  445. else:
  446. Salle = Salles()
  447. form = SalleForm(request.POST, Salle, meta={'csrf_context': request.session})
  448. form.year_uid.choices = map(tuple, DBSession.query(JM2L_Year.year_uid, JM2L_Year.year_uid).all())
  449. form.phy_salle_id.choices = map(tuple, DBSession.query(SallePhy.uid, SallePhy.name).all())
  450. if request.method == 'POST' and form.validate():
  451. form.populate_obj(Salle)
  452. if 'uid' in form._fields.keys():
  453. DBSession.merge(Salle)
  454. else:
  455. DBSession.add(Salle)
  456. return HTTPFound(location=request.route_url('list_salles'))
  457. return {'form':form }
  458. @view_config(route_name='handle_salle_phy', renderer='jm2l:templates/Salles/salle_phy.mako')
  459. def handle_salle_phy(request):
  460. if request.user is None:
  461. # Don't answer to users that aren't logged
  462. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  463. if not request.user.Staff:
  464. # Don't answer to users that aren't logged
  465. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  466. salle_id = request.matchdict.get('salle_id')
  467. if salle_id:
  468. Salle = SallePhy.by_id(int(salle_id))
  469. if not Salle:
  470. raise HTTPNotFound()
  471. form = EditSallePhyForm(request.POST, Salle, meta={'csrf_context': request.session})
  472. else:
  473. Salle = SallePhy()
  474. form = SallePhyForm(request.POST, Salle, meta={'csrf_context': request.session})
  475. if request.method == 'POST' and form.validate():
  476. form.populate_obj(Salle)
  477. Salle.slug = slugify(Salle.name)
  478. if 'uid' in form._fields.keys():
  479. DBSession.merge(Salle)
  480. else:
  481. DBSession.add(Salle)
  482. return HTTPFound(location=request.route_url('list_salles'))
  483. return {'form':form }
  484. @view_config(route_name='action_salle')
  485. def action_salle(request):
  486. if request.user is None:
  487. # Don't answer to users that aren't logged
  488. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  489. if not request.user.Staff:
  490. # Don't answer to users that aren't logged
  491. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  492. action = request.matchdict.get('action')
  493. salle_id = request.matchdict.get('salle_id')
  494. Salle = Salles.by_id(int(salle_id))
  495. if not Salle:
  496. raise HTTPNotFound()
  497. if action=='delete':
  498. request.session.flash(('info', u'La Salle a été supprimée !'))
  499. DBSession.delete(Salle)
  500. return HTTPFound(location=request.route_url('list_salles'))
  501. ## =-=- Here, We handle HTTP requests - User Logged Part -=-=
  502. @view_config(route_name='exchange', renderer="jm2l:templates/Logistique/Logistique.mako")
  503. def exchange(request):
  504. modtype = request.matchdict.get('modtype', None)
  505. action = request.matchdict.get('action', None)
  506. uid = int(request.matchdict.get('id', -1))
  507. Exch = Exchange.by_id(uid)
  508. if not Exch:
  509. MainTab = {
  510. 'Exchanges':Exchange,
  511. 'Type':modtype[-1:],
  512. 'reload':True,
  513. 'logged_in':request.authenticated_userid
  514. }
  515. return MainTab
  516. if action in ['delete', 'accept', 'refuse', 'deal']:
  517. if action=='delete': # delete exchange
  518. DBSession.delete(Exch)
  519. elif action=='accept': # accept exchange
  520. Exch.exch_done=True
  521. DBSession.merge(Exch)
  522. elif action=='refuse': # refuse exchange
  523. Exch.exch_done=False
  524. if Exch.exch_state=="Ask":
  525. Exch.provider_id = None
  526. elif Exch.exch_state=="Proposal":
  527. Exch.asker_id = None
  528. DBSession.merge(Exch)
  529. elif action=='deal':
  530. # ask to deal the exchange
  531. if Exch.exch_state=="Ask":
  532. Exch.provider_id = request.user.uid
  533. elif Exch.exch_state=="Proposal":
  534. Exch.asker_id = request.user.uid
  535. # Return javascript to parent page
  536. response = render_to_response('jm2l:templates/modals_js.mako',
  537. {'modtype':modtype, 'action':action},
  538. request=request)
  539. response.content_type = 'text/javascript'
  540. return response
  541. else:
  542. MainTab = {
  543. 'Exchanges':Exchange,
  544. 'Type':modtype[-1:],
  545. 'reload':True,
  546. 'logged_in':request.authenticated_userid
  547. }
  548. return MainTab
  549. @view_config(route_name='sejour')
  550. def sejour(request):
  551. if request.user is None:
  552. # Don't answer to users that aren't logged
  553. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  554. if request.method == 'POST':
  555. print request.POST
  556. return HTTPFound(location='/MesJM2L#Sejour')
  557. @view_config(route_name='vote_logo')
  558. def vote_logo(request):
  559. if request.user is None:
  560. # Don't answer to users that aren't logged
  561. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  562. else:
  563. vote = int(request.matchdict.get('num', -1))
  564. come = request.params.get('come_from')
  565. if vote:
  566. request.user.vote_logo=vote
  567. DBSession.merge(request.user)
  568. request.session.flash(('info',u'Votre vote à été pris en compte.'))
  569. return HTTPFound('/')
  570. else:
  571. request.session.flash(('warning',u"Votre vote n'a été pris en compte."))
  572. if come:
  573. return HTTPFound(location=come)
  574. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  575. @view_config(route_name='jm2l', renderer="jm2l:templates/jm2l.mako")
  576. def jm2l_page(request):
  577. if request.user is None:
  578. # Don't answer to users that aren't logged
  579. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  580. page = int(request.params.get('page', 1))
  581. UserNum = request.params.get('user')
  582. if UserNum:
  583. profil = User.by_id(int(UserNum))
  584. if not profil:
  585. raise HTTPNotFound()
  586. if not request.user.Staff:
  587. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  588. else:
  589. profil = request.user
  590. # Build Form
  591. profil_form = ProfilForm(request.POST, profil, meta={'csrf_context': request.session})
  592. miam_form = MiamForm(request.POST, profil, meta={'csrf_context': request.session})
  593. if request.method == 'POST' and profil_form.validate():
  594. ToDelete = list()
  595. # First, we remove entries no more present
  596. for obj in profil_form.tiersship.object_data:
  597. MatchEntry = filter( lambda x: x.object_data and x.object_data._sa_instance_state == obj._sa_instance_state,
  598. profil_form.tiersship.entries )
  599. if not MatchEntry:
  600. ToDelete.append(obj)
  601. # Then, it's time to consider new entries
  602. for entry in profil_form.tiersship.entries:
  603. if entry.object_data is None:
  604. TmpUser = User_Tiers()
  605. entry.object_data = TmpUser
  606. profil.tiersship.append(TmpUser)
  607. profil_form.tiersship.object_data = profil.tiersship
  608. profil_form.populate_obj(profil)
  609. # We should remove it as it's not in original data
  610. for obj in ToDelete:
  611. #profil.tiersship.remove(obj)
  612. DBSession.delete(obj)
  613. profil.last_change = datetime.datetime.utcnow()
  614. profil.slug = slugify(remove_accents('%s %s' % (profil.prenom, profil.nom)).lower().strip())
  615. DBSession.merge(profil)
  616. request.session.flash(('info',u'Votre fiche a été mise à jour avec succès'))
  617. MainTab = {'participer':'active',
  618. 'Places':Place.get_list(False),
  619. 'DBTiers':Tiers,
  620. 'DBTiersOpt':TiersOpt,
  621. 'Exchanges':Exchange,
  622. 'profil_form':profil_form,
  623. 'miam_form':miam_form,
  624. 'uprofil':profil,
  625. 'logged_in':request.authenticated_userid
  626. }
  627. return MainTab
  628. @view_config(route_name='modal', renderer="jm2l:templates/modals.mako")
  629. def Modal(request):
  630. year = int(request.matchdict.get('year', None))
  631. modtype = request.matchdict.get('modtype', None)
  632. uid = int(request.matchdict.get('id', -1))
  633. session = request.session
  634. if modtype=='Password':
  635. form = UserPasswordForm(request.POST, request.user, meta={'csrf_context': request.session})
  636. if request.method == 'POST' and form.validate():
  637. response = render_to_response('jm2l:templates/modals_js.mako',
  638. {'modtype':modtype},
  639. request=request)
  640. request.user.password = form.password.data
  641. DBSession.merge(request.user)
  642. response.content_type = 'text/javascript'
  643. return response
  644. if modtype=='UserPicture':
  645. form = None
  646. if request.method == 'POST':
  647. response = render_to_response('jm2l:templates/modals_js.mako',
  648. {'modtype':modtype},
  649. request=request)
  650. response.content_type = 'text/javascript'
  651. return response
  652. if modtype=='Place':
  653. if uid>0:
  654. place = Place.by_id(uid)
  655. if not place:
  656. raise HTTPNotFound()
  657. form = PlaceUpdateForm(request.POST, place, meta={'csrf_context': request.session})
  658. else:
  659. place = Place()
  660. form = PlaceCreateForm(request.POST, meta={'csrf_context': request.session})
  661. if request.method == 'POST' and form.validate():
  662. form.populate_obj(place)
  663. place.created_by=request.user.uid
  664. if uid>0:
  665. DBSession.merge(place)
  666. else:
  667. DBSession.add(place)
  668. response = render_to_response('jm2l:templates/modals_js.mako',
  669. {'modtype':modtype},
  670. request=request)
  671. response.content_type = 'text/javascript'
  672. return response
  673. if modtype in ['AskC', 'AskH', 'AskM', 'PropC', 'PropH', 'PropM']:
  674. if uid>0:
  675. Exch = Exchange.by_id(uid)
  676. if not Exch:
  677. raise HTTPNotFound()
  678. if modtype in ['AskC','PropC']:
  679. form = globals()["Update%sForm" % modtype](request.POST, Exch,
  680. start_place = Exch.Itin.start_place,
  681. arrival_place = Exch.Itin.arrival_place,
  682. Hour_start = Exch.start_time.strftime("%H:%M"),
  683. Day_start = Exch.start_time.strftime("%w"),
  684. exch_id = uid, meta={'csrf_context': request.session}
  685. )
  686. elif modtype in ['AskM','PropM']:
  687. form = globals()["Update%sForm" % modtype](request.POST, Exch,
  688. description = Exch.description,
  689. exch_categ = Exch.exch_categ,
  690. Hour_start = Exch.start_time.strftime("%H:%M"),
  691. Day_start = Exch.start_time.strftime("%w"),
  692. Hour_end = Exch.end_time.strftime("%H:%M"),
  693. Day_end = Exch.end_time.strftime("%w"),
  694. exch_id = uid, meta={'csrf_context': request.session}
  695. )
  696. elif modtype in ['AskH','PropH']:
  697. form = globals()["Update%sForm" % modtype](request.POST, Exch,
  698. description = Exch.description,
  699. exch_categ = Exch.exch_categ,
  700. Day_start = Exch.start_time.strftime("%w"),
  701. exch_id = uid, meta={'csrf_context': request.session}
  702. )
  703. # Itinerary, first get itinerary
  704. if 0:
  705. form.itin.form.start_place.data = Exch.Itin.start_place
  706. form.itin.form.arrival_place.data = Exch.Itin.arrival_place
  707. form.dateform.form.Hour.data = Exch.start_time.strftime("%H:%M")
  708. form.dateform.form.Day.data = Exch.start_time.strftime("%w")
  709. form.exch_id.data = uid
  710. else:
  711. Exch = Exchange()
  712. form = globals()["%sForm" % modtype](request.POST, meta={'csrf_context': request.session})
  713. if modtype in ['AskC', 'PropC']:
  714. # Put some place on form
  715. Places = DBSession.query(Place.place_id, Place.display_name)\
  716. .order_by('name').all()
  717. form.start_place.choices = Places
  718. form.arrival_place.choices = Places
  719. if modtype in ['PropH']:
  720. form.exch_categ.choices = DBSession.query( Exchange_Cat.cat_id, Exchange_Cat.exch_subtype)\
  721. .filter( Exchange_Cat.exch_type=='H' ).all()
  722. form.place_id.choices = DBSession.query( Place.place_id, Place.display_name)\
  723. .filter( Place.created_by==request.user.uid ).all()
  724. if modtype in ['AskM', 'PropM']:
  725. form.exch_categ.choices = DBSession.query( Exchange_Cat.cat_id, Exchange_Cat.exch_subtype)\
  726. .filter( Exchange_Cat.exch_type=='M' ).all()
  727. if request.method == 'POST' and form.validate():
  728. # Form has been validated, it's time to create our Exchange
  729. Exch.for_year = year
  730. Exch.exch_state = {'Ask':'Ask', 'Prop':'Proposal'}[modtype[:-1]]
  731. Exch.exch_type = modtype[-1:]
  732. if modtype in ['AskC', 'PropC']:
  733. # Itinerary, first Let's see if itinerary exist
  734. Itinerary = DBSession.query(Itineraire)\
  735. .filter(Itineraire.start_place==form.start_place.data) \
  736. .filter(Itineraire.arrival_place==form.arrival_place.data) \
  737. .filter(Itineraire.tr_voiture==True) \
  738. .first()
  739. if not Itinerary: # Not exist yet !
  740. Itinerary = Itineraire(start_place=form.start_place.data, \
  741. arrival_place=form.arrival_place.data, \
  742. tr_voiture=True, \
  743. created_by=1
  744. )
  745. DBSession.add(Itinerary)
  746. DBSession.flush()
  747. Exch.itin_id = Itinerary.itin_id
  748. # Start Time
  749. StartEvent = DBSession.query(JM2L_Year.start_time).filter(JM2L_Year.year_uid==year).first()
  750. Week = StartEvent[0].strftime("%W")
  751. # populate
  752. form.populate_obj(Exch)
  753. if modtype in ['AskC', 'PropC']:
  754. Exch.itin_id = Itinerary.itin_id
  755. if form._fields.has_key("Hour_start"):
  756. TargetTime = datetime.datetime.strptime('%d %d %d %s' % (year, int(Week), \
  757. int(form.Day_start.data), form.Hour_start.data), "%Y %W %w %H:%M")
  758. Exch.start_time = TargetTime
  759. elif form._fields.has_key("Day_start"):
  760. TargetTime = datetime.datetime.strptime('%d %d %d' % (year, int(Week), \
  761. int(form.Day_start.data)), "%Y %W %w")
  762. Exch.start_time = TargetTime
  763. if form._fields.has_key("Hour_end"):
  764. TargetTime = datetime.datetime.strptime('%d %d %d %s' % (year, int(Week), \
  765. int(form.Day_end.data), form.Hour_end.data), "%Y %W %w %H:%M")
  766. Exch.end_time = TargetTime
  767. elif form._fields.has_key("Day_end"):
  768. TargetTime = datetime.datetime.strptime('%d %d %d' % (year, int(Week), \
  769. int(form.Day_end.data)), "%Y %W %w")
  770. Exch.end_time = TargetTime
  771. Exch.last_change = datetime.datetime.utcnow()
  772. if Exch.exch_state=='Ask':
  773. Exch.asker_id = request.user.uid
  774. elif Exch.exch_state=='Proposal':
  775. Exch.provider_id = request.user.uid
  776. #print vars(form.itin.form)
  777. if uid>0:
  778. DBSession.merge(Exch)
  779. else:
  780. DBSession.add(Exch)
  781. response = render_to_response('jm2l:templates/modals_js.mako',
  782. {'modtype':modtype},
  783. request=request)
  784. response.content_type = 'text/javascript'
  785. return response
  786. # Fallback to HTML Display with errors
  787. return {'modtype':modtype, 'form':form, 'update':uid>0,
  788. 'logged_in':request.authenticated_userid }
  789. if modtype in ['ShowC', 'ShowH', 'ShowM']:
  790. if uid>0:
  791. Exch = Exchange.by_id(uid)
  792. if not Exch:
  793. raise HTTPNotFound()
  794. else:
  795. raise HTTPNotFound()
  796. # Show Details around the Current Exchange
  797. return {'modtype':modtype, 'Exch':Exch, 'logged_in':request.authenticated_userid }
  798. MainTab = {'modtype':modtype, 'form':form, 'update':uid>0, 'uid':uid,
  799. 'DisplayYear':year, 'session':session,
  800. 'logged_in':request.authenticated_userid }
  801. return MainTab
  802. @view_config(route_name='participer', renderer="jm2l:templates/Participer.mako")
  803. def participer(request):
  804. session = request.session
  805. session['year'] = 2015
  806. TmpUsr = User()
  807. form = UserRegisterForm(request.POST, TmpUsr, meta={'csrf_context': request.session})
  808. MyLink=None
  809. if request.method == 'POST' and form.validate():
  810. # Prepare mailer
  811. form.populate_obj(TmpUsr)
  812. TmpUsr.nom = TmpUsr.nom.capitalize()
  813. TmpUsr.prenom = TmpUsr.prenom.capitalize()
  814. TmpUsr.slug = slugify(remove_accents('%s %s' % (form.prenom.data, form.nom.data)).lower().strip())
  815. TmpUsr.password = TmpUsr.my_hash
  816. if len(TmpUsr.slug):
  817. CheckExist = DBSession.query(User)\
  818. .filter(User.slug==TmpUsr.slug)\
  819. .first()
  820. else:
  821. CheckExist=None
  822. if CheckExist:
  823. MyLink = CheckExist.my_hash
  824. NewUser = CheckExist
  825. else:
  826. DBSession.add(TmpUsr)
  827. DBSession.flush()
  828. MyLink = TmpUsr.my_hash
  829. NewUser = TmpUsr
  830. # Send the Welcome Mail
  831. mailer = request.registry['mailer']
  832. # Prepare Plain Text Message :
  833. Mail_template = Template(filename='jm2l/templates/mail_plain.mako')
  834. mail_plain = Mail_template.render(request=request, User=NewUser, action="Welcome")
  835. # Prepare HTML Message :
  836. Mail_template = Template(filename='jm2l/templates/mail_html.mako')
  837. mail_html = Mail_template.render(request=request, User=NewUser, action="Welcome")
  838. # Prepare Message
  839. message = Message(subject="[JM2L] Mon inscription au site web JM2L",
  840. sender="contact@jm2l.linux-azur.org",
  841. recipients=[NewUser.mail],
  842. body=mail_plain, html=mail_html)
  843. message.add_bcc("spam@style-python.fr")
  844. mailer.send(message)
  845. request.session.flash(('info',u"Un mail vous a été envoyé afin de continuer votre quête !"))
  846. MainTab = {'programme':'','presse':'', 'plan':'',
  847. 'participer':'active', 'form':form, "link": MyLink,
  848. 'logged_in':request.authenticated_userid }
  849. return MainTab
  850. @view_config(route_name='year')
  851. def change_year(request):
  852. year = int(request.matchdict.get('year', -1))
  853. session = request.session
  854. if year>-1:
  855. session['year'] = year
  856. return HTTPFound(location='/%s/' % year)
  857. return HTTPFound(location=request.route_url('home', year=''))
  858. @view_config(route_name='pict_user', renderer="jm2l:templates/Profil/pict_user.mako")
  859. def pict_user(request):
  860. return {"uprofil":request.user}
  861. @view_config(route_name='pict_salle', renderer="jm2l:templates/Salles/pict_salle.mako")
  862. def pict_salle(request):
  863. salle_id = int(request.matchdict.get('salle_id', -1))
  864. return {"Salles":Salles, "IdSalle":salle_id}
  865. @view_config(route_name='event', renderer="jm2l:templates/view_event.mako")
  866. def show_event(request):
  867. year = int(request.matchdict.get('year', -1))
  868. event_id = request.matchdict.get('event_id')
  869. if event_id.isdigit():
  870. TheEvent = Event.by_id(event_id)
  871. if TheEvent is None:
  872. raise HTTPNotFound()
  873. else:
  874. TheEvent = Event.by_slug(event_id, year)
  875. if TheEvent is None:
  876. raise HTTPNotFound()
  877. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  878. 'event':TheEvent, 'logged_in':request.authenticated_userid, "Salles":Salles }
  879. return MainTab
  880. @view_config(route_name='link_event_user')
  881. def link_event_user(request):
  882. """ Get user and add it to current event """
  883. year = int(request.matchdict.get('year', -1))
  884. form = AddIntervenant(request.POST, meta={'csrf_context': request.session})
  885. intervention = request.matchdict.get('intervention', None)
  886. TargetEvent = Event.by_id(form.event_uid.data)
  887. Exist = User.by_id(form.intervenant.data)
  888. if not Exist:
  889. request.session.flash(('error',u"Une erreur s'est produite lors de l'ajout de votre intervenant !"))
  890. return HTTPFound(location=request.route_url('edit_event', sep='/',
  891. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid)))
  892. else:
  893. TargetUser = Exist
  894. uev = User_Event(year_uid=year, role=u"Animateur d'un évenement JM2L", user_uid=TargetUser.uid)
  895. TargetEvent.interventions.append( uev )
  896. return HTTPFound(location=request.route_url('edit_event', sep='/',
  897. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid)))
  898. @view_config(route_name='link_event_tiers')
  899. def link_event_tiers(request):
  900. """ Create user if not exist, add it to current event """
  901. year = int(request.matchdict.get('year', -1))
  902. form = AddTiers(request.POST, meta={'csrf_context': request.session})
  903. intervention = request.matchdict.get('intervention', None)
  904. TargetEvent = Event.by_id(form.event_uid.data)
  905. Exist = Tiers.by_id(form.tiers.data)
  906. if not Exist:
  907. request.session.flash(('error',u"Une erreur s'est produite lors de l'ajout de votre entitée !"))
  908. return HTTPFound(location=request.route_url('edit_event', sep='/',
  909. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid)))
  910. else:
  911. TargetTiers = Exist
  912. if len(DBSession.query(Role_Tiers)\
  913. .filter(Role_Tiers.year_uid==year)\
  914. .filter(Role_Tiers.tiers_role=="Exposant")\
  915. .filter(Role_Tiers.tiers_uid==TargetTiers.uid)\
  916. .all())==0:
  917. tev = Role_Tiers(year_uid=year, tiers_role="Exposant", tiers_uid=TargetTiers.uid)
  918. DBSession.add(tev)
  919. return HTTPFound(location=request.route_url('edit_event', sep='/',
  920. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid)))
  921. @view_config(route_name='edit_event', renderer="jm2l:templates/edit_event.mako")
  922. def edit_event(request):
  923. year = int(request.matchdict.get('year', -1))
  924. event_id = request.matchdict.get('event_id')
  925. intervention = request.matchdict.get('intervention', None)
  926. IntervLabel = intervention.replace('_',' ').lower()
  927. if intervention=='Conference':
  928. IntervLabel = u'conférence'
  929. # Check intervention
  930. if not intervention in ['Stand', 'Table ronde', 'Atelier', 'Conference', 'Concert']:
  931. raise HTTPNotFound(u"Ce type d'évenement n'est pas reconnu")
  932. TheYear = DBSession.query(JM2L_Year)\
  933. .filter(JM2L_Year.year_uid==year)\
  934. .first()
  935. # Check year avaibility
  936. if not TheYear:
  937. raise HTTPNotFound(u"Cette année n'est pas pris en charge")
  938. # Generate Timeslots for current year
  939. TimeSlots = list(enumerate( [ x.strftime('%a %d %b %H:%M') for x in
  940. TheYear.AvailableTimeSlots ] ))
  941. if event_id:
  942. # We try to update an existing record
  943. if event_id.isdigit():
  944. TheEvent = Event.by_id(event_id)
  945. if TheEvent is None:
  946. raise HTTPNotFound(u"Cette réference n'existe pas")
  947. else:
  948. TheEvent = Event.by_slug(event_id, year)
  949. if TheEvent is None:
  950. raise HTTPNotFound(u"Cette réference n'existe pas")
  951. if request.user is None or not (request.user.Staff or request.user in TheEvent.intervenants):
  952. raise HTTPForbidden(u"Vous n'êtes pas identifié comme étant un participant à cette intervention.")
  953. # Compute some field value from selected event
  954. if TheEvent.start_time in TheYear.AvailableTimeSlots:
  955. start_sel = TheYear.AvailableTimeSlots.index(TheEvent.start_time)
  956. else:
  957. start_sel = len(TimeSlots)
  958. TimeSlots.append( (len(TimeSlots), TheEvent.start_time.strftime('%a %d %b %H:%M')))
  959. duration = (TheEvent.end_time - TheEvent.start_time).total_seconds()/60
  960. end = TheEvent.start_time + datetime.timedelta(minutes=duration)
  961. # prepare the form with update
  962. form = ConfUpdateForm(request.POST, TheEvent, start_sel=start_sel, duration=duration, end_time=end,
  963. meta={'csrf_context': request.session} )
  964. # Customize labels
  965. form.name.label.text += IntervLabel
  966. form.description.label.text += IntervLabel
  967. # Each event can get severals members
  968. formAdd = AddIntervenant(event_uid=TheEvent.uid)
  969. # Build list of intervenant
  970. # Get users from db
  971. Users = DBSession.query(User)\
  972. .filter(User.Staff==1)\
  973. .order_by('nom').all()
  974. # Put some users on form
  975. formAdd.intervenant.choices = [(u.uid, "%s %s" % (u.nom, u.prenom))
  976. for u in Users]
  977. # Each event can get severals entities
  978. formAddT = AddTiers(event_uid=TheEvent.uid)
  979. # Build list of entities
  980. # Get entities from db
  981. TmpTiers = DBSession.query(Tiers)\
  982. .order_by('name').limit(10)
  983. # Put some entities on form
  984. formAddT.tiers.choices = [(u.uid, "%s %s" % (u.nom, u.prenom))
  985. for u in Users]
  986. else:
  987. TheEvent = Event()
  988. # prepare the form for creation
  989. form = ConfCreateForm(request.POST,
  990. event_type=intervention,
  991. for_year=str(year), meta={'csrf_context': request.session}
  992. )
  993. # Customize labels
  994. form.name.label.text += IntervLabel
  995. form.description.label.text += IntervLabel
  996. duration=60
  997. # No intervenant
  998. formAdd = None
  999. formAddT = None
  1000. SalleDispo = DBSession.query(Salles)\
  1001. .filter(Salles.year_uid==year)\
  1002. .order_by('name')
  1003. if intervention=="Conference":
  1004. form.duration.choices =[
  1005. (15,u'Lighting talk ( 5 min)'),
  1006. (30,u'Conférence (20 min)'),
  1007. (60,u'Conférence (50 min)'),
  1008. (90,u'Conférence (75 min)'),
  1009. ]
  1010. if not duration in [15, 30, 60, 90]:
  1011. form.duration.choices.append( (duration,u'Conférence (%d min)' % duration) )
  1012. if not form._fields.has_key("uid"):
  1013. form.duration.data=60
  1014. SalleDispo = SalleDispo.filter(Salles.place_type=='Conference')
  1015. elif intervention=="Stand":
  1016. form.duration.choices =[
  1017. (8*60, u'Toute la journée'),
  1018. (4*60, u'une demi-journée')
  1019. ]
  1020. SalleDispo = SalleDispo.filter(Salles.place_type=='Stand')
  1021. elif intervention=="Atelier":
  1022. form.duration.choices = map( lambda d:(d, u'Atelier (%dh%.2d)' % (d/60, d%60) ), \
  1023. [60, 90, 120, 150, 180, 210, 240] )
  1024. if not duration in map(lambda (d,y): d, form.duration.choices):
  1025. form.duration.choices.append( (duration,u'Atelier (%dh%.2d)' % (duration/60, duration%60) ) )
  1026. SalleDispo = SalleDispo.filter(Salles.place_type=='Ateliers')
  1027. elif intervention=="Table ronde":
  1028. form.duration.choices = map( lambda d:(d, u'Table ronde (%dh%.2d)' % (d/60, d%60) ), \
  1029. [60, 90, 120, 150] )
  1030. if not duration in map(lambda (d,y): d, form.duration.choices):
  1031. form.duration.choices.append( (duration,u'Table ronde (%dh%.2d)' % (duration/60, duration%60) ) )
  1032. SalleDispo = SalleDispo.filter(Salles.place_type=='Conference')
  1033. else:
  1034. raise HTTPForbidden(u"Pas encore disponible.")
  1035. form.salle_uid.choices = [(s.salle_id, s.name) for s in SalleDispo]
  1036. form.start_sel.choices = TimeSlots
  1037. if request.method == 'POST' and form.validate():
  1038. form.populate_obj(TheEvent)
  1039. TheEvent.start_time = TheYear.AvailableTimeSlots[form.start_sel.data]
  1040. TheEvent.end_time = TheEvent.start_time + datetime.timedelta(minutes=form.duration.data)
  1041. # Ok, time to put in database
  1042. if not form._fields.has_key("uid"):
  1043. TheEvent.slug = slugify(TheEvent.name)
  1044. DBSession.add(TheEvent)
  1045. # Append creator by default
  1046. if request.user.uid!=1:
  1047. uev = User_Event(year_uid=TheYear.year_uid, role="Animateur")
  1048. uev.user_uid = request.user.uid
  1049. TheEvent.interventions.append( uev )
  1050. DBSession.flush()
  1051. request.session.flash(('sucess',u'Votre intervention a été créee !'))
  1052. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1053. year=str(year), intervention=intervention, event_id=str(TheEvent.slug)))
  1054. else:
  1055. DBSession.merge(TheEvent)
  1056. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1057. 'event':TheEvent, 'form':form, 'formAdd':formAdd, 'formAddT':formAddT,
  1058. 'Salles':Salles,
  1059. 'logged_in':request.authenticated_userid }
  1060. return MainTab
  1061. @view_config(route_name='entities', renderer="jm2l:templates/list_tiers.mako")
  1062. def list_tiers(request):
  1063. Entities = dict()
  1064. EntityType = DBSession.query(TiersOpt.entity_type)\
  1065. .group_by(TiersOpt.entity_type).all()
  1066. for EType in EntityType:
  1067. Entities[EType.entity_type] = DBSession.query(Tiers).join(TiersOpt)\
  1068. .filter(TiersOpt.entity_type==EType.entity_type)\
  1069. .order_by(TiersOpt.entity_subtype, Tiers.name)
  1070. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1071. 'entities':Entities, 'logged_in':request.authenticated_userid }
  1072. return MainTab
  1073. @view_config(route_name='show_entity', renderer="jm2l:templates/view_tiers.mako")
  1074. def show_tiers(request):
  1075. tiers_type = request.matchdict.get('tiers_type')
  1076. entity_id = request.matchdict.get('entity_id')
  1077. if entity_id.isdigit():
  1078. TheTiers = Tiers.by_id(entity_id)
  1079. if TheTiers is None:
  1080. raise HTTPNotFound()
  1081. else:
  1082. TheTiers = Tiers.by_slug(entity_id)
  1083. if TheTiers is None:
  1084. raise HTTPNotFound()
  1085. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1086. 'entity':TheTiers, 'logged_in':request.authenticated_userid }
  1087. return MainTab
  1088. @view_config(route_name='delete_entity')
  1089. def delete_tiers(request):
  1090. entity_id = request.matchdict.get('entity_id', None)
  1091. if entity_id:
  1092. if entity_id.isdigit():
  1093. TheTiers = Tiers.by_id(int(entity_id))
  1094. if TheTiers is None:
  1095. raise HTTPNotFound()
  1096. else:
  1097. TheTiers = Tiers.by_slug(entity_id)
  1098. if TheTiers is None:
  1099. raise HTTPNotFound()
  1100. if len(TheTiers.membership)!=0:
  1101. request.session.flash(('error', u"Vous devez supprimer tous les membres liés avant la suppression d'une entitée."))
  1102. return HTTPFound(location=request.route_url('show_entity', entity_id=TheTiers.slug, tiers_type=TheTiers.get_entity_type.slug_entity_type))
  1103. if len(TheTiers.membership)!=0:
  1104. request.session.flash(('error', u"Vous devez supprimer tous les roles liés avant la suppression d'une entitée."))
  1105. return HTTPFound(location=request.route_url('show_entity', entity_id=TheTiers.slug, tiers_type=TheTiers.get_entity_type.slug_entity_type))
  1106. DBSession.delete(TheTiers)
  1107. request.session.flash(('info', u"L'entitée a bien été supprimée"))
  1108. return HTTPFound(location=request.route_url('entities'))
  1109. else:
  1110. raise HTTPNotFound()
  1111. @view_config(route_name='add_entity', renderer="jm2l:templates/edit_tiers.mako")
  1112. @view_config(route_name='edit_entity', renderer="jm2l:templates/edit_tiers.mako")
  1113. def edit_tiers(request):
  1114. entity_id = request.matchdict.get('entity_id', None)
  1115. TargetList = list()
  1116. if request.user is None:
  1117. # Don't answer to users that aren't logged
  1118. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1119. entity_types = DBSession.query(TiersOpt.entity_type).group_by(TiersOpt.entity_type).all()
  1120. for entity_type in entity_types:
  1121. entity_subtypes = DBSession.query(TiersOpt)\
  1122. .filter(TiersOpt.entity_type==entity_type.entity_type)\
  1123. .group_by(TiersOpt.entity_subtype).all()
  1124. ListType = [(i.uid, i.entity_subtype) for i in entity_subtypes]
  1125. TargetList.append( (entity_type.entity_type, ListType) )
  1126. if entity_id:
  1127. if entity_id.isdigit():
  1128. TheTiers = Tiers.by_id(entity_id)
  1129. if TheTiers is None:
  1130. raise HTTPNotFound()
  1131. else:
  1132. TheTiers = Tiers.by_slug(entity_id)
  1133. if TheTiers is None:
  1134. raise HTTPNotFound()
  1135. form = UpdateTiersForm(request.POST, TheTiers, meta={'csrf_context': request.session})
  1136. UserOptions = DBSession.query(TiersOpt)\
  1137. .filter(TiersOpt.entity_type==TheTiers.tiers_type)\
  1138. .all()
  1139. form.tiers_type.choices = TargetList
  1140. else:
  1141. TheTiers = Tiers()
  1142. # prepare the form for creation
  1143. form = TiersForm(request.POST, TheTiers, meta={'csrf_context': request.session})
  1144. form.tiers_type.choices = TargetList
  1145. UserOptions = list()
  1146. #test_form = TiersForm(request.POST, TheTiers, meta={'csrf_context': request.session})
  1147. if request.method == 'POST' and form.validate():
  1148. ToDelete = list()
  1149. ToDeleteR = list()
  1150. # First, we remove entries no more present
  1151. for obj in form.membership.object_data:
  1152. MatchEntry = filter( lambda x: x.object_data and x.object_data._sa_instance_state == obj._sa_instance_state,
  1153. form.membership.entries )
  1154. if not MatchEntry:
  1155. ToDelete.append(obj)
  1156. # For roles too
  1157. for obj in form.roles.object_data:
  1158. MatchEntry = filter( lambda x: x.object_data and x.object_data._sa_instance_state == obj._sa_instance_state,
  1159. form.roles.entries )
  1160. if not MatchEntry:
  1161. ToDeleteR.append(obj)
  1162. # We should remove it as it's not in original data
  1163. for obj in ToDelete:
  1164. TheTiers.membership.remove(obj)
  1165. DBSession.delete(obj)
  1166. # For roles too
  1167. for obj in ToDeleteR:
  1168. TheTiers.roles.remove(obj)
  1169. DBSession.delete(obj)
  1170. # Then, it's time to consider new entries
  1171. for entry in form.membership.entries:
  1172. if entry.object_data is None:
  1173. TmpUser = User_Tiers()
  1174. entry.object_data = TmpUser
  1175. TheTiers.membership.append(TmpUser)
  1176. form.membership.object_data = TheTiers.membership
  1177. # For roles too
  1178. for entry in form.roles.entries:
  1179. if entry.object_data is None:
  1180. TmpRole = Role_Tiers()
  1181. entry.object_data = TmpRole
  1182. TheTiers.roles.append(TmpRole)
  1183. form.roles.object_data = TheTiers.roles
  1184. form.populate_obj(TheTiers)
  1185. # Handle Remove of accents
  1186. TheTiers.slug = slugify(form.name.data)
  1187. if not form._fields.has_key('uid'):
  1188. TheTiers.creator_id = request.user.uid
  1189. DBSession.add(TheTiers)
  1190. DBSession.flush()
  1191. return HTTPFound(location=request.route_url('edit_entity', sep='/',
  1192. entity_id=str(TheTiers.slug), tiers_type=TheTiers.get_entity_type.entity_type))
  1193. DBSession.merge(TheTiers)
  1194. return HTTPFound(location=request.route_url('show_entity', entity_id=TheTiers.slug,
  1195. tiers_type=TheTiers.get_entity_type.slug_entity_type))
  1196. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1197. 'form':form, 'DBUser':User, 'UserOptions':UserOptions,
  1198. 'logged_in':request.authenticated_userid }
  1199. return MainTab
  1200. @view_config(route_name='edit_entity_cat', renderer="jm2l:templates/edit_tiers_categ.mako")
  1201. def edit_tiers_category(request):
  1202. DicResult = dict()
  1203. ListChanges = list()
  1204. if request.method == 'POST':
  1205. # Reformat data
  1206. RegExist = re.compile('collection\[(?P<slug>[\w-]+)\]\[(?P<num>\d+)\]\[(?P<id>\d+)\]')
  1207. RegTitle = re.compile('collection\[(?P<slug>[\w-]+)\]\[title]')
  1208. RegNew = re.compile('collection\[(?P<slug>[\w-]+)\]\[(?P<num>\d+)\]\[id\]')
  1209. for key, value in request.POST.iteritems():
  1210. regN= RegNew.match(key)
  1211. regT= RegTitle.match(key)
  1212. reg = RegExist.match(key)
  1213. if reg:
  1214. if not DicResult.has_key(reg.group('slug')):
  1215. DicResult[reg.group('slug')] = dict()
  1216. if DicResult[reg.group('slug')].has_key('items'):
  1217. DicResult[reg.group('slug')]['items'].append( ( int(reg.group('id')), value ) )
  1218. else:
  1219. DicResult[reg.group('slug')]['items'] = [ ( int(reg.group('id')), value ) ]
  1220. elif regN:
  1221. if not DicResult.has_key(regN.group('slug')):
  1222. DicResult[regN.group('slug')] = dict()
  1223. if DicResult[regN.group('slug')].has_key('items'):
  1224. DicResult[regN.group('slug')]['items'].append( ( 'id', value ) )
  1225. else:
  1226. DicResult[regN.group('slug')]['items'] = [ ( 'id', value ) ]
  1227. ListChanges.append(('add', 0, DicResult[regN.group('slug')]['title'], value))
  1228. elif regT:
  1229. if not DicResult.has_key(regT.group('slug')):
  1230. DicResult[regT.group('slug')] = dict()
  1231. DicResult[regT.group('slug')]['title'] = value
  1232. else:
  1233. raise
  1234. for opt in DBSession.query(TiersOpt).all():
  1235. if DicResult.has_key(opt.slug_entity_type):
  1236. found = filter( lambda (x,y): opt.uid==x,
  1237. DicResult[opt.slug_entity_type].get('items', []))
  1238. if not found:
  1239. ListChanges.append(('remove', opt.uid, opt.entity_type, opt.entity_subtype))
  1240. else:
  1241. for tst in found:
  1242. # Check changes on Cat Name
  1243. if DicResult[opt.slug_entity_type]['title']!=opt.entity_type or \
  1244. tst[1]!=opt.entity_subtype:
  1245. ListChanges.append(('changed', opt.uid,
  1246. DicResult[opt.slug_entity_type]['title'],
  1247. tst[1]))
  1248. else:
  1249. ListChanges.append(('remove', opt.uid, opt.entity_type, opt.entity_subtype))
  1250. # Do The change
  1251. for action, uid, entity, subentity in ListChanges:
  1252. if action=="changed":
  1253. opt = TiersOpt.by_id(uid)
  1254. opt.entity_type = entity
  1255. opt.entity_subtype = subentity
  1256. elif action=="remove":
  1257. opt = TiersOpt.by_id(uid)
  1258. DBSession.delete(opt)
  1259. elif action=="add":
  1260. opt = TiersOpt()
  1261. opt.entity_type = entity
  1262. opt.entity_subtype = subentity
  1263. DBSession.add(opt)
  1264. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1265. 'logged_in':request.authenticated_userid, 'TiersOpt':TiersOpt }
  1266. return MainTab
  1267. @view_config(route_name='show_user', renderer="jm2l:templates/view_user.mako")
  1268. def show_user(request):
  1269. user_slug = request.matchdict.get('user_slug', None)
  1270. if user_slug is None or len(user_slug)==0:
  1271. raise HTTPNotFound(u"Cet utilisateur n'a pas été reconnu")
  1272. # Query database
  1273. DispUser = User.by_slug(user_slug)
  1274. if DispUser is None:
  1275. raise HTTPNotFound()
  1276. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1277. 'DispUser':DispUser, 'logged_in':request.authenticated_userid }
  1278. return MainTab
  1279. #@view_config(route_name='link_user_entity')
  1280. def link_user_entity(request):
  1281. uid = int(request.matchdict.get('uid', -1))
  1282. year = int(request.matchdict.get('year', -1))
  1283. user_id = int(request.matchdict.get('uid', -1))
  1284. TheTiers = Tiers.by_id(uid)
  1285. if TheTiers is None:
  1286. raise HTTPNotFound()
  1287. return HTTPFound(location=request.route_url('edit_entity', uid=uid) )
  1288. #@view_config(route_name='link_role_entity')
  1289. def link_role_entity(request):
  1290. uid = int(request.matchdict.get('uid', -1))
  1291. year = int(request.matchdict.get('year', -1))
  1292. role_id = int(request.matchdict.get('role_id', -1))
  1293. TheTiers = Tiers.by_id(uid)
  1294. if TheTiers is None:
  1295. raise HTTPNotFound()
  1296. return HTTPFound(location=request.route_url('edit_entity', uid=uid) )
  1297. @forbidden_view_config()
  1298. def forbidden(reason, request):
  1299. if 'ident' in reason.detail:
  1300. request.session.flash(('info', reason.detail))
  1301. return HTTPFound(location='/sign/login' )
  1302. else:
  1303. request.response.status = 403
  1304. return render_to_response('jm2l:templates/Errors/403.mako', { "reason":reason },
  1305. request=request)
  1306. @notfound_view_config()
  1307. def notfound(reason, request):
  1308. request.response.status = 404
  1309. return render_to_response('jm2l:templates/Errors/404.mako', { "reason":reason },
  1310. request=request)