cleaned up code and integrated some simple CSS
[rapidsms] / rapidsms.py
1 #!/usr/bin/env python
2
3 # UNICEF SMS Phone Application
4 #
5 # Copyright (C) 2007 Benjamin Mako Hill <mako@atdot.cc>
6 #
7 # This program is free software: you can redistribute it and/or modify
8 # it under the terms of the Affero General Public License as published
9 # by the Free Software Foundation, either version 1 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 # General Public License for more details.
16 #
17 # You should have received a copy of the Affero General Public License
18 # along with this program.  If not, see
19 # <http://http://www.affero.org/oagpl.html>.
20
21 import web
22 import sys, os, re
23
24 from db import *
25
26 # recalculate the path based on the location of the file
27 from jinja import Environment, FileSystemLoader
28 jinja_env = Environment(loader=FileSystemLoader(os.path.dirname(__file__) + "/templates/"))
29
30 def render(filename, vars={}):
31     """Render Jinja Templates"""
32
33     web.header("Content-Type","text/html; charset=utf-8")
34
35     tmpl = jinja_env.get_template(filename)
36
37     vars['ctx'] = web.ctx
38     vars['home'] = web.ctx.home
39     vars['homepath'] = web.ctx.homepath
40     #vars['session'] = web.ctx.environ['com.saddi.service'].session
41
42     print tmpl.render(vars)
43
44 # the url map for the application
45 urls = ( '/?', 'index',
46          '/?new_name', 'new_name',
47          '/?show_names', 'show_names',
48          '/?questionaires', 'questionaires',
49          '/?edit_questions/(\d+)', 'edit_questions')
50
51 class index:
52     def GET(self):
53         render('index.tmpl')
54
55 class new_name:
56     def GET(self):
57         render('new_name.tmpl')
58
59     def POST(self):
60         input = web.input()
61
62         errors = []
63         if not input.name:
64             errors.append('You must provide a name.')
65         if not input.phone_number:
66             errors.append('You must provide a phone number.')
67         elif not re.match(r'[0-9\+\- ]', input.phone_number):
68             errors.append('Your phone number must be only numbers.')
69
70         if not errors:
71             for error in self.validate_phone(input.phone_number):
72                 errors.append(error)
73         if errors:
74             render('new_name.tmpl', locals())
75         else:
76             # try to save it to the database
77             new_person = Person(name=input.name, phone_number=input.phone_number)
78             # TODO make this work
79             # errors.append('There was an error saving to the database')
80             store.add(new_person)
81             store.commit()
82             render('success.tmpl', locals())
83
84     def validate_phone(self, phone_number):
85         errors = []
86         if len(phone_number) < 7:
87             errors.append('Your phone number is too short')
88         else:
89             people = store.find(Person)
90             for person in people:
91                 if phone_number[-7:] == person.phone_number[-7:]:
92                     errors.append('That phone number already exists in our datbase.')
93                     break
94         
95         return(errors)
96
97 class show_names:
98     def GET(self):
99         people = store.find(Person)
100         render('show_names.tmpl', locals())
101
102
103 class questionaires:
104     def GET(self):
105         questionaires = store.find(Questionaire)
106         render('questionaires.tmpl', locals())
107
108     def POST(self):
109         questionaires = store.find(Questionaire)
110         input = web.input()
111
112         errors = []
113         if not input.code:
114             errors.append('You must enter a code.')
115
116         if not errors:
117             new_questionaire = Questionaire(code=input.code,
118                 description=input.description)
119             store.add(new_questionaire)
120             store.commit()
121             
122         render('questionaires.tmpl', locals())
123
124 class edit_questions:
125     def GET(self, id):
126         input = web.input()
127         questionaire = store.get(Questionaire, int(id))
128         render('edit_questions.tmpl', locals())
129
130     def POST(self, id):
131         input = web.input()
132         questionaire = store.get(Questionaire, int(id))
133
134         errors = []
135         if not input.longdesc:
136             errors.append('You must have a long description.')
137
138         code = self.__get_code(questionaire)
139
140         if not errors:
141             new_question = Question(code=code,
142                                     shortdesc=input.shortdesc,
143                                     datatype=input.datatype,
144                                     longdesc=input.longdesc,
145                                     questionaire_id=questionaire.id)
146             store.add(new_question)
147             store.commit()
148             
149         render('edit_questions.tmpl', locals())
150
151     def __get_code(self, questionaire):
152         """Return a new code that is higher than the others."""
153
154         codes = list(int(q.code) for q in questionaire.questions)
155         return(len(codes) + 1)
156
157 #class test:
158 #    def GET(self):
159 #        render('test.tmpl', locals())
160 #
161 #    def POST(self):
162 #        render('test_sent.tmpl', locals())
163 #
164 #class raw_sms_in:
165 #    def POST(self):
166 #        #TODO magic to parse sms
167 #        pass
168
169
170 web.webapi.internalerror = web.debugerror
171 if __name__ == "__main__":
172     web.run(urls, globals(), web.reloader)
173
174 application = web.wsgifunc(web.webpyfunc(urls, globals()))
175

Benjamin Mako Hill || Want to submit a patch?