Le repo des sources pour le site web des JM2L
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 

1006 rader
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) )