main.py 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. from flask import Flask, request, session, g, redirect, url_for, abort, \
  4. render_template, flash
  5. from flaskext.openid import OpenID
  6. import sqlite3
  7. from datetime import date, time, timedelta, datetime
  8. import time
  9. from contextlib import closing
  10. import locale
  11. locale.setlocale(locale.LC_ALL, '')
  12. import os
  13. import hashlib
  14. import smtplib
  15. import string
  16. DATABASE = '/tmp/cavote.db'
  17. PASSWD_SALT = 'change this value to some random chars!'
  18. SECRET_KEY = '{J@uRKO,xO-PK7B,jF?>iHbxLasF9s#zjOoy=+:'
  19. DEBUG = True
  20. TITLE = u"Cavote FFDN"
  21. EMAIL = '"' + TITLE + '"' + ' <' + u"cavote@ffdn.org" + '>'
  22. VERSION = "cavote 0.2.0"
  23. SMTP_SERVER = "127.0.0.1"
  24. PATTERNS = {u'Oui/Non': [u'Oui', u'Non'], u'Oui/Non/Blanc': [u'Oui', u'Non', u'Blanc'], u'Oui/Non/Peut-être': [u'Oui', u'Non', u'Peut-être']}
  25. app = Flask(__name__)
  26. app.config.from_object(__name__)
  27. oid = OpenID(app)
  28. def connect_db():
  29. return sqlite3.connect(app.config['DATABASE'])
  30. @app.before_request
  31. def before_request():
  32. g.db = connect_db()
  33. g.db.execute("PRAGMA foreign_keys = ON")
  34. @app.teardown_request
  35. def teardown_request(exception):
  36. g.db.close()
  37. @app.route('/')
  38. def home():
  39. return render_template('index.html', active_button="home")
  40. def query_db(query, args=(), one=False):
  41. cur = g.db.execute(query, args)
  42. rv = [dict((cur.description[idx][0], value)
  43. for idx, value in enumerate(row)) for row in cur.fetchall()]
  44. return (rv[0] if rv else None) if one else rv
  45. def init_db():
  46. with closing(connect_db()) as db:
  47. with app.open_resource('schema.sql') as f:
  48. db.cursor().executescript(f.read())
  49. db.commit()
  50. #----------------
  51. # Login / Logout
  52. def valid_login(email, password):
  53. # get user key
  54. user_key = query_db('select key from users where email = ?', (email,),
  55. one=True)
  56. if not user_key:
  57. # no such user
  58. return None
  59. user_key = user_key['key']
  60. # try password
  61. return query_db('select * from users where email = ? and password = ?',
  62. [email, crypt(password, user_key)], one=True)
  63. def connect_user(user):
  64. session['user'] = user
  65. del session['user']['password']
  66. del session['user']['key']
  67. def disconnect_user():
  68. session.pop('user', None)
  69. def crypt(passwd, user_key):
  70. # the per-user salt should not be stored in the db
  71. # storing the passwd... but this is better than nothing
  72. per_user_salt = hashlib.sha1(user_key).hexdigest()
  73. salt_passwd = '%s%s%s' % (app.config['PASSWD_SALT'], per_user_salt, passwd)
  74. return hashlib.sha1(salt_passwd).hexdigest()
  75. def keygen():
  76. return hashlib.sha1(os.urandom(24)).hexdigest()
  77. def get_userid():
  78. user = session.get('user')
  79. if user is None:
  80. return -1
  81. elif user.get('id') < 0:
  82. return -1
  83. else:
  84. return user.get('id')
  85. @app.route('/login', methods=['GET', 'POST'])
  86. @oid.loginhandler
  87. def login():
  88. if request.method == 'POST':
  89. user = valid_login(request.form['username'], request.form['password'])
  90. if user is None:
  91. if request.form['openid']:
  92. return oid.try_login(request.form['openid'], ask_for=['email', 'fullname', 'nickname'])
  93. else:
  94. flash(u'Email ou mot de passe invalide.', 'error')
  95. else:
  96. connect_user(user)
  97. flash(u'Vous êtes connecté. Bienvenue, %s !' % user['name'], 'success')
  98. if request.args.get('continue'):
  99. return redirect(request.args['continue'])
  100. return redirect(url_for('home'))
  101. return render_template('login.html')
  102. @oid.after_login
  103. def create_or_login(resp):
  104. openid_url = resp.identity_url
  105. user = query_db('select * from users where openid = ?', [openid_url], one=True)
  106. if user is not None:
  107. flash(u'Successfully signed in')
  108. connect_user(user)
  109. return redirect(oid.get_next_url())
  110. return redirect(url_for('home'))
  111. @app.route('/logout')
  112. def logout():
  113. disconnect_user()
  114. flash(u'Vous avez été déconnecté.', 'info')
  115. if request.args.get('continue') and not "admin" in request.args.get('continue'):
  116. return redirect(request.args['continue'])
  117. return redirect(url_for('home'))
  118. #-----------------
  119. # Change password
  120. @app.route('/password/lost', methods=['GET', 'POST'])
  121. def password_lost():
  122. info = None
  123. if request.method == 'POST':
  124. user = query_db('select * from users where email = ?', [request.form['email']], one=True)
  125. if user is None:
  126. flash('Cet utilisateur n\'existe pas !', 'error')
  127. else:
  128. key = 'v%s' % keygen() # start with v: valid key
  129. g.db.execute('update users set key = ? where id = ?', [key, user['id']])
  130. g.db.commit()
  131. link = request.url_root + url_for('login_key', userid=user['id'], key=key)
  132. BODY = string.join((
  133. "From: %s" % EMAIL,
  134. "To: %s" % user['email'],
  135. "Subject: [Cavote] Password lost",
  136. "Date: %s" % time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime()).decode('utf-8'),
  137. "X-Mailer: %s" % VERSION,
  138. "",
  139. "You have lost your password.",
  140. "This link will log you without password.",
  141. "Don't forget to define a new one as soon a possible!",
  142. "This link will only work one time.",
  143. "",
  144. link,
  145. "",
  146. "If you think this mail is not for you, please ignore and delete it."
  147. ), "\r\n")
  148. server = smtplib.SMTP(SMTP_SERVER)
  149. server.sendmail(EMAIL, [user['email']], BODY)
  150. server.quit()
  151. flash(u"Un mail a été envoyé à " + user['email'], 'info')
  152. return render_template('password_lost.html')
  153. @app.route('/login/<userid>/<key>')
  154. def login_key(userid, key):
  155. user = query_db('select * from users where id = ? and key = ?', [userid, key], one=True)
  156. if user is None or user['key'][0] != "v":
  157. abort(404)
  158. else:
  159. connect_user(user)
  160. flash(u"Veuillez mettre à jour votre mot de passe", 'info')
  161. return redirect(url_for('user_password', userid=user['id']))
  162. #---------------
  163. # User settings
  164. @app.route('/user/<userid>')
  165. def user(userid):
  166. if int(userid) != get_userid():
  167. abort(401)
  168. groups = query_db('select * from groups join user_group on id=id_group where id_user = ?', userid)
  169. return render_template('user.html', groups=groups)
  170. @app.route('/user/settings/<userid>', methods=['GET', 'POST'])
  171. def user_edit(userid):
  172. if int(userid) != get_userid():
  173. abort(401)
  174. if request.method == 'POST':
  175. if query_db('select * from users where email=? and id!=?', [request.form['email'], userid], one=True) is None:
  176. if query_db('select * from users where name=? and id!=?', [request.form['name'], userid], one=True) is None:
  177. g.db.execute('update users set email = ?, openid = ?, name = ?, organization = ? where id = ?',
  178. [request.form['email'], request.form['openid'], request.form['name'], request.form['organization'], session['user']['id']])
  179. g.db.commit()
  180. disconnect_user()
  181. user = query_db('select * from users where id=?', [userid], one=True)
  182. if user is None:
  183. flash(u'Une erreur s\'est produite.', 'error')
  184. return redirect(url_for('login'))
  185. connect_user(user)
  186. flash(u'Votre profil a été mis à jour !', 'success')
  187. else:
  188. flash(u'Le nom ' + request.form['name'] + u' est déjà pris ! Veuillez en choisir un autre.', 'error')
  189. else:
  190. flash(u'Il existe déjà un compte pour cette adresse e-mail : ' + request.form['email'], 'error')
  191. return render_template('user_edit.html')
  192. @app.route('/user/password/<userid>', methods=['GET', 'POST'])
  193. def user_password(userid):
  194. if int(userid) != get_userid():
  195. abort(401)
  196. if request.method == 'POST':
  197. if request.form['password'] == request.form['password2']:
  198. # new (invalid) key
  199. key = 'i%s' % keygen() # start with i: invalid key
  200. print "\n\nchange key for %s\n" % key # FIXME TMP
  201. g.db.execute('update users set password = ?, key = ? where id = ?',
  202. [crypt(request.form['password'], key),
  203. key, session['user']['id']])
  204. g.db.commit()
  205. flash(u'Votre mot de passe a été mis à jour.', 'success')
  206. else:
  207. flash(u'Les mots de passe sont différents.', 'error')
  208. return render_template('user_edit.html')
  209. #------------
  210. # User admin
  211. @app.route('/admin/users')
  212. def admin_users():
  213. if not session.get('user').get('is_admin'):
  214. abort(401)
  215. tuples = query_db('select *, groups.name as groupname from (select *, id as userid, name as username from users join user_group on id=id_user order by id desc) join groups on id_group=groups.id')
  216. users = dict()
  217. for t in tuples:
  218. if t['userid'] in users:
  219. users[t['userid']]['groups'].append(t["groupname"])
  220. else:
  221. users[t['userid']] = dict()
  222. users[t['userid']]['userid'] = t['userid']
  223. users[t['userid']]['email'] = t['email']
  224. users[t['userid']]['username'] = t['username']
  225. users[t['userid']]['is_admin'] = t['is_admin']
  226. users[t['userid']]['groups'] = [t['groupname']]
  227. return render_template('admin_users.html', users=users.values())
  228. @app.route('/admin/users/add', methods=['GET', 'POST'])
  229. def admin_user_add():
  230. if not session.get('user').get('is_admin'):
  231. abort(401)
  232. if request.method == 'POST':
  233. if request.form['email']:
  234. if query_db('select * from users where email=?', [request.form['email']], one=True) is None:
  235. if request.form['username']:
  236. if query_db('select * from users where name=?', [request.form['username']], one=True) is None:
  237. admin = 0
  238. if 'admin' in request.form.keys():
  239. admin = 1
  240. key = 'v%s' % keygen()
  241. g.db.execute('insert into users (email, openid, name, organization, password, is_admin, key) values (?, ?, ?, ?, ?, ?, ?)',
  242. [request.form['email'],
  243. request.form['openid'],
  244. request.form['username'],
  245. request.form['organization'],
  246. '', admin, key])
  247. g.db.commit()
  248. user = query_db('select * from users where email = ?', [request.form["email"]], one=True)
  249. if user:
  250. groups = request.form.getlist('groups')
  251. groups.append('1')
  252. for group in groups:
  253. if query_db('select id from groups where id = ?', group, one=True) is None:
  254. flash(u'Le groupe portant l\'id %s n\'existe pas.' % group, 'warning')
  255. else:
  256. g.db.execute('insert into user_group values (?, ?)', [user['id'], group])
  257. g.db.commit()
  258. link = request.url_root + url_for('login_key', userid=user['id'], key=user['key'])
  259. BODY = string.join((
  260. "From: %s" % EMAIL,
  261. "To: %s" % user['email'],
  262. "Subject: [Cavote] Welcome",
  263. "Date: %s" % time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime()).decode('utf-8'),
  264. "X-Mailer: %s" % VERSION,
  265. "",
  266. "Hi %s!" % user['name'],
  267. "Welcome on %s." % TITLE,
  268. "Your account's adresse is : %s." % user['email'],
  269. "",
  270. "To log in for the first time and set your password, please follow this link :",
  271. link,
  272. ""
  273. ), "\r\n")
  274. server = smtplib.SMTP(SMTP_SERVER)
  275. server.sendmail(EMAIL, [user['email']], BODY)
  276. server.quit()
  277. flash(u'Le nouvel utilisateur a été créé avec succès', 'success')
  278. return redirect(url_for('admin_users'))
  279. else:
  280. flash(u'Une erreur s\'est produite.', 'error')
  281. else:
  282. flash(u'Le nom ' + request.form['username'] + u' est déjà pris ! Veuillez en choisir un autre.', 'error')
  283. else:
  284. flash(u"Vous devez spécifier un nom d'utilisateur.", 'error')
  285. else:
  286. flash(u'Il existe déjà un compte pour cette adresse e-mail : ' + request.form['email'], 'error')
  287. else:
  288. flash(u"Vous devez spécifier une adresse email.", 'error')
  289. groups = query_db('select * from groups where system=0')
  290. return render_template('admin_user_new.html', groups=groups)
  291. @app.route('/admin/users/edit/<iduser>', methods=['GET', 'POST'])
  292. def admin_user_edit(iduser):
  293. if not session.get('user').get('is_admin'):
  294. abort(401)
  295. user = query_db('select * from users where id = ?', [iduser], one=True)
  296. user['groups'] = query_db('select groups.* from groups join user_group on groups.id = user_group.id_group where id_user = ?', [iduser])
  297. if user is None:
  298. abort(404)
  299. if request.method == 'POST':
  300. if query_db('select * from users where email=? and id!=?', [request.form['email'], iduser], one=True) is None:
  301. if query_db('select * from users where name=? and id!=?', [request.form['name'], iduser], one=True) is None:
  302. admin = 0
  303. if 'admin' in request.form.keys():
  304. admin = 1
  305. g.db.execute('update users set email = ?, name = ?, organization = ?, openid= ?, is_admin = ? where id = ?',
  306. [request.form['email'], request.form['name'], request.form['organization'], request.form['openid'], admin, iduser])
  307. g.db.commit()
  308. groups = request.form.getlist('groups')
  309. groups.append('1')
  310. for group in user['groups']:
  311. if not group['id'] in groups:
  312. g.db.execute('delete from user_group where id_user = ? and id_group = ?', [iduser, group['id']])
  313. g.db.commit()
  314. for group in groups:
  315. group = query_db('select id from groups where id = ?', group, one=True)
  316. if group is None:
  317. flash(u'Le groupe portant l\'id %s n\'existe pas.' % group, 'warning')
  318. else:
  319. if not group in user['groups']:
  320. g.db.execute('insert into user_group values (?, ?)', [user['id'], group['id']])
  321. g.db.commit()
  322. user = query_db('select * from users where id = ?', [iduser], one=True)
  323. user['groups'] = query_db('select groups.* from groups join user_group on groups.id = user_group.id_group where id_user = ?', [iduser])
  324. flash(u'Le profil a été mis à jour !', 'success')
  325. else:
  326. flash(u'Le nom ' + request.form['name'] + u' est déjà pris ! Veuillez en choisir un autre.', 'error')
  327. else:
  328. flash(u'Il existe déjà un compte pour cette adresse e-mail : ' + request.form['email'], 'error')
  329. groups = query_db('select * from groups where system=0')
  330. return render_template('admin_user_edit.html', user=user, groups=groups)
  331. @app.route('/admin/users/delete/<iduser>')
  332. def admin_user_del(iduser):
  333. if not session.get('user').get('is_admin'):
  334. abort(401)
  335. user = query_db('select * from users where id = ?', [iduser], one=True)
  336. if user is None:
  337. abort(404)
  338. g.db.execute('delete from users where id = ?', [iduser])
  339. g.db.commit()
  340. return redirect(url_for('admin_users'))
  341. #-------------
  342. # Roles admin
  343. @app.route('/admin/groups')
  344. def admin_groups():
  345. if not session.get('user').get('is_admin'):
  346. abort(401)
  347. groups = query_db('select groups.*, count(user_group.id_user) as nb_users from (select groups.*, count(votes.id) as nb_votes from groups left join votes on votes.id_group = groups.id group by groups.id) as groups left join user_group on user_group.id_group = groups.id group by groups.id')
  348. return render_template('admin_groups.html', groups=groups)
  349. @app.route('/admin/groups/add', methods=['POST'])
  350. def admin_group_add():
  351. if not session.get('user').get('is_admin'):
  352. abort(401)
  353. if request.method == 'POST':
  354. if request.form['name']:
  355. g.db.execute('insert into groups (name) values (?)', [request.form['name']])
  356. g.db.commit()
  357. else:
  358. flash(u"Vous devez spécifier un nom.", "error")
  359. return redirect(url_for('admin_groups'))
  360. @app.route('/admin/groups/delete/<idgroup>')
  361. def admin_group_del(idgroup):
  362. if not session.get('user').get('is_admin'):
  363. abort(401)
  364. group = query_db('select * from groups where id = ?', [idgroup], one=True)
  365. if group is None:
  366. abort(404)
  367. if group['system']:
  368. abort(401)
  369. g.db.execute('delete from groups where id = ?', [idgroup])
  370. g.db.commit()
  371. return redirect(url_for('admin_groups'))
  372. #------------
  373. # Votes list
  374. @app.route('/votes/<votes>')
  375. def votes(votes):
  376. today = date.today()
  377. active_button = votes
  378. max_votes ='select id_group, count(*) as max_votes from user_group group by id_group'
  379. basequery = 'select votes.*, max_votes from votes left join (' + max_votes + ') as max_votes on votes.id_group = max_votes.id_group'
  380. nb_votes = 'select id_vote, count(*) as nb_votes from (select id_user, id_vote from user_choice join choices on id_choice = choices.id group by id_user, id_vote) group by id_vote'
  381. basequery = 'select * from (' + basequery + ') left join (' + nb_votes + ') on id = id_vote'
  382. basequery = 'select *, votes.id as voteid, groups.name as groupname from (' + basequery + ') as votes join groups on groups.id = id_group where is_open=1 and is_hidden=0'
  383. if votes == 'all':
  384. votes = query_db(basequery + ' order by date_end')
  385. elif votes == 'archive':
  386. votes = query_db(basequery + ' and is_terminated=1 order by date_end desc')
  387. elif votes == 'current':
  388. votes = query_db(basequery + ' and is_terminated=0 order by date_end')
  389. elif votes == 'waiting':
  390. basequery = 'select votes.* from user_group join (' + basequery + ') as votes on votes.id_group = user_group.id_group where user_group.id_user = ?'
  391. already_voted = 'select id_vote from user_choice join choices on user_choice.id_choice = choices.id where id_user = ?'
  392. votes = query_db(basequery + ' and votes.id not in (' + already_voted + ') and is_terminated=0', [get_userid(), get_userid()])
  393. else:
  394. abort(404)
  395. for vote in votes:
  396. if not vote.get('nb_votes'):
  397. vote['nb_votes'] = 0
  398. if vote.get('max_votes'):
  399. vote['percent'] = int((float(vote['nb_votes']) / float(vote['max_votes'])) * 100)
  400. return render_template('votes.html', votes=votes, active_button=active_button)
  401. #------
  402. # Vote
  403. def can_see_vote(idvote, iduser=-1):
  404. vote = query_db('select * from votes where id=?', [idvote], one=True)
  405. if vote is None:
  406. return False
  407. if not vote['is_public']:
  408. user = query_db('select * from users where id=?', [iduser], one=True)
  409. if query_db('select * from user_group where id_user = ? and id_group = ?', [iduser, vote['id']], one=True) is None:
  410. return False
  411. return True
  412. def can_vote(idvote, iduser=-1):
  413. vote = query_db('select * from votes where id=?', [idvote], one=True)
  414. if vote is None:
  415. return False
  416. if vote['is_terminated'] == 0:
  417. if iduser > 0:
  418. if can_see_vote(idvote, iduser):
  419. if not has_voted(idvote, iduser):
  420. if query_db('select * from user_group where id_user = ? and id_group = ?', [iduser, vote['id_group']], one=True):
  421. return True
  422. return False
  423. def has_voted(idvote, iduser=-1):
  424. vote = query_db('select * from user_choice join choices on id_choice=choices.id where id_vote = ? and id_user = ?', [idvote, iduser], one=True)
  425. return (vote is not None)
  426. @app.route('/vote/<idvote>', methods=['GET', 'POST'])
  427. def vote(idvote):
  428. vote = query_db('select votes.*, groups.name as groupname, users.name as author from votes join groups on groups.id=votes.id_group join users on users.id=votes.id_author where votes.id=?', [idvote], one=True)
  429. if vote is None:
  430. abort(404)
  431. if can_see_vote(idvote, get_userid()):
  432. if request.method == 'POST':
  433. if can_vote(idvote, get_userid()):
  434. if vote['is_multiplechoice'] == 0:
  435. if query_db('select * from choices where id = ?', [request.form['choice']], one=True) is not None:
  436. g.db.execute('insert into user_choice (id_user, id_choice) values (?, ?)',
  437. [session.get('user').get('id'), request.form['choice']])
  438. g.db.commit()
  439. else:
  440. choices = query_db('select name, id from choices where id_vote=?', [idvote])
  441. for choice in choices:
  442. if str(choice['id']) in request.form.keys():
  443. g.db.execute('insert into user_choice (id_user, id_choice) values (?, ?)',
  444. [session.get('user').get('id'), choice['id']])
  445. g.db.commit()
  446. else:
  447. abort(401)
  448. tuples = query_db('select choiceid, choicename, users.id as userid, users.name as username from (select choices.id as choiceid, choices.name as choicename, id_user as userid from choices join user_choice on choices.id = user_choice.id_choice where id_vote = ?) join users on userid = users.id', [idvote])
  449. users = dict()
  450. for t in tuples:
  451. if t['userid'] in users:
  452. users[t['userid']]['choices'].append(t['choiceid'])
  453. else:
  454. users[t['userid']] = dict()
  455. users[t['userid']]['userid'] = t['userid']
  456. users[t['userid']]['username'] = t['username']
  457. users[t['userid']]['choices'] = [t['choiceid']]
  458. choices = query_db('select choices.name, choices.id, choices.name, choices.id_vote, count(id_choice) as nb from choices left join user_choice on id_choice = choices.id where id_vote = ? group by id_choice, name, id_vote order by id', [idvote])
  459. attachments = query_db('select * from attachments where id_vote=?', [idvote])
  460. tmp = query_db('select id_group, count(*) as nb from user_group where id_group = ? group by id_group', [vote['id_group']], one=True)
  461. if tmp is None:
  462. vote['percent'] = 0
  463. else:
  464. vote['max_votes'] = tmp['nb']
  465. tmp = query_db('select id_vote, count(*) as nb from (select id_user, id_vote from user_choice join choices on id_choice = choices.id group by id_user, id_vote) where id_vote = ? group by id_vote', [idvote], one=True)
  466. if tmp is None:
  467. vote['percent'] = 0
  468. vote['nb_votes'] = 0
  469. else:
  470. vote['nb_votes'] = tmp['nb']
  471. vote['percent'] = int((float(vote['nb_votes']) / float(vote['max_votes'])) * 100)
  472. if query_db('select * from user_group where id_group = ? and id_user = ?', [vote['id_group'], get_userid()], one=True) and not vote['is_terminated']:
  473. flash(u'Ce vote vous concerne !', 'info')
  474. return render_template('vote.html', vote=vote, attachments=attachments, choices=choices, users=users.values(), can_vote=can_vote(idvote, get_userid()))
  475. flash(u'Vous n\'avez pas le droit de voir ce vote, désolé.')
  476. return redirect(url_for('home'))
  477. @app.route('/vote/deletechoices/<idvote>/<iduser>')
  478. def vote_deletechoices(idvote, iduser):
  479. if int(iduser) != get_userid():
  480. abort(401)
  481. g.db.execute('delete from user_choice where id_user = ? and id_choice in (select id from choices where id_vote = ?)',
  482. [iduser, idvote])
  483. g.db.commit()
  484. return redirect(url_for('vote', idvote=idvote))
  485. #-------------
  486. # Votes admin
  487. @app.route('/admin/votes/list')
  488. def admin_votes():
  489. if not session.get('user').get('is_admin'):
  490. abort(401)
  491. votes = query_db('select *, votes.id as voteid, groups.name as groupname from votes join groups on groups.id=votes.id_group where is_hidden=0 order by id desc')
  492. return render_template('admin_votes.html', votes=votes, today=date.today().strftime("%Y-%m-%d"))
  493. @app.route('/admin/votes/add', methods=['GET', 'POST'])
  494. def admin_vote_add():
  495. if not session.get('user').get('is_admin'):
  496. abort(401)
  497. if request.method == 'POST':
  498. if request.form['title']:
  499. if query_db('select * from votes where title = ?', [request.form['title']], one=True) is None:
  500. date_begin = date.today()
  501. date_end = date.today() + timedelta(days=int(request.form['days']))
  502. transparent = 0
  503. public = 0
  504. multiplechoice = 0
  505. if 'transparent' in request.form.keys():
  506. transparent = 1
  507. if 'public' in request.form.keys():
  508. public = 1
  509. if 'multiplechoice' in request.form.keys():
  510. multiplechoice = 1
  511. group = query_db('select id from groups where name = ?', [request.form['group']], one=True)
  512. if group is None:
  513. group[id] = 1
  514. g.db.execute('insert into votes (title, description, category, date_begin, date_end, is_transparent, is_public, is_multiplechoice, id_group, id_author) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
  515. [request.form['title'], request.form['description'], request.form['category'], date_begin, date_end, transparent, public, multiplechoice, group['id'], session['user']['id']])
  516. g.db.commit()
  517. vote = query_db('select * from votes where title = ? and date_begin = ? order by id desc',
  518. [request.form['title'], date_begin], one=True)
  519. if vote is None:
  520. flash(u'Une erreur est survenue !', 'error')
  521. return redirect(url_for('home'))
  522. else:
  523. if request.form['pattern'] in PATTERNS.keys():
  524. pattern = PATTERNS[request.form['pattern']]
  525. for choice in pattern:
  526. g.db.execute('insert into choices (name, id_vote) values (?, ?)', [choice, vote['id']])
  527. g.db.commit()
  528. flash(u"Le vote a été créé", 'info')
  529. return redirect(url_for('admin_vote_edit', voteid=vote['id']))
  530. else:
  531. flash(u'Le titre que vous avez choisi est déjà pris.', 'error')
  532. else:
  533. flash(u'Vous devez spécifier un titre.', 'error')
  534. groups = query_db('select * from groups')
  535. return render_template('admin_vote_new.html', groups=groups, patterns=PATTERNS)
  536. @app.route('/admin/votes/edit/<voteid>', methods=['GET', 'POST'])
  537. def admin_vote_edit(voteid):
  538. if not session.get('user').get('is_admin'):
  539. abort(401)
  540. vote = query_db('select * from votes where id = ?', [voteid], one=True)
  541. if vote is None:
  542. abort(404)
  543. if request.method == 'POST':
  544. if request.form['title']:
  545. if request.form['days'] > 0:
  546. date_end = datetime.strptime(vote['date_begin'], "%Y-%m-%d") + timedelta(days=int(request.form['days']))
  547. date_end = date_end.strftime("%Y-%m-%d")
  548. transparent = 0
  549. public = 0
  550. if 'transparent' in request.form.keys():
  551. transparent = 1
  552. if 'public' in request.form.keys():
  553. public = 1
  554. isopen = 0
  555. isterminated = 0
  556. if request.form['status'] == 'Ouvert':
  557. choices = query_db('select id_vote, count(*) as nb from choices where id_vote = ? group by id_vote', [voteid], one=True)
  558. if choices is not None and choices['nb'] >= 2:
  559. isopen = 1
  560. else:
  561. flash(u'Vous devez proposer au moins deux choix pour ouvrir le vote.', 'error')
  562. elif request.form['status'] == u'Terminé':
  563. isterminated = 1
  564. if vote['is_open']:
  565. isopen = 1
  566. g.db.execute('update votes set title = ?, description = ?, category = ?, is_transparent = ?, is_public = ?, is_open = ?, is_terminated = ?, date_end = ? where id = ?',
  567. [request.form['title'], request.form['description'], request.form['category'], transparent, public, isopen, isterminated, date_end, voteid])
  568. g.db.commit()
  569. vote = query_db('select * from votes where id = ?', [voteid], one=True)
  570. flash(u"Le vote a bien été mis à jour.", "success")
  571. else:
  572. flash(u'Vous devez spécifier un titre.', 'error')
  573. vote['duration'] = (datetime.strptime(vote['date_end'], "%Y-%m-%d")
  574. - datetime.strptime(vote['date_begin'], "%Y-%m-%d")).days
  575. group = query_db('select name from groups where id = ?', [vote['id_group']], one=True)
  576. choices = query_db('select * from choices where id_vote = ?', [voteid])
  577. attachments = query_db('select * from attachments where id_vote = ?', [voteid])
  578. if date.today().strftime("%Y-%m-%d") > vote['date_end']:
  579. flash(u'La deadline du vote est expirée, vous devriez terminer le vote.')
  580. return render_template('admin_vote_edit.html', vote=vote, group=group, choices=choices, attachments=attachments)
  581. @app.route('/admin/votes/delete/<idvote>')
  582. def admin_vote_del(idvote):
  583. if not session.get('user').get('is_admin'):
  584. abort(401)
  585. vote = query_db('select * from votes where id = ?', [idvote], one=True)
  586. if vote is None:
  587. abort(404)
  588. g.db.execute('update votes set is_hidden=1 where id = ?', [idvote])
  589. g.db.commit()
  590. return redirect(url_for('admin_votes'))
  591. @app.route('/admin/votes/addchoice/<voteid>', methods=['POST'])
  592. def admin_vote_addchoice(voteid):
  593. if not session.get('user').get('is_admin'):
  594. abort(401)
  595. vote = query_db('select * from votes where id = ?', [voteid], one=True)
  596. if vote is None:
  597. abort(404)
  598. g.db.execute('insert into choices (name, id_vote) values (?, ?)', [request.form['title'], voteid])
  599. g.db.commit()
  600. return redirect(url_for('admin_vote_edit', voteid=voteid))
  601. @app.route('/admin/votes/editchoice/<voteid>/<choiceid>', methods=['POST', 'DELETE'])
  602. def admin_vote_editchoice(voteid, choiceid):
  603. if not session.get('user').get('is_admin'):
  604. abort(401)
  605. choice = query_db('select * from choices where id = ? and id_vote = ?', [choiceid, voteid], one=True)
  606. if choice is None:
  607. abort(404)
  608. if request.method == 'POST':
  609. g.db.execute('update choices set name=? where id = ? and id_vote = ?', [request.form['title'], choiceid, voteid])
  610. g.db.commit()
  611. return redirect(url_for('admin_vote_edit', voteid=voteid))
  612. @app.route('/admin/votes/deletechoice/<voteid>/<choiceid>')
  613. def admin_vote_deletechoice(voteid, choiceid):
  614. if not session.get('user').get('is_admin'):
  615. abort(401)
  616. choice = query_db('select * from choices where id = ? and id_vote = ?', [choiceid, voteid], one=True)
  617. if choice is None:
  618. abort(404)
  619. g.db.execute('delete from choices where id = ? and id_vote = ?', [choiceid, voteid])
  620. g.db.commit()
  621. choices = query_db('select id_vote, count(*) as nb from choices where id_vote = ? group by id_vote', [voteid], one=True)
  622. if choices is None or choices['nb'] < 2:
  623. g.db.execute('update votes set is_open=0 where id = ?', [voteid])
  624. g.db.commit()
  625. flash(u'Attention ! Il y a moins de deux choix. Le vote a été fermé.', 'error')
  626. return redirect(url_for('admin_vote_edit', voteid=voteid))
  627. @app.route('/admin/votes/addattachment/<voteid>', methods=['POST'])
  628. def admin_vote_addattachment(voteid):
  629. if not session.get('user').get('is_admin'):
  630. abort(401)
  631. vote = query_db('select * from votes where id = ?', [voteid], one=True)
  632. if vote is None:
  633. abort(404)
  634. g.db.execute('insert into attachments (url, id_vote) values (?, ?)', [request.form['url'], voteid])
  635. g.db.commit()
  636. return redirect(url_for('admin_vote_edit', voteid=voteid))
  637. @app.route('/admin/votes/deleteattachment/<voteid>/<attachmentid>')
  638. def admin_vote_deleteattachment(voteid, attachmentid):
  639. if not session.get('user').get('is_admin'):
  640. abort(401)
  641. attachment = query_db('select * from attachments where id = ? and id_vote = ?', [attachmentid, voteid], one=True)
  642. if attachment is None:
  643. abort(404)
  644. g.db.execute('delete from attachments where id = ? and id_vote = ?', [attachmentid, voteid])
  645. g.db.commit()
  646. return redirect(url_for('admin_vote_edit', voteid=voteid))
  647. #------
  648. # Main
  649. if __name__ == '__main__':
  650. app.run()