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

1814 lines
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)