Le repo des sources pour le site web des JM2L
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 

1940 linhas
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)