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.
 
 
 
 
 

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