Le repo des sources pour le site web des JM2L
Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 

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