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.
 
 
 
 
 

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