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.
 
 
 
 
 

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