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

1051 lines
45 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. # Import Web Forms
  9. from .forms import *
  10. # Database access imports
  11. from .models import *
  12. from sqlalchemy.exc import DBAPIError
  13. from sqlalchemy import func, or_
  14. # Usefull tools
  15. from slugify import slugify
  16. from icalendar import Calendar
  17. from pytz import timezone
  18. from icalendar import Event as Evt
  19. # Then, standard libs
  20. import webhelpers.paginate as paginate
  21. import unicodedata
  22. import time
  23. import datetime
  24. import re
  25. CurrentYear = 2015
  26. ## =-=- Here, We keep some usefull function -=-=
  27. def remove_accents(input_str):
  28. """ This function is intended to remove all accent from input unicode string """
  29. nkfd_form = unicodedata.normalize('NFKD', input_str)
  30. only_ascii = nkfd_form.encode('ASCII', 'ignore')
  31. return only_ascii
  32. @view_config(route_name='tester', renderer="jm2l:templates/tester.mako")
  33. def Tester(request):
  34. JTiers = DBSession.query(Tiers).all()
  35. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  36. 'Tiers':JTiers, "logged_in":request.authenticated_userid }
  37. return MainTab
  38. ## =-=- Here, We handle ICal requests -=-=
  39. @view_config(route_name='progr_iCal', renderer="string")
  40. def ICal_Progamme_Request(request):
  41. year = int(request.matchdict.get('year', CurrentYear))
  42. # Initialization
  43. DicResult = dict()
  44. # Query database
  45. # Compute days used by all events matching the specified input year
  46. Events = DBSession.query(Event)\
  47. .filter(Event.for_year == year)\
  48. .filter(Event.event_type != 'Stand')\
  49. .order_by(Event.start_time)
  50. cal = Calendar()
  51. cal.add('prodid', '-//Programme %d//jm2l.linux-azur.org//' % year)
  52. cal.add('version', '2.0')
  53. tz = timezone('Europe/Paris')
  54. for ev in Events:
  55. if ev.event_type:
  56. event = Evt()
  57. event['uid'] = "%d/%d" % ( year, ev.uid )
  58. event.add('summary', ev.name )
  59. event.add('dtstart', ev.start_time.replace(tzinfo=tz) )
  60. event.add('dtend', ev.end_time.replace(tzinfo=tz) )
  61. event.add('created', ev.last_change.replace(tzinfo=tz) )
  62. event.add('description', "http://www.linux-azur.org/event/%s/%s" % (ev.for_year, ev.slug) )
  63. event.add('url', "http://www.linux-azur.org/event/%s/%s" % (ev.for_year, ev.slug) )
  64. event.add('priority', 5)
  65. cal.add_component(event)
  66. return cal.to_ical()
  67. ## =-=- Here, We handle Json requests -=-=
  68. @view_config(route_name='users_json', renderer="json")
  69. def JSON_User_Request(request):
  70. """ Build a JSON answer with active users and pagination handling """
  71. # Check arguments consitency
  72. pageSize = request.params.get('pageSize',"8")
  73. current_page = request.params.get('pageNum',"1")
  74. UserQuery = request.params.get('searchTerm', u"")
  75. # Don't answer to users that aren't logged
  76. if not request.user:
  77. return HTTPUnauthorized('You have to be logged to hope an answer.')
  78. # Check consistancy of parameters
  79. if pageSize.isdigit() and current_page.isdigit():
  80. current_page = int(current_page)
  81. pageSize = int(pageSize)
  82. else:
  83. return HTTPBadRequest('pageSize and pageNum accept only digits.')
  84. # Query database
  85. Users = DBSession.query(User.uid, User.nom, User.prenom)\
  86. .filter(User.slug.contains( remove_accents(UserQuery) ))
  87. page_url = paginate.PageURL_WebOb(request)
  88. records = paginate.Page(Users, current_page, url=page_url, items_per_page=pageSize)
  89. ListMatchUser = map( lambda u:{"id": u.uid, "text":"%s %s" % ( u.prenom, u.nom )}, records )
  90. return { "Results": ListMatchUser, "Total":records.item_count,
  91. "logged_in":request.authenticated_userid }
  92. @view_config(route_name='tiers_json', renderer="json")
  93. def JSON_Tiers_Request(request):
  94. """ Build a JSON answer with active users and pagination handling """
  95. # Check arguments consitency
  96. pageSize = request.params.get('pageSize',"8")
  97. current_page = request.params.get('pageNum',"1")
  98. TiersQuery = request.params.get('searchTerm', u"")
  99. # Don't answer to users that aren't logged
  100. if not request.user:
  101. return HTTPUnauthorized('You have to be logged to hope an answer.')
  102. # Check consistancy of parameters
  103. if pageSize.isdigit() and current_page.isdigit():
  104. current_page = int(current_page)
  105. pageSize = int(pageSize)
  106. else:
  107. return HTTPBadRequest('pageSize and pageNum accept only digits.')
  108. # Query database
  109. JTiers = DBSession.query(Tiers.uid, Tiers.name)\
  110. .filter(Tiers.slug.contains( remove_accents(TiersQuery) ))
  111. page_url = paginate.PageURL_WebOb(request)
  112. records = paginate.Page(JTiers, current_page, url=page_url, items_per_page=pageSize)
  113. ListMatchTiers = map( lambda t:{"id": t.uid, "text": t.name }, records )
  114. return { "Results": ListMatchTiers, "Total":records.item_count,
  115. "logged_in":request.authenticated_userid }
  116. @view_config(route_name='progr_json', renderer="json")
  117. def JSON_Progamme_Request(request):
  118. year = int(request.matchdict.get('year', CurrentYear))
  119. # Initialization
  120. DicResult = dict()
  121. # Query database
  122. # Compute days used by all events matching the specified input year
  123. Days = DBSession.query( func.strftime('%d', Event.start_time).label('day') )\
  124. .filter(Event.for_year == year)\
  125. .filter(Event.event_type != None)\
  126. .group_by(func.strftime('%d', Event.start_time)).all()
  127. for Day in Days:
  128. Events = DBSession.query(Event)\
  129. .filter(Event.for_year == year)\
  130. .filter(Event.event_type != 'Stand')\
  131. .filter("strftime('%d', start_time) = :dow").params(dow=Day.day)\
  132. .order_by(Event.start_time)
  133. ListEv = []
  134. for ev in Events:
  135. if ev.event_type:
  136. ListEv.append( {
  137. "uid":"%d/%d" % ( year, ev.uid ),
  138. "desc":ev.name,
  139. "startDate":ev.start_time.strftime('%Y-%m-%dT%H:%M:%S'),
  140. "endDate":ev.end_time.strftime('%Y-%m-%dT%H:%M:%S'),
  141. "placeName":ev.Salle and (ev.Salle.name or "unk") ,
  142. "status":ev.event_type
  143. } )
  144. DicResult[Day.day] = ListEv
  145. return { 'all':DicResult }
  146. @view_config(route_name='timeline_json', renderer="json")
  147. def JSON_TimeLine_Request(request):
  148. year = int(request.matchdict.get('year', CurrentYear))
  149. # Initialization
  150. DicResult = dict()
  151. # Query database
  152. # Compute days used by all events matching the specified input year
  153. Days = DBSession.query( func.strftime('%d', Event.start_time).label('day') )\
  154. .filter(Event.for_year == year)\
  155. .filter(Event.event_type != None)\
  156. .group_by(func.strftime('%d', Event.start_time)).all()
  157. ListEv = []
  158. for Day in Days:
  159. Events = DBSession.query(Event)\
  160. .filter(Event.for_year == year)\
  161. .filter(Event.event_type != 'Stand')\
  162. .filter("strftime('%d', start_time) = :dow").params(dow=Day.day)\
  163. .order_by(Event.start_time)
  164. ListEv = []
  165. for ev in Events:
  166. if ev.event_type:
  167. ListEv.append( {
  168. #"uid":"%d/%d" % ( year, ev.uid ),
  169. "headline":ev.name,
  170. "startDate":ev.start_time.strftime('%Y,%m,%d,%H,%M'),
  171. "endDate":ev.end_time.strftime('%Y,%m,%d,%H,%M'),
  172. "text":ev.Salle and (ev.Salle.name or "unk"),
  173. "tags":ev.Salle and (ev.Salle.name or "unk") ,
  174. #"status":ev.event_type,
  175. "asset": {
  176. "media":"", #http://jm2l.linux-azur.org/sites/jm2l.linux-azur.org/files/videos/2012/2012_Introduction_aux_logiciels_libres__Frederic_Couchet.ogv",
  177. "credit":"",
  178. "caption":"" }
  179. } )
  180. break
  181. DicResult = {
  182. "lang":"fr",
  183. "headline":"JM2L 2015",
  184. "type":"default",
  185. "startDate":"2015,11,28,10",
  186. "text":"<i><span class='c1'>9ème Édition</span></i>",
  187. "asset":
  188. {
  189. "media":"",
  190. "credit":"JM2L",
  191. "caption":""
  192. }
  193. }
  194. DicResult["date"] = ListEv
  195. return { 'timeline':DicResult }
  196. ## =-=- Here, We handle HTTP requests - Public Part -=-=
  197. @view_config(route_name='home', renderer="jm2l:templates/NewIndex.mako")
  198. def index_page(request):
  199. page = int(request.params.get('page', 1))
  200. paginator = Entry.get_paginator(request, page)
  201. profil = User.by_id(4)
  202. profil_form = ProfilForm(request.POST, profil, meta={'csrf_context': request.session})
  203. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'', 'paginator':paginator,
  204. "logged_in":request.authenticated_userid }
  205. return MainTab
  206. @view_config(route_name='programme', renderer="jm2l:templates/Public/Programme.mako")
  207. def programme(request):
  208. year = int(request.matchdict.get('year'))
  209. if 2006 > year:
  210. return HTTPBadRequest('The first JM2L event was in 2006.')
  211. # Query database about selected Year.
  212. Events = DBSession.query(Event)\
  213. .filter(Event.for_year == year)\
  214. .order_by(Event.start_time)
  215. Days = DBSession.query(func.strftime('%d-%m-%Y', Event.start_time))\
  216. .filter(Event.for_year == year)\
  217. .filter(Event.event_type != None)\
  218. .group_by(func.strftime('%d', Event.start_time)).all()
  219. ListDay = []
  220. for day in Days:
  221. RefDay = datetime.datetime.strptime(day[0],'%d-%m-%Y')
  222. ListDay.append( ( RefDay.strftime('%A %d %b %Y'),
  223. RefDay.strftime('%d') ) )
  224. MainTab = {'programme':'active','presse':'', 'plan':'', 'participer':'', 'DisplayYear':year, \
  225. 'Events':Events, 'Event':Event, 'Days':ListDay, "logged_in":request.authenticated_userid }
  226. return MainTab
  227. @view_config(route_name='presse', renderer="jm2l:templates/Public/Presse.mako")
  228. def static_presse(request):
  229. year = int(request.matchdict.get('year', None))
  230. content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==year).first()
  231. MainTab = {'programme':'','presse':'active', 'plan':'', 'participer':'',
  232. "logged_in":request.authenticated_userid, 'content':content, 'DisplayYear':year}
  233. return MainTab
  234. @view_config(route_name='edit_presse', renderer="jm2l:templates/Staff/EditPresse.mako")
  235. def edit_presse(request):
  236. year = int(request.matchdict.get('year', None))
  237. content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==year).first()
  238. form = DossPresse(request.POST, content, meta={'csrf_context': request.session})
  239. if request.method == 'POST' and form.validate():
  240. form.populate_obj(content)
  241. MainTab = {'programme':'','presse':'active', 'plan':'', 'participer':'',
  242. "logged_in":request.authenticated_userid, 'form':form, 'DisplayYear':year}
  243. return MainTab
  244. @view_config(route_name='plan', renderer="jm2l:templates/Public/Plan.mako")
  245. def static_plan(request):
  246. MainTab = {'programme':'','presse':'', 'plan':'active', 'participer':'',
  247. "logged_in":request.authenticated_userid }
  248. return MainTab
  249. ## =-=- Here, We handle HTTP requests - Staff Logged Part -=-=
  250. @view_config(route_name='list_task', renderer='jm2l:templates/Staff/list.mako')
  251. def list_view(request):
  252. DicTask = {}
  253. taskgroup = DBSession.query( TasksArea ).all()
  254. for grp in taskgroup:
  255. tasks = DBSession.query( Tasks )\
  256. .filter( Tasks.area_uid==grp.uid )\
  257. .order_by(Tasks.closed, Tasks.due_date).all()
  258. DicTask[grp] = tasks
  259. return {'tasks': DicTask }
  260. @view_config(route_name='handle_task', renderer='jm2l:templates/Staff/tasks.mako')
  261. def tasks(request):
  262. task_id = request.matchdict.get('task_id')
  263. if task_id:
  264. Task = Tasks.by_id(int(task_id))
  265. if not Task:
  266. raise HTTPNotFound()
  267. form = EditStaffTasks(request.POST, Task, meta={'csrf_context': request.session})
  268. else:
  269. Task = Tasks()
  270. form = StaffTasks(request.POST, Task, meta={'csrf_context': request.session})
  271. # Put some areas on form
  272. Areas = DBSession.query(TasksArea.uid, TasksArea.name)\
  273. .order_by('name').all()
  274. form.area_uid.choices = Areas
  275. # Put some users on form
  276. Users = DBSession.query(User)\
  277. .filter(User.Staff==1)\
  278. .order_by('nom').all()
  279. form.closed_by.choices = [(u.uid, "%s %s" % (u.nom, u.prenom))
  280. for u in Users]
  281. if request.method == 'POST' and form.validate():
  282. form.populate_obj(Task)
  283. Task.closed = False
  284. if 'uid' in form._fields.keys():
  285. DBSession.merge(Task)
  286. else:
  287. DBSession.add(Task)
  288. return HTTPFound(location=request.route_url('list_task'))
  289. return {'form':form }
  290. @view_config(route_name='handle_pole', renderer='jm2l:templates/Staff/pole.mako')
  291. def tasks_area(request):
  292. pole_id = request.matchdict.get('pole_id')
  293. if pole_id:
  294. Pole = TasksArea.by_id(int(pole_id))
  295. if not Pole:
  296. raise HTTPNotFound()
  297. form = EditStaffArea(request.POST, Pole, meta={'csrf_context': request.session})
  298. else:
  299. Pole = TasksArea()
  300. form = StaffArea(request.POST, Pole, meta={'csrf_context': request.session})
  301. if request.method == 'POST' and form.validate():
  302. form.populate_obj(Pole)
  303. if 'uid' in form._fields.keys():
  304. DBSession.merge(Pole)
  305. else:
  306. DBSession.add(Pole)
  307. return HTTPFound(location=request.route_url('list_task'))
  308. return {'form':form }
  309. @view_config(route_name='action_task')
  310. def action_task(request):
  311. action = request.matchdict.get('action')
  312. task_id = request.matchdict.get('task_id')
  313. raise 'test'
  314. Task = Tasks.by_id(int(task_id))
  315. if action=='close':
  316. Task.closed = True
  317. if action=='open':
  318. Task.closed = False
  319. DBSession.merge(Task)
  320. request.session.flash('Task was successfully closed!')
  321. return HTTPFound(location=request.route_url('list_task'))
  322. ## =-=- Here, We handle HTTP requests - User Logged Part -=-=
  323. @view_config(route_name='exchange', renderer="jm2l:templates/Logistique/Logistique.mako")
  324. def exchange(request):
  325. modtype = request.matchdict.get('modtype', None)
  326. action = request.matchdict.get('action', None)
  327. uid = int(request.matchdict.get('id', -1))
  328. Exch = Exchange.by_id(uid)
  329. if not Exch:
  330. MainTab = {
  331. 'Exchanges':Exchange,
  332. 'Type':modtype[-1:],
  333. 'reload':True,
  334. 'logged_in':request.authenticated_userid
  335. }
  336. return MainTab
  337. if action in ['delete', 'accept', 'refuse', 'deal']:
  338. if action=='delete': # delete exchange
  339. DBSession.delete(Exch)
  340. elif action=='accept': # accept exchange
  341. Exch.exch_done=True
  342. DBSession.merge(Exch)
  343. elif action=='refuse': # refuse exchange
  344. Exch.exch_done=False
  345. if Exch.exch_state=="Ask":
  346. Exch.provider_id = None
  347. elif Exch.exch_state=="Proposal":
  348. Exch.asker_id = None
  349. DBSession.merge(Exch)
  350. elif action=='deal':
  351. # ask to deal the exchange
  352. if Exch.exch_state=="Ask":
  353. Exch.provider_id = request.user.uid
  354. elif Exch.exch_state=="Proposal":
  355. Exch.asker_id = request.user.uid
  356. # Return javascript to parent page
  357. response = render_to_response('jm2l:templates/modals_js.mako',
  358. {'modtype':modtype, 'action':action},
  359. request=request)
  360. response.content_type = 'text/javascript'
  361. return response
  362. else:
  363. MainTab = {
  364. 'Exchanges':Exchange,
  365. 'Type':modtype[-1:],
  366. 'reload':True,
  367. 'logged_in':request.authenticated_userid
  368. }
  369. return MainTab
  370. @view_config(route_name='jm2l', renderer="jm2l:templates/jm2l.mako")
  371. def jm2l_page(request):
  372. if request.user is None:
  373. # Don't answer to users that aren't logged
  374. return HTTPUnauthorized('You have to be logged to hope an answer.')
  375. page = int(request.params.get('page', 1))
  376. UserNum = request.params.get('user')
  377. if UserNum:
  378. profil = User.by_id(int(UserNum))
  379. if not profil:
  380. raise HTTPNotFound()
  381. else:
  382. profil = request.user
  383. # Build Form
  384. profil_form = ProfilForm(request.POST, profil, meta={'csrf_context': request.session})
  385. if request.method == 'POST' and profil_form.validate():
  386. ToDelete = list()
  387. # First, we remove entries no more present
  388. for obj in profil_form.tiersship.object_data:
  389. MatchEntry = filter( lambda x: x.object_data and x.object_data._sa_instance_state == obj._sa_instance_state,
  390. profil_form.tiersship.entries )
  391. if not MatchEntry:
  392. ToDelete.append(obj)
  393. # Then, it's time to consider new entries
  394. for entry in profil_form.tiersship.entries:
  395. if entry.object_data is None:
  396. TmpUser = User_Tiers()
  397. entry.object_data = TmpUser
  398. profil.tiersship.append(TmpUser)
  399. profil_form.tiersship.object_data = profil.tiersship
  400. profil_form.populate_obj(profil)
  401. # We should remove it as it's not in original data
  402. for obj in ToDelete:
  403. #profil.tiersship.remove(obj)
  404. DBSession.delete(obj)
  405. profil.last_change = datetime.datetime.utcnow()
  406. profil.slug = slugify(remove_accents('%s %s' % (profil.prenom, profil.nom)).lower().strip())
  407. DBSession.merge(profil)
  408. MainTab = {'participer':'active',
  409. 'Places':Place.get_list(False),
  410. 'DBTiers':Tiers,
  411. 'DBTiersOpt':TiersOpt,
  412. 'Exchanges':Exchange,
  413. 'profil_form':profil_form,
  414. 'uprofil':profil,
  415. 'logged_in':request.authenticated_userid
  416. }
  417. return MainTab
  418. @view_config(route_name='modal', renderer="jm2l:templates/modals.mako")
  419. def Modal(request):
  420. year = int(request.matchdict.get('year', None))
  421. modtype = request.matchdict.get('modtype', None)
  422. uid = int(request.matchdict.get('id', -1))
  423. session = request.session
  424. if modtype=='Password':
  425. form = UserPasswordForm(request.POST, request.user, meta={'csrf_context': request.session})
  426. if request.method == 'POST' and form.validate():
  427. response = render_to_response('jm2l:templates/modals_js.mako',
  428. {'modtype':modtype},
  429. request=request)
  430. response.content_type = 'text/javascript'
  431. return response
  432. if modtype=='UserPicture':
  433. form = None
  434. if request.method == 'POST':
  435. response = render_to_response('jm2l:templates/modals_js.mako',
  436. {'modtype':modtype},
  437. request=request)
  438. response.content_type = 'text/javascript'
  439. return response
  440. if modtype=='Place':
  441. if uid>0:
  442. place = Place.by_id(uid)
  443. if not place:
  444. raise HTTPNotFound()
  445. form = PlaceUpdateForm(request.POST, place, meta={'csrf_context': request.session})
  446. else:
  447. place = Place()
  448. form = PlaceCreateForm(request.POST, meta={'csrf_context': request.session})
  449. if request.method == 'POST' and form.validate():
  450. form.populate_obj(place)
  451. place.created_by=request.user.uid
  452. if uid>0:
  453. DBSession.merge(place)
  454. else:
  455. DBSession.add(place)
  456. response = render_to_response('jm2l:templates/modals_js.mako',
  457. {'modtype':modtype},
  458. request=request)
  459. response.content_type = 'text/javascript'
  460. return response
  461. if modtype in ['AskC', 'AskH', 'AskM', 'PropC', 'PropH', 'PropM']:
  462. if uid>0:
  463. Exch = Exchange.by_id(uid)
  464. if not Exch:
  465. raise HTTPNotFound()
  466. if modtype in ['AskC','PropC']:
  467. form = globals()["Update%sForm" % modtype](request.POST, Exch,
  468. start_place = Exch.Itin.start_place,
  469. arrival_place = Exch.Itin.arrival_place,
  470. Hour_start = Exch.start_time.strftime("%H:%M"),
  471. Day_start = Exch.start_time.strftime("%w"),
  472. exch_id = uid, meta={'csrf_context': request.session}
  473. )
  474. elif modtype in ['AskM','PropM']:
  475. form = globals()["Update%sForm" % modtype](request.POST, Exch,
  476. description = Exch.description,
  477. exch_categ = Exch.exch_categ,
  478. Hour_start = Exch.start_time.strftime("%H:%M"),
  479. Day_start = Exch.start_time.strftime("%w"),
  480. Hour_end = Exch.end_time.strftime("%H:%M"),
  481. Day_end = Exch.end_time.strftime("%w"),
  482. exch_id = uid, meta={'csrf_context': request.session}
  483. )
  484. elif modtype in ['AskH','PropH']:
  485. form = globals()["Update%sForm" % modtype](request.POST, Exch,
  486. description = Exch.description,
  487. exch_categ = Exch.exch_categ,
  488. Day_start = Exch.start_time.strftime("%w"),
  489. exch_id = uid, meta={'csrf_context': request.session}
  490. )
  491. # Itinerary, first get itinerary
  492. if 0:
  493. form.itin.form.start_place.data = Exch.Itin.start_place
  494. form.itin.form.arrival_place.data = Exch.Itin.arrival_place
  495. form.dateform.form.Hour.data = Exch.start_time.strftime("%H:%M")
  496. form.dateform.form.Day.data = Exch.start_time.strftime("%w")
  497. form.exch_id.data = uid
  498. else:
  499. Exch = Exchange()
  500. form = globals()["%sForm" % modtype](request.POST, meta={'csrf_context': request.session})
  501. if modtype in ['AskC', 'PropC']:
  502. # Put some place on form
  503. Places = DBSession.query(Place.place_id, Place.display_name)\
  504. .order_by('name').all()
  505. form.start_place.choices = Places
  506. form.arrival_place.choices = Places
  507. if modtype in ['PropH']:
  508. form.exch_categ.choices = DBSession.query( Exchange_Cat.cat_id, Exchange_Cat.exch_subtype)\
  509. .filter( Exchange_Cat.exch_type=='H' ).all()
  510. form.place_id.choices = DBSession.query( Place.place_id, Place.display_name)\
  511. .filter( Place.created_by==request.user.uid ).all()
  512. if modtype in ['AskM', 'PropM']:
  513. form.exch_categ.choices = DBSession.query( Exchange_Cat.cat_id, Exchange_Cat.exch_subtype)\
  514. .filter( Exchange_Cat.exch_type=='M' ).all()
  515. if request.method == 'POST' and form.validate():
  516. # Form has been validated, it's time to create our Exchange
  517. Exch.for_year = year
  518. Exch.exch_state = {'Ask':'Ask', 'Prop':'Proposal'}[modtype[:-1]]
  519. Exch.exch_type = modtype[-1:]
  520. if modtype in ['AskC', 'PropC']:
  521. # Itinerary, first Let's see if itinerary exist
  522. Itinerary = DBSession.query(Itineraire)\
  523. .filter(Itineraire.start_place==form.start_place.data) \
  524. .filter(Itineraire.arrival_place==form.arrival_place.data) \
  525. .filter(Itineraire.tr_voiture==True) \
  526. .first()
  527. if not Itinerary: # Not exist yet !
  528. Itinerary = Itineraire(start_place=form.start_place.data, \
  529. arrival_place=form.arrival_place.data, \
  530. tr_voiture=True, \
  531. created_by=1
  532. )
  533. DBSession.add(Itinerary)
  534. DBSession.flush()
  535. Exch.itin_id = Itinerary.itin_id
  536. # Start Time
  537. StartEvent = DBSession.query(JM2L_Year.start_time).filter(JM2L_Year.year_uid==year).first()
  538. Week = StartEvent[0].strftime("%W")
  539. # populate
  540. form.populate_obj(Exch)
  541. if modtype in ['AskC', 'PropC']:
  542. Exch.itin_id = Itinerary.itin_id
  543. if form._fields.has_key("Hour_start"):
  544. TargetTime = datetime.datetime.strptime('%d %d %d %s' % (year, int(Week), \
  545. int(form.Day_start.data), form.Hour_start.data), "%Y %W %w %H:%M")
  546. Exch.start_time = TargetTime
  547. elif form._fields.has_key("Day_start"):
  548. TargetTime = datetime.datetime.strptime('%d %d %d' % (year, int(Week), \
  549. int(form.Day_start.data)), "%Y %W %w")
  550. Exch.start_time = TargetTime
  551. if form._fields.has_key("Hour_end"):
  552. TargetTime = datetime.datetime.strptime('%d %d %d %s' % (year, int(Week), \
  553. int(form.Day_end.data), form.Hour_end.data), "%Y %W %w %H:%M")
  554. Exch.end_time = TargetTime
  555. elif form._fields.has_key("Day_end"):
  556. TargetTime = datetime.datetime.strptime('%d %d %d' % (year, int(Week), \
  557. int(form.Day_end.data)), "%Y %W %w")
  558. Exch.end_time = TargetTime
  559. Exch.last_change = datetime.datetime.utcnow()
  560. if Exch.exch_state=='Ask':
  561. Exch.asker_id = request.user.uid
  562. elif Exch.exch_state=='Proposal':
  563. Exch.provider_id = request.user.uid
  564. #print vars(form.itin.form)
  565. if uid>0:
  566. DBSession.merge(Exch)
  567. else:
  568. DBSession.add(Exch)
  569. response = render_to_response('jm2l:templates/modals_js.mako',
  570. {'modtype':modtype},
  571. request=request)
  572. response.content_type = 'text/javascript'
  573. return response
  574. # Fallback to HTML Display with errors
  575. return {'modtype':modtype, 'form':form, 'update':uid>0,
  576. 'logged_in':request.authenticated_userid }
  577. if modtype in ['ShowC', 'ShowH', 'ShowM']:
  578. if uid>0:
  579. Exch = Exchange.by_id(uid)
  580. if not Exch:
  581. raise HTTPNotFound()
  582. else:
  583. raise HTTPNotFound()
  584. # Show Details around the Current Exchange
  585. return {'modtype':modtype, 'Exch':Exch, 'logged_in':request.authenticated_userid }
  586. MainTab = {'modtype':modtype, 'form':form, 'update':uid>0, 'uid':uid,
  587. 'DisplayYear':year, 'session':session,
  588. 'logged_in':request.authenticated_userid }
  589. return MainTab
  590. @view_config(route_name='participer', renderer="jm2l:templates/Participer.mako")
  591. def participer(request):
  592. session = request.session
  593. session['year'] = 2015
  594. TmpUsr = User()
  595. form = UserRegisterForm(request.POST, TmpUsr, meta={'csrf_context': request.session})
  596. MyLink=None
  597. if request.method == 'POST' and form.validate():
  598. form.populate_obj(TmpUsr)
  599. TmpUsr.nom = TmpUsr.nom.capitalize()
  600. TmpUsr.prenom = TmpUsr.prenom.capitalize()
  601. TmpUsr.slug = slugify(remove_accents('%s %s' % (form.prenom.data, form.nom.data)).lower().strip())
  602. TmpUsr.password = TmpUsr.my_hash
  603. if len(TmpUsr.slug):
  604. CheckExist = DBSession.query(User)\
  605. .filter(User.slug==TmpUsr.slug)\
  606. .first()
  607. else:
  608. CheckExist=None
  609. if CheckExist:
  610. MyLink = CheckExist.my_hash
  611. else:
  612. DBSession.add(TmpUsr)
  613. DBSession.flush()
  614. MyLink = TmpUsr.my_hash
  615. MainTab = {'programme':'','presse':'', 'plan':'',
  616. 'participer':'active', 'form':form, "link": MyLink,
  617. 'logged_in':request.authenticated_userid }
  618. return MainTab
  619. @view_config(route_name='year')
  620. def change_year(request):
  621. year = int(request.matchdict.get('year', -1))
  622. session = request.session
  623. if year>-1:
  624. session['year'] = year
  625. return HTTPFound(location='/%s/le-programme' % year)
  626. return HTTPFound(location=request.route_url('home'))
  627. @view_config(route_name='pict_user', renderer="jm2l:templates/Profil/pict_user.mako")
  628. def pict_user(request):
  629. return {"uprofil":request.user}
  630. @view_config(route_name='event', renderer="jm2l:templates/view_event.mako")
  631. def show_event(request):
  632. year = int(request.matchdict.get('year', -1))
  633. event_id = request.matchdict.get('event_id')
  634. if event_id.isdigit():
  635. TheEvent = Event.by_id(event_id)
  636. if TheEvent is None:
  637. raise HTTPNotFound()
  638. else:
  639. TheEvent = Event.by_slug(event_id, year)
  640. if TheEvent is None:
  641. raise HTTPNotFound()
  642. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  643. 'event':TheEvent, 'logged_in':request.authenticated_userid }
  644. return MainTab
  645. @view_config(route_name='link_event')
  646. def link_event(request):
  647. """ Create user if not exist, add it to current event """
  648. year = int(request.matchdict.get('year', -1))
  649. form = AddIntervenant(request.POST, meta={'csrf_context': request.session})
  650. intervention = request.matchdict.get('intervention', None)
  651. TargetEvent = Event.by_id(form.event_uid.data)
  652. Exist = DBSession.query(User)\
  653. .filter(User.nom==form.nom.data)\
  654. .filter(User.prenom==form.prenom.data)\
  655. .first()
  656. if Exist:
  657. TargetUser = Exist
  658. else:
  659. # Add it to user base
  660. TargetUser = User(nom=form.nom.data,
  661. prenom=form.prenom.data, password=form.nom.data)
  662. DBSession.add(TargetUser)
  663. DBSession.flush()
  664. uev = User_Event(year_uid=year, role="Animateur", user_uid=TargetUser.uid)
  665. TargetEvent.interventions.append( uev )
  666. return HTTPFound(location=request.route_url('edit_event', sep='/',
  667. year=str(year), intervention=intervention, uid=str(TargetEvent.uid)))
  668. @view_config(route_name='edit_event', renderer="jm2l:templates/edit_event.mako")
  669. def edit_event(request):
  670. year = int(request.matchdict.get('year', -1))
  671. event_id = request.matchdict.get('event_id')
  672. intervention = request.matchdict.get('intervention', None)
  673. IntervLabel = intervention.replace('_',' ').lower()
  674. if intervention=='Conference':
  675. IntervLabel = u'conférence'
  676. # Check intervention
  677. if not intervention in ['Stand', 'Table ronde', 'Atelier', 'Conference']:
  678. raise HTTPNotFound(u"Ce type d'évenement n'est pas reconnu")
  679. TheYear = DBSession.query(JM2L_Year)\
  680. .filter(JM2L_Year.year_uid==year)\
  681. .all()
  682. # Check year avaibility
  683. if not TheYear:
  684. raise HTTPNotFound(u"Cette année n'est pas pris en charge")
  685. # Generate Timeslots for current year
  686. TimeSlots = list(enumerate( [ x.strftime('%a %d %b %H:%M') for x in
  687. TheYear[0].AvailableTimeSlots ] ))
  688. if event_id:
  689. # We try to update an existing record
  690. if event_id.isdigit():
  691. TheEvent = Event.by_id(event_id)
  692. if TheEvent is None:
  693. raise HTTPNotFound(u"Cette réference n'existe pas")
  694. else:
  695. TheEvent = Event.by_slug(event_id, year)
  696. if TheEvent is None:
  697. raise HTTPNotFound(u"Cette réference n'existe pas")
  698. if not (request.user.uid==1 or request.user in TheEvent.intervenants):
  699. return HTTPForbidden(u"Vous n'êtes pas identifié comme étant un participant à cette intervention.")
  700. # Compute some field value from selected event
  701. if TheEvent.start_time in TheYear[0].AvailableTimeSlots:
  702. start_sel = TheYear[0].AvailableTimeSlots.index(TheEvent.start_time)
  703. else:
  704. start_sel = len(TimeSlots)
  705. TimeSlots.append( (len(TimeSlots), TheEvent.start_time.strftime('%a %d %b %H:%M')))
  706. duration = (TheEvent.end_time - TheEvent.start_time).total_seconds()/60
  707. end = TheEvent.start_time + datetime.timedelta(minutes=duration)
  708. # prepare the form with update
  709. form = ConfUpdateForm(request.POST, TheEvent, start_sel=start_sel, duration=duration, end_time=end,
  710. meta={'csrf_context': request.session} )
  711. # Customize labels
  712. form.name.label.text += IntervLabel
  713. form.description.label.text += IntervLabel
  714. # Each event can get severals members
  715. formAdd = AddIntervenant(event_uid=TheEvent.uid)
  716. else:
  717. TheEvent = Event()
  718. # prepare the form for creation
  719. form = ConfCreateForm(request.POST,
  720. event_type=intervention,
  721. for_year=str(year), meta={'csrf_context': request.session}
  722. )
  723. # Customize labels
  724. form.name.label.text += IntervLabel
  725. form.description.label.text += IntervLabel
  726. duration=60
  727. # No intervenant
  728. formAdd = None
  729. if intervention=="Conference":
  730. form.duration.choices =[
  731. (15,u'Lighting talk ( 5 min)'),
  732. (30,u'Conférence (20 min)'),
  733. (60,u'Conférence (50 min)'),
  734. (90,u'Conférence (75 min)'),
  735. ]
  736. if not duration in [15, 30, 60, 90]:
  737. form.duration.choices.append( (duration,u'Conférence (%d min)' % duration) )
  738. if not form._fields.has_key("uid"):
  739. form.duration.data=60
  740. elif intervention=="Stand":
  741. form.duration.choices =[
  742. (8*60, u'Toute la journée'),
  743. (4*60, u'une demi-journée')
  744. ]
  745. elif intervention=="Atelier":
  746. form.duration.choices = map( lambda d:(d, u'Atelier (%dh%.2d)' % (d/60, d%60) ), \
  747. [60, 90, 120, 150, 180, 210, 240] )
  748. if not duration in map(lambda (d,y): d, form.duration.choices):
  749. form.duration.choices.append( (duration,u'Atelier (%dh%.2d)' % (duration/60, duration%60) ) )
  750. elif intervention=="Table_Ronde":
  751. form.duration.choices = map( lambda d:(d, u'Table ronde (%dh%.2d)' % (d/60, d%60) ), \
  752. [60, 90, 120, 150] )
  753. if not duration in map(lambda (d,y): d, form.duration.choices):
  754. form.duration.choices.append( (duration,u'Table ronde (%dh%.2d)' % (duration/60, duration%60) ) )
  755. else:
  756. return HTTPForbidden(u"Pas encore disponible.")
  757. SalleDispo = DBSession.query(Salles)\
  758. .filter(Salles.year_uid==year)\
  759. .order_by('name')
  760. form.salle_uid.choices = [(s.salle_id, s.name) for s in SalleDispo]
  761. form.start_sel.choices = TimeSlots
  762. if request.method == 'POST' and form.validate():
  763. form.populate_obj(TheEvent)
  764. TheEvent.start_time = TheYear[0].AvailableTimeSlots[form.start_sel.data]
  765. TheEvent.end_time = TheEvent.start_time + datetime.timedelta(minutes=form.duration.data)
  766. # Ok, time to put in database
  767. if not form._fields.has_key("uid"):
  768. TheEvent.slug = slugify(TheEvent.name)
  769. DBSession.add(TheEvent)
  770. # Append creator by default
  771. if request.user.uid!=1:
  772. uev = User_Event(year_uid=TheYear.year_uid, role="Animateur")
  773. uev.user_uid = request.user.uid
  774. TheEvent.interventions.append( uev )
  775. DBSession.flush()
  776. return HTTPFound(location=request.route_url('edit_event', sep='/',
  777. year=str(year), intervention=intervention, event_id=str(TheEvent.slug)))
  778. else:
  779. DBSession.merge(TheEvent)
  780. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  781. 'event':TheEvent, 'form':form, 'formAdd':formAdd,
  782. 'logged_in':request.authenticated_userid }
  783. return MainTab
  784. @view_config(route_name='entities', renderer="jm2l:templates/list_tiers.mako")
  785. def list_tiers(request):
  786. Entities = dict()
  787. EntityType = DBSession.query(TiersOpt.entity_type)\
  788. .group_by(TiersOpt.entity_type).all()
  789. for EType in EntityType:
  790. Entities[EType.entity_type] = DBSession.query(Tiers).join(TiersOpt)\
  791. .filter(TiersOpt.entity_type==EType.entity_type)\
  792. .order_by(TiersOpt.entity_subtype, Tiers.name)
  793. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  794. 'entities':Entities, 'logged_in':request.authenticated_userid }
  795. return MainTab
  796. @view_config(route_name='show_entity', renderer="jm2l:templates/view_tiers.mako")
  797. def show_tiers(request):
  798. tiers_type = request.matchdict.get('tiers_type')
  799. entity_id = request.matchdict.get('entity_id')
  800. if entity_id.isdigit():
  801. TheTiers = Tiers.by_id(entity_id)
  802. if TheTiers is None:
  803. raise HTTPNotFound()
  804. else:
  805. TheTiers = Tiers.by_slug(entity_id)
  806. if TheTiers is None:
  807. raise HTTPNotFound()
  808. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  809. 'entity':TheTiers, 'logged_in':request.authenticated_userid }
  810. return MainTab
  811. @view_config(route_name='add_entity', renderer="jm2l:templates/edit_tiers.mako")
  812. @view_config(route_name='edit_entity', renderer="jm2l:templates/edit_tiers.mako",
  813. permission='edit')
  814. def edit_tiers(request):
  815. entity_id = request.matchdict.get('entity_id', None)
  816. TargetList = list()
  817. entity_types = DBSession.query(TiersOpt.entity_type).group_by(TiersOpt.entity_type).all()
  818. for entity_type in entity_types:
  819. entity_subtypes = DBSession.query(TiersOpt)\
  820. .filter(TiersOpt.entity_type==entity_type.entity_type)\
  821. .group_by(TiersOpt.entity_subtype).all()
  822. ListType = [(i.uid, i.entity_subtype) for i in entity_subtypes]
  823. TargetList.append( (entity_type.entity_type, ListType) )
  824. if entity_id:
  825. if entity_id.isdigit():
  826. TheTiers = Tiers.by_id(entity_id)
  827. if TheTiers is None:
  828. raise HTTPNotFound()
  829. else:
  830. TheTiers = Tiers.by_slug(entity_id)
  831. if TheTiers is None:
  832. raise HTTPNotFound()
  833. form = UpdateTiersForm(request.POST, TheTiers, meta={'csrf_context': request.session})
  834. UserOptions = DBSession.query(TiersOpt)\
  835. .filter(TiersOpt.entity_type==TheTiers.tiers_type)\
  836. .all()
  837. form.tiers_type.choices = TargetList
  838. else:
  839. TheTiers = Tiers()
  840. # prepare the form for creation
  841. form = TiersForm(request.POST, TheTiers, meta={'csrf_context': request.session})
  842. form.tiers_type.choices = TargetList
  843. UserOptions = list()
  844. #test_form = TiersForm(request.POST, TheTiers, meta={'csrf_context': request.session})
  845. if request.method == 'POST' and form.validate():
  846. ToDelete = list()
  847. # First, we remove entries no more present
  848. for obj in form.membership.object_data:
  849. MatchEntry = filter( lambda x: x.object_data and x.object_data._sa_instance_state == obj._sa_instance_state,
  850. form.membership.entries )
  851. if not MatchEntry:
  852. ToDelete.append(obj)
  853. # We should remove it as it's not in original data
  854. for obj in ToDelete:
  855. TheTiers.membership.remove(obj)
  856. DBSession.delete(obj)
  857. # Then, it's time to consider new entries
  858. for entry in form.membership.entries:
  859. if entry.object_data is None:
  860. TmpUser = User_Tiers()
  861. entry.object_data = TmpUser
  862. TheTiers.membership.append(TmpUser)
  863. form.membership.object_data = TheTiers.membership
  864. form.populate_obj(TheTiers)
  865. # Handle Remove of accents
  866. TheTiers.slug = slugify(form.name.data)
  867. if not form._fields.has_key('uid'):
  868. TheTiers.creator_id = request.user.uid
  869. DBSession.add(TheTiers)
  870. DBSession.flush()
  871. return HTTPFound(location=request.route_url('edit_entity', sep='/',
  872. entity_id=str(TheTiers.slug), tiers_type=TheTiers.get_entity_type.entity_type))
  873. DBSession.merge(TheTiers)
  874. return HTTPFound(location=request.route_url('entities'))
  875. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  876. 'form':form, 'DBUser':User, 'UserOptions':UserOptions,
  877. 'logged_in':request.authenticated_userid }
  878. return MainTab
  879. @view_config(route_name='edit_entity_cat', renderer="jm2l:templates/edit_tiers_categ.mako")
  880. def edit_tiers_category(request):
  881. DicResult = dict()
  882. ListChanges = list()
  883. if request.method == 'POST':
  884. # Reformat data
  885. RegExist = re.compile('collection\[(?P<slug>[\w-]+)\]\[(?P<num>\d+)\]\[(?P<id>\d+)\]')
  886. RegTitle = re.compile('collection\[(?P<slug>[\w-]+)\]\[title]')
  887. RegNew = re.compile('collection\[(?P<slug>[\w-]+)\]\[(?P<num>\d+)\]\[id\]')
  888. for key, value in request.POST.iteritems():
  889. regN= RegNew.match(key)
  890. regT= RegTitle.match(key)
  891. reg = RegExist.match(key)
  892. if reg:
  893. if not DicResult.has_key(reg.group('slug')):
  894. DicResult[reg.group('slug')] = dict()
  895. if DicResult[reg.group('slug')].has_key('items'):
  896. DicResult[reg.group('slug')]['items'].append( ( int(reg.group('id')), value ) )
  897. else:
  898. DicResult[reg.group('slug')]['items'] = [ ( int(reg.group('id')), value ) ]
  899. elif regN:
  900. if not DicResult.has_key(regN.group('slug')):
  901. DicResult[regN.group('slug')] = dict()
  902. if DicResult[regN.group('slug')].has_key('items'):
  903. DicResult[regN.group('slug')]['items'].append( ( 'id', value ) )
  904. else:
  905. DicResult[regN.group('slug')]['items'] = [ ( 'id', value ) ]
  906. ListChanges.append(('add', 0, DicResult[regN.group('slug')]['title'], value))
  907. elif regT:
  908. if not DicResult.has_key(regT.group('slug')):
  909. DicResult[regT.group('slug')] = dict()
  910. DicResult[regT.group('slug')]['title'] = value
  911. else:
  912. raise
  913. for opt in DBSession.query(TiersOpt).all():
  914. if DicResult.has_key(opt.slug_entity_type):
  915. found = filter( lambda (x,y): opt.uid==x,
  916. DicResult[opt.slug_entity_type].get('items', []))
  917. if not found:
  918. ListChanges.append(('remove', opt.uid, opt.entity_type, opt.entity_subtype))
  919. else:
  920. for tst in found:
  921. # Check changes on Cat Name
  922. if DicResult[opt.slug_entity_type]['title']!=opt.entity_type or \
  923. tst[1]!=opt.entity_subtype:
  924. ListChanges.append(('changed', opt.uid,
  925. DicResult[opt.slug_entity_type]['title'],
  926. tst[1]))
  927. else:
  928. ListChanges.append(('remove', opt.uid, opt.entity_type, opt.entity_subtype))
  929. # Do The change
  930. for action, uid, entity, subentity in ListChanges:
  931. if action=="changed":
  932. opt = TiersOpt.by_id(uid)
  933. opt.entity_type = entity
  934. opt.entity_subtype = subentity
  935. elif action=="remove":
  936. opt = TiersOpt.by_id(uid)
  937. DBSession.delete(opt)
  938. elif action=="add":
  939. opt = TiersOpt()
  940. opt.entity_type = entity
  941. opt.entity_subtype = subentity
  942. DBSession.add(opt)
  943. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  944. 'logged_in':request.authenticated_userid, 'TiersOpt':TiersOpt }
  945. return MainTab
  946. @view_config(route_name='show_user', renderer="jm2l:templates/view_user.mako")
  947. def show_user(request):
  948. user_slug = request.matchdict.get('user_slug', None)
  949. # Query database
  950. DispUser = User.by_slug(user_slug)
  951. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  952. 'DispUser':DispUser, 'logged_in':request.authenticated_userid }
  953. return MainTab
  954. #@view_config(route_name='link_user_entity')
  955. def link_user_entity(request):
  956. uid = int(request.matchdict.get('uid', -1))
  957. year = int(request.matchdict.get('year', -1))
  958. user_id = int(request.matchdict.get('uid', -1))
  959. TheTiers = Tiers.by_id(uid)
  960. if TheTiers is None:
  961. raise HTTPNotFound()
  962. return HTTPFound(location=request.route_url('edit_entity', uid=uid) )
  963. #@view_config(route_name='link_role_entity')
  964. def link_role_entity(request):
  965. uid = int(request.matchdict.get('uid', -1))
  966. year = int(request.matchdict.get('year', -1))
  967. role_id = int(request.matchdict.get('role_id', -1))
  968. TheTiers = Tiers.by_id(uid)
  969. if TheTiers is None:
  970. raise HTTPNotFound()
  971. return HTTPFound(location=request.route_url('edit_entity', uid=uid) )
  972. @notfound_view_config()
  973. def notfound(reason, request):
  974. request.response.status = 404
  975. return render_to_response('jm2l:templates/Errors/404.mak', { "reason":reason },
  976. request=request)
  977. @forbidden_view_config()
  978. def forbidden(reason, request):
  979. return Response('forbidden')
  980. request.response.status = 404
  981. return render_to_response('jm2l:templates/Errors/404.mak', { "reason":reason },
  982. request=request)