+ ident=prefix.per_host[cat]+"."+t.strftime("%Y%m%d")+"."+("%03d" % (int(sr[0][0].split(".")[2])+1))
+ p = db.prepare("INSERT INTO motion(\"name\", \"content\", \"deadline\", \"posed_by\", \"type\", \"identifier\", \"host\") VALUES($1, $2, CURRENT_TIMESTAMP + $3 * interval '1 days', $4, $5, $6, $7)")
+ p(title, content, time, g.voter, cat, ident, request.host)
+ return rel_redirect("/")
+
+def motion_edited(motion):
+ return rel_redirect("/motion/" + motion)
+
+def validate_motion_access(privilege):
+ def decorator(f):
+ def decorated_function(motion):
+ db = get_db()
+ with db.xact():
+ rv = db.prepare("SELECT id, type, deadline < CURRENT_TIMESTAMP AS expired, canceled FROM motion WHERE identifier=$1 AND host=$2")(motion, request.host);
+ if len(rv) == 0:
+ return _('Error, Not found'), 404
+ id = rv[0].get("id")
+ if not may(privilege, rv[0].get("type")):
+ return _('Forbidden'), 403
+ if rv[0].get("canceled") is not None:
+ return _('Error, motion was canceled'), 403
+ if rv[0].get("expired"):
+ return _('Error, out of time'), 403
+ return f(motion, id)
+ decorated_function.__name__ = f.__name__
+ return decorated_function
+ return decorator
+
+def validate_motion_access_vote(privilege):
+ simple_decorator = validate_motion_access(privilege)
+ def decorator(f):
+ def decorated_function(motion, voter):
+ return simple_decorator(lambda motion, id : f(motion, voter, id))(motion)
+ decorated_function.__name__ = f.__name__
+ return decorated_function
+ return decorator
+
+@app.route("/motion/<string:motion>/cancel", methods=['POST'])
+@validate_motion_access('cancel')
+def cancel_motion(motion, id):
+ if request.form.get("reason", "none") == "none":
+ return _('Error, form requires reason'), 500
+ rv = get_db().prepare("UPDATE motion SET canceled=CURRENT_TIMESTAMP, cancelation_reason=$1, canceled_by=$2 WHERE identifier=$3 AND host=$4 AND canceled is NULL")(request.form.get("reason", ""), g.voter, motion, request.host)
+ return motion_edited(motion)
+
+@app.route("/motion/<string:motion>/finish", methods=['POST'])
+@validate_motion_access('finish')
+def finish_motion(motion, id):
+ rv = get_db().prepare("UPDATE motion SET deadline=CURRENT_TIMESTAMP WHERE identifier=$1 AND host=$2 AND canceled is NULL")(motion, request.host)
+ return motion_edited(motion)
+
+@app.route("/motion/<string:motion>")
+def show_motion(motion):
+ p = get_db().prepare("SELECT motion.*, poser.email AS poser, canceler.email AS canceler, (motion.deadline > CURRENT_TIMESTAMP AND canceled is NULL) AS running, vote.result FROM motion "\
+ + "LEFT JOIN vote on vote.motion_id=motion.id AND vote.voter_id=$2 "\
+ + "LEFT JOIN voter poser ON poser.id = motion.posed_by "\
+ + "LEFT JOIN voter canceler ON canceler.id = motion.canceled_by "
+ + "WHERE motion.identifier=$1 AND motion.host=$3")
+ resultmotion = p(motion, g.voter, request.host)
+ if len(resultmotion) == 0:
+ return _('Error, Not found'), 404
+
+ p = get_db().prepare("SELECT voter.email FROM vote INNER JOIN voter ON vote.proxy_id = voter.id WHERE vote.motion_id=$1 AND vote.voter_id=$2 AND vote.proxy_id <> vote.voter_id")
+ resultproxyname = p(resultmotion[0][0], g.voter)
+
+ p = get_db().prepare("SELECT v.result, proxy.voter_id, voter.email, CASE WHEN proxy.proxy_id = v.proxy_id THEN NULL ELSE voter.email END AS owneremail FROM proxy LEFT JOIN "\
+ + "(SELECT vote.voter_id, vote.result, vote.proxy_id FROM vote "\
+ + "WHERE vote.motion_id=$1) AS v ON proxy.voter_id = v.voter_id "\
+ + "LEFT JOIN voter ON proxy.voter_id = voter.id "\
+ + "WHERE proxy.proxy_id=$2 AND proxy.revoked IS NULL")
+ resultproxyvote = p(resultmotion[0][0], g.voter)
+
+ votes = None
+ if may("audit", resultmotion[0].get("type")) and not resultmotion[0].get("running") and not resultmotion[0].get("canceled"):
+ votes = get_db().prepare("SELECT vote.result, voter.email FROM vote INNER JOIN voter ON voter.id = vote.voter_id WHERE vote.motion_id=$1")(resultmotion[0].get("id"));
+ votes = get_db().prepare("SELECT vote.result, voter.email, CASE voter.email WHEN proxy.email THEN NULL ELSE proxy.email END as proxyemail FROM vote INNER JOIN voter ON voter.id = vote.voter_id INNER JOIN voter as proxy ON proxy.id = vote.proxy_id WHERE vote.motion_id=$1")(resultmotion[0].get("id"));
+ return render_template('single_motion.html', motion=resultmotion[0], may_vote=may("vote", resultmotion[0].get("type")), may_cancel=may("cancel", resultmotion[0].get("type")), votes=votes, proxyvote=resultproxyvote, proxyname=resultproxyname, languages=get_languages())
+
+@app.route("/motion/<string:motion>/vote/<string:voter>", methods=['POST'])
+@validate_motion_access_vote('vote')
+def vote(motion, voter, id):
+ v = request.form.get("vote", "abstain")
+ voterid=int(voter)
+ db = get_db()
+
+ # test if voter is proxy
+ if (voterid != g.voter):
+ rv = db.prepare("SELECT voter_id FROM proxy WHERE proxy.revoked IS NULL AND proxy.proxy_id = $1 AND proxy.voter_id = $2")(g.voter, voterid);
+ if len(rv) == 0:
+ return _('Error, proxy not found.'), 400
+
+ p = db.prepare("SELECT * FROM vote WHERE motion_id = $1 AND voter_id = $2")
+ rv = p(id, voterid)
+ if len(rv) == 0:
+ db.prepare("INSERT INTO vote(motion_id, voter_id, result, proxy_id) VALUES($1,$2,$3,$4)")(id, voterid, v, g.voter)
+ else:
+ db.prepare("UPDATE vote SET result=$3, entered=CURRENT_TIMESTAMP, proxy_id=$4 WHERE motion_id=$1 AND voter_id = $2")(id, voterid, v, g.voter)
+ return motion_edited(motion)
+
+@app.route("/proxy")
+def proxy():
+ if not may_admin("proxyadmin"):
+ return _('Forbidden'), 403
+ return render_template('proxy.html', voters=get_voters(), proxies=get_all_proxies(), may_proxyadmin=may_admin("proxyadmin"), languages=get_languages())
+
+@app.route("/proxy/add", methods=['POST'])
+def add_proxy():
+ if not may_admin("proxyadmin"):
+ return _('Forbidden'), 403
+ voter=request.form.get("voter", "")
+ proxy=request.form.get("proxy", "")
+ if voter == proxy :
+ return _('Error, voter equals proxy.'), 400
+ rv = get_db().prepare("SELECT id FROM voter WHERE email=$1")(voter);
+ if len(rv) == 0:
+ return _('Error, voter not found.'), 400
+ voterid = rv[0].get("id")
+ rv = get_db().prepare("SELECT id FROM voter WHERE email=$1")(proxy);
+ if len(rv) == 0:
+ return _('Error, proxy not found.'), 400
+ proxyid = rv[0].get("id")
+ rv = get_db().prepare("SELECT id FROM proxy WHERE voter_id=$1 AND revoked is NULL")(voterid);
+ if len(rv) != 0:
+ return _('Error, proxy allready given.'), 400
+ rv = get_db().prepare("SELECT COUNT(id) as c FROM proxy WHERE proxy_id=$1 AND revoked is NULL GROUP BY proxy_id")(proxyid);
+ if len(rv) != 0:
+ if rv[0].get("c") >= max_proxy:
+ return _("Error, Max proxy for '%s' reached.") % (proxy), 400
+ rv = get_db().prepare("INSERT INTO proxy(voter_id, proxy_id, granted_by) VALUES ($1,$2,$3)")(voterid, proxyid, g.voter)
+ return rel_redirect("/proxy")
+
+@app.route("/proxy/revoke", methods=['POST'])
+def revoke_proxy():
+ if not may_admin("proxyadmin"):
+ return _('Forbidden'), 403
+ id=request.form.get("id", "")
+ rv = get_db().prepare("UPDATE proxy SET revoked=CURRENT_TIMESTAMP, revoked_by=$1 WHERE id=$2")(g.voter, int(id))
+ return rel_redirect("/proxy")
+
+@app.route("/proxy/revokeall", methods=['POST'])
+def revoke_proxy_all():
+ if not may_admin("proxyadmin"):
+ return _('Forbidden'), 403
+ rv = get_db().prepare("UPDATE proxy SET revoked=CURRENT_TIMESTAMP, revoked_by=$1 WHERE revoked IS NULL")(g.voter)
+ return rel_redirect("/proxy")