Le repo des sources pour le site web des JM2L
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 

1006 lignes
43 KiB

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