main.py 35 KB

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