--- /dev/null
+DROP TABLE IF EXISTS people;
+CREATE TABLE people (
+ id INT NOT NULL auto_increment,
+ name VARCHAR(255) NULL DEFAULT NULL,
+ phone_number VARCHAR(255) NOT NULL,
+ PRIMARY KEY (id)
+);
+
+DROP TABLE IF EXISTS questionaires;
+CREATE TABLE questionaires (
+ id INT NOT NULL auto_increment,
+ code VARCHAR(100) NOT NULL, -- always a letter
+ description VARCHAR(255) NOT NULL,
+ PRIMARY KEY (id)
+);
+
+DROP TABLE IF EXISTS questions;
+CREATE TABLE questions (
+ id INT NOT NULL auto_increment,
+ questionaire_id INT NOT NULL,
+ code VARCHAR(100) NOT NULL , -- always a number
+ longdesc VARCHAR(255) NULL DEFAULT NULL,
+ shortdesc VARCHAR(20) NULL DEFAULT NULL,
+ datatype VARCHAR(100) NOT NULL, -- number, char, bool
+ PRIMARY KEY (id)
+);
+
+DROP TABLE IF EXISTS answers;
+CREATE TABLE answers (
+ id INT NOT NULL auto_increment,
+ question_id INT NOT NULL,
+ person_id INT NOT NULL,
+ answer VARCHAR(255) NOT NULL,
+ recieved TIMESTAMP NOT NULL DEFAULT NOW(),
+ PRIMARY KEY (id)
+);
+
+-- add group table in the future
--- /dev/null
+from storm.locals import *
+database = create_database("mysql:uniphone")
+store = Store(database)
+
+class Person(object):
+ __storm_table__ = "people"
+ id = Int(primary=True)
+ name = Unicode()
+ phone_number = Unicode()
+
+ def __init__(self, **kw):
+ self.name = unicode(kw['name'])
+ self.phone_number = unicode(kw['phone_number'])
+
+class Questionaire(object):
+ __storm_table__ = "questionaires"
+ id = Int(primary=True)
+ code = Unicode()
+ description = Unicode()
+
+ def __init__(self, **kw):
+ self.code = unicode(kw['code'])
+ self.description = unicode(kw['description'])
+
+class Question(object):
+ __storm_table__ = "questions"
+ id = Int(primary=True)
+ code = Unicode()
+ longdesc = Unicode()
+ shortdesc = Unicode()
+ datatype = Unicode()
+ questionaire_id = Int()
+ questionaire = Reference(questionaire_id, Questionaire.id)
+
+ def __init__(self, **kw):
+ self.code = unicode(kw['code'])
+ self.longdesc = unicode(kw['longdesc'])
+ self.shortdesc = unicode(kw['shortdesc'])
+ self.datatype = unicode(kw['datatype'])
+ self.questionaire_id = int(kw['questionaire_id'])
+
+class Answer(object):
+ __storm_table__ = "answers"
+ id = Int(primary=True)
+ answer = Unicode()
+ received = DateTime()
+ question_id = Int()
+ question = Reference(question_id, Question.id)
+ people_id = Int()
+ person = Reference(people_id, Person.id)
+
+ def __init__(self, **kw):
+ self.answer = unicode(kw['answer'])
+ self.received = unicode(kw['received']) # have this change to the right type
+
+# define the many to one relationships
+Person.answers = ReferenceSet(Person.id, Answer.id)
+Questionaire.questions = ReferenceSet(Questionaire.id, Question.questionaire_id)
+Question.answers = ReferenceSet(Question.id, Answer.id)
+
--- /dev/null
+#!/usr/bin/env python
+
+# UNICEF SMS Phone Application
+#
+# Copyright (C) 2007 Benjamin Mako Hill <mako@atdot.cc>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the Affero General Public License as published
+# by the Free Software Foundation, either version 1 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the Affero General Public License
+# along with this program. If not, see
+# <http://http://www.affero.org/oagpl.html>.
+
+import web
+import sys, os, re
+
+from db import *
+
+# recalculate the path based on the location of the file
+from jinja import Environment, FileSystemLoader
+jinja_env = Environment(loader=FileSystemLoader(os.path.dirname(__file__) + "/templates/"))
+
+def render(filename, vars={}):
+ """Render Jinja Templates"""
+
+ web.header("Content-Type","text/html; charset=utf-8")
+
+ tmpl = jinja_env.get_template(filename)
+
+ vars['ctx'] = web.ctx
+ vars['home'] = web.ctx.home
+ vars['homepath'] = web.ctx.homepath
+ #vars['session'] = web.ctx.environ['com.saddi.service'].session
+
+ print tmpl.render(vars)
+
+# the url map for the application
+urls = ( '/?', 'index',
+ '/?new_name', 'new_name',
+ '/?show_names', 'show_names',
+ '/?questionaires', 'questionaires',
+ '/?edit_questions/(\d+)', 'edit_questions')
+
+class index:
+ def GET(self):
+ render('index.tmpl')
+
+class new_name:
+ def GET(self):
+ render('new_name.tmpl')
+
+ def POST(self):
+ input = web.input()
+
+ errors = []
+ if not input.name:
+ errors.append('You must provide a name.')
+ if not input.phone_number:
+ errors.append('You must provide a phone number.')
+ elif not re.match(r'[0-9\+\- ]', input.phone_number):
+ errors.append('Your phone number must be only numbers.')
+
+ if not errors:
+ for error in self.validate_phone(input.phone_number):
+ errors.append(error)
+ if errors:
+ render('new_name.tmpl', locals())
+ else:
+ # try to save it to the database
+ new_person = Person(name=input.name, phone_number=input.phone_number)
+ # TODO make this work
+ # errors.append('There was an error saving to the database')
+ store.add(new_person)
+ store.commit()
+ render('success.tmpl', locals())
+
+ def validate_phone(self, phone_number):
+ errors = []
+ if len(phone_number) < 7:
+ errors.append('Your phone number is too short')
+ else:
+ people = store.find(Person)
+ for person in people:
+ if phone_number[-7:] == person.phone_number[-7:]:
+ errors.append('That phone number already exists in our datbase.')
+ break
+
+ return(errors)
+
+class show_names:
+ def GET(self):
+ people = store.find(Person)
+ render('show_names.tmpl', locals())
+
+
+class questionaires:
+ def GET(self):
+ questionaires = store.find(Questionaire)
+ render('questionaires.tmpl', locals())
+
+ def POST(self):
+ questionaires = store.find(Questionaire)
+ input = web.input()
+
+ errors = []
+ if not input.code:
+ errors.append('You must enter a code.')
+
+ if not errors:
+ new_questionaire = Questionaire(code=input.code,
+ description=input.description)
+ store.add(new_questionaire)
+ store.commit()
+
+ render('questionaires.tmpl', locals())
+
+class edit_questions:
+ def GET(self, id):
+ input = web.input()
+ questionaire = store.get(Questionaire, int(id))
+ render('edit_questions.tmpl', locals())
+
+ def POST(self, id):
+ input = web.input()
+ questionaire = store.get(Questionaire, int(id))
+
+ errors = []
+ if not input.longdesc:
+ errors.append('You must have a long description.')
+
+ code = self.__get_code(questionaire)
+
+ if not errors:
+ new_question = Question(code=code,
+ shortdesc=input.shortdesc,
+ datatype=input.datatype,
+ longdesc=input.longdesc,
+ questionaire_id=questionaire.id)
+ store.add(new_question)
+ store.commit()
+
+ render('edit_questions.tmpl', locals())
+
+ def __get_code(self, questionaire):
+ """Return a new code that is higher than the others."""
+
+ codes = list(int(q.code) for q in questionaire.questions)
+ return(len(codes) + 1)
+
+class test:
+ def GET(self):
+ render('test.tmpl')
+
+ def POST(self):
+ render('test_sent.tmpl')
+
+class raw_sms_in:
+ def POST(self):
+ #TODO magic to parse sms
+ pass
+
+
+web.webapi.internalerror = web.debugerror
+if __name__ == "__main__":
+ web.run(urls, globals(), web.reloader)
+
+application = web.wsgifunc(web.webpyfunc(urls, globals()))
+
--- /dev/null
+<div id="errormsg">
+<h3>Error</h3>
+
+<ul>
+{% for error in errors %}
+<li>{{error}}</li>
+{% endfor %}
+</ul>
+</div>
--- /dev/null
+{% extends 'layout.tmpl' %}
+
+{% block content %}
+<h2>List of Questions for {{questionaire.description}}</h2>
+
+
+<table>
+<tr>
+<th>Code</th>
+<th>Long Description</th>
+<th>Short Description</th>
+<th>Data Type</th>
+</tr>
+
+{% for q in questionaire.questions %}
+<tr>
+<td>{{q.code}}</td>
+<td>{{q.longdesc}}</td>
+<td>{{q.shortdesc}}</td>
+<td>{{q.datatype}}</td>
+</tr>
+{% endfor %}
+</table>
+
+<h2>New Question</h2>
+
+<form method="POST"
+ action="{{homepath}}/edit_questions/{{questionaire.id}}">
+
+<p><label for="shortdesc">Short Description</label>
+<input name="shortdesc" type="text" size="15" value="{{shortdesc}}" /></p>
+
+<p><label for="longdesc">Long Description</label>
+<input name="longdesc" type="text" size="50" value="{{longdesc}}" /></p>
+
+<p><label for="datatype">Data Type</lable>
+<select name="datatype">
+<option value="number" />Number
+<option value="word" />Word
+<option value="bool" />Yes/No
+</select></p>
+
+<input type="submit" value="Save" />
+</form>
+
+{% endblock %}
--- /dev/null
+{% extends 'layout.tmpl' %}
+
+{% block content %}
+
+<ul>
+<li><a href="{{homepath}}/new_name">Enter a new name/phone number</a></li>
+<li><a href="{{homepath}}/show_names">Display names and phone numbers</a></li>
+<li><a href="{{homepath}}/questionaires">Display questionaires</a></li>
+</ul>
+{% endblock %}
--- /dev/null
+<html>
+<head>
+<title>UNICEF Phone Application</title>
+</head>
+<body>
+<h1>UNICEF Phone Application</h1>
+<div id="content">
+{% block content %}
+{% endblock %}
+</div>
+</body>
+</html>
--- /dev/null
+{% extends 'layout.tmpl' %}
+
+{% block content %}
+<h2>Enter Name/Phone Number</h2>
+
+{% if errors %}
+{% include '_error.tmpl' %}
+{% endif %}
+
+<form method="POST" action="{{homepath}}/new_name">
+
+<p><label>Name</label>
+<input name="name" type="text" size="50" value="{{input.name}}" /></p>
+
+<p><label>Phone Number</label>
+<input name="phone_number" type="text" size="50"
+ value="{{input.phone_number}}" /></p>
+
+<input type="submit" value="Save" />
+</form>
+{% endblock %}
--- /dev/null
+{% extends 'layout.tmpl' %}
+
+{% block content %}
+<h2>List of Questionaires</h2>
+
+<table>
+<tr>
+<th>Code</th>
+<th>Description</th>
+<th>Num. Questions</th>
+<th></th>
+</tr>
+
+{% for q in questionaires %}
+<tr>
+<td>{{q.code}}</td>
+<td>{{q.description}}</td>
+<td>{{len(q.questions) or 0}}</td>
+<td><a href="{{homepath}}/edit_questions/{{q.id}}">edit</a></td>
+</tr>
+{% endfor %}
+</table>
+
+<h2>New Questionaire</h2>
+
+<form method="POST" action="{{homepath}}/questionaires">
+<p><label for="code">Code</label>
+<input name="code" type="text" size="3" value="{{code}}" /></p>
+
+<p><label for="description">Description</label>
+<input name="description" type="text" size="50" value="{{description}}" /></p>
+
+<input type="submit" value="Save" />
+</form>
+
+{% endblock %}
--- /dev/null
+{% extends 'layout.tmpl' %}
+
+{% block content %}
+<h2>List of Registered Phone Numbers</h2>
+
+<table>
+<tr>
+<th>Name</th>
+<th>Phone Number</th>
+</tr>
+
+{% for person in people %}
+<tr>
+<td>{{person.name}}</td>
+<td>{{person.phone_number}}</td>
+</tr>
+{% endfor %}
+</table>
+
+{% endblock %}
--- /dev/null
+{% extends 'layout.tmpl' %}
+
+{% block content %}
+<h2>Success!</h2>
+
+Successfully entered name <strong>{{input.name}}</strong> for phone
+number <strong>{{input.phone_number}}</strong>.
+
+{% endblock %}