Author: humbedooh
Date: Wed Mar 18 12:17:02 2015
New Revision: 1667520

URL: http://svn.apache.org/r1667520
Log:
First stab at a REST API for STeVe in Python (via CGI).
This just contains the backend API for setting up and viewing elections and 
issues, nothing else.
Voting via API is not implemented yet.
No authentication feature yet either.

Added:
    steve/trunk/pytest/
    steve/trunk/pytest/REST_API_README.txt
    steve/trunk/pytest/httpd.conf
    steve/trunk/pytest/steve.cfg
    steve/trunk/pytest/www/
    steve/trunk/pytest/www/cgi-bin/
    steve/trunk/pytest/www/cgi-bin/lib/
    steve/trunk/pytest/www/cgi-bin/lib/__init__.py
    steve/trunk/pytest/www/cgi-bin/lib/response.py
    steve/trunk/pytest/www/cgi-bin/rest_admin.py
    steve/trunk/pytest/www/cgi-bin/rest_voter.py
    steve/trunk/pytest/www/htdocs/

Added: steve/trunk/pytest/REST_API_README.txt
URL: 
http://svn.apache.org/viewvc/steve/trunk/pytest/REST_API_README.txt?rev=1667520&view=auto
==============================================================================
--- steve/trunk/pytest/REST_API_README.txt (added)
+++ steve/trunk/pytest/REST_API_README.txt Wed Mar 18 12:17:02 2015
@@ -0,0 +1,274 @@
+##################
+# ADMIN REST API #
+##################
+
+==========================
+Setting up a new election:
+==========================
+
+/steve/admin/setup/$electionid
+  POST
+    input: 
+          title: Title of the election
+          owner: uid of election owner
+          monitors: email addresses of monitors
+          starts: UNIX timestamp of start (optional)
+          ends: UNIX timestamp when it closes (optional)
+    output:
+      HTTP 201 Created on success
+      HTTP 400 Bad request if params missing or invalid or already exists
+      HTTP 500 on error
+    response payload:
+       JSON formatted
+        {
+        "message": "created"
+        }
+        
+==============================
+Editing an existing election:
+==============================
+
+/steve/admin/edit/$electionid
+  POST
+    input: 
+          title: Title of the election (optional)
+          owner: uid of election owner (optional)
+          monitors: email addresses of monitors (optional)
+          starts: UNIX timestamp of start (optional)
+          ends: UNIX timestamp when it closes (optional)
+    output:
+      HTTP 200 Saved on success
+      HTTP 404 Not Found if no such election
+      HTTP 500 on error
+    response payload:
+       JSON formatted
+        {
+        "message": "Changes saved"
+        }
+        
+        
+        
+=================================
+Creating an issue in an election:
+=================================
+
+/steve/admin/create/$electionid/$issueid
+  POST
+    input: 
+          title: Title of the issue
+          description: (optional) Description of the issue
+          type: type of issue (yna, stv[1-9])
+          candidates: (if stv[1-9]) \n separated list of candidate names
+          nominatedby: (if YNA) Person to nominate this issue
+          seconds: (if YNA) \n separated list of seconds for the issue
+          
+    output:
+      HTTP 201 Created on success
+      HTTP 400 Bad request if params missing or invalid or already exists
+      HTTP 500 on error
+    response payload:
+       JSON formatted
+        {
+        "message": "created"
+        }
+       
+        
+================================
+Editing an issue in an election:
+================================
+
+/steve/admin/edit/$electionid/$issueid
+  POST
+    input: 
+          title: Title of the issue (optional)
+          description: (optional) Description of the issue (optional)
+          type: type of issue (yna, stv[1-9]) (optional)
+          candidates: (if stv[1-9]) \n separated list of candidate names 
(optional)
+          nominatedby: (if YNA) Person to nominate this issue (optional)
+          seconds: (if YNA) \n separated list of seconds for the issue 
(optional)
+          
+    output:
+      HTTP 200 Saved on success
+      HTTP 404 Not Found if no such issue or election
+      HTTP 500 on error
+    response payload:
+       JSON formatted
+        {
+        "message": "Changes saved"
+        }
+        
+        
+==================================
+Adding a statement to a candidate:
+==================================
+
+/steve/admin/statement/$electionid/$issueid
+  POST
+    input: 
+          candidate: Candidate to set statement for
+          statement: Statement to set/add
+          
+    output:
+      HTTP 200 Saved on success
+      HTTP 400 Bad request if params missing
+      HTTP 404 Not Found if candidate is not on the ballot
+      HTTP 500 on error
+    response payload:
+       JSON formatted
+        {
+        "message": "Changes saved"
+        }
+
+        
+================================
+Adding a candidate to the issue:
+================================
+
+/steve/admin/addcandidate/$electionid/$issueid
+  POST
+    input: 
+          candidate: Candidate to set add
+          statement: Statement to set/add (optional)
+          
+    output:
+      HTTP 200 Saved on success
+      HTTP 400 Bad request if params missing
+      HTTP 404 Not Found if no such issue/election
+      HTTP 500 on error
+    response payload:
+       JSON formatted
+        {
+        "message": "Changes saved"
+        }
+
+
+===================================
+Deleting a candidate to the issue:
+===================================
+
+/steve/admin/delcandidate/$electionid/$issueid
+  POST
+    input: 
+          candidate: Candidate to delete
+          
+    output:
+      HTTP 200 Saved on success
+      HTTP 400 Bad request if params missing
+      HTTP 404 Not Found if candidate is not on the ballot
+      HTTP 500 on error
+    response payload:
+       JSON formatted
+        {
+        "message": "Changes saved"
+        }
+
+
+
+
+
+
+##################
+# VOTER REST API #
+##################
+
+============================
+Viewing election and issues:
+============================
+
+/steve/voter/view/$electionid
+  GET
+    input:
+      none
+    output:
+      HTTP 200 Okay if election exists
+      HTTP 404 Not Found if no such election
+    response payload:
+      JSON formatted
+        {
+        "base_data": {
+            "owner": "humbedooh", 
+            "starts": null, 
+            "ends": null, 
+            "monitors": [
+                "[email protected]"
+            ], 
+            "title": "Foo Elections, 2015"
+        }, 
+        "baseurl": "https://stv.website/steve/election?foo";, 
+        "issues": [
+            {
+                "description": null, 
+                "title": "Test Board Election", 
+                "APIURL": "https://stv.website/steve/voter/view/foo/baz";, 
+                "prettyURL": "https://stv.website/steve/ballot?foo/baz";, 
+                "candidates": [
+                    {
+                        "name": "Just One Guy"
+                    }, 
+                    {
+                        "name": "John Doe", 
+                        "statement": "Vote for me!"
+                    }, 
+                    {
+                        "name": "Kate Smurf", 
+                        "statement": "Vote for me too!"
+                    }
+                ], 
+                "type": "stv6", 
+                "id": "baz"
+            }, 
+            {
+                "description": "This is to nominate WALL-E for ASF 
membership", 
+                "title": "Membership for WALL-E", 
+                "seconds": "humbedooh", 
+                "APIURL": 
"https://stv.website/steve/voter/view/foo/member-wall-e";, 
+                "prettyURL": 
"https://stv.website/steve/ballot?foo/member-wall-e";, 
+                "candidates": [], 
+                "nominatedby": "mattman", 
+                "type": "yna", 
+                "id": "member-wall-e"
+            }
+        ]
+    }
+    
+    
+=======================
+Viewing a single issue:
+=======================
+/steve/voter/view/$electionid/$issueid
+  GET
+    input:
+      none
+    output:
+      HTTP 200 Okay if issue exists
+      HTTP 404 Not Found if no such election/issue
+    response payload:
+      JSON formatted
+        {
+          "issue": {
+              "description": null, 
+              "title": "Test Board Election", 
+              "APIURL": "https://stv.website/steve/voter/view/foo/baz";, 
+              "prettyURL": "https://stv.website/steve/ballot?foo/baz";, 
+              "candidates": [
+                  {
+                      "name": "Just One Guy"
+                  }, 
+                  {
+                      "name": "John Doe", 
+                      "statement": "Vote for me!"
+                  }, 
+                  {
+                      "name": "Kate Smurf", 
+                      "statement": "Vote for me too!"
+                  }
+              ], 
+              "type": "stv6", 
+              "id": "baz"
+          }
+      }
+      
+      
+      
+      
+MORE TO COME!
\ No newline at end of file

