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

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