Le repo des sources pour le site web des JM2L
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 
 
 

1808 行
80 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.view import notfound_view_config, forbidden_view_config
  6. from pyramid.view import view_config
  7. from mako.template import Template
  8. from .upload import IMAGEPATH
  9. # Import Web Forms
  10. from .forms import *
  11. # Database access imports
  12. from .models import *
  13. from .helpers import Orga_helpers
  14. from sqlalchemy import func, or_
  15. from os import path, makedirs
  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.message import Message
  22. # Then, standard libs
  23. import webhelpers.paginate as paginate
  24. import unicodedata
  25. import datetime
  26. import re
  27. import shutil
  28. CurrentYear = 2015
  29. ## =-=- Here, We keep some usefull function -=-=
  30. def remove_accents(input_str):
  31. """ This function is intended to remove all accent from input unicode string """
  32. nkfd_form = unicodedata.normalize('NFKD', input_str)
  33. only_ascii = nkfd_form.encode('ASCII', 'ignore')
  34. return only_ascii
  35. def embeed_video(mime_type, link):
  36. Container = "<video controls='controls' preload='metadata' style='width:60%'>"
  37. Container += "<source type='%s' " % mime_type
  38. Container += "src='%s' />" % link
  39. Container += "</video>"
  40. return Container
  41. ## =-=- Here, We handle ICal requests -=-=
  42. @view_config(route_name='progr_iCal', renderer="string")
  43. def ICal_Progamme_Request(request):
  44. year = int(request.matchdict.get('year', CurrentYear))
  45. # Initialization
  46. # Compute days used by all events matching the specified input year
  47. Events = DBSession.query(Event)\
  48. .filter(Event.for_year == year)\
  49. .filter(Event.event_type != 'Stand')\
  50. .order_by(Event.start_time)
  51. cal = Calendar()
  52. cal.add('prodid', '-//Programme %d//jm2l.linux-azur.org//' % year)
  53. cal.add('version', '2.0')
  54. tz = timezone('Europe/Paris')
  55. for ev in Events:
  56. if ev.event_type:
  57. event = Evt()
  58. event['uid'] = "%d/%d" % ( year, ev.uid )
  59. event.add('summary', ev.name )
  60. event.add('dtstart', ev.start_time.replace(tzinfo=tz) )
  61. event.add('dtend', ev.end_time.replace(tzinfo=tz) )
  62. event.add('created', ev.last_change.replace(tzinfo=tz) )
  63. event.add('description', "http://www.linux-azur.org/event/%s/%s" % (ev.for_year, ev.slug) )
  64. event.add('url', "http://www.linux-azur.org/event/%s/%s" % (ev.for_year, ev.slug) )
  65. event.add('priority', 5)
  66. cal.add_component(event)
  67. request.response.content_type = "text/calendar"
  68. return cal.to_ical()
  69. ## =-=- Here, We handle Json requests -=-=
  70. @view_config(route_name='users_json', renderer="json")
  71. def JSON_User_Request(request):
  72. """ Build a JSON answer with active users and pagination handling """
  73. # Check arguments consitency
  74. pageSize = request.params.get('pageSize',"8")
  75. current_page = request.params.get('pageNum',"1")
  76. UserQuery = request.params.get('searchTerm', u"")
  77. # Don't answer to users that aren't logged
  78. if not request.user:
  79. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  80. # Check consistancy of parameters
  81. if pageSize.isdigit() and current_page.isdigit():
  82. current_page = int(current_page)
  83. pageSize = int(pageSize)
  84. else:
  85. return HTTPBadRequest('pageSize and pageNum accept only digits.')
  86. # Query database
  87. Users = DBSession.query(User.uid, User.nom, User.prenom)\
  88. .filter(User.slug.contains( remove_accents(UserQuery) ))
  89. page_url = paginate.PageURL_WebOb(request)
  90. records = paginate.Page(Users, current_page, url=page_url, items_per_page=pageSize)
  91. ListMatchUser = map( lambda u:{"id": u.uid, "text":"%s %s" % ( u.prenom, u.nom )}, records )
  92. return { "Results": ListMatchUser, "Total":records.item_count,
  93. "logged_in":request.authenticated_userid }
  94. @view_config(route_name='tiers_json', renderer="json")
  95. def JSON_Tiers_Request(request):
  96. """ Build a JSON answer with active users and pagination handling """
  97. # Check arguments consitency
  98. pageSize = request.params.get('pageSize',"8")
  99. current_page = request.params.get('pageNum',"1")
  100. TiersQuery = request.params.get('searchTerm', u"")
  101. # Don't answer to users that aren't logged
  102. if not request.user:
  103. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  104. # Check consistancy of parameters
  105. if pageSize.isdigit() and current_page.isdigit():
  106. current_page = int(current_page)
  107. pageSize = int(pageSize)
  108. else:
  109. return HTTPBadRequest('pageSize and pageNum accept only digits.')
  110. # Query database
  111. JTiers = DBSession.query(Tiers.uid, Tiers.name)\
  112. .filter(Tiers.slug.contains( remove_accents(TiersQuery) ))
  113. page_url = paginate.PageURL_WebOb(request)
  114. records = paginate.Page(JTiers, current_page, url=page_url, items_per_page=pageSize)
  115. ListMatchTiers = map( lambda t:{"id": t.uid, "text": t.name }, records )
  116. return { "Results": ListMatchTiers, "Total":records.item_count,
  117. "logged_in":request.authenticated_userid }
  118. @view_config(route_name='progr_json', renderer="json")
  119. def JSON_Progamme_Request(request):
  120. year = int(request.matchdict.get('year', CurrentYear))
  121. # Initialization
  122. DicResult = dict()
  123. # Query database
  124. # Compute days used by all events matching the specified input year
  125. Days = DBSession.query( func.strftime('%d', Event.start_time).label('day') )\
  126. .filter(Event.for_year == year)\
  127. .filter(Event.event_type != None)\
  128. .group_by(func.strftime('%d', Event.start_time)).all()
  129. for Day in Days:
  130. Events = DBSession.query(Event)\
  131. .filter(Event.for_year == year)\
  132. .filter(Event.event_type != 'Stand')\
  133. .filter("strftime('%d', start_time) = :dow").params(dow=Day.day)\
  134. .order_by(Event.start_time)
  135. ListEv = []
  136. for ev in Events:
  137. if ev.event_type:
  138. ListEv.append( {
  139. "uid":"%d/%d" % ( year, ev.uid ),
  140. "desc":ev.name,
  141. "startDate":ev.start_time.strftime('%Y-%m-%dT%H:%M:%S'),
  142. "endDate":ev.end_time.strftime('%Y-%m-%dT%H:%M:%S'),
  143. "placeName":ev.Salle and (ev.Salle.name or "unk") ,
  144. "status":ev.event_type
  145. } )
  146. DicResult[Day.day] = ListEv
  147. return { 'all':DicResult }
  148. @view_config(route_name='timeline_json', renderer="json")
  149. def JSON_TimeLine_Request(request):
  150. year = int(request.matchdict.get('year', CurrentYear))
  151. # Initialization
  152. DicResult = dict()
  153. # Query database
  154. # Compute days used by all events matching the specified input year
  155. Days = DBSession.query( func.strftime('%d', Event.start_time).label('day') )\
  156. .filter(Event.for_year == year)\
  157. .filter(Event.event_type != None)\
  158. .group_by(func.strftime('%d', Event.start_time)).all()
  159. ListEv = []
  160. for Day in Days:
  161. Events = DBSession.query(Event)\
  162. .filter(Event.for_year == year)\
  163. .filter(Event.event_type != 'Stand')\
  164. .filter("strftime('%d', start_time) = :dow").params(dow=Day.day)\
  165. .order_by(Event.start_time)
  166. #ListEv = []
  167. for ev in Events:
  168. if ev.event_type:
  169. CurMedia = ev.video.first() or ""
  170. if CurMedia:
  171. Container = "<video controls='controls' preload='metadata' style='width:60%'>"
  172. Container += "<source type='%s' " % CurMedia.mime_type
  173. Container += "src='%s' />" % CurMedia.get_path
  174. Container += "</video>"
  175. else:
  176. Container = ""
  177. ListEv.append( {
  178. #"uid":"%d/%d" % ( year, ev.uid ),
  179. "headline":ev.name,
  180. "startDate":ev.start_time.strftime('%Y,%m,%d,%H,%M'),
  181. "endDate":ev.end_time.strftime('%Y,%m,%d,%H,%M'),
  182. "text":ev.Salle and (ev.Salle.name or "unk"),
  183. #"text":ev.description[:100],
  184. "tags":ev.Salle and (ev.Salle.salle_id or "unk") ,
  185. #"status":ev.event_type,
  186. "asset": {
  187. "media": Container,
  188. "credit": ",".join(["%s %s" % (i.prenom, i.nom) for i in ev.intervenants]),
  189. "caption":"" }
  190. } )
  191. if year==2015:
  192. DicResult = {
  193. "lang":"fr",
  194. "headline":"JM2L 2015",
  195. "type":"default",
  196. "startDate":"2015,11,28,10",
  197. "text":"<i><span class='c1'>9ème Édition</span></i>",
  198. "asset":
  199. {
  200. "media":"https://www.youtube.com/watch?v=DnfjrxVoLao",
  201. "credit":"JM2L",
  202. "caption":""
  203. }
  204. }
  205. elif year==2011:
  206. DicResult = {
  207. "lang":"fr",
  208. "headline":"JM2L 2011",
  209. "type":"default",
  210. "startDate":"2011,11,25,10",
  211. "text":"<i><span class='c1'>6ème Édition</span></i>",
  212. "asset":
  213. {
  214. "media":"https://www.youtube.com/embed/rcaNeXuAEhs",
  215. "credit":"JM2L",
  216. "caption":"Reportage FR3"
  217. },
  218. }
  219. elif year==2010:
  220. DicResult = {
  221. "lang":"fr",
  222. "headline":"JM2L 2010",
  223. "type":"default",
  224. "text":"<i><span class='c1'>5ème Édition</span></i>",
  225. "asset":
  226. {
  227. "media":embeed_video("video/ogg","http://jm2l.linux-azur.org/resources/2010/Video/reportages/JM2L2010-PleinSudTV.ogv"),
  228. "credit":"<a href='http://pleinsudtv.com/index.php/casa/affichage-en-vignettes/93-casa-culture/582-les-jm-du-logiciel-libre-2010'>Le reportage Plein-sud TV</a>",
  229. "caption":"JM2L",
  230. }
  231. }
  232. elif year==2007:
  233. DicResult = {
  234. "lang":"fr",
  235. "headline":"JM2L 2007",
  236. "type":"default",
  237. "text":"<i><span class='c1'>2ème Édition</span></i>",
  238. "asset":
  239. {
  240. "media":embeed_video("video/ogg","http://jm2l.linux-azur.org/resources/2007/Video/20071110-linux.ogv"),
  241. "credit":"<a href='http://pleinsudtv.com/index.php/casa/affichage-en-vignettes/93-casa-culture/245-logiciel-libre-linux-jm2l'>Le reportage Plein-sud TV</a>",
  242. "caption":"JM2L 2007",
  243. }
  244. }
  245. else:
  246. DicResult = {
  247. "lang":"fr",
  248. "headline":"JM2L %d" % year,
  249. "type":"default",
  250. "asset":
  251. {
  252. "media":"",
  253. "credit":"JM2L",
  254. "caption":""
  255. }
  256. }
  257. DicResult["date"] = ListEv
  258. return { 'timeline':DicResult }
  259. ## =-=- Here, We handle HTTP requests - Public Part -=-=
  260. @view_config(route_name='home', renderer="jm2l:templates/NewIndex.mako")
  261. def index_page(request):
  262. year = request.matchdict.get('year')
  263. if year:
  264. year=int(year[:-1])
  265. content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==year).first()
  266. if content:
  267. content = content.description
  268. else:
  269. content = ""
  270. if 2004<year<=CurrentYear:
  271. if year==2006:
  272. return {'year': year, 'content':content, 'edition':u"1<sup>ère</sup>" }
  273. elif year==2015:
  274. return {'year': year, 'content':content, 'edition':u"9<sup>ème</sup>" }
  275. else:
  276. edition = year - 2005
  277. return {'year': year, 'content':content, 'edition':u"%d<sup>ème</sup>" % edition }
  278. else:
  279. raise HTTPNotFound()
  280. else:
  281. content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==CurrentYear).first().description
  282. return {'year': CurrentYear, 'content':content, 'edition':u"9<sup>ème</sup>"}
  283. @view_config(route_name='edit_index', renderer="jm2l:templates/Staff/EditIndex.mako")
  284. def edit_index(request):
  285. year = int(request.matchdict.get('year', None))
  286. if not request.user.Staff:
  287. # Don't answer to users that aren't logged
  288. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  289. content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==year).first()
  290. form = IndexForm(request.POST, content, meta={'csrf_context': request.session})
  291. if request.method == 'POST' and form.validate():
  292. form.populate_obj(content)
  293. return HTTPFound(location=request.route_url('home', year="%d/" % year))
  294. MainTab = {'home':'active', "logged_in":request.authenticated_userid,
  295. 'form':form, 'DisplayYear':year}
  296. return MainTab
  297. @view_config(route_name='programme', renderer="jm2l:templates/Public/Programme.mako")
  298. def programme(request):
  299. year = int(request.matchdict.get('year'))
  300. if 2006 > year:
  301. return HTTPBadRequest('The first JM2L event was in 2006.')
  302. # Query database about selected Year.
  303. Events = DBSession.query(Event)\
  304. .filter(Event.for_year == year)\
  305. .order_by(Event.start_time)
  306. Days = DBSession.query(func.strftime('%d-%m-%Y', Event.start_time))\
  307. .filter(Event.for_year == year)\
  308. .filter(Event.event_type != None)\
  309. .group_by(func.strftime('%d', Event.start_time)).all()
  310. ListDay = []
  311. for day in Days:
  312. RefDay = datetime.datetime.strptime(day[0],'%d-%m-%Y')
  313. ListDay.append( ( RefDay.strftime('%A %d %b %Y'),
  314. RefDay.strftime('%d') ) )
  315. MainTab = {'programme':'active','DisplayYear':year, \
  316. 'Events':Events, 'Event':Event, 'Days':ListDay, "logged_in":request.authenticated_userid }
  317. return MainTab
  318. @view_config(route_name='presse', renderer="jm2l:templates/Public/Presse.mako")
  319. def static_presse(request):
  320. year = int(request.matchdict.get('year', None))
  321. content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==year).first()
  322. MainTab = {'presse':'active', "logged_in":request.authenticated_userid, 'content':content, 'DisplayYear':year}
  323. return MainTab
  324. @view_config(route_name='edit_presse', renderer="jm2l:templates/Staff/EditPresse.mako")
  325. def edit_presse(request):
  326. year = int(request.matchdict.get('year', None))
  327. if request.user is None:
  328. # Don't answer to users that aren't logged
  329. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  330. if not request.user.Staff:
  331. # Don't answer to users that aren't logged
  332. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  333. content = DBSession.query(JM2L_Year).filter(JM2L_Year.year_uid==year).first()
  334. form = DossPresse(request.POST, content, meta={'csrf_context': request.session})
  335. if request.method == 'POST' and form.validate():
  336. form.populate_obj(content)
  337. MainTab = {'presse':'active', "logged_in":request.authenticated_userid, 'form':form, 'DisplayYear':year}
  338. return MainTab
  339. @view_config(route_name='plan', renderer="jm2l:templates/Public/Plan.mako")
  340. def static_plan(request):
  341. session = request.session
  342. session['year'] = 2015
  343. MainTab = {'plan':'active', "logged_in":request.authenticated_userid }
  344. return MainTab
  345. ## =-=- Here, We handle HTTP requests - Staff Logged Part -=-=
  346. @view_config(route_name='list_task', renderer='jm2l:templates/Staff/list.mako')
  347. def list_view(request):
  348. if request.user is None:
  349. # Don't answer to users that aren't logged
  350. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  351. if not request.user.Staff:
  352. # Don't answer to users that aren't logged
  353. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  354. DicTask = {}
  355. taskgroup = DBSession.query( TasksArea ).all()
  356. for grp in taskgroup:
  357. tasks = DBSession.query( Tasks )\
  358. .filter( Tasks.area_uid==grp.uid )\
  359. .order_by(Tasks.closed, Tasks.due_date).all()
  360. DicTask[grp] = tasks
  361. return {'tasks': DicTask }
  362. @view_config(route_name='handle_task', renderer='jm2l:templates/Staff/tasks.mako')
  363. def tasks(request):
  364. if request.user is None:
  365. # Don't answer to users that aren't logged
  366. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  367. if not request.user.Staff:
  368. # Don't answer to users that aren't logged
  369. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  370. task_id = request.matchdict.get('task_id')
  371. # Convert the pole_id GET parameter to int or 0
  372. if request.params.get('pole_id') and request.params.get('pole_id').isdigit():
  373. pole_id = int(request.params.get('pole_id'))
  374. else:
  375. pole_id = None
  376. # Get areas from db
  377. Areas = DBSession.query(TasksArea.uid, TasksArea.name)\
  378. .order_by('name').all()
  379. # Get users from db
  380. Users = DBSession.query(User)\
  381. .filter(User.Staff==1)\
  382. .order_by('nom').all()
  383. if task_id:
  384. TmpTask = Tasks.by_id(int(task_id))
  385. if not TmpTask:
  386. raise HTTPNotFound()
  387. form = EditStaffTasks(request.POST, TmpTask, meta={'csrf_context': request.session})
  388. else:
  389. TmpTask = Tasks()
  390. # Check if the supplied pole_id is in the Areas' range
  391. form = StaffTasks(request.POST, TmpTask, meta={'csrf_context': request.session})
  392. Area = TasksArea.by_id(pole_id)
  393. if Area:
  394. form.area_uid.data = Area.uid
  395. # Put some areas on form
  396. form.area_uid.choices = Areas
  397. # Put some users on form
  398. form.closed_by.choices = [(u.uid, "%s %s" % (u.nom, u.prenom))
  399. for u in Users]
  400. form.due_date.type = "date"
  401. if request.method=='POST' and form.validate():
  402. form.populate_obj(TmpTask)
  403. TmpTask.closed = False
  404. if 'uid' in form._fields.keys():
  405. DBSession.merge(TmpTask)
  406. else:
  407. DBSession.add(TmpTask)
  408. DBSession.flush()
  409. return HTTPFound(location=request.route_url('list_task')+"#"+slugify(TmpTask.area.name))
  410. return {'form':form, 'area':TmpTask.area and slugify(TmpTask.area.name) or ''}
  411. @view_config(route_name='handle_pole', renderer='jm2l:templates/Staff/pole.mako')
  412. def tasks_area(request):
  413. if request.user is None:
  414. # Don't answer to users that aren't logged
  415. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  416. if not request.user.Staff:
  417. # Don't answer to users that aren't logged
  418. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  419. pole_id = request.matchdict.get('pole_id')
  420. if pole_id:
  421. Pole = TasksArea.by_id(int(pole_id))
  422. if not Pole:
  423. raise HTTPNotFound()
  424. form = EditStaffArea(request.POST, Pole, meta={'csrf_context': request.session})
  425. else:
  426. Pole = TasksArea()
  427. form = StaffArea(request.POST, Pole, meta={'csrf_context': request.session})
  428. if request.method == 'POST' and form.validate():
  429. form.populate_obj(Pole)
  430. if 'uid' in form._fields.keys():
  431. DBSession.merge(Pole)
  432. else:
  433. DBSession.add(Pole)
  434. return HTTPFound(location=request.route_url('list_task')+"#"+slugify(Pole.name))
  435. return {'form':form }
  436. @view_config(route_name='action_task')
  437. def action_task(request):
  438. if request.user is None:
  439. # Don't answer to users that aren't logged
  440. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  441. if not request.user.Staff:
  442. # Don't answer to users that aren't logged
  443. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  444. action = request.matchdict.get('action')
  445. task_id = request.matchdict.get('task_id')
  446. Task = Tasks.by_id(int(task_id))
  447. if action=='close':
  448. Task.closed = True
  449. request.session.flash(('info', u'La tâche a été fermé, Félicitations !'))
  450. DBSession.merge(Task)
  451. if action=='open':
  452. Task.closed = False
  453. request.session.flash(('info', u'La tâche a été ré-ouverte !'))
  454. DBSession.merge(Task)
  455. if action=='delete':
  456. request.session.flash(('info', u'La tâche a été supprimée !'))
  457. DBSession.delete(Task)
  458. return HTTPFound(location=request.route_url('list_task')+"#"+slugify(Task.area.name))
  459. @view_config(route_name='action_task_area')
  460. def action_task_area(request):
  461. if request.user is None:
  462. # Don't answer to users that aren't logged
  463. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  464. if not request.user.Staff:
  465. # Don't answer to users that aren't logged
  466. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  467. action = request.matchdict.get('action')
  468. pole_id = request.matchdict.get('pole_id')
  469. Pole = TasksArea.by_id(int(pole_id))
  470. if not Pole:
  471. raise HTTPNotFound()
  472. if action=='delete':
  473. request.session.flash(('info', u'Le pôle a été supprimé !'))
  474. DBSession.delete(Pole)
  475. return HTTPFound(location=request.route_url('list_task'))
  476. @view_config(route_name='list_salles', renderer='jm2l:templates/Salles/list.mako')
  477. def list_salles(request):
  478. if request.user is None:
  479. # Don't answer to users that aren't logged
  480. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  481. if not request.user.Staff:
  482. # Don't answer to users that aren't logged
  483. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  484. DicSalle = {}
  485. years = DBSession.query( JM2L_Year ).all()
  486. for year in years:
  487. salles = DBSession.query( Salles )\
  488. .filter( Salles.year_uid==year.year_uid )\
  489. .order_by(Salles.name).all()
  490. DicSalle[year] = salles
  491. return {'DicSalle': DicSalle }
  492. @view_config(route_name='handle_salle', renderer='jm2l:templates/Salles/salle.mako')
  493. def handle_salle(request):
  494. if request.user is None:
  495. # Don't answer to users that aren't logged
  496. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  497. if not request.user.Staff:
  498. # Don't answer to users that aren't logged
  499. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  500. salle_id = request.matchdict.get('salle_id')
  501. if salle_id:
  502. Salle = Salles.by_id(int(salle_id))
  503. if not Salle:
  504. raise HTTPNotFound()
  505. form = EditSalleForm(request.POST, Salle, meta={'csrf_context': request.session})
  506. else:
  507. Salle = Salles()
  508. form = SalleForm(request.POST, Salle, meta={'csrf_context': request.session})
  509. form.year_uid.choices = map(tuple, DBSession.query(JM2L_Year.year_uid, JM2L_Year.year_uid).all())
  510. form.phy_salle_id.choices = map(tuple, DBSession.query(SallePhy.uid, SallePhy.name).all())
  511. if request.method == 'POST' and form.validate():
  512. form.populate_obj(Salle)
  513. if 'uid' in form._fields.keys():
  514. DBSession.merge(Salle)
  515. else:
  516. DBSession.add(Salle)
  517. return HTTPFound(location=request.route_url('list_salles'))
  518. return {'form':form }
  519. @view_config(route_name='handle_salle_phy', renderer='jm2l:templates/Salles/salle_phy.mako')
  520. def handle_salle_phy(request):
  521. if request.user is None:
  522. # Don't answer to users that aren't logged
  523. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  524. if not request.user.Staff:
  525. # Don't answer to users that aren't logged
  526. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  527. salle_id = request.matchdict.get('salle_id')
  528. if salle_id:
  529. Salle = SallePhy.by_id(int(salle_id))
  530. if not Salle:
  531. raise HTTPNotFound()
  532. form = EditSallePhyForm(request.POST, Salle, meta={'csrf_context': request.session})
  533. else:
  534. Salle = SallePhy()
  535. form = SallePhyForm(request.POST, Salle, meta={'csrf_context': request.session})
  536. if request.method == 'POST' and form.validate():
  537. form.populate_obj(Salle)
  538. Salle.slug = slugify(Salle.name)
  539. if 'uid' in form._fields.keys():
  540. DBSession.merge(Salle)
  541. else:
  542. DBSession.add(Salle)
  543. return HTTPFound(location=request.route_url('list_salles'))
  544. return {'form':form }
  545. @view_config(route_name='action_salle')
  546. def action_salle(request):
  547. if request.user is None:
  548. # Don't answer to users that aren't logged
  549. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  550. if not request.user.Staff:
  551. # Don't answer to users that aren't logged
  552. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  553. action = request.matchdict.get('action')
  554. salle_id = request.matchdict.get('salle_id')
  555. Salle = Salles.by_id(int(salle_id))
  556. if not Salle:
  557. raise HTTPNotFound()
  558. if action=='delete':
  559. request.session.flash(('info', u'La Salle a été supprimée !'))
  560. DBSession.delete(Salle)
  561. return HTTPFound(location=request.route_url('list_salles'))
  562. ## =-=- Here, We handle HTTP requests - User Logged Part -=-=
  563. @view_config(route_name='exchange', renderer="jm2l:templates/Logistique/Logistique.mako")
  564. def exchange(request):
  565. modtype = request.matchdict.get('modtype', None)
  566. action = request.matchdict.get('action', None)
  567. uid = int(request.matchdict.get('id', -1))
  568. Exch = Exchange.by_id(uid)
  569. if not Exch:
  570. MainTab = {
  571. 'Exchanges':Exchange,
  572. 'Type':modtype[-1:],
  573. 'reload':True,
  574. 'logged_in':request.authenticated_userid
  575. }
  576. return MainTab
  577. if action in ['delete', 'accept', 'refuse', 'deal']:
  578. if action=='delete': # delete exchange
  579. DBSession.delete(Exch)
  580. elif action=='accept': # accept exchange
  581. Exch.exch_done=True
  582. DBSession.merge(Exch)
  583. elif action=='refuse': # refuse exchange
  584. Exch.exch_done=False
  585. if Exch.exch_state=="Ask":
  586. Exch.provider_id = None
  587. elif Exch.exch_state=="Proposal":
  588. Exch.asker_id = None
  589. DBSession.merge(Exch)
  590. elif action=='deal':
  591. # ask to deal the exchange
  592. if Exch.exch_state=="Ask":
  593. Exch.provider_id = request.user.uid
  594. elif Exch.exch_state=="Proposal":
  595. Exch.asker_id = request.user.uid
  596. # Return javascript to parent page
  597. response = render_to_response('jm2l:templates/modals_js.mako',
  598. {'modtype':modtype, 'action':action},
  599. request=request)
  600. response.content_type = 'text/javascript'
  601. return response
  602. else:
  603. MainTab = {
  604. 'Exchanges':Exchange,
  605. 'Type':modtype[-1:],
  606. 'reload':True,
  607. 'logged_in':request.authenticated_userid
  608. }
  609. return MainTab
  610. @view_config(route_name='miam')
  611. def miam(request):
  612. if request.user is None:
  613. # Don't answer to users that aren't logged
  614. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  615. miam_form = MiamForm(request.POST, request.user, meta={'csrf_context': request.session})
  616. if request.method == 'POST' and miam_form.validate():
  617. FicheSejour = Sejour.by_user(request.user.uid)
  618. if FicheSejour:
  619. Update=True
  620. else:
  621. FicheSejour = Sejour()
  622. FicheSejour.created = datetime.datetime.now()
  623. Update=False
  624. Repas=0
  625. for num, item in enumerate(['RepasVendredi', 'RepasSamediMidi', 'RepasSamediSoir']):
  626. if request.params.get(item)==u"1":
  627. Repas += 2**num
  628. FicheSejour.repas = Repas
  629. FicheSejour.repas_allerg = request.params.get('Allergies')
  630. FicheSejour.repas_contr = request.params.get('Contraintes')
  631. FicheSejour.user_id = request.user.uid
  632. FicheSejour.for_year = CurrentYear
  633. if Update:
  634. DBSession.merge(FicheSejour)
  635. else:
  636. DBSession.add(FicheSejour)
  637. request.session.flash(('info',u'Votre fiche a été mise à jour avec succès'))
  638. else:
  639. request.session.flash(('error',u'Un problème est survenu'))
  640. return HTTPFound(location='/MesJM2L#Miam')
  641. @view_config(route_name='sejour')
  642. def sejour(request):
  643. if request.user is None:
  644. # Don't answer to users that aren't logged
  645. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  646. if request.method == 'POST':
  647. FicheSejour = Sejour.by_user(request.user.uid)
  648. if FicheSejour:
  649. Update=True
  650. else:
  651. FicheSejour = Sejour()
  652. FicheSejour.created = datetime.datetime.now()
  653. Update=False
  654. FicheSejour.user_id = request.user.uid
  655. FicheSejour.last_change = datetime.datetime.now()
  656. FicheSejour.for_year = CurrentYear
  657. # Arrival
  658. ArrDate = datetime.datetime.strptime(request.params.get('Arrival:Day'),"%d/%m/%y")
  659. ArrTime = datetime.datetime.strptime(request.params.get('Arrival:Hour'),"%H:%M")
  660. FicheSejour.arrival_time = datetime.datetime.combine(ArrDate.date(), ArrTime.time())
  661. ArrivalCheck=0
  662. for num, item in enumerate(['Arrival:PMR', 'Arrival:Cov', 'Arrival:Bras', 'Arrival:Other']):
  663. if request.params.get(item):
  664. ArrivalCheck += 2**num
  665. FicheSejour.arrival_check = ArrivalCheck
  666. FicheSejour.arrival_text = request.params.get('Arrival:Comment')
  667. FicheSejour.arrival_place = request.params.get('Arrival:Place')
  668. # Departure
  669. DepDate = datetime.datetime.strptime(request.params.get('Departure:Day'),"%d/%m/%y")
  670. DepTime = datetime.datetime.strptime(request.params.get('Departure:Hour'),"%H:%M")
  671. FicheSejour.depart_time = datetime.datetime.combine(DepDate.date(), DepTime.time())
  672. DepartCheck=0
  673. for num, item in enumerate(['Departure:PMR', 'Departure:Cov', 'Departure:Bras', 'Departure:Other']):
  674. if request.params.get(item):
  675. DepartCheck += 2**num
  676. FicheSejour.depart_check = DepartCheck
  677. FicheSejour.depart_text = request.params.get('Departure:Comment')
  678. FicheSejour.depart_place = request.params.get('Departure:Place')
  679. if Update:
  680. DBSession.merge(FicheSejour)
  681. request.session.flash(('info',u'Vos modifications de séjour ont été pris en compte.'))
  682. else:
  683. DBSession.add(FicheSejour)
  684. request.session.flash(('info',u'\\o/ Votre séjour est enregistré ! Complétez la partie Logistique.'))
  685. return HTTPFound(location='/MesJM2L#Sejour')
  686. @view_config(route_name='orga')
  687. def orga(request):
  688. if request.user is None:
  689. # Don't answer to users that aren't logged
  690. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  691. if request.method == 'POST':
  692. FicheSejour = Sejour.by_user(request.user.uid)
  693. UpdateOrga=False
  694. if FicheSejour:
  695. Update=True
  696. if FicheSejour.orga_part:
  697. UpdateOrga=True
  698. else:
  699. FicheSejour = Sejour()
  700. FicheSejour.created = datetime.datetime.now()
  701. Update=False
  702. FicheSejour.user_id = request.user.uid
  703. FicheSejour.last_change = datetime.datetime.now()
  704. FicheSejour.for_year = CurrentYear
  705. OrgaPart=0
  706. for item in request.params:
  707. try:
  708. nb = int(item[1:])
  709. except:
  710. continue
  711. OrgaPart += 2**nb
  712. FicheSejour.orga_part = OrgaPart
  713. if UpdateOrga:
  714. request.session.flash(('info',u'Vos modifications de participation à l\'organisation ont été pris en compte.'))
  715. else:
  716. request.session.flash(('info',u'\\o/ Votre participation à l\'organisation est enregistrée !'))
  717. if Update:
  718. DBSession.merge(FicheSejour)
  719. else:
  720. DBSession.add(FicheSejour)
  721. return HTTPFound(location='/MesJM2L#Organisation')
  722. @view_config(route_name='vote_logo')
  723. def vote_logo(request):
  724. if request.user is None:
  725. # Don't answer to users that aren't logged
  726. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  727. else:
  728. vote = int(request.matchdict.get('num', -1))
  729. come = request.params.get('come_from')
  730. if vote:
  731. request.user.vote_logo=vote
  732. DBSession.merge(request.user)
  733. request.session.flash(('info',u'Votre vote à été pris en compte.'))
  734. return HTTPFound('/')
  735. else:
  736. request.session.flash(('warning',u"Votre vote n'a été pris en compte."))
  737. if come:
  738. return HTTPFound(location=come)
  739. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  740. @view_config(route_name='list_users', renderer="jm2l:templates/Participant/list_users.mako")
  741. def list_users(request):
  742. if request.user is None:
  743. # Don't answer to users that aren't logged
  744. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  745. if not request.user.Staff:
  746. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  747. Data = DBSession.query(User, Sejour).outerjoin(Sejour).all()
  748. Repas = DBSession.query(Sejour.repas).all()
  749. DicRepas = {"Ven":0, "Midi":0, "Soir":0}
  750. for r in Repas:
  751. if r[0] is None:
  752. continue
  753. if (r[0] & 1 == 1): DicRepas["Ven"]+=1
  754. if (r[0] & 2 == 2): DicRepas["Midi"]+=1
  755. if (r[0] & 4 == 4): DicRepas["Soir"]+=1
  756. return { 'Users':Data, 'UserEvent' : User_Event, "DicRepas":DicRepas }
  757. @view_config(route_name='list_orga', renderer="jm2l:templates/Participant/list_orga.mako")
  758. def list_orga(request):
  759. if request.user is None:
  760. # Don't answer to users that aren't logged
  761. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  762. if not request.user.Staff:
  763. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  764. Data = DBSession.query(User, Sejour).outerjoin(Sejour).all()
  765. return { 'Users':Data }
  766. @view_config(route_name='jm2l', renderer="jm2l:templates/jm2l.mako")
  767. def jm2l_page(request):
  768. if request.user is None:
  769. # Don't answer to users that aren't logged
  770. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  771. UserNum = request.params.get('user')
  772. if UserNum:
  773. profil = User.by_id(int(UserNum))
  774. if not profil:
  775. raise HTTPNotFound()
  776. if not request.user.Staff:
  777. raise HTTPForbidden(u'Vous n\'avez pas l\'autorité suffisante pour effectuer cette action.')
  778. else:
  779. profil = request.user
  780. FicheSejour = Sejour()
  781. FicheSejour.created = datetime.datetime.now()
  782. # Build Form
  783. profil_form = ProfilForm(request.POST, profil, meta={'csrf_context': request.session})
  784. miam_form = MiamForm(request.POST, profil, meta={'csrf_context': request.session})
  785. # Feed FicheSejour if any
  786. FicheSejour = Sejour.by_user(profil.uid)
  787. if FicheSejour:
  788. if FicheSejour.repas is not None:
  789. for num, item in enumerate(['RepasVendredi', 'RepasSamediMidi', 'RepasSamediSoir']):
  790. if FicheSejour.repas & 2**num:
  791. miam_form._fields[item].data = "1"
  792. else:
  793. miam_form._fields[item].data = "0"
  794. miam_form._fields['Allergies'].data = FicheSejour.repas_allerg
  795. miam_form._fields['Contraintes'].data = FicheSejour.repas_contr
  796. if request.method == 'POST' and profil_form.validate():
  797. ToDelete = list()
  798. # First, we remove entries no more present
  799. for obj in profil_form.tiersship.object_data:
  800. MatchEntry = filter( lambda x: x.object_data and x.object_data._sa_instance_state == obj._sa_instance_state,
  801. profil_form.tiersship.entries )
  802. if not MatchEntry:
  803. ToDelete.append(obj)
  804. # Then, it's time to consider new entries
  805. for entry in profil_form.tiersship.entries:
  806. if entry.object_data is None:
  807. TmpUser = User_Tiers()
  808. entry.object_data = TmpUser
  809. profil.tiersship.append(TmpUser)
  810. profil_form.tiersship.object_data = profil.tiersship
  811. profil_form.populate_obj(profil)
  812. # We should remove it as it's not in original data
  813. for obj in ToDelete:
  814. #profil.tiersship.remove(obj)
  815. DBSession.delete(obj)
  816. profil.last_change = datetime.datetime.utcnow()
  817. profil.slug = slugify(remove_accents('%s %s' % (profil.prenom, profil.nom)).lower().strip())
  818. DBSession.merge(profil)
  819. request.session.flash(('info',u'Votre fiche a été mise à jour avec succès'))
  820. MainTab = {'participer':'active',
  821. 'Places':Place.get_list(False),
  822. 'DBTiers':Tiers,
  823. 'DBTiersOpt':TiersOpt,
  824. 'Exchanges':Exchange,
  825. 'profil_form':profil_form,
  826. 'miam_form':miam_form,
  827. 'uprofil':profil,
  828. 'logged_in':request.authenticated_userid
  829. }
  830. return MainTab
  831. @view_config(route_name='modal', renderer="jm2l:templates/modals.mako")
  832. def Modal(request):
  833. year = int(request.matchdict.get('year', None))
  834. modtype = request.matchdict.get('modtype', None)
  835. uid = int(request.matchdict.get('id', -1))
  836. session = request.session
  837. if modtype=='Password':
  838. form = UserPasswordForm(request.POST, request.user, meta={'csrf_context': request.session})
  839. if request.method == 'POST' and form.validate():
  840. response = render_to_response('jm2l:templates/modals_js.mako',
  841. {'modtype':modtype},
  842. request=request)
  843. request.user.password = form.password.data
  844. DBSession.merge(request.user)
  845. response.content_type = 'text/javascript'
  846. return response
  847. if modtype=='UserPicture':
  848. form = None
  849. if request.method == 'POST':
  850. response = render_to_response('jm2l:templates/modals_js.mako',
  851. {'modtype':modtype},
  852. request=request)
  853. response.content_type = 'text/javascript'
  854. return response
  855. if modtype=='Place':
  856. if uid>0:
  857. place = Place.by_id(uid)
  858. if not place:
  859. raise HTTPNotFound()
  860. form = PlaceUpdateForm(request.POST, place, meta={'csrf_context': request.session})
  861. else:
  862. place = Place()
  863. form = PlaceCreateForm(request.POST, meta={'csrf_context': request.session})
  864. if request.method == 'POST' and form.validate():
  865. form.populate_obj(place)
  866. place.created_by=request.user.uid
  867. if uid>0:
  868. DBSession.merge(place)
  869. else:
  870. DBSession.add(place)
  871. response = render_to_response('jm2l:templates/modals_js.mako',
  872. {'modtype':modtype},
  873. request=request)
  874. response.content_type = 'text/javascript'
  875. return response
  876. if modtype in ['AskC', 'AskH', 'AskM', 'PropC', 'PropH', 'PropM']:
  877. if uid>0:
  878. Exch = Exchange.by_id(uid)
  879. if not Exch:
  880. raise HTTPNotFound()
  881. if modtype in ['AskC','PropC']:
  882. form = globals()["Update%sForm" % modtype](request.POST, Exch,
  883. start_place = Exch.Itin.start_place,
  884. arrival_place = Exch.Itin.arrival_place,
  885. Hour_start = Exch.start_time.strftime("%H:%M"),
  886. Day_start = Exch.start_time.strftime("%w"),
  887. exch_id = uid, meta={'csrf_context': request.session}
  888. )
  889. elif modtype in ['AskM','PropM']:
  890. form = globals()["Update%sForm" % modtype](request.POST, Exch,
  891. description = Exch.description,
  892. exch_categ = Exch.exch_categ,
  893. Hour_start = Exch.start_time.strftime("%H:%M"),
  894. Day_start = Exch.start_time.strftime("%w"),
  895. Hour_end = Exch.end_time.strftime("%H:%M"),
  896. Day_end = Exch.end_time.strftime("%w"),
  897. exch_id = uid, meta={'csrf_context': request.session}
  898. )
  899. elif modtype in ['AskH','PropH']:
  900. form = globals()["Update%sForm" % modtype](request.POST, Exch,
  901. description = Exch.description,
  902. exch_categ = Exch.exch_categ,
  903. Day_start = Exch.start_time.strftime("%w"),
  904. exch_id = uid, meta={'csrf_context': request.session}
  905. )
  906. # Itinerary, first get itinerary
  907. if 0:
  908. form.itin.form.start_place.data = Exch.Itin.start_place
  909. form.itin.form.arrival_place.data = Exch.Itin.arrival_place
  910. form.dateform.form.Hour.data = Exch.start_time.strftime("%H:%M")
  911. form.dateform.form.Day.data = Exch.start_time.strftime("%w")
  912. form.exch_id.data = uid
  913. else:
  914. Exch = Exchange()
  915. form = globals()["%sForm" % modtype](request.POST, meta={'csrf_context': request.session})
  916. if modtype in ['AskC', 'PropC']:
  917. # Put some place on form
  918. Places = DBSession.query(Place.place_id, Place.display_name)\
  919. .order_by('name').all()
  920. form.start_place.choices = Places
  921. form.arrival_place.choices = Places
  922. if modtype in ['PropH']:
  923. form.exch_categ.choices = DBSession.query( Exchange_Cat.cat_id, Exchange_Cat.exch_subtype)\
  924. .filter( Exchange_Cat.exch_type=='H' ).all()
  925. form.place_id.choices = DBSession.query( Place.place_id, Place.display_name)\
  926. .filter( Place.created_by==request.user.uid ).all()
  927. if modtype in ['AskM', 'PropM']:
  928. form.exch_categ.choices = DBSession.query( Exchange_Cat.cat_id, Exchange_Cat.exch_subtype)\
  929. .filter( Exchange_Cat.exch_type=='M' ).all()
  930. if request.method == 'POST' and form.validate():
  931. # Form has been validated, it's time to create our Exchange
  932. Exch.for_year = year
  933. Exch.exch_state = {'Ask':'Ask', 'Prop':'Proposal'}[modtype[:-1]]
  934. Exch.exch_type = modtype[-1:]
  935. if modtype in ['AskC', 'PropC']:
  936. # Itinerary, first Let's see if itinerary exist
  937. Itinerary = DBSession.query(Itineraire)\
  938. .filter(Itineraire.start_place==form.start_place.data) \
  939. .filter(Itineraire.arrival_place==form.arrival_place.data) \
  940. .filter(Itineraire.tr_voiture==True) \
  941. .first()
  942. if not Itinerary: # Not exist yet !
  943. Itinerary = Itineraire(start_place=form.start_place.data, \
  944. arrival_place=form.arrival_place.data, \
  945. tr_voiture=True, \
  946. created_by=1
  947. )
  948. DBSession.add(Itinerary)
  949. DBSession.flush()
  950. Exch.itin_id = Itinerary.itin_id
  951. # Start Time
  952. StartEvent = DBSession.query(JM2L_Year.start_time).filter(JM2L_Year.year_uid==year).first()
  953. Week = StartEvent[0].strftime("%W")
  954. # populate
  955. form.populate_obj(Exch)
  956. if modtype in ['AskC', 'PropC']:
  957. Exch.itin_id = Itinerary.itin_id
  958. if form._fields.has_key("Hour_start"):
  959. TargetTime = datetime.datetime.strptime('%d %d %d %s' % (year, int(Week), \
  960. int(form.Day_start.data), form.Hour_start.data), "%Y %W %w %H:%M")
  961. Exch.start_time = TargetTime
  962. elif form._fields.has_key("Day_start"):
  963. TargetTime = datetime.datetime.strptime('%d %d %d' % (year, int(Week), \
  964. int(form.Day_start.data)), "%Y %W %w")
  965. Exch.start_time = TargetTime
  966. if form._fields.has_key("Hour_end"):
  967. TargetTime = datetime.datetime.strptime('%d %d %d %s' % (year, int(Week), \
  968. int(form.Day_end.data), form.Hour_end.data), "%Y %W %w %H:%M")
  969. Exch.end_time = TargetTime
  970. elif form._fields.has_key("Day_end"):
  971. TargetTime = datetime.datetime.strptime('%d %d %d' % (year, int(Week), \
  972. int(form.Day_end.data)), "%Y %W %w")
  973. Exch.end_time = TargetTime
  974. Exch.last_change = datetime.datetime.utcnow()
  975. if Exch.exch_state=='Ask':
  976. Exch.asker_id = request.user.uid
  977. elif Exch.exch_state=='Proposal':
  978. Exch.provider_id = request.user.uid
  979. #print vars(form.itin.form)
  980. if uid>0:
  981. DBSession.merge(Exch)
  982. else:
  983. DBSession.add(Exch)
  984. response = render_to_response('jm2l:templates/modals_js.mako',
  985. {'modtype':modtype},
  986. request=request)
  987. response.content_type = 'text/javascript'
  988. return response
  989. # Fallback to HTML Display with errors
  990. return {'modtype':modtype, 'form':form, 'update':uid>0,
  991. 'logged_in':request.authenticated_userid }
  992. if modtype in ['ShowC', 'ShowH', 'ShowM']:
  993. if uid>0:
  994. Exch = Exchange.by_id(uid)
  995. if not Exch:
  996. raise HTTPNotFound()
  997. else:
  998. raise HTTPNotFound()
  999. # Show Details around the Current Exchange
  1000. return {'modtype':modtype, 'Exch':Exch, 'logged_in':request.authenticated_userid }
  1001. MainTab = {'modtype':modtype, 'form':form, 'update':uid>0, 'uid':uid,
  1002. 'DisplayYear':year, 'session':session,
  1003. 'logged_in':request.authenticated_userid }
  1004. return MainTab
  1005. @view_config(route_name='participer', renderer="jm2l:templates/Participer.mako")
  1006. def participer(request):
  1007. session = request.session
  1008. session['year'] = 2015
  1009. TmpUsr = User()
  1010. form = UserRegisterForm(request.POST, TmpUsr, meta={'csrf_context': request.session})
  1011. MyLink=None
  1012. if request.method == 'POST' and form.validate():
  1013. # Prepare mailer
  1014. form.populate_obj(TmpUsr)
  1015. TmpUsr.nom = TmpUsr.nom.capitalize()
  1016. TmpUsr.prenom = TmpUsr.prenom.capitalize()
  1017. TmpUsr.slug = slugify(remove_accents('%s %s' % (form.prenom.data, form.nom.data)).lower().strip())
  1018. TmpUsr.password = TmpUsr.my_hash
  1019. if len(TmpUsr.slug):
  1020. CheckExist = DBSession.query(User)\
  1021. .filter(User.slug==TmpUsr.slug)\
  1022. .first()
  1023. else:
  1024. CheckExist=None
  1025. if CheckExist:
  1026. MyLink = CheckExist.my_hash
  1027. NewUser = CheckExist
  1028. else:
  1029. DBSession.add(TmpUsr)
  1030. DBSession.flush()
  1031. MyLink = TmpUsr.my_hash
  1032. NewUser = TmpUsr
  1033. # Send the Welcome Mail
  1034. mailer = request.registry['mailer']
  1035. # Prepare Plain Text Message :
  1036. Mail_template = Template(filename='jm2l/templates/mail_plain.mako')
  1037. mail_plain = Mail_template.render(request=request, User=NewUser, action="Welcome")
  1038. # Prepare HTML Message :
  1039. Mail_template = Template(filename='jm2l/templates/mail_html.mako')
  1040. mail_html = Mail_template.render(request=request, User=NewUser, action="Welcome")
  1041. # Prepare Message
  1042. message = Message(subject="[JM2L] Mon inscription au site web JM2L",
  1043. sender="contact@jm2l.linux-azur.org",
  1044. recipients=[NewUser.mail or TmpUsr.mail],
  1045. body=mail_plain, html=mail_html)
  1046. message.add_bcc("spam@style-python.fr")
  1047. mailer.send(message)
  1048. request.session.flash(('info',u"Un mail vous a été envoyé afin de continuer votre quête !"))
  1049. MainTab = {'programme':'','presse':'', 'plan':'',
  1050. 'participer':'active', 'form':form, "link": MyLink,
  1051. 'logged_in':request.authenticated_userid }
  1052. return MainTab
  1053. @view_config(route_name='year')
  1054. def change_year(request):
  1055. year = int(request.matchdict.get('year', -1))
  1056. session = request.session
  1057. if year>-1:
  1058. session['year'] = year
  1059. return HTTPFound(location='/%s/' % year)
  1060. return HTTPFound(location=request.route_url('home', year=''))
  1061. @view_config(route_name='pict_user', renderer="jm2l:templates/Profil/pict_user.mako")
  1062. def pict_user(request):
  1063. return {"uprofil":request.user}
  1064. @view_config(route_name='pict_salle', renderer="jm2l:templates/Salles/pict_salle.mako")
  1065. def pict_salle(request):
  1066. salle_id = int(request.matchdict.get('salle_id', -1))
  1067. return {"Salles":Salles, "IdSalle":salle_id}
  1068. @view_config(route_name='event', renderer="jm2l:templates/view_event.mako")
  1069. def show_event(request):
  1070. year = int(request.matchdict.get('year', -1))
  1071. event_id = request.matchdict.get('event_id')
  1072. if event_id.isdigit():
  1073. TheEvent = Event.by_id(event_id)
  1074. if TheEvent is None:
  1075. raise HTTPNotFound()
  1076. else:
  1077. TheEvent = Event.by_slug(event_id, year)
  1078. if TheEvent is None:
  1079. raise HTTPNotFound()
  1080. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1081. 'event':TheEvent, 'logged_in':request.authenticated_userid, "Salles":Salles }
  1082. return MainTab
  1083. @view_config(route_name='link_event_user')
  1084. def link_event_user(request):
  1085. """ Get user and add it to current event """
  1086. if request.user is None:
  1087. # Don't answer to users that aren't logged
  1088. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1089. year = int(request.matchdict.get('year', -1))
  1090. form = AddIntervenant(request.POST, meta={'csrf_context': request.session})
  1091. intervention = request.matchdict.get('intervention', None)
  1092. TargetEvent = Event.by_id(form.event_uid.data)
  1093. Exist = User.by_id(form.intervenant.data)
  1094. if not Exist:
  1095. request.session.flash(('error',u"Une erreur s'est produite lors de l'ajout de votre intervenant !"))
  1096. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1097. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid)))
  1098. else:
  1099. TargetUser = Exist
  1100. uev = User_Event(year_uid=year, role=u"Animateur d'un évenement JM2L", user_uid=TargetUser.uid)
  1101. TargetEvent.interventions.append( uev )
  1102. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1103. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid)))
  1104. @view_config(route_name='link_event_tiers')
  1105. def link_event_tiers(request):
  1106. """ Create user if not exist, add it to current event """
  1107. if request.user is None:
  1108. # Don't answer to users that aren't logged
  1109. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1110. year = int(request.matchdict.get('year', -1))
  1111. form = AddTiers(request.POST, meta={'csrf_context': request.session})
  1112. intervention = request.matchdict.get('intervention', None)
  1113. TargetEvent = Event.by_id(form.event_uid.data)
  1114. Exist = Tiers.by_id(form.tiers.data)
  1115. if not Exist:
  1116. request.session.flash(('error',u"Une erreur s'est produite lors de l'ajout de votre entité !"))
  1117. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1118. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid)))
  1119. else:
  1120. TargetTiers = Exist
  1121. Matching = DBSession.query(Role_Tiers)\
  1122. .filter(Role_Tiers.year_uid==year)\
  1123. .filter(Role_Tiers.tiers_role=="Exposant")\
  1124. .filter(Role_Tiers.tiers_uid==TargetTiers.uid)\
  1125. .filter(Role_Tiers.event_uid==TargetEvent.uid)\
  1126. .all()
  1127. if len(Matching)==0:
  1128. tev = Role_Tiers(year_uid=year, tiers_role="Exposant", tiers_uid=TargetTiers.uid, event_uid=TargetEvent.uid)
  1129. DBSession.add(tev)
  1130. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1131. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid), _anchor="Tiers"))
  1132. @view_config(route_name='delete_link_u')
  1133. def delete_link_event_user(request):
  1134. """ Create user if not exist, add it to current event """
  1135. if request.user is None:
  1136. # Don't answer to users that aren't logged
  1137. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1138. year = int(request.matchdict.get('year', -1))
  1139. intervention = request.matchdict.get('intervention', None)
  1140. TargetEvent = Event.by_id( request.params.get('eid') )
  1141. Exist = User.by_id( request.params.get('uid') )
  1142. if not Exist:
  1143. request.session.flash(('error',u"Une erreur s'est produite lors de votre suppression !"))
  1144. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1145. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid)))
  1146. else:
  1147. TargetUser = Exist
  1148. Matching = DBSession.query(User_Event)\
  1149. .filter(User_Event.year_uid==year)\
  1150. .filter(User_Event.user_uid==TargetUser.uid)\
  1151. .filter(User_Event.event_uid==TargetEvent.uid)\
  1152. .all()
  1153. if len(Matching)==0:
  1154. request.session.flash(('error',u"Une erreur s'est produite lors de la suppression !"))
  1155. else:
  1156. for item in Matching:
  1157. DBSession.delete(item)
  1158. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1159. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid), _anchor="Tiers"))
  1160. @view_config(route_name='delete_link_t')
  1161. def delete_link_event_tiers(request):
  1162. """ Create user if not exist, add it to current event """
  1163. if request.user is None:
  1164. # Don't answer to users that aren't logged
  1165. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1166. year = int(request.matchdict.get('year', -1))
  1167. intervention = request.matchdict.get('intervention', None)
  1168. TargetEvent = Event.by_id( request.params.get('uid') )
  1169. Exist = Tiers.by_id( request.params.get('tid') )
  1170. if not Exist:
  1171. request.session.flash(('error',u"Une erreur s'est produite lors de l'ajout de votre entité !"))
  1172. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1173. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid)))
  1174. else:
  1175. TargetTiers = Exist
  1176. Matching = DBSession.query(Role_Tiers)\
  1177. .filter(Role_Tiers.year_uid==year)\
  1178. .filter(Role_Tiers.tiers_role=="Exposant")\
  1179. .filter(Role_Tiers.tiers_uid==TargetTiers.uid)\
  1180. .filter(Role_Tiers.event_uid==TargetEvent.uid)\
  1181. .all()
  1182. if len(Matching)==0:
  1183. request.session.flash(('error',u"Une erreur s'est produite lors de la suppression de votre entité !"))
  1184. else:
  1185. for item in Matching:
  1186. DBSession.delete(item)
  1187. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1188. year=str(year), intervention=intervention, event_id=str(TargetEvent.uid), _anchor="Tiers"))
  1189. @view_config(route_name='delete_event')
  1190. def delete_event(request):
  1191. if request.user is None:
  1192. # Don't answer to users that aren't logged
  1193. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1194. year = int(request.matchdict.get('year', -1))
  1195. event_id = request.matchdict.get('event_id')
  1196. intervention = request.matchdict.get('intervention', None)
  1197. # Check intervention
  1198. if not intervention in ['Stand', 'Table_ronde', 'Atelier', 'Conference', 'Concert']:
  1199. raise HTTPNotFound(u"Ce type d'évenement n'est pas reconnu")
  1200. # We should remove all links before to remove the event
  1201. if event_id.isdigit():
  1202. TheEvent = Event.by_id(event_id)
  1203. if TheEvent is None:
  1204. raise HTTPNotFound(u"Cette réference n'existe pas")
  1205. else:
  1206. TheEvent = Event.by_slug(event_id, year)
  1207. if TheEvent is None:
  1208. raise HTTPNotFound(u"Cette réference n'existe pas")
  1209. # Remove Roles
  1210. Roles_Link = DBSession.query(Role_Tiers).filter(Role_Tiers.event_uid==TheEvent.uid).all()
  1211. for tmp in Roles_Link:
  1212. DBSession.delete(tmp)
  1213. # Remove Intervenant
  1214. User_Link = DBSession.query(User_Event).filter(User_Event.event_uid==TheEvent.uid).all()
  1215. for tmp in User_Link:
  1216. DBSession.delete(tmp)
  1217. # Remove attachment if any
  1218. SRCPath = path.join('jm2l/upload', *(IMAGEPATH + ['event'] + [ str(year) ] + [ TheEvent.slug ]) )
  1219. shutil.rmtree(SRCPath, ignore_errors=True)
  1220. # Remove Event
  1221. DBSession.delete(TheEvent)
  1222. return HTTPFound(location=request.route_url('jm2l', _anchor="Interventions"))
  1223. @view_config(route_name='edit_event', renderer="jm2l:templates/edit_event.mako")
  1224. def edit_event(request):
  1225. if request.user is None:
  1226. # Don't answer to users that aren't logged
  1227. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1228. year = int(request.matchdict.get('year', -1))
  1229. event_id = request.matchdict.get('event_id')
  1230. intervention = request.matchdict.get('intervention', None)
  1231. IntervLabel = intervention.replace('_',' ').lower()
  1232. if intervention=='Conference':
  1233. IntervLabel = u'conférence'
  1234. # Check intervention
  1235. if not intervention in ['Stand', 'Table_ronde', 'Atelier', 'Conference', 'Concert']:
  1236. raise HTTPNotFound(u"Ce type d'évenement n'est pas reconnu")
  1237. TheYear = DBSession.query(JM2L_Year)\
  1238. .filter(JM2L_Year.year_uid==year)\
  1239. .first()
  1240. # Check year avaibility
  1241. if not TheYear:
  1242. raise HTTPNotFound(u"Cette année n'est pas pris en charge")
  1243. # Generate Timeslots for current year
  1244. TimeSlots = list(enumerate( [ x.strftime('%a %d %b %H:%M') for x in
  1245. TheYear.AvailableTimeSlots ] ))
  1246. if event_id:
  1247. # We try to update an existing record
  1248. if event_id.isdigit():
  1249. TheEvent = Event.by_id(event_id)
  1250. if TheEvent is None:
  1251. raise HTTPNotFound(u"Cette réference n'existe pas")
  1252. else:
  1253. TheEvent = Event.by_slug(event_id, year)
  1254. if TheEvent is None:
  1255. raise HTTPNotFound(u"Cette réference n'existe pas")
  1256. if request.user is None or not (request.user.Staff or request.user in TheEvent.intervenants):
  1257. raise HTTPForbidden(u"Vous n'êtes pas identifié comme étant un participant à cette intervention.")
  1258. # Compute some field value from selected event
  1259. if TheEvent.start_time in TheYear.AvailableTimeSlots:
  1260. start_sel = TheYear.AvailableTimeSlots.index(TheEvent.start_time)
  1261. else:
  1262. start_sel = len(TimeSlots)
  1263. TimeSlots.append( (len(TimeSlots), TheEvent.start_time.strftime('%a %d %b %H:%M')))
  1264. duration = (TheEvent.end_time - TheEvent.start_time).total_seconds()/60
  1265. end = TheEvent.start_time + datetime.timedelta(minutes=duration)
  1266. # prepare the form with update
  1267. form = ConfUpdateForm(request.POST, TheEvent, start_sel=start_sel, duration=duration, end_time=end,
  1268. meta={'csrf_context': request.session} )
  1269. # Customize labels
  1270. form.name.label.text += IntervLabel
  1271. form.description.label.text += IntervLabel
  1272. # Each event can get severals members
  1273. formAdd = AddIntervenant(event_uid=TheEvent.uid)
  1274. # Build list of intervenant
  1275. # Get users from db
  1276. Users = DBSession.query(User)\
  1277. .filter(User.Staff==1)\
  1278. .order_by('nom').all()
  1279. # Put some users on form
  1280. formAdd.intervenant.choices = [(u.uid, "%s %s" % (u.nom, u.prenom))
  1281. for u in Users]
  1282. # Each event can get severals entities
  1283. formAddT = AddTiers(event_uid=TheEvent.uid)
  1284. # Build list of entities
  1285. # Get entities from db
  1286. TmpTiers = DBSession.query(Tiers)\
  1287. .order_by('name').limit(10)
  1288. # Put some entities on form
  1289. formAddT.tiers.choices = [(u.uid, "%s %s" % (u.nom, u.prenom))
  1290. for u in Users]
  1291. else:
  1292. TheEvent = Event()
  1293. # prepare the form for creation
  1294. form = ConfCreateForm(request.POST,
  1295. event_type=intervention,
  1296. for_year=str(year), meta={'csrf_context': request.session}
  1297. )
  1298. # Customize labels
  1299. form.name.label.text += IntervLabel
  1300. form.description.label.text += IntervLabel
  1301. duration=60
  1302. # No intervenant
  1303. formAdd = None
  1304. formAddT = None
  1305. SalleDispo = DBSession.query(Salles)\
  1306. .filter(Salles.year_uid==year)\
  1307. .order_by('name')
  1308. if intervention=="Conference":
  1309. form.duration.choices =[
  1310. (15,u'Lighting talk ( 5 min)'),
  1311. (30,u'Conférence (20 min)'),
  1312. (60,u'Conférence (50 min)'),
  1313. (90,u'Conférence (75 min)'),
  1314. ]
  1315. if not duration in [15, 30, 60, 90]:
  1316. form.duration.choices.append( (duration,u'Conférence (%d min)' % duration) )
  1317. if not form._fields.has_key("uid"):
  1318. form.duration.data=60
  1319. SalleDispo = SalleDispo.filter(Salles.place_type.in_(['Conference', 'MAO']))
  1320. elif intervention=="Stand":
  1321. form.duration.choices =[
  1322. (8*60, u'Toute la journée'),
  1323. (4*60, u'une demi-journée')
  1324. ]
  1325. SalleDispo = SalleDispo.filter(Salles.place_type=='Stand')
  1326. elif intervention=="Atelier":
  1327. form.duration.choices = map( lambda d:(d, u'Atelier (%dh%.2d)' % (d/60, d%60) ), \
  1328. [60, 90, 120, 150, 180, 210, 240] )
  1329. if not duration in map(lambda (d,y): d, form.duration.choices):
  1330. form.duration.choices.append( (duration,u'Atelier (%dh%.2d)' % (duration/60, duration%60) ) )
  1331. SalleDispo = SalleDispo.filter(Salles.place_type.in_(['Ateliers', 'MAO']))
  1332. elif intervention=="Table_ronde":
  1333. form.duration.choices = map( lambda d:(d, u'Table ronde (%dh%.2d)' % (d/60, d%60) ), \
  1334. [60, 90, 120, 150] )
  1335. if not duration in map(lambda (d,y): d, form.duration.choices):
  1336. form.duration.choices.append( (duration,u'Table ronde (%dh%.2d)' % (duration/60, duration%60) ) )
  1337. SalleDispo = SalleDispo.filter(Salles.place_type=='Table ronde')
  1338. elif intervention=="Concert":
  1339. form.duration.choices = map( lambda d:(d, u'Concert (%dh%.2d)' % (d/60, d%60) ), \
  1340. [60, 90, 120, 150, 180, 210, 240] )
  1341. if not duration in map(lambda (d,y): d, form.duration.choices):
  1342. form.duration.choices.append( (duration,u'Concert (%dh%.2d)' % (duration/60, duration%60) ) )
  1343. SalleDispo = SalleDispo.filter(Salles.place_type.in_(['Stand', 'MAO']))
  1344. else:
  1345. raise HTTPForbidden(u"Pas encore disponible.")
  1346. form.salle_uid.choices = [(s.salle_id, s.name) for s in SalleDispo]
  1347. form.start_sel.choices = TimeSlots
  1348. if request.method == 'POST' and form.validate():
  1349. form.populate_obj(TheEvent)
  1350. TheEvent.start_time = TheYear.AvailableTimeSlots[form.start_sel.data]
  1351. TheEvent.end_time = TheEvent.start_time + datetime.timedelta(minutes=form.duration.data)
  1352. # Ok, time to put in database
  1353. if not form._fields.has_key("uid"):
  1354. TheEvent.slug = slugify(TheEvent.name)
  1355. DBSession.add(TheEvent)
  1356. # Append creator by default
  1357. if request.user.uid!=1:
  1358. uev = User_Event(year_uid=TheYear.year_uid, role="Animateur")
  1359. uev.user_uid = request.user.uid
  1360. TheEvent.interventions.append( uev )
  1361. DBSession.flush()
  1362. request.session.flash(('sucess',u'Votre intervention a été créee ! Vous pouvez la compléter à tout moment.'))
  1363. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1364. year=str(year), intervention=intervention, event_id=str(TheEvent.slug)))
  1365. else:
  1366. if slugify(TheEvent.name)!=TheEvent.slug:
  1367. # We should move some file as slug have been changed
  1368. # First we ensure there is no related event that already exist with that slug
  1369. CheckEvent = Event.by_slug( slugify(TheEvent.name), year)
  1370. if CheckEvent:
  1371. request.session.flash(('warning',u'Choisissez un autre titre pour votre évenement, il est en conflit avec un autre.'))
  1372. return {'event':TheEvent, 'form':form, 'formAdd':formAdd, 'formAddT':formAddT, 'Salles':Salles }
  1373. else:
  1374. SRCPath = path.join('jm2l/upload', *(IMAGEPATH + ['event'] + [ str(year) ] + [ TheEvent.slug ]) )
  1375. TheEvent.slug=slugify(TheEvent.name)
  1376. DSTPath = path.join('jm2l/upload', *(IMAGEPATH + ['event'] + [ str(year) ] + [ TheEvent.slug ]) )
  1377. if not path.isdir(path.dirname(DSTPath)):
  1378. makedirs(path.dirname(DSTPath))
  1379. # Then we should move event attachments to the new slug (if any)
  1380. if path.exists(SRCPath):
  1381. shutil.move(SRCPath, DSTPath)
  1382. DBSession.merge(TheEvent)
  1383. request.session.flash(('sucess',u'Votre intervention a été mis à jour !'))
  1384. return HTTPFound(location=request.route_url('edit_event', sep='/',
  1385. year=str(year), intervention=intervention, event_id=str(TheEvent.slug)))
  1386. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1387. 'event':TheEvent, 'form':form, 'formAdd':formAdd, 'formAddT':formAddT,
  1388. 'Salles':Salles }
  1389. return MainTab
  1390. @view_config(route_name='entities', renderer="jm2l:templates/list_tiers.mako")
  1391. def list_tiers(request):
  1392. Entities = dict()
  1393. EntityType = DBSession.query(TiersOpt.entity_type)\
  1394. .group_by(TiersOpt.entity_type).all()
  1395. for EType in EntityType:
  1396. Entities[EType.entity_type] = DBSession.query(Tiers).join(TiersOpt)\
  1397. .filter(TiersOpt.entity_type==EType.entity_type)\
  1398. .order_by(TiersOpt.entity_subtype, Tiers.name)
  1399. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1400. 'entities':Entities, 'logged_in':request.authenticated_userid }
  1401. return MainTab
  1402. @view_config(route_name='show_entity', renderer="jm2l:templates/view_tiers.mako")
  1403. def show_tiers(request):
  1404. tiers_type = request.matchdict.get('tiers_type')
  1405. entity_id = request.matchdict.get('entity_id')
  1406. if entity_id.isdigit():
  1407. TheTiers = Tiers.by_id(entity_id)
  1408. if TheTiers is None:
  1409. raise HTTPNotFound()
  1410. else:
  1411. TheTiers = Tiers.by_slug(entity_id)
  1412. if TheTiers is None:
  1413. raise HTTPNotFound()
  1414. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1415. 'entity':TheTiers, 'logged_in':request.authenticated_userid }
  1416. return MainTab
  1417. @view_config(route_name='delete_entity')
  1418. def delete_tiers(request):
  1419. if request.user is None:
  1420. # Don't answer to users that aren't logged
  1421. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1422. entity_id = request.matchdict.get('entity_id', None)
  1423. if entity_id:
  1424. if entity_id.isdigit():
  1425. TheTiers = Tiers.by_id(int(entity_id))
  1426. if TheTiers is None:
  1427. raise HTTPNotFound()
  1428. else:
  1429. TheTiers = Tiers.by_slug(entity_id)
  1430. if TheTiers is None:
  1431. raise HTTPNotFound()
  1432. if len(TheTiers.membership)!=0:
  1433. request.session.flash(('error', u"Vous devez supprimer tous les membres liés avant la suppression d'une entité."))
  1434. return HTTPFound(location=request.route_url('show_entity', entity_id=TheTiers.slug, tiers_type=TheTiers.get_entity_type.slug_entity_type))
  1435. if len(TheTiers.membership)!=0:
  1436. request.session.flash(('error', u"Vous devez supprimer tous les roles liés avant la suppression d'une entité."))
  1437. return HTTPFound(location=request.route_url('show_entity', entity_id=TheTiers.slug, tiers_type=TheTiers.get_entity_type.slug_entity_type))
  1438. DBSession.delete(TheTiers)
  1439. request.session.flash(('info', u"L'entité a bien été supprimée"))
  1440. return HTTPFound(location=request.route_url('entities'))
  1441. else:
  1442. raise HTTPNotFound()
  1443. @view_config(route_name='add_entity', renderer="jm2l:templates/edit_tiers.mako")
  1444. @view_config(route_name='edit_entity', renderer="jm2l:templates/edit_tiers.mako")
  1445. def edit_tiers(request):
  1446. entity_id = request.matchdict.get('entity_id', None)
  1447. TargetList = list()
  1448. if request.user is None:
  1449. # Don't answer to users that aren't logged
  1450. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1451. entity_types = DBSession.query(TiersOpt.entity_type).group_by(TiersOpt.entity_type).all()
  1452. for entity_type in entity_types:
  1453. entity_subtypes = DBSession.query(TiersOpt)\
  1454. .filter(TiersOpt.entity_type==entity_type.entity_type)\
  1455. .group_by(TiersOpt.entity_subtype).all()
  1456. ListType = [(i.uid, i.entity_subtype) for i in entity_subtypes]
  1457. TargetList.append( (entity_type.entity_type, ListType) )
  1458. if entity_id:
  1459. if entity_id.isdigit():
  1460. TheTiers = Tiers.by_id(entity_id)
  1461. if TheTiers is None:
  1462. raise HTTPNotFound()
  1463. else:
  1464. TheTiers = Tiers.by_slug(entity_id)
  1465. if TheTiers is None:
  1466. raise HTTPNotFound()
  1467. form = UpdateTiersForm(request.POST, TheTiers, meta={'csrf_context': request.session})
  1468. UserOptions = DBSession.query(TiersOpt)\
  1469. .filter(TiersOpt.entity_type==TheTiers.tiers_type)\
  1470. .all()
  1471. form.tiers_type.choices = TargetList
  1472. else:
  1473. TheTiers = Tiers()
  1474. # prepare the form for creation
  1475. form = TiersForm(request.POST, TheTiers, meta={'csrf_context': request.session})
  1476. form.tiers_type.choices = TargetList
  1477. UserOptions = list()
  1478. #test_form = TiersForm(request.POST, TheTiers, meta={'csrf_context': request.session})
  1479. if request.method == 'POST' and form.validate():
  1480. ToDelete = list()
  1481. ToDeleteR = list()
  1482. # First, we remove entries no more present
  1483. for obj in form.membership.object_data:
  1484. MatchEntry = filter( lambda x: x.object_data and x.object_data._sa_instance_state == obj._sa_instance_state,
  1485. form.membership.entries )
  1486. if not MatchEntry:
  1487. ToDelete.append(obj)
  1488. # For roles too
  1489. for obj in form.roles.object_data:
  1490. MatchEntry = filter( lambda x: x.object_data and x.object_data._sa_instance_state == obj._sa_instance_state,
  1491. form.roles.entries )
  1492. if not MatchEntry:
  1493. ToDeleteR.append(obj)
  1494. # We should remove it as it's not in original data
  1495. for obj in ToDelete:
  1496. TheTiers.membership.remove(obj)
  1497. DBSession.delete(obj)
  1498. # For roles too
  1499. for obj in ToDeleteR:
  1500. TheTiers.roles.remove(obj)
  1501. DBSession.delete(obj)
  1502. # Then, it's time to consider new entries
  1503. for entry in form.membership.entries:
  1504. if entry.object_data is None:
  1505. TmpUser = User_Tiers()
  1506. entry.object_data = TmpUser
  1507. TheTiers.membership.append(TmpUser)
  1508. form.membership.object_data = TheTiers.membership
  1509. # For roles too
  1510. for entry in form.roles.entries:
  1511. if entry.object_data is None:
  1512. TmpRole = Role_Tiers()
  1513. entry.object_data = TmpRole
  1514. TheTiers.roles.append(TmpRole)
  1515. form.roles.object_data = TheTiers.roles
  1516. form.populate_obj(TheTiers)
  1517. # Handle Remove of accents
  1518. OriginalSlug = TheTiers.slug
  1519. if not form._fields.has_key('uid'):
  1520. TheTiers.slug = slugify(form.name.data)
  1521. TheTiers.creator_id = request.user.uid
  1522. DBSession.add(TheTiers)
  1523. DBSession.flush()
  1524. return HTTPFound(location=request.route_url('edit_entity', sep='/',
  1525. entity_id=str(TheTiers.slug), tiers_type=TheTiers.get_entity_type.entity_type))
  1526. else:
  1527. if OriginalSlug!=slugify(form.name.data):
  1528. # We should move some file as slug have been changed
  1529. # First we ensure there is no related event that already exist with that slug
  1530. CheckTiers = Tiers.by_slug( slugify(form.name.data) )
  1531. if CheckTiers:
  1532. request.session.flash(('warning',u'Attention, Choisissez un autre titre pour votre entitée, elle est en conflit avec une autre.'))
  1533. DBSession.rollback()
  1534. return HTTPFound(location=request.route_url('edit_entity', sep='/',
  1535. entity_id=str(OriginalSlug), tiers_type=TheTiers.get_entity_type.entity_type))
  1536. else:
  1537. TheTiers.slug = slugify(form.name.data)
  1538. SRCPath = path.join('jm2l/upload', *(IMAGEPATH + ['tiers'] + [ OriginalSlug ]) )
  1539. DSTPath = path.join('jm2l/upload', *(IMAGEPATH + ['tiers'] + [ TheTiers.slug ]) )
  1540. if not path.isdir(path.dirname(DSTPath)):
  1541. makedirs(path.dirname(DSTPath))
  1542. # Then we should move event attachments to the new slug (if any)
  1543. if path.exists(SRCPath):
  1544. shutil.move(SRCPath, DSTPath)
  1545. DBSession.merge(TheTiers)
  1546. return HTTPFound(location=request.route_url('show_entity', entity_id=TheTiers.slug,
  1547. tiers_type=TheTiers.get_entity_type.slug_entity_type))
  1548. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1549. 'form':form, 'DBUser':User, 'UserOptions':UserOptions,
  1550. 'logged_in':request.authenticated_userid }
  1551. return MainTab
  1552. @view_config(route_name='edit_entity_cat', renderer="jm2l:templates/edit_tiers_categ.mako")
  1553. def edit_tiers_category(request):
  1554. if request.user is None:
  1555. # Don't answer to users that aren't logged
  1556. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1557. DicResult = dict()
  1558. ListChanges = list()
  1559. if request.method == 'POST':
  1560. # Reformat data
  1561. RegExist = re.compile('collection\[(?P<slug>[\w-]+)\]\[(?P<num>\d+)\]\[(?P<id>\d+)\]')
  1562. RegTitle = re.compile('collection\[(?P<slug>[\w-]+)\]\[title]')
  1563. RegNew = re.compile('collection\[(?P<slug>[\w-]+)\]\[(?P<num>\d+)\]\[id\]')
  1564. for key, value in request.POST.iteritems():
  1565. regN= RegNew.match(key)
  1566. regT= RegTitle.match(key)
  1567. reg = RegExist.match(key)
  1568. if reg:
  1569. if not DicResult.has_key(reg.group('slug')):
  1570. DicResult[reg.group('slug')] = dict()
  1571. if DicResult[reg.group('slug')].has_key('items'):
  1572. DicResult[reg.group('slug')]['items'].append( ( int(reg.group('id')), value ) )
  1573. else:
  1574. DicResult[reg.group('slug')]['items'] = [ ( int(reg.group('id')), value ) ]
  1575. elif regN:
  1576. if not DicResult.has_key(regN.group('slug')):
  1577. DicResult[regN.group('slug')] = dict()
  1578. if DicResult[regN.group('slug')].has_key('items'):
  1579. DicResult[regN.group('slug')]['items'].append( ( 'id', value ) )
  1580. else:
  1581. DicResult[regN.group('slug')]['items'] = [ ( 'id', value ) ]
  1582. ListChanges.append(('add', 0, DicResult[regN.group('slug')]['title'], value))
  1583. elif regT:
  1584. if not DicResult.has_key(regT.group('slug')):
  1585. DicResult[regT.group('slug')] = dict()
  1586. DicResult[regT.group('slug')]['title'] = value
  1587. else:
  1588. raise
  1589. for opt in DBSession.query(TiersOpt).all():
  1590. if DicResult.has_key(opt.slug_entity_type):
  1591. found = filter( lambda (x,y): opt.uid==x,
  1592. DicResult[opt.slug_entity_type].get('items', []))
  1593. if not found:
  1594. ListChanges.append(('remove', opt.uid, opt.entity_type, opt.entity_subtype))
  1595. else:
  1596. for tst in found:
  1597. # Check changes on Cat Name
  1598. if DicResult[opt.slug_entity_type]['title']!=opt.entity_type or \
  1599. tst[1]!=opt.entity_subtype:
  1600. ListChanges.append(('changed', opt.uid,
  1601. DicResult[opt.slug_entity_type]['title'],
  1602. tst[1]))
  1603. else:
  1604. ListChanges.append(('remove', opt.uid, opt.entity_type, opt.entity_subtype))
  1605. # Do The change
  1606. for action, uid, entity, subentity in ListChanges:
  1607. if action=="changed":
  1608. opt = TiersOpt.by_id(uid)
  1609. opt.entity_type = entity
  1610. opt.entity_subtype = subentity
  1611. elif action=="remove":
  1612. opt = TiersOpt.by_id(uid)
  1613. DBSession.delete(opt)
  1614. elif action=="add":
  1615. opt = TiersOpt()
  1616. opt.entity_type = entity
  1617. opt.entity_subtype = subentity
  1618. DBSession.add(opt)
  1619. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1620. 'logged_in':request.authenticated_userid, 'TiersOpt':TiersOpt }
  1621. return MainTab
  1622. @view_config(route_name='show_user', renderer="jm2l:templates/view_user.mako")
  1623. def show_user(request):
  1624. user_slug = request.matchdict.get('user_slug', None)
  1625. if user_slug is None or len(user_slug)==0:
  1626. raise HTTPNotFound(u"Cet utilisateur n'a pas été reconnu")
  1627. # Query database
  1628. DispUser = User.by_slug(user_slug)
  1629. if DispUser is None:
  1630. raise HTTPNotFound()
  1631. MainTab = {'programme':'','presse':'', 'plan':'', 'participer':'',
  1632. 'DispUser':DispUser, 'logged_in':request.authenticated_userid }
  1633. return MainTab
  1634. #@view_config(route_name='link_user_entity')
  1635. def link_user_entity(request):
  1636. if request.user is None:
  1637. # Don't answer to users that aren't logged
  1638. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1639. uid = int(request.matchdict.get('uid', -1))
  1640. year = int(request.matchdict.get('year', -1))
  1641. user_id = int(request.matchdict.get('uid', -1))
  1642. TheTiers = Tiers.by_id(uid)
  1643. if TheTiers is None:
  1644. raise HTTPNotFound()
  1645. return HTTPFound(location=request.route_url('edit_entity', uid=uid) )
  1646. #@view_config(route_name='link_role_entity')
  1647. def link_role_entity(request):
  1648. if request.user is None:
  1649. # Don't answer to users that aren't logged
  1650. raise HTTPForbidden(u'Vous devez vous identifier pour obtenir une réponse.')
  1651. uid = int(request.matchdict.get('uid', -1))
  1652. year = int(request.matchdict.get('year', -1))
  1653. role_id = int(request.matchdict.get('role_id', -1))
  1654. TheTiers = Tiers.by_id(uid)
  1655. if TheTiers is None:
  1656. raise HTTPNotFound()
  1657. return HTTPFound(location=request.route_url('edit_entity', uid=uid) )
  1658. @forbidden_view_config()
  1659. def forbidden(reason, request):
  1660. if 'ident' in reason.detail:
  1661. request.session.flash(('info', reason.detail))
  1662. return HTTPFound(location='/sign/login?from='+request.environ['PATH_INFO'] )
  1663. else:
  1664. request.response.status = 403
  1665. return render_to_response('jm2l:templates/Errors/403.mako', { "reason":reason },
  1666. request=request)
  1667. @notfound_view_config()
  1668. def notfound(reason, request):
  1669. request.response.status = 404
  1670. return render_to_response('jm2l:templates/Errors/404.mako', { "reason":reason },
  1671. request=request)