Added: steve/trunk/pytest/httpd.conf
URL: 
http://svn.apache.org/viewvc/steve/trunk/pytest/httpd.conf?rev=1667520&view=auto
==============================================================================
--- steve/trunk/pytest/httpd.conf (added)
+++ steve/trunk/pytest/httpd.conf Wed Mar 18 12:17:02 2015
@@ -0,0 +1,22 @@
+# Sample httpd configuration for Steve's Python REST API test
+# see http://stv.website/steve/voter/view/foo for an example.
+
+<VirtualHost *80>
+DocumentRoot /home/voter/pytest/www/htdocs
+ServerName stv.website
+DirectoryIndex index.html
+<Directory /home/voter/pytest/www>
+  Require all granted
+  Options +ExecCGI
+  AddHandler cgi-script .py
+</Directory>
+
+# REST API
+ScriptAlias /steve/admin /home/voter/pytest//www/cgi-bin/rest_admin.py
+ScriptAlias /steve/voter /home/voter/pytest/www/cgi-bin/rest_voter.py
+
+# HTML generators
+ScriptAlias /steve/ballot /home/voter/pytest/www/cgi-bin/html_ballot.py
+ScriptAlias /steve/election /home/voter/pytest/www/cgi-bin/html_election.py
+
+</VirtualHost>

