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

Benjamin Mako Hill || Want to submit a patch?