From de04e2bd443678277e50de3cda5f0cdc4ff5451c Mon Sep 17 00:00:00 2001 From: =?utf8?q?Felix=20D=C3=B6rre?= Date: Mon, 17 Aug 2020 20:33:34 +0200 Subject: [PATCH] fix things, use decorator, make stuff consistent --- README.md | 2 +- motion.py | 68 ++++++++++++++++++++------------------------ tests/test_motion.py | 10 +++---- 3 files changed, 37 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index a3fd493..6b2618d 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ The following user rights can be granted: - finish: user is able to close a running motion - audit: user is able to see given votes of a finished motion -To grant right use the following (here with vote right as example): +To grant right use the following (here with vote right as example): - on all groups add "vote:*" - on one given group add "vote:group1" - on two given groups add "vote:group1 vote:group2" diff --git a/motion.py b/motion.py index 1c83fc9..06cde68 100644 --- a/motion.py +++ b/motion.py @@ -204,35 +204,38 @@ def put_motion(): def motion_edited(motion): return rel_redirect("/?start=" + str(motion) + "#motion-" + str(motion)) - - -def validate_access(data): - rv = get_db().prepare("SELECT id, type, deadline, canceled FROM motion WHERE identifier=$1 AND host=$2")(data[0], data[1]); - if len(rv) == 0: - return "Error, Not found", 404 - id = rv[0].get("id") - if not may(data[2], rv[0].get("type")): - return "Forbidden", 403 - if rv[0].get("deadline") < datetime.now() or rv[0].get("canceled") is not None: - return "Error, out of time", 403 - return id +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 @app.route("/motion//cancel", methods=['POST']) -def cancel_motion(motion): - id = validate_access([motion, request.host, 'cancel']) - if not isinstance(id, int): - return id[0], id[1] +@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(id) @app.route("/motion//finish", methods=['POST']) -def finish_motion(motion): - id = validate_access([motion, request.host, 'finish']) - if not isinstance(id, int): - return id[0], id[1] +@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(id) @@ -252,23 +255,14 @@ def show_motion(motion): return render_template('single_motion.html', motion=rv[0], may_vote=may("vote", rv[0].get("type")), may_cancel=may("cancel", rv[0].get("type")), may_finish=may("finish", rv[0].get("type")), votes=votes, singlemotion=True) @app.route("/motion//vote", methods=['POST']) -def vote(motion): +@validate_motion_access('vote') +def vote(motion, id): v = request.form.get("vote", "abstain") db = get_db() - with db.xact(): - rv = db.prepare("SELECT id, type FROM motion WHERE identifier=$1 AND host=$2")(motion, request.host); - if len(rv) == 0: - return "Error, Not found", 404 - if not may("vote", rv[0].get("type")): - return "Forbidden", 403 - p = db.prepare("SELECT deadline > CURRENT_TIMESTAMP FROM motion WHERE identifier = $1 AND host=$2") - id = rv[0].get("id") - if not p(motion, request.host)[0][0]: - return "Error, motion deadline has passed", 500 - p = db.prepare("SELECT * FROM vote WHERE motion_id = $1 AND voter_id = $2") - rv = p(id, g.voter) - if len(rv) == 0: - db.prepare("INSERT INTO vote(motion_id, voter_id, result) VALUES($1,$2,$3)")(id, g.voter, v) - else: - db.prepare("UPDATE vote SET result=$3, entered=CURRENT_TIMESTAMP WHERE motion_id=$1 AND voter_id = $2")(id, g.voter, v) + p = db.prepare("SELECT * FROM vote WHERE motion_id = $1 AND voter_id = $2") + rv = p(id, g.voter) + if len(rv) == 0: + db.prepare("INSERT INTO vote(motion_id, voter_id, result) VALUES($1,$2,$3)")(id, g.voter, v) + else: + db.prepare("UPDATE vote SET result=$3, entered=CURRENT_TIMESTAMP WHERE motion_id=$1 AND voter_id = $2")(id, g.voter, v) return motion_edited(id) diff --git a/tests/test_motion.py b/tests/test_motion.py index 1577f3e..b6622a2 100644 --- a/tests/test_motion.py +++ b/tests/test_motion.py @@ -276,14 +276,14 @@ class VoterTests(BasicTest): def test_vote_closed(self): motion='g1.20200402.002' response = self.createVote(user, motion, 'abstain') - self.assertEqual(response.status_code, 500) - self.assertIn(str.encode('Error, motion deadline has passed'), response.data) + self.assertEqual(response.status_code, 403) + self.assertIn(str.encode('Error, out of time'), response.data) def test_vote_canceled(self): motion='g1.20200402.003' response = self.createVote(user, motion, 'abstain') - self.assertEqual(response.status_code, 500) - self.assertIn(str.encode('Error, motion deadline has passed'), response.data) + self.assertEqual(response.status_code, 403) + self.assertIn(str.encode('Error, motion was canceled'), response.data) def test_vote_not_given(self): motion='g1.30190402.001' @@ -461,7 +461,7 @@ class CreateMotionTests(BasicTest): motion='g1.20200402.004' response = self.cancelMotion(user, motion, reason) self.assertEqual(response.status_code, 403) - self.assertIn(str.encode('Error, out of time'), response.data) + self.assertIn(str.encode('Error, motion was canceled'), response.data) def test_finishMotion(self): self.db_sampledata() -- 2.39.2