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.
 
 
 
 
 

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