Le repo des sources pour le site web des JM2L
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 

1500 строки
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)