Le repo des sources pour le site web des JM2L
Não pode escolher mais do que 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.
 
 
 
 
 

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