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

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