]> WPIA git - motion.git/commitdiff
Merge branch 'admin_cleanup' into 'master'
authorFelix Dörre <felix@dogcraft.de>
Sun, 10 Jan 2021 22:16:14 +0000 (23:16 +0100)
committerFelix Dörre <felix@dogcraft.de>
Sun, 10 Jan 2021 22:16:14 +0000 (23:16 +0100)
add: implement motion cleanup

See merge request felixdoerre/motion!28

1  2 
motion.py
tests/test_basics.py
tests/test_motion.py

diff --combined motion.py
index 21e3e1605a39e9aa70c70e63613208a1acc47aa9,51ec30bc795d9782fce9eb6a1aed42e33d9c0c4d..c4337f98d4abe8f6c71d76f5f02e39b9ebac2482
+++ b/motion.py
@@@ -12,6 -12,7 +12,7 @@@ from datetime import date, time, dateti
  from flask_language import Language, current_language
  import gettext
  import click
+ import re
  
  def get_db():
      db = getattr(g, '_database', None)
@@@ -61,7 -62,6 +62,7 @@@ class ConfigProxy
  prefix = ConfigProxy("GROUP_PREFIX")
  times = ConfigProxy("DURATION")
  debuguser = ConfigProxy("DEBUGUSER")
 +motion_wait_minutes = ConfigProxy("MOTION_WAIT_MINUTES")
  
  max_proxy=app.config.get("MAX_PROXY")
  
@@@ -261,19 -261,13 +262,24 @@@ def init_db()
                  db.prepare("ALTER TABLE \"voter\" ALTER COLUMN \"host\" SET NOT NULL")()
                  db.prepare("UPDATE \"schema_version\" SET \"version\"=6")()
  
+         if ver < 7:
+             with app.open_resource('sql/from_6.sql', mode='r') as f:
+                 db.execute(f.read())
+                 db.prepare("UPDATE \"schema_version\" SET \"version\"=7")()
  init_db()
  
 +def is_in_ratelimit(group):
 +    rv = get_db().prepare("SELECT EXTRACT(EPOCH FROM (CURRENT_TIMESTAMP - posed)) AS timedifference FROM motion WHERE type=$1 AND host=$2 ORDER BY posed DESC LIMIT 1")(group, request.host)
 +    if len(rv) == 0:
 +        return True
 +    rate_limit = motion_wait_minutes.per_host
 +    if rate_limit is None:
 +        rate_limit = 0
 +    if rv[0]['timedifference'] > rate_limit*60:
 +        return True
 +    else:
 +        return _('Error, time between last motion to short. The current setting is %s minute(s).') % (str(rate_limit))
  
  @app.route("/")
  def main():
@@@ -305,6 -299,12 +311,12 @@@ def rel_redirect(loc)
      r.autocorrect_location_header = False
      return r
  
+ def write_proxy_log(userid, action, comment):
+     get_db().prepare("INSERT INTO adminlog(user_id, action, comment, action_user_id) VALUES($1, $2, $3, $4)")(userid, action, comment, g.voter)
+ def write_masking_log(comment):
+     get_db().prepare("INSERT INTO adminlog(user_id, action, comment, action_user_id) VALUES($1, 'motionmasking', $2, $1)")(0, comment)
  @app.route("/motion", methods=['POST'])
  def put_motion():
      cat=request.form.get("category", "")
      content=content.strip()
      if content =='':
          return _('Error, missing content'), 400
 +    ratelimit = is_in_ratelimit(cat)
 +    if ratelimit is not True:
 +        return ratelimit, 400
  
      db = get_db()
      with db.xact():
@@@ -466,6 -463,7 +478,7 @@@ def add_proxy()
          if rv[0].get("c") is None or 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)
+     write_proxy_log(voterid, 'proxygranted', 'proxy: '+str(proxyid))
      return rel_redirect("/proxy")
  
  @app.route("/proxy/revoke", methods=['POST'])
@@@ -474,6 -472,7 +487,7 @@@ def revoke_proxy()
          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))
