Le repo des sources pour le site web des JM2L
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 
 

1070 Zeilen
46 KiB

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