Le repo des sources pour le site web des JM2L
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

1406 lines
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)