Added: steve/trunk/pytest/steve.cfg
URL: 
http://svn.apache.org/viewvc/steve/trunk/pytest/steve.cfg?rev=1667520&view=auto
==============================================================================
--- steve/trunk/pytest/steve.cfg (added)
+++ steve/trunk/pytest/steve.cfg Wed Mar 18 12:17:02 2015
@@ -0,0 +1,3 @@
+[general]
+
+homedir:            /home/voter

Added: steve/trunk/pytest/www/cgi-bin/lib/__init__.py
URL: 
http://svn.apache.org/viewvc/steve/trunk/pytest/www/cgi-bin/lib/__init__.py?rev=1667520&view=auto
==============================================================================
--- steve/trunk/pytest/www/cgi-bin/lib/__init__.py (added)
+++ steve/trunk/pytest/www/cgi-bin/lib/__init__.py Wed Mar 18 12:17:02 2015
@@ -0,0 +1,3 @@
+"""
+Stuff
+"""
\ No newline at end of file

Added: steve/trunk/pytest/www/cgi-bin/lib/response.py
URL: 
http://svn.apache.org/viewvc/steve/trunk/pytest/www/cgi-bin/lib/response.py?rev=1667520&view=auto
==============================================================================
--- steve/trunk/pytest/www/cgi-bin/lib/response.py (added)
+++ steve/trunk/pytest/www/cgi-bin/lib/response.py Wed Mar 18 12:17:02 2015
@@ -0,0 +1,21 @@
+#!/usr/bin/env python
+import json
+
+responseCodes = {
+    200: 'Okay',
+    201: 'Created',
+    304: 'Not Modified',
+    400: 'Bad Request',
+    403: 'Access denied',
+    404: 'Not Found',
+    500: 'Server Error'
+}
+
+def respond(code, js):
+    c = responseCodes[code] if code in responseCodes else "Unknown Response 
Code(?)"
+    out = json.dumps(js, indent=4)
+    print("Status: %u %s\r\nContent-Type: application/json\r\nContent-Length: 
%u\r\n" % (code, c, len(out)))
+    print(out)
+    
+    
+    
\ No newline at end of file

Added: steve/trunk/pytest/www/cgi-bin/rest_admin.py
URL: 
http://svn.apache.org/viewvc/steve/trunk/pytest/www/cgi-bin/rest_admin.py?rev=1667520&view=auto
==============================================================================
--- steve/trunk/pytest/www/cgi-bin/rest_admin.py (added)
+++ steve/trunk/pytest/www/cgi-bin/rest_admin.py Wed Mar 18 12:17:02 2015
@@ -0,0 +1,301 @@
+#!/usr/bin/env python
+#####
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#####
+import os, sys, json, re, time, base64, cgi, subprocess, hashlib
+version = 2
+if sys.hexversion < 0x03000000:
+    import ConfigParser as configparser
+else:
+    import configparser
+    version = 3
+
+path = os.path.abspath(os.getcwd())
+
+sys.path.append(path)
+sys.path.append(os.path.basename(sys.argv[0]))
+if 'SCRIPT_FILENAME' in os.environ:
+    sys.path.insert(0, os.path.basename(os.environ['SCRIPT_FILENAME']))
+    
+from lib import response
+
+
+# Fetch config (hack, hack, hack)
+config = configparser.RawConfigParser()
+config.read(path + '/../../steve.cfg')
+
+# Some quick paths
+homedir = config.get("general", "homedir")
+pathinfo = os.environ['PATH_INFO'] if 'PATH_INFO' in os.environ else None
+form = cgi.FieldStorage();
+
+
+
+# TODO: Authentication goes here
+karma = 5 # assume admin karma for now
+
+# Figure out what to do and where
+if pathinfo:
+    l = pathinfo.split("/")
+    if l[0] == "":
+        l.pop(0)
+    action = l[0]
+    election = l[1] if len(l) > 1 else None
+
+
+    # Set up new election?
+    if action == "setup":
+        if karma >= 5: # karma of 5 required to set up an election base
+            if election:
+                if os.path.isdir(os.path.join(homedir, "issues", election)):
+                    response.respond(403, {'message': "Election already 
exists!"})
+                else:
+                    try:
+                        required = ['title','owner','monitors']
+                        xr = required
+                        for i in required:
+                            if not form.getvalue(i):
+                                raise Exception("Required fields missing: %s" 
% ", ".join(xr))
+                            else:
+                                xr.pop(0)
+                        elpath = os.path.join(homedir, "issues", election)
+                        os.mkdir(elpath)
+                        with open(elpath  + "/basedata.json", "w") as f:
+                            f.write(json.dumps({
+                                'title': form.getvalue('title'),
+                                'owner': form.getvalue('owner'),
+                                'monitors': 
form.getvalue('monitors').split(","),
+                                'starts': form.getvalue('starts'),
+                                'ends': form.getvalue('ends')
+                            }))
+                            f.close()
+                        response.respond(201, {'message': 'Created!'})
+                    except Exception as err:
+                        response.respond(500, {'message': "Could not create 
election: %s" % err})
+            else:
+                response.respond(400, {'message': "No election name 
specified!"})
+        else:
+            response.respond(403, {'message': 'You do not have enough karma 
for this'})
+            
+    # Create an issue in an election
+    elif action == "create":
+        if karma >= 4: # karma of 4 required to set up an issue for the 
election
+            if election:
+                issue = l[2] if len(l) > 2 else None
+                if not issue:
+                    response.respond(400, {'message': 'No issue ID specified'})
+                else:
+                    issuepath = os.path.join(homedir, "issues", election, 
issue)
+                    if os.path.isfile(issuepath + ".json"):
+                        response.respond(400, {'message': 'An issue with this 
ID already exists'})
+                    else:
+                        try:
+                            required = ['title','type']
+                            xr = required
+                            for i in required:
+                                if not form.getvalue(i):
+                                    raise Exception("Required fields missing: 
%s" % ", ".join(xr))
+                                else:
+                                    xr.pop(0)
+                            valid_types = 
['yna','stv1','stv2','stv3','stv4','stv5','stv6','stv7','stv8','stv9']
+                            if not form.getvalue('type') in valid_types:
+                                raise Exception('Invalid vote type: %s' % 
form.getvalue('type'))
+                            with open(issuepath + ".json", "w") as f:
+                                candidates = []
+                                if form.getvalue('candidates'):
+                                    for name in 
form.getvalue('candidates').split("\n"):
+                                        candidates.append({'name': name})
+                                f.write(json.dumps({
+                                    'title': form.getvalue('title'),
+                                    'description': 
form.getvalue('description'),
+                                    'type': form.getvalue('type'),
+                                    'candidates': candidates,
+                                    'seconds': form.getvalue('seconds'),
+                                    'nominatedby': form.getvalue('nominatedby')
+                                }))
+                                f.close()
+                            response.respond(201, {'message': 'Created!'})
+                        except Exception as err:
+                            response.respond(500, {'message': "Could not 
create issue: %s" % err})
+            else:
+                response.respond(400, {'message': "No election specified!"})
+        else:
+            response.respond(403, {'message': 'You do not have enough karma 
for this'})
+    
+    # Edit an issue or election
+    elif action == "edit":
+        issue = l[2] if len(l) > 2 else None
+        if (issue and karma >= 4) or (karma >= 5 and election):
+            if election:
+                if not issue:
+                    elpath = os.path.join(homedir, "issues", election)
+                    if not os.path.isdir(elpath) or not 
os.path.isfile(elpath+"/basedata.json"):
+                        response.respond(404, {'message': 'No such issue'})
+                    else:
+                        try:
+                            js = {}
+                            with open(elpath + "/basedata.json", "r") as f:
+                                js = json.loads(f.read())
+                                f.close()
+                            fields = 
['title','owner','monitors','starts','ends']
+                            for field in fields:
+                                val = form.getvalue(field)
+                                if val:
+                                    if field == "monitors":
+                                        val = val.split(",")
+                                    js[field] = val
+                            with open(elpath + "/basedata.json", "w") as f:
+                                f.write(json.dumps(js))
+                                f.close()
+                            response.respond(200, {'message': "Changed saved"})
+                        except Exception as err:
+                            response.respond(500, {'message': "Could not edit 
election: %s" % err})
+                else:
+                    issuepath = os.path.join(homedir, "issues", election, 
issue)
+                    if not os.path.isfile(issuepath + ".json"):
+                        response.respond(404, {'message': 'No such issue'})
+                    else:
+                        try:
+                            js = {}
+                            with open(issuepath + ".json", "r") as f:
+                                js = json.loads(f.read())
+                                f.close()
+                            fields = 
['title','description','type','candidates','seconds','nominatedby']
+                            for field in fields:
+                                val = form.getvalue(field)
+                                if val:
+                                    if field == "candidates" or field == 
"seconds":
+                                        xval = val.split("\n")
+                                        val = []
+                                        for entry in xval:
+                                            val.append({'name': entry})
+                                    js[field] = val
+                            with open(issuepath + ".json", "w") as f:
+                                f.write(json.dumps(js))
+                                f.close()
+                            response.respond(200, {'message': "Changed saved"})
+                        except Exception as err:
+                            response.respond(500, {'message': "Could not edit 
issue: %s" % err})
+            else:
+                response.respond(400, {'message': "No election specified!"})
+        else:
+            response.respond(403, {'message': 'You do not have enough karma 
for this'})
+    
+    # Edit/add a statement
+    elif action == "statement":
+        issue = l[2] if len(l) > 2 else None
+        if (issue and karma >= 4):
+            issuepath = os.path.join(homedir, "issues", election, issue)
+            if not os.path.isfile(issuepath + ".json"):
+                response.respond(404, {'message': 'No such issue'})
+            else:
+                try:
+                    js = {}
+                    with open(issuepath + ".json", "r") as f:
+                        js = json.loads(f.read())
+                        f.close()
+                    
+                    cand = form.getvalue('candidate')
+                    stat = form.getvalue('statement')
+                    found = False
+                    for entry in js['candidates']:
+                        if entry['name'] == cand:
+                            found = True
+                            entry['statement'] = stat
+                            break
+                    if not found:
+                        raise Exception("No such candidate: " + cand)          
          
+                    with open(issuepath + ".json", "w") as f:
+                        f.write(json.dumps(js))
+                        f.close()
+                    response.respond(200, {'message': "Changed saved"})
+                except Exception as err:
+                    response.respond(500, {'message': "Could not edit issue: 
%s" % err})
+        else:
+            response.respond(403, {'message': 'You do not have enough karma 
for this'})
+            
+    # Edit/add a statement
+    elif action == "addcandidate":
+        issue = l[2] if len(l) > 2 else None
+        if (issue and karma >= 4):
+            issuepath = os.path.join(homedir, "issues", election, issue)
+            if not os.path.isfile(issuepath + ".json"):
+                response.respond(404, {'message': 'No such issue'})
+            else:
+                try:
+                    js = {}
+                    with open(issuepath + ".json", "r") as f:
+                        js = json.loads(f.read())
+                        f.close()
+                    
+                    cand = form.getvalue('candidate')
+                    stat = form.getvalue('statement')
+                    found = False
+                    for entry in js['candidates']:
+                        if entry['name'] == cand:
+                            found = True
+                            break
+                    if found:
+                        raise Exception("Candidate already exists: " + cand)
+                    else:
+                        js['candidates'].append( {
+                            'name': cand,
+                            'statement': stat
+                        })
+                    with open(issuepath + ".json", "w") as f:
+                        f.write(json.dumps(js))
+                        f.close()
+                    response.respond(200, {'message': "Changed saved"})
+                except Exception as err:
+                    response.respond(500, {'message': "Could not edit issue: 
%s" % err})
+        else:
+            response.respond(403, {'message': 'You do not have enough karma 
for this'})
+    elif action == "delcandidate":
+        issue = l[2] if len(l) > 2 else None
+        if (issue and karma >= 4):
+            issuepath = os.path.join(homedir, "issues", election, issue)
+            if not os.path.isfile(issuepath + ".json"):
+                response.respond(404, {'message': 'No such issue'})
+            else:
+                try:
+                    js = {}
+                    with open(issuepath + ".json", "r") as f:
+                        js = json.loads(f.read())
+                        f.close()
+                    
+                    cand = form.getvalue('candidate')
+                    found = False
+                    i = 0
+                    for entry in js['candidates']:
+                        if entry['name'] == cand:
+                            js['candidates'].pop(i)
+                            found = True
+                            break
+                        i += 1
+                    if not found:
+                        raise Exception("Candidate does nost exist: " + cand)
+                    with open(issuepath + ".json", "w") as f:
+                        f.write(json.dumps(js))
+                        f.close()
+                    response.respond(200, {'message': "Changed saved"})
+                except Exception as err:
+                    response.respond(500, {'message': "Could not edit issue: 
%s" % err})
+        else:
+            response.respond(403, {'message': 'You do not have enough karma 
for this'})
+    else:
+        response.respond(400, {'message': "No (or invalid) action supplied"})
+else:
+    response.respond(500, {'message': "No path_info supplied"})

Added: steve/trunk/pytest/www/cgi-bin/rest_voter.py
URL: 
http://svn.apache.org/viewvc/steve/trunk/pytest/www/cgi-bin/rest_voter.py?rev=1667520&view=auto
==============================================================================
--- steve/trunk/pytest/www/cgi-bin/rest_voter.py (added)
+++ steve/trunk/pytest/www/cgi-bin/rest_voter.py Wed Mar 18 12:17:02 2015
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+#####
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#####
+import os, sys, json, re, time, base64, cgi, subprocess, hashlib
+from os import listdir
+version = 2
+if sys.hexversion < 0x03000000:
+    import ConfigParser as configparser
+else:
+    import configparser
+    version = 3
+
+path = os.path.abspath(os.getcwd())
+
+sys.path.append(path)
+sys.path.append(os.path.basename(sys.argv[0]))
+if 'SCRIPT_FILENAME' in os.environ:
+    sys.path.insert(0, os.path.basename(os.environ['SCRIPT_FILENAME']))
+    
+from lib import response
+
+
+# Fetch config (hack, hack, hack)
+config = configparser.RawConfigParser()
+config.read(path + '/../../steve.cfg')
+
+# Some quick paths
+homedir = config.get("general", "homedir")
+pathinfo = os.environ['PATH_INFO'] if 'PATH_INFO' in os.environ else None
+form = cgi.FieldStorage();
+
+
+
+# TODO: Authentication goes here
+karma = 5 # assume admin karma for now
+
+# Figure out what to do and where
+if pathinfo:
+    l = pathinfo.split("/")
+    if l[0] == "":
+        l.pop(0)
+    action = l[0]
+    election = l[1] if len(l) > 1 else None
+    issue = l[2]  if len(l) > 2 else None
+    voterid = l[3] if len(l) > 3 else None
+    
+    if action == "view":
+        # View a list of issues for an election
+        if election and not issue:
+            js = []
+            elpath = os.path.join(homedir, "issues", election)
+            if os.path.isdir(elpath):
+                basedata = {}
+                try:
+                    with open(elpath + "/basedata.json", "r") as f:
+                        basedata = json.loads(f.read())
+                        f.close()
+                    issues = [ f for f in listdir(elpath) if 
os.path.isfile(os.path.join(elpath,f)) and f != "basedata.json" ]
+                    for issue in issues:
+                        try:
+                            with open(elpath + "/" + issue, "r") as f:
+                                entry = json.loads(f.read())
+                                f.close()
+                                entry['id'] = issue.strip(".json")
+                                entry['APIURL'] = 
"https://%s/steve/voter/view/%s/%s"; % (os.environ['SERVER_NAME'], election, 
issue.strip(".json"))
+                                entry['prettyURL'] = 
"https://%s/steve/ballot?%s/%s"; % (os.environ['SERVER_NAME'], election, 
issue.strip(".json"))
+                                js.append(entry)
+                        except Exception as err:
+                            response.respond(500, {'message': 'Could not load 
issues: %s' % err})
+                except Exception as err:
+                    response.respond(500, {'message': 'Could not load base 
data: %s' % err})
+                response.respond(200, {'base_data': basedata, 'issues': js, 
'baseurl': "https://%s/steve/election?%s"; % (os.environ['SERVER_NAME'], 
election)})
+            else:
+                response.respond(404, {'message': 'No such election'})
+                
+        # View a speficic issue
+        elif election and issue:
+            js = []
+            issuepath = os.path.join(homedir, "issues", election, issue)
+            if os.path.isfile(issuepath + ".json"):
+                try:
+                    with open(issuepath + ".json", "r") as f:
+                        entry = json.loads(f.read())
+                        f.close()
+                        entry['id'] = issue.strip(".json")
+                        entry['APIURL'] = "https://%s/steve/voter/view/%s/%s"; 
% (os.environ['SERVER_NAME'], election, issue)
+                        entry['prettyURL'] = "https://%s/steve/ballot?%s/%s"; % 
(os.environ['SERVER_NAME'], election, issue)
+                        response.respond(200, {'issue': entry})
+                except Exception as err:
+                    response.respond(500, {'message': "Could not load issue: 
%s" % err})
+            else:
+                response.respond(404, {'message': 'No such issue'})
+        else:
+            response.respond(404, {'message': 'No election ID supplied'})
+    elif action == "vote":
+        response.respond(500, {'message': 'Not implemented yet'})
+    else:
+        response.respond(400, {'message': 'Invalid action supplied'})
+else:
+    response.respond(500, {'message': 'No path info supplied, aborting'})
\ No newline at end of file


Reply via email to