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

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