fixed several bugs
[yourule] / yourule.py
1 #!/usr/bin/env python
2
3 from __future__ import division
4 import web
5 import sys, os, re
6 from storm.locals import *
7
8 # recalculate the path based on the location of the file
9 sys.path.append(os.path.dirname(__file__))
10 from svgruler import SVGRuler
11
12 from jinja import Environment, FileSystemLoader
13 jinja_env = Environment('<%', '%>', '<%=', '%>', '<%#', '%>', 
14                         loader=FileSystemLoader(os.path.dirname(__file__) + "/templates/"))
15
16 def render(filename, vars):
17     web.header("Content-Type","text/html; charset=utf-8")
18     tmpl = jinja_env.get_template(filename + '.tmpl')
19     print tmpl.render(vars)
20     print web.ctx
21
22 # the url map for the application
23 urls = ( '/?', 'index',
24          '/ruler_([0-9\.]+)px_([0-9\.]+)([A-Za-z]+).(svg|png|jpg)', 'ruler_img',
25          '/show/(.*(svg|png|jpg))', 'show_ruler',
26          '/gallery(.*)', 'gallery',
27          '/delete/(\d+)', 'delete',
28          '/undelete/(\d+)', 'undelete')
29
30 database = create_database("sqlite:%s/db/yourule.db" %
31                            os.path.dirname(__file__))
32
33 store = Store(database)
34
35 class Ruler(object):
36     __storm_table__ = "gallery"
37     id = Int(primary=True)
38     pixel_width = Float()
39     unit_width = Float()
40     model = Unicode()
41     units = Unicode()
42     show = Int()
43     cm_in_ratio = 0.3937
44
45     def __init__(self, **kw):
46         self.pixel_width = float(kw['pixel_width'])
47         self.unit_width = float(kw['unit_width'])
48         self.units = unicode(kw['units'])
49         if kw.has_key('model'):
50             self.model = unicode(kw['model'])
51         else:
52             self.model = u''
53
54     def cm_width(self):
55         if self.units == 'centimeters':
56             return self.unit_width
57         elif self.units == 'inches':
58             return(round(self.unit_width / self.cm_in_ratio, 2))
59
60     def in_width(self):
61         if self.units == 'inches':
62             return self.unit_width
63         elif self.units == 'centimeters':
64             return(round(self.unit_width * self.cm_in_ratio, 2))
65
66     def url(self):
67         return('ruler_%spx_%s%s.png' % (self.pixel_width,
68                                         self.unit_width, self.units))
69
70
71 class index:
72     def GET(self):
73         render('index', locals())
74
75     def POST(self):
76         input = web.input()
77
78         errormsg = validate_input(input)
79
80         if errormsg:
81             pixel_width = input['pixel_width']
82             unit_width = input['unit_width']
83             units = input['units']
84             render('index', locals())
85         else:
86             ruler = Ruler(pixel_width = input['pixel_width'], 
87                           unit_width = input['unit_width'], 
88                           units = input['units'])
89             
90             web.redirect('/show/%s' % ruler.url())
91
92 class show_ruler:
93     def GET(self, ruler_url, ext):
94         if web.input().has_key('fromgallery'):
95             fromgallery = True
96         else:
97             fromgallery = False
98
99         other_unit, other_unit_url = get_other_unit(ruler_url)
100
101         render('show_ruler', locals())
102
103 class ruler_img:
104     def GET(self, pixel_width=None, unit_width=None, units=None, ext=None):
105
106         # TODO check to see if it's a format that we support
107
108         # set ruler height to be 200 px always
109         pixel_width = float(pixel_width)
110         unit_width = float(unit_width)
111
112         ruler_height = 200
113
114         scale = pixel_width / unit_width
115         ruler_length = int(unit_width)
116
117         ruler = SVGRuler(scale, units, ruler_height, ruler_length)
118
119         # print the header
120         if ext == 'svg': ext = 'svg+xml'
121         web.header("Content-Type", "image/%s" % ext)
122
123         if ext == 'svg+xml':
124             sys.stdout.write(ruler.getxml())
125         else:
126             pin, pout = os.popen2('convert -size %sx%s - %s:-' % \
127                                   (pixel_width, ruler_height, ext))
128
129             pin.write(ruler.getxml())
130             pin.close()
131             sys.stdout.write(pout.read())
132
133 class gallery:
134     def GET(self, ruler_url):
135
136         if ruler_url:
137             pixel_width, unit_width, units = process_ruler_url(ruler_url)[0:3]
138
139         rulers = store.find(Ruler, Ruler.show == 1)
140         rulers.order_by(Ruler.model)
141         render('gallery', locals())
142
143     def POST(self, ruler_url):
144         input = web.input()
145
146         errormsg = validate_input(input)
147         if not input.model:
148             errormsg = 'Please fill out all fields.'
149
150         if errormsg:
151             pixel_width = input['pixel_width']
152             unit_width = input['unit_width']
153             units = input['units']
154             model = input['model']
155         else:
156             new_ruler = Ruler(pixel_width = input['pixel_width'],
157                               unit_width = input['unit_width'],
158                               units = input['units'],
159                               model = input['model'])
160
161             store.add(new_ruler)
162             store.commit()
163
164         rulers = store.find(Ruler, Ruler.show == 1)
165         rulers.order_by(Ruler.model)
166         render('gallery', locals())
167
168 class delete:
169     def GET(self, id):
170         ruler = store.get(Ruler, int(id))
171         ruler.show = 0
172         store.commit()
173         web.redirect('/gallery')
174
175
176 class undelete:
177     def GET(self, id):
178         ruler = store.get(Ruler, int(id))
179         ruler.show = 1
180         store.commit()
181         web.redirect('/gallery')
182
183 def get_other_unit(url):
184     pixel_width, unit_width, units = process_ruler_url(url)[0:3]
185
186     ruler = Ruler(pixel_width=pixel_width, unit_width=unit_width, units=units)
187     pixel_width, unit_width, units = process_ruler_url(url)[0:3]
188
189     if units == 'centimeters':
190         units = 'inches'
191         unit_width = ruler.in_width()
192     elif units == 'inches':
193         units = 'centimeters'
194         unit_width = ruler.cm_width()
195
196     new_ruler = Ruler(pixel_width=pixel_width, unit_width=unit_width,
197                       units=units)
198
199     web.debug(units)
200     return(units, new_ruler.url())
201
202
203 def process_ruler_url(url):
204     url = re.sub(r'^/?(ruler.*)$', r'\1', url)
205     return(re.match( r'ruler_([\d\.]+)px_([\d\.]+)(\w+).(png|svg|jpg)',
206            url).groups())
207
208 def validate_input(input):
209     errormsg = False
210
211     if not input.pixel_width \
212         or not input.unit_width:
213         errormsg = 'Please fill out all fields.'
214     elif not re.match('^[\d\.]+$', input.pixel_width) \
215         or not re.match('^[\d\.]+$', input.unit_width):
216         errormsg = "Widths must be numbers."
217     elif input['pixel_width'] < 0 \
218         or input['unit_width'] < 0:
219         errormsg = 'Widths must be greater than postive.'
220
221     return(errormsg)
222
223
224 web.webapi.internalerror = web.debugerror
225 if __name__ == "__main__":
226     web.run(urls, globals(), web.reloader)
227
228 application = web.wsgifunc(web.webpyfunc(urls, globals()))
229

Benjamin Mako Hill || Want to submit a patch?