+     write_proxy_log(int(id), 'proxyrevoked', '')
      return rel_redirect("/proxy")
  
  @app.route("/proxy/revokeall", methods=['POST'])
@@@ -481,6 -480,7 +495,7 @@@ 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)
+     write_proxy_log(g.voter, 'proxyrevokedall', '')
      return rel_redirect("/proxy")
  
  @app.route("/language/<string:language>")
@@@ -500,3 -500,25 +515,25 @@@ def create_user(email, host)
              db.prepare("INSERT INTO voter(\"email\", \"host\") VALUES($1, $2)")(email, host)
              messagetext=_("User '%s' inserted to %s.") % (email, host)
      click.echo(messagetext)
+ @app.cli.command("motion-masking")
+ @click.argument("motion")
+ @click.argument("motionreason")
+ @click.argument("host")
+ def motion_masking(motion, motionreason, host):
+     if re.search(r"[%_\\]", motion):
+         messagetext = _("No wildcards allowed for motion entry '%s'.") % (motion)
+         click.echo(messagetext)
+     else:
+         db = get_db()
+         with db.xact():
+             rv = db.prepare("SELECT id FROM motion WHERE identifier LIKE $1 AND host = $2")(motion+"%", host)
+             count = len(rv)
+             messagetext = _("%s record(s) affected by masking of '%s'.") % (count, motion)
+             click.echo(messagetext)
+             if len(rv) != 0:
+                 rv = db.prepare("SELECT id FROM motion WHERE content LIKE $1 AND host = $2")('%'+motionreason+"%", host)
+                 rv = db.prepare("UPDATE motion SET name=$3, content=$4 WHERE identifier LIKE $1 AND host = $2 RETURNING id ")(motion+"%", host, _("Motion masked"), _("Motion masked on base of motion [%s](%s) on %s") % (motionreason, motionreason, datetime.now().strftime("%Y-%m-%d")))
+                 messagetext = _("%s record(s) updated by masking of '%s'.") % (len(rv), motion)
+                 write_masking_log(_("%s motion(s) masked on base of motion %s with motion identifier '%s' on host %s") %(len(rv), motionreason, motion, host))
+                 click.echo(messagetext)
diff --combined tests/test_basics.py
index b6f111cb6660c49a4dae7d136ac6911574b501b2,85dc7b6690bc90ddca4e264cbf27fa604907c911..0f27f48a2a84a7068b34f2f8b38bbe3db7b72199
@@@ -17,6 -17,7 +17,6 @@@ app.config.update
  app.config['TESTING'] = True
  app.config['DEBUG'] = False
  
 -
  class BasicTest(TestCase):
  
      def init_test(self):
              + '\nNo <span class=\"badge badge-pill badge-secondary\">'+str(no)+'</span><br>'\
              + '\nAbstain <span class=\"badge badge-pill badge-secondary\">'+str(abstain)+'</span>'
  
+     # functions handling or using database
      def open_DB(self):
          return postgresql.open(app.config.get("DATABASE"), user=app.config.get("USER"), password=app.config.get("PASSWORD"))
  
+     def db_select(self, sql, parameter):
+         with self.open_DB() as db:
+             rv = db.prepare(sql)(parameter)
+             return rv
+     def db_select2(self, sql, parameter, parameter2):
+         with self.open_DB() as db:
+             rv = db.prepare(sql)(parameter, parameter2)
+             return rv
+     def recordCountLog(self, parameter):
+         return self.recordCount("SELECT * FROM adminlog WHERE action=$1", parameter)
+     def recordCount(self, sql, parameter):
+         rv = self.db_select(sql, parameter)
+         return len(rv)
+     def logRecordDetailsTest(self, parameter, recordno, voterid, comment, actionuserid):
+         rv = self.db_select("SELECT * FROM adminlog WHERE action=$1 ORDER BY id", parameter)
+         self.assertEqual(voterid, rv[recordno].get("user_id"))
+         if comment:
+             self.assertEqual(comment, rv[recordno].get("comment"))
+         else:
+             self.assertEqual('', rv[recordno].get("comment"))
+         self.assertEqual(actionuserid, rv[recordno].get("action_user_id"))
+     
      # functions to clear database
      def db_clear(self):
          with self.open_DB() as db:
