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.
 
 
 
 
 

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