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

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