diff --combined tests/test_motion.py
index 7ef5ceac11c309943e8fdb0e910d999c8e051bef,f6992968ff128e05375539cc51ba1d4f19e9ff54..b1ec4335b59fdb04154bb4bccccea2174ae40d76
@@@ -1,5 -1,6 +1,5 @@@
  from datetime import datetime
  from tests.test_basics import BasicTest
 -import postgresql
  from motion import app
  
  # no specific rights required
@@@ -478,24 -479,6 +478,24 @@@ class CreateMotionTests(BasicTest)
          self.assertEqual(response.status_code, 403)
          self.assertIn(str.encode('Error, out of time'), response.data)
  
 +    def test_createMotionWait(self):
 +        # test no limit given
 +        self.db_sampledata()
 +        title='My Motion'
 +        content='My body'
 +        response = self.createMotion(user, title, content, '3', 'group1')
 +        self.assertEqual(response.status_code, 302)
 +
 +        # test different host
 +        app.config.update(MOTION_WAIT_MINUTES={'127.0.0.1:5001':1})
 +        response = self.createMotion(user, title, content, '3', 'group1')
 +        self.assertEqual(response.status_code, 302)
 +
 +        # test 3 minutes
 +        app.config.update(MOTION_WAIT_MINUTES={'127.0.0.1:5000':3})
 +        response = self.createMotion(user, title, content, '3', 'group1')
 +        self.assertIn(str.encode('Error, time between last motion to short. The current setting is 3 minute(s).'), response.data)
 +
  class AuditMotionTests(BasicTest):
  
      def setUp(self):
              + '\n    <div>User C: no</div>\n  </div>\n</div>\n<a href="/?start=2#motion-2" class="btn btn-primary">Back</a>'
          self.assertIn(str.encode(testtext), result.data)
  
- class ProxyManagementTests(BasicTest):
-     def setUp(self):
-         self.init_test()
-         global user
-         user='testuser/proxyadmin:*'
-         global userid
-         userid=4
-         self.db_sampledata()
-     def tearDown(self):
-         pass
-     def test_see_proxy(self):
-         result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
-         testtext= 'div class="container">\n<form action="/proxy/add" method="POST">'
-         self.assertIn(str.encode(testtext), result.data)
-         testtext= 'proxy granted to:'
-         self.assertNotIn(str.encode(testtext), result.data)
-         testtext= 'holds proxy of:'
-         self.assertNotIn(str.encode(testtext), result.data)
-         testtext= '<select class="float form-control" name="voter">\n        '\
-             + '<option>User A</option>\n        <option>User B</option>\n        '\
-             + '<option>User C</option>\n        '\
-             + '<option>testuser</option>\n      '\
-             + '</select>\n'
-         self.assertIn(str.encode(testtext), result.data)
-         testtext= '<select class="float form-control" name="proxy">\n          '\
-             + '<option>User A</option>\n          '\
-             + '<option>User B</option>\n          '\
-             + '<option>User C</option>\n          '\
-             + '<option>testuser</option>\n      '\
-             + '</select>\n'
-         self.assertIn(str.encode(testtext), result.data)
-         testtext= '<table>\n      '\
-             + '<thead>\n        '\
-             + '<th>Voter</th>\n        <th>Proxy</th>\n        <th></th>\n      </thead>\n    '\
-             + '</table>\n'
-         self.assertIn(str.encode(testtext), result.data)
-         testtext= '<a class="nav-link" href="/proxy">Proxy management</a>'
-         self.assertIn(str.encode(testtext), result.data)
-     def test_add_proxy(self):
-         voter=''
-         proxy=''
-         response = self.addProxy(user, voter, proxy)
-         self.assertEqual(response.status_code, 400)
-         self.assertIn(str.encode('Error, voter equals proxy.'), response.data)
-         voter='User A'
-         response = self.addProxy(user, voter, proxy)
-         self.assertEqual(response.status_code, 400)
-         self.assertIn(str.encode('Error, proxy not found.'), response.data)
-         voter='User Z'
-         response = self.addProxy(user, voter, proxy)
-         self.assertEqual(response.status_code, 400)
-         self.assertIn(str.encode('Error, voter not found.'), response.data)
-         voter=''
-         proxy='User B'
-         response = self.addProxy(user, voter, proxy)
-         self.assertEqual(response.status_code, 400)
-         self.assertIn(str.encode('Error, voter not found.'), response.data)
-         voter='User B'
-         proxy='User B'
-         response = self.addProxy(user, voter, proxy)
-         self.assertEqual(response.status_code, 400)
-         self.assertIn(str.encode('Error, voter equals proxy.'), response.data)
-         
-         voter='User A'
-         proxy='User Z'
-         response = self.addProxy(user, voter, proxy)
-         self.assertEqual(response.status_code, 400)
-         self.assertIn(str.encode('Error, proxy not found.'), response.data)
-         voter='User A'
-         proxy='User B'
-         response = self.addProxy(user, voter, proxy)
-         self.assertEqual(response.status_code, 302)
-         result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
-         testtext= '<form action="/proxy/revoke" method="POST">'
-         self.assertIn(str.encode(testtext), result.data)
-         testtext= '<table>\n      '\
-             + '<thead>\n        '\
-             + '<th>Voter</th>\n        '\
-             + '<th>Proxy</th>\n        <th></th>\n      </thead>\n      '\
-             + '<tr>\n        <td>User A</td>\n        <td>User B</td>\n        '\
-             + '<td><button type="submit" class="btn btn-danger" name="id" value="1">Revoke</button></td>\n      '\
-             + '</tr>\n    </table>\n'
-         self.assertIn(str.encode(testtext), result.data)
-         response = self.addProxy(user, voter, proxy)
-         self.assertEqual(response.status_code, 400)
-         self.assertIn(str.encode('Error, proxy allready given.'), response.data)
-         voter='User A'
-         proxy='User C'
-         response = self.addProxy(user, voter, proxy)
-         self.assertEqual(response.status_code, 400)
-         self.assertIn(str.encode('Error, proxy allready given.'), response.data)
-         voter='User C'
-         proxy='User B'
-         response = self.addProxy(user, voter, proxy)
-         self.assertEqual(response.status_code, 302)
-         result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
-         testtext= '<table>\n      '\
-             + '<thead>\n        '\
-             + '<th>Voter</th>\n        '\
-             + '<th>Proxy</th>\n        <th></th>\n      </thead>\n      '\
-             + '<tr>\n        <td>User A</td>\n        <td>User B</td>\n        '\
-             + '<td><button type="submit" class="btn btn-danger" name="id" value="1">Revoke</button></td>\n      </tr>\n      '\
-             + '<tr>\n        <td>User C</td>\n        <td>User B</td>\n        '\
-             + '<td><button type="submit" class="btn btn-danger" name="id" value="2">Revoke</button></td>\n      '\
-             + '</tr>\n    </table>\n'
-         self.assertIn(str.encode(testtext), result.data)
-         testtext= 'proxy granted to:'
-         self.assertNotIn(str.encode(testtext), result.data)
-         testtext= 'holds proxy of:'
-         self.assertNotIn(str.encode(testtext), result.data)
-         voter='testuser'
-         proxy='User B'
-         response = self.addProxy(user, voter, proxy)
-         self.assertEqual(response.status_code, 400)
-         self.assertIn(str.encode('Error, Max proxy for \'User B\' reached.'), response.data)
-         
-         voter='testuser'
-         proxy='User A'
-         response = self.addProxy(user, voter, proxy)
-         self.assertEqual(response.status_code, 302)
-         result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
-         testtext= '<table>\n      '\
-             + '<thead>\n        '\
-             + '<th>Voter</th>\n        <th>Proxy</th>\n        <th></th>\n      </thead>\n      '\
-             + '<tr>\n        <td>testuser</td>\n        <td>User A</td>\n        '\
-             + '<td><button type="submit" class="btn btn-danger" name="id" value="3">Revoke</button></td>\n      </tr>\n      '\
-             + '<tr>\n        <td>User A</td>\n        <td>User B</td>\n        '\
-             + '<td><button type="submit" class="btn btn-danger" name="id" value="1">Revoke</button></td>\n      </tr>\n      '\
-             + '<tr>\n        <td>User C</td>\n        <td>User B</td>\n        '\
-             + '<td><button type="submit" class="btn btn-danger" name="id" value="2">Revoke</button></td>\n      '\
-             + '</tr>\n    </table>\n'
-         self.assertIn(str.encode(testtext), result.data)
-         testtext= 'proxy granted to: User A\n'
-         self.assertIn(str.encode(testtext), result.data)
-         testtext= 'holds proxy of:'
-         self.assertNotIn(str.encode(testtext), result.data)
-         voter='User B'
-         proxy='testuser'
-         response = self.addProxy(user, voter, proxy)
-         self.assertEqual(response.status_code, 302)
-         result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
-         testtext= '<table>\n      '\
-             + '<thead>\n        '\
-             + '<th>Voter</th>\n        <th>Proxy</th>\n        <th></th>\n      </thead>\n      '\
-             + '<tr>\n        <td>testuser</td>\n        <td>User A</td>\n        '\
-             + '<td><button type="submit" class="btn btn-danger" name="id" value="3">Revoke</button></td>\n      </tr>\n      '\
-             + '<tr>\n        <td>User A</td>\n        <td>User B</td>\n        '\
-             + '<td><button type="submit" class="btn btn-danger" name="id" value="1">Revoke</button></td>\n      </tr>\n      '\
-             + '<tr>\n        <td>User B</td>\n        <td>testuser</td>\n        '\
-             + '<td><button type="submit" class="btn btn-danger" name="id" value="4">Revoke</button></td>\n      </tr>\n      '\
-             + '<tr>\n        <td>User C</td>\n        <td>User B</td>\n        '\
-             + '<td><button type="submit" class="btn btn-danger" name="id" value="2">Revoke</button></td>\n      '\
-             + '</tr>\n    </table>\n'
-         self.assertIn(str.encode(testtext), result.data)
-         testtext= 'proxy granted to: User A\n'
-         self.assertIn(str.encode(testtext), result.data)
-         testtext= 'holds proxy of: User B\n'
-         self.assertIn(str.encode(testtext), result.data)
-         response = self.revokeProxy(user, userid)
-         self.assertEqual(response.status_code, 302)
-         result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
-         testtext= '<table>\n      '\
-             + '<thead>\n        '\
-             + '<th>Voter</th>\n        <th>Proxy</th>\n        <th></th>\n      </thead>\n      '\
-             + '<tr>\n        <td>testuser</td>\n        <td>User A</td>\n        '\
-             + '<td><button type="submit" class="btn btn-danger" name="id" value="3">Revoke</button></td>\n      </tr>\n      '\
-             + '<tr>\n        <td>User A</td>\n        <td>User B</td>\n        '\
-             + '<td><button type="submit" class="btn btn-danger" name="id" value="1">Revoke</button></td>\n      </tr>\n      '\
-             + '<tr>\n        <td>User C</td>\n        <td>User B</td>\n        '\
-             + '<td><button type="submit" class="btn btn-danger" name="id" value="2">Revoke</button></td>\n      '\
-             + '</tr>\n    </table>\n'
-         self.assertIn(str.encode(testtext), result.data)
-         testtext= 'proxy granted to: User A\n'
-         self.assertIn(str.encode(testtext), result.data)
-         testtext= 'holds proxy of:'
-         self.assertNotIn(str.encode(testtext), result.data)
-         response = self.revokeProxy(user, 3)
-         self.assertEqual(response.status_code, 302)
-         result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
-         testtext= '<table>\n      '\
-             + '<thead>\n        '\
-             + '<th>Voter</th>\n        <th>Proxy</th>\n        <th></th>\n      </thead>\n      '\
-             + '<tr>\n        <td>User A</td>\n        <td>User B</td>\n        '\
-             + '<td><button type="submit" class="btn btn-danger" name="id" value="1">Revoke</button></td>\n      </tr>\n      '\
-             + '<tr>\n        <td>User C</td>\n        <td>User B</td>\n        '\
-             + '<td><button type="submit" class="btn btn-danger" name="id" value="2">Revoke</button></td>\n      '\
-             + '</tr>\n    </table>\n'
-         self.assertIn(str.encode(testtext), result.data)
-         testtext= 'proxy granted to:'
-         self.assertNotIn(str.encode(testtext), result.data)
-         testtext= 'holds proxy of:'
-         self.assertNotIn(str.encode(testtext), result.data)
-         result = self.app.post('proxy/revokeall', environ_base={'USER_ROLES': user}, follow_redirects=True)
-         self.assertEqual(response.status_code, 302)
-         result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
-         testtext= '<table>\n      '\
-             + '<thead>\n        '\
-             + '<th>Voter</th>\n        <th>Proxy</th>\n        <th></th>\n      </thead>\n'\
-             + '</table>\n'
-         self.assertNotIn(str.encode(testtext), result.data)
-         proxytest="proxytest"
-         with self.open_DB() as db:
-             db.prepare("INSERT INTO voter(\"email\", \"host\") VALUES($1, $2)")(proxytest, '127.0.0.1:5001')
-         result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
-         response = self.addProxy(user, proxytest, 'testuser')
-         self.assertEqual(response.status_code, 400)
-         self.assertIn(str.encode('Error, voter not found.'), response.data)
-         response = self.addProxy(user, 'testuser', proxytest)
-         self.assertEqual(response.status_code, 400)
-         self.assertIn(str.encode('Error, proxy not found.'), response.data)
-     def test_see_proxy_host_only(self):
-         proxytest="proxytest"
-         with self.open_DB() as db:
-             db.prepare("INSERT INTO voter(\"email\", \"host\") VALUES($1, $2)")(proxytest, '127.0.0.1:5001')
-         result = self.app.get('proxy', environ_base={'USER_ROLES': user}, follow_redirects=True)
-         testtext= 'div class="container">\n<form action="/proxy/add" method="POST">'
-         self.assertIn(str.encode(testtext), result.data)
-         testtext= 'proxy granted to:'
-         self.assertNotIn(str.encode(testtext), result.data)
-         testtext= 'holds proxy of:'
-         self.assertNotIn(str.encode(testtext), result.data)
-         testtext= '<select class="float form-control" name="voter">\n        '\
-             + '<option>User A</option>\n        <option>User B</option>\n        '\
-             + '<option>User C</option>\n        '\
-             + '<option>testuser</option>\n      '\
-             + '</select>\n'
-         self.assertIn(str.encode(testtext), result.data)
-         testtext= '<select class="float form-control" name="proxy">\n          '\
-             + '<option>User A</option>\n          '\
-             + '<option>User B</option>\n          '\
-             + '<option>User C</option>\n          '\
-             + '<option>testuser</option>\n      '\
-             + '</select>\n'
-         self.assertIn(str.encode(testtext), result.data)
-         self.assertNotIn(str.encode(proxytest), result.data)
- class ProxyVoteTests(BasicTest):
-     def setUp(self):
-         self.init_test()
-         global user
-         user='testuser/vote:* proxyadmin:*'
-         self.db_sampledata()
-     def tearDown(self):
-         pass
-     def test_proxy_vote(self):
-         voter='testuser'
-         proxy='User B'
-         proxyid=2
-         proxyuser='User B/vote:*'
-         response = self.addProxy(user, proxy, voter)
-         self.assertEqual(response.status_code, 302)
-         motion='g1.20200402.004'
-         response = self.createVote(user, motion, 'yes', proxyid)
-         self.assertEqual(response.status_code, 302)
-         # testuser view
-         result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
-         # own vote without change
-         testtext= '<form action="/motion/g1.20200402.004/vote/4" method="POST">\n'\
-             + '<button type="submit" class="btn btn-primary" name="vote" value="yes" id="vote-yes">Yes</button>\n'\
-             + '<button type="submit" class="btn btn-primary" name="vote" value="no" id="vote-no">No</button>\n'\
-             + '<button type="submit" class="btn btn-primary" name="vote" value="abstain" id="vote-abstain">Abstain</button>\n</form>'
-         self.assertIn(str.encode(testtext), result.data)
-         # proxy vote with change
-         testtext= '<form action="/motion/g1.20200402.004/vote/2" method="POST">\n'\
-             + '<button type="submit" class="btn btn-success" name="vote" value="yes" id="vote-yes">Yes</button>\n'\
-             + '<button type="submit" class="btn btn-primary" name="vote" value="no" id="vote-no">No</button>\n'\
-             + '<button type="submit" class="btn btn-primary" name="vote" value="abstain" id="vote-abstain">Abstain</button>\n</form>\n'
-         self.assertIn(str.encode(testtext), result.data)
-         
-         # User B view
-         result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': proxyuser}, follow_redirects=True)
-         # own vote without change
-         testtext= '<h3>My vote</h3>\nGiven by testuser\n'\
-             + '<form action="/motion/g1.20200402.004/vote/2" method="POST">\n'\
-             + '<button type="submit" class="btn btn-success" name="vote" value="yes" id="vote-yes">Yes</button>\n'\
-             + '<button type="submit" class="btn btn-primary" name="vote" value="no" id="vote-no">No</button>\n'\
-             + '<button type="submit" class="btn btn-primary" name="vote" value="abstain" id="vote-abstain">Abstain</button>\n</form>'
-         self.assertIn(str.encode(testtext), result.data)
-         
-         # change vote
-         response = self.createVote(user, motion, 'no', proxyid)
-         self.assertEqual(response.status_code, 302)
-         result = self.app.get('/motion/' + motion, environ_base={'USER_ROLES': user}, follow_redirects=True)
-         testtext= '<form action="/motion/g1.20200402.004/vote/2" method="POST">\n'\
-             + '<button type="submit" class="btn btn-primary" name="vote" value="yes" id="vote-yes">Yes</button>\n'\
-             + '<button type="submit" class="btn btn-success" name="vote" value="no" id="vote-no">No</button>\n'\
-             + '<button type="submit" class="btn btn-primary" name="vote" value="abstain" id="vote-abstain">Abstain</button>\n</form>\n'
-         self.assertIn(str.encode(testtext), result.data)
-     def test_proxy_vote_no_proxy(self):
-         voter='testuser'
-         proxy='User B'
-         # wrong proxy id
-         proxyid=3
-         response = self.addProxy(user, proxy, voter)
-         self.assertEqual(response.status_code, 302)
-         motion='g1.20200402.004'
-         response = self.createVote(user, motion, 'yes', proxyid)
-         self.assertEqual(response.status_code, 400)
-         self.assertIn(str.encode('Error, proxy not found'), response.data)
-         
-         # non existing id
-         proxyid=10000
-         motion='g1.20200402.004'
-         response = self.createVote(user, motion, 'yes', proxyid)
-         self.assertEqual(response.status_code, 400)
-         self.assertIn(str.encode('Error, proxy not found'), response.data)
-     def test_proxy_vote_no_voter(self):
-         voter='User A'
-         proxy='User B'
-         proxyid=2
-         response = self.addProxy(user, proxy, voter)
-         self.assertEqual(response.status_code, 302)
-         user1='testuser1/'
-         motion='g1.20200402.004'
-         response = self.createVote(user1, motion, 'yes', proxyid)
-         self.assertEqual(response.status_code, 403)
-         self.assertIn(str.encode('Forbidden'), response.data)
  
  if __name__ == "__main__":
      unittest.main()