Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100755 474 lines (396 sloc) 15.711 kb
42db4a6 @aaronsw use env instead of usr/bin
authored
1 #!/usr/bin/env python
dcb7d7f @jdthomas Add a basic page for earmarks.
jdthomas authored
2 import re, sys
5308049 reorganize
Aaron Swartz authored
3 import web
ef757cc @aaronsw template fixes
authored
4
623fed2 use xapian for search
Aaron Swartz authored
5 from utils import zip2rep, simplegraphs, apipublish, users, writerep, se
b89f844 add a blog
Aaron Swartz authored
6 import blog
82ae3f3 petitions - first cut
Devi authored
7 import petition
6fb4989 @asldevi javascript to add petition URL
asldevi authored
8 import settings
2dba2db @asldevi using production mode from environment, use the same for writerep too
asldevi authored
9 from settings import db, render, production_mode
ece0a70 @aaronsw first try at using smartersql; apipublish still broken
authored
10 import schema
5858fbb @asldevi Send email on crashes - #67
asldevi authored
11 import config
5308049 reorganize
Aaron Swartz authored
12
57f54c0 @asldevi Don't autoreload in production mode;
asldevi authored
13 if not production_mode:
14 web.config.debug = True
15
a067eb2 @aaronsw add API export support for major pages
authored
16 options = r'(?:\.(html|xml|rdf|n3|json))'
d6e03b5 add web.py to REQUISITES
Aaron Swartz authored
17 urls = (
a067eb2 @aaronsw add API export support for major pages
authored
18 r'/', 'index',
19 r'/us/(?:index%s)?' % options, 'find',
20 r'/us/([A-Z][A-Z])', 'redistrict',
21 r'/us/([a-z][a-z])%s?' % options, 'state',
22 r'/us/([A-Z][A-Z]-\d+)', 'redistrict',
23 r'/us/([a-z][a-z]-\d+)%s?' % options, 'district',
e3e3e68 @aaronsw show votepcts
authored
24 r'/(us|p)/by/(.*)/distribution\.png', 'sparkdist',
08827f0 @aaronsw add speech information to pol pages
authored
25 r'/(us|p)/by/(.*)', 'dproperty',
cd5bad1 @jdthomas Fix url for politician specific earmarks. Bug 162.
jdthomas authored
26 r'/p/(.*?)/earmarks', 'politician_earmarks',
670b7e4 @aaronsw add more links for bills, aligned groups
authored
27 r'/p/(.*?)/introduced', 'politician_introduced',
28 r'/p/(.*?)/groups', 'politician_groups',
29 r'/p/(.*?)/(\d+)', 'politician_group',
a067eb2 @aaronsw add API export support for major pages
authored
30 r'/p/(.*?)%s?' % options, 'politician',
dcb7d7f @jdthomas Add a basic page for earmarks.
jdthomas authored
31 r'/e/(.*?)%s?' % options, 'earmark',
3ef7d52 first cut at individual pages for bills
A.S.L. Devi authored
32 r'/b/(.*?)%s?' % options, 'bill',
3be04aa @aaronsw import rolls, allow staggered import of bills
authored
33 r'/r/us/(.*?)%s?' % options, 'roll',
417b9d2 @aaronsw web.py upgrade
authored
34 r'/c', petition.app,
a62c1c1 @asldevi move all user related URLs to be /u/*
asldevi authored
35 r'/u', users.app,
59484d7 @jdthomas Some initial pages for lobbyist stuff.
jdthomas authored
36 r'/l/c/?(.*?)', 'lob_contrib',
37 r'/l/f/?(.*?)', 'lob_filing',
38 r'/l/o/?(.*?)', 'lob_org',
39 r'/l/pa/?(.*?)', 'lob_pac',
40 r'/l/pe/?(.*?)', 'lob_person',
b222188 @asldevi Ajax verification for zip and captcha (works w/o js too)
asldevi authored
41 r'/writerep', writerep.app,
a067eb2 @aaronsw add API export support for major pages
authored
42 r'/about(/?)', 'about',
50572a0 webchick redesign
Rebecca Malamud authored
43 r'/about/team', 'aboutteam',
44 r'/about/help', 'abouthelp',
37659f4 @aaronsw add list of politicians, API docs
authored
45 r'/about/api', 'aboutapi',
a067eb2 @aaronsw add API export support for major pages
authored
46 r'/about/feedback', 'feedback',
417b9d2 @aaronsw web.py upgrade
authored
47 r'/blog', blog.app,
0aca1e4 @asldevi share page/petition
asldevi authored
48 r'/share', 'petition.share',
5daa1d3 @aaronsw add yauth code
authored
49 r'/data/(.*)', 'staticdata',
1236166 @asldevi support for MSN contacts import
asldevi authored
50 r'/bbauth/', 'contacts.auth_yahoo',
51 r'/authsub', 'contacts.auth_google',
52 r'/auth/msn', 'contacts.auth_msn',
d6e03b5 add web.py to REQUISITES
Aaron Swartz authored
53 )
54
55 class index:
56 def GET(self):
57 return render.index()
58
4eee6b0 add population, distribution pages for each, code and url cleanup
Aaron Swartz authored
59 class about:
2495917 make feedback work, add about redirect
Aaron Swartz authored
60 def GET(self, endslash=None):
61 if not endslash: raise web.seeother('/about/')
4eee6b0 add population, distribution pages for each, code and url cleanup
Aaron Swartz authored
62 return render.about()
63
37659f4 @aaronsw add list of politicians, API docs
authored
64 class aboutapi:
65 def GET(self):
66 return render.about_api()
67
50572a0 webchick redesign
Rebecca Malamud authored
68 class aboutteam:
69 def GET(self):
70 return render.about_team()
71
72 class abouthelp:
73 def GET(self):
74 return render.about_help()
75
2495917 make feedback work, add about redirect
Aaron Swartz authored
76 class feedback:
77 def GET(self):
19fdd2c @aaronsw minor bug fixes
authored
78 return render.feedback()
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
79
2495917 make feedback work, add about redirect
Aaron Swartz authored
80 def POST(self):
81 i = web.input(email='info@watchdog.net')
82 web.sendmail('Feedback <%s>' % i.email, 'Watchdog <info@watchdog.net>',
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
83 'watchdog.net feedback',
2495917 make feedback work, add about redirect
Aaron Swartz authored
84 i.content +'\n\n' + web.ctx.ip)
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
85
2495917 make feedback work, add about redirect
Aaron Swartz authored
86 return render.feedback_thanks()
87
320eb4d add about, zip2rep
Aaron Swartz authored
88 class find:
a067eb2 @aaronsw add API export support for major pages
authored
89 def GET(self, format=None):
5680b85 @aaronsw clean up address finding errors
authored
90 i = web.input(address=None)
d667b36 @aaronsw support zip+4
authored
91 pzip5 = re.compile(r'\d{5}')
92 pzip4 = re.compile(r'\d{5}-\d{4}')
93 pdist = re.compile(r'[a-zA-Z]{2}\-\d{2}')
776fe4c @aaronsw get most important pages using smartersql
authored
94
95 dists = None
623fed2 use xapian for search
Aaron Swartz authored
96 if not i.get('q'):
97 i.q = i.get('zip')
98
99 if i.q:
100 if pzip4.match(i.q):
101 zip, plus4 = i.q.split('-')
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
102 dists = [x.district for x in
d667b36 @aaronsw support zip+4
authored
103 db.select('zip4', where='zip=$zip and plus4=$plus4', vars=locals())]
776fe4c @aaronsw get most important pages using smartersql
authored
104
623fed2 use xapian for search
Aaron Swartz authored
105 elif pzip5.match(i.q):
c03b916 @btbytes handle zip5 and district identifier entry to the search box using RE and...
btbytes authored
106 try:
623fed2 use xapian for search
Aaron Swartz authored
107 dists = zip2rep.zip2dist(i.q, i.address)
c03b916 @btbytes handle zip5 and district identifier entry to the search box using RE and...
btbytes authored
108 except zip2rep.BadAddress:
623fed2 use xapian for search
Aaron Swartz authored
109 return render.find_badaddr(i.q, i.address)
776fe4c @aaronsw get most important pages using smartersql
authored
110
111 if dists:
112 d_dists = schema.District.select(where=web.sqlors('name=', dists))
113 out = apipublish.publish(d_dists, format)
114 if out: return out
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
115
c03b916 @btbytes handle zip5 and district identifier entry to the search box using RE and...
btbytes authored
116 if len(dists) == 1:
117 raise web.seeother('/us/%s' % dists[0].lower())
118 elif len(dists) == 0:
623fed2 use xapian for search
Aaron Swartz authored
119 return render.find_none(i.q)
8207ebc @btbytes representative search by name; resolve multiple resutls for rep search
btbytes authored
120 else:
623fed2 use xapian for search
Aaron Swartz authored
121 return render.find_multi(i.q, d_dists)
122
123 if pdist.match(i.q):
124 raise web.seeother('/us/%s' % i.q)
125
126 results = se.query(i.q)
127 reps = db.select('politician', where=web.sqlors('id=', results))
128 if len(reps) > 1:
129 return render.find_multi_reps(reps)
130 else:
131 try:
132 rep = reps[0]
133 web.seeother('/p/%s' % rep.id)
134 except IndexError:
135 raise web.notfound
8207ebc @btbytes representative search by name; resolve multiple resutls for rep search
btbytes authored
136
320eb4d add about, zip2rep
Aaron Swartz authored
137 else:
776fe4c @aaronsw get most important pages using smartersql
authored
138 index = schema.District.select(order='name asc')
139 out = apipublish.publish(index, format)
140 if out: return out
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
141
776fe4c @aaronsw get most important pages using smartersql
authored
142 return render.districtlist(index)
320eb4d add about, zip2rep
Aaron Swartz authored
143
d23baf8 @aaronsw add state pages (very slow at the moment)
authored
144 class state:
a067eb2 @aaronsw add API export support for major pages
authored
145 def GET(self, state, format=None):
d23baf8 @aaronsw add state pages (very slow at the moment)
authored
146 try:
776fe4c @aaronsw get most important pages using smartersql
authored
147 state = schema.State.where(code=state.upper())[0]
d23baf8 @aaronsw add state pages (very slow at the moment)
authored
148 except IndexError:
149 raise web.notfound
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
150
776fe4c @aaronsw get most important pages using smartersql
authored
151 out = apipublish.publish([state], format)
152 if out: return out
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
153
776fe4c @aaronsw get most important pages using smartersql
authored
154 return render.state(state)
d23baf8 @aaronsw add state pages (very slow at the moment)
authored
155
4eee6b0 add population, distribution pages for each, code and url cleanup
Aaron Swartz authored
156 class redistrict:
157 def GET(self, district):
158 return web.seeother('/us/' + district.lower())
159
d6e03b5 add web.py to REQUISITES
Aaron Swartz authored
160 class district:
a067eb2 @aaronsw add API export support for major pages
authored
161 def GET(self, district, format=None):
d6e03b5 add web.py to REQUISITES
Aaron Swartz authored
162 try:
776fe4c @aaronsw get most important pages using smartersql
authored
163 d = schema.District.where(name=district.upper())[0]
d6e03b5 add web.py to REQUISITES
Aaron Swartz authored
164 except IndexError:
4eee6b0 add population, distribution pages for each, code and url cleanup
Aaron Swartz authored
165 raise web.notfound
776fe4c @aaronsw get most important pages using smartersql
authored
166
167 out = apipublish.publish([d], format)
168 if out: return out
169
75110f0 @jdthomas Move call to sparkpos into template file.
jdthomas authored
170 return render.district(d, sparkpos)
d6e03b5 add web.py to REQUISITES
Aaron Swartz authored
171
670b7e4 @aaronsw add more links for bills, aligned groups
authored
172 def group_politician_similarity(politician_id, qmin=None):
a04e88f @aaronsw List interest group alignment, bills introduced
authored
173 """Find the interest groups that vote most like a politician."""
174 query_min = lambda mintotal, politician_id=politician_id: db.select(
175 'group_politician_similarity'
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
176 ' JOIN interest_group ON (interest_group.id = group_id)',
a04e88f @aaronsw List interest group alignment, bills introduced
authored
177 what='*, cast(agreed as float)/total as agreement',
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
178 where='total >= $mintotal AND politician_id=$politician_id ',
a04e88f @aaronsw List interest group alignment, bills introduced
authored
179 vars=locals()).list()
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
180
670b7e4 @aaronsw add more links for bills, aligned groups
authored
181 if qmin:
182 q = query_min(qmin)
183 else:
184 q = query_min(5)
a04e88f @aaronsw List interest group alignment, bills introduced
authored
185 if not q:
670b7e4 @aaronsw add more links for bills, aligned groups
authored
186 q = query_min(3)
187 if not q:
188 q = query_min(1)
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
189
a04e88f @aaronsw List interest group alignment, bills introduced
authored
190 q.sort(lambda x, y: cmp(x.agreement, y.agreement), reverse=True)
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
191 return q
a04e88f @aaronsw List interest group alignment, bills introduced
authored
192
76ada98 @asldevi paginate bills list, real name for bill sponsor, votes by party on bill ...
asldevi authored
193 def bill_list(format, page=0, limit=50):
776fe4c @aaronsw get most important pages using smartersql
authored
194 bills = schema.Bill.select(limit=limit, offset=page*limit, order='session desc, introduced desc, number desc')
195
196 out = apipublish.publish(bills, format)
197 if out: return out
198 #@@ add link to next page
199
76ada98 @asldevi paginate bills list, real name for bill sponsor, votes by party on bill ...
asldevi authored
200 return render.bill_list(bills, limit)
201
3be04aa @aaronsw import rolls, allow staggered import of bills
authored
202 class roll:
203 def GET(self, roll_id, format=None):
204 try:
205 b = schema.Roll.where(id=roll_id)[0]
206 votes = schema.Vote.where(roll_id=b.id)
207 except IndexError:
208 raise web.notfound
209
210 out = apipublish.publish([b], format)
211 if out: return out
e3e3e68 @aaronsw show votepcts
authored
212
213 def votepct(pvotes):
214 s = (float(pvotes.get(1, 0)) / sum(pvotes.values()))
215 return str(s * 100)[:4].rstrip('.') + '%'
3be04aa @aaronsw import rolls, allow staggered import of bills
authored
216
e3e3e68 @aaronsw show votepcts
authored
217 return render.roll(b, votes, votepct)
3be04aa @aaronsw import rolls, allow staggered import of bills
authored
218
3ef7d52 first cut at individual pages for bills
A.S.L. Devi authored
219 class bill:
220 def GET(self, bill_id, format=None):
221 if bill_id == "" or bill_id == "index":
76ada98 @asldevi paginate bills list, real name for bill sponsor, votes by party on bill ...
asldevi authored
222 i = web.input(page=0)
223 return bill_list(format, int(i.page))
776fe4c @aaronsw get most important pages using smartersql
authored
224
3ef7d52 first cut at individual pages for bills
A.S.L. Devi authored
225 try:
7f1f060 @aaronsw fix crashing typo
authored
226 b = schema.Bill.where(id=bill_id)[0]
3ef7d52 first cut at individual pages for bills
A.S.L. Devi authored
227 except IndexError:
228 raise web.notfound
776fe4c @aaronsw get most important pages using smartersql
authored
229
230 out = apipublish.publish([b], format)
231 if out: return out
232
3ef7d52 first cut at individual pages for bills
A.S.L. Devi authored
233 return render.bill(b)
234
dcb7d7f @jdthomas Add a basic page for earmarks.
jdthomas authored
235 def earmark_list(format, page=0, limit=50):
236 earmarks = schema.Earmark.select(limit=limit, offset=page*limit, order='id')
237
238 out = apipublish.publish(earmarks, format)
239 if out: return out
8f89018 @jdthomas Add list of earmarks by politician.
jdthomas authored
240 return render.earmark_list(earmarks, limit)
241 def earmark_pol_list(pol_id, format, page=0, limit=50):
3528f21 @jdthomas Order politician's earmarks by cost. (Bug 186)
jdthomas authored
242 earmarks = db.select(['earmark_sponsor', 'earmark'], what='earmark.*',
243 where='politician_id = $pol_id AND earmark_id=earmark.id',
244 order='final_amt desc', vars=locals())
245 if not earmarks:
e9f4585 @jdthomas Fix problem for people with NoneType data. For instance john_mccain's an...
jdthomas authored
246 # @@TODO: something better here.
247 raise web.notfound
8f89018 @jdthomas Add list of earmarks by politician.
jdthomas authored
248 out = apipublish.publish(earmarks, format)
249 if out: return out
dcb7d7f @jdthomas Add a basic page for earmarks.
jdthomas authored
250 return render.earmark_list(earmarks, limit)
251
cd5bad1 @jdthomas Fix url for politician specific earmarks. Bug 162.
jdthomas authored
252 class politician_earmarks:
253 def GET(self, polid, format=None):
254 try:
255 em = schema.Politician.where(id=polid)[0]
256 except IndexError:
257 raise web.notfound
258 return earmark_pol_list(polid, format)
dcb7d7f @jdthomas Add a basic page for earmarks.
jdthomas authored
259 class earmark:
260 def GET(self, earmark_id, format=None):
8f89018 @jdthomas Add list of earmarks by politician.
jdthomas authored
261 # No earmark id, show list
dcb7d7f @jdthomas Add a basic page for earmarks.
jdthomas authored
262 if earmark_id == "" or earmark_id == "index":
263 # Show earmark list
264 i = web.input(page=0)
265 return earmark_list(format, int(i.page))
8f89018 @jdthomas Add list of earmarks by politician.
jdthomas authored
266 # Display the specific earmark
267 try:
268 em = schema.Earmark.where(id=int(earmark_id))[0]
269 except IndexError:
270 raise web.notfound
271 except ValueError:
dcb7d7f @jdthomas Add a basic page for earmarks.
jdthomas authored
272 raise web.notfound
273 return render.earmark(em)
274
275
8dfd496 @aaronsw add initial politician data from govtrack
authored
276 class politician:
a067eb2 @aaronsw add API export support for major pages
authored
277 def GET(self, polid, format=None):
8dfd496 @aaronsw add initial politician data from govtrack
authored
278 if polid != polid.lower():
279 raise web.seeother('/p/' + polid.lower())
58c2be1 @aaronsw look up by ID
authored
280
281 i = web.input()
282 idlookup = False
283 for k in ['votesmartid', 'bioguideid', 'opensecretsid', 'govtrackid']:
284 if i.get(k):
285 idlookup = True
286 ps = schema.Politician.where(**{k: i[k]})
287 if ps: raise web.seeother('/p/' + ps[0].id)
288
289 if idlookup:
290 # we were looking up by ID but nothing matched
291 raise web.notfound
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
292
37659f4 @aaronsw add list of politicians, API docs
authored
293 if polid == "" or polid == "index":
776fe4c @aaronsw get most important pages using smartersql
authored
294 p = schema.Politician.select(order='district_id asc')
295
296 out = apipublish.publish(p, format)
297 if out: return out
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
298
37659f4 @aaronsw add list of politicians, API docs
authored
299 return render.pollist(p)
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
300
a067eb2 @aaronsw add API export support for major pages
authored
301 try:
776fe4c @aaronsw get most important pages using smartersql
authored
302 p = schema.Politician.where(id=polid)[0]
a067eb2 @aaronsw add API export support for major pages
authored
303 except IndexError:
304 raise web.notfound
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
305
776fe4c @aaronsw get most important pages using smartersql
authored
306 #@@move into schema
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
307 p.fec_ids = [x.fec_id for x in db.select('politician_fec_ids', what='fec_id',
b6037cc @aaronsw add FEC data
authored
308 where='politician_id=$polid', vars=locals())]
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
309
c1face8 @asldevi added related_groups and sponsored_bills to politician API
asldevi authored
310 p.related_groups = group_politician_similarity(polid)
776fe4c @aaronsw get most important pages using smartersql
authored
311
312 out = apipublish.publish([p], format)
313 if out: return out
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
314
75110f0 @jdthomas Move call to sparkpos into template file.
jdthomas authored
315 return render.politician(p, sparkpos)
8dfd496 @aaronsw add initial politician data from govtrack
authored
316
59484d7 @jdthomas Some initial pages for lobbyist stuff.
jdthomas authored
317 class lob_filing:
318 def GET(self, filing_id):
319 limit = 50
320 page = int(web.input(page=0).page)
321 if filing_id:
322 f = schema.lob_filing.select(where='id=$filing_id', limit=limit, offset=page*limit, vars=locals())
323 else:
324 f = schema.lob_filing.select(limit=limit, offset=page*limit)
325 return render.lob_filings(f,limit)
326 class lob_contrib:
327 def GET(self, filing_id):
328 limit = 50
329 page = int(web.input(page=0).page)
330 if filing_id:
331 c = schema.lob_contribution.select(where='filing_id=$filing_id', limit=limit, offset=page*limit, order='amount desc', vars=locals())
332 else:
333 c = schema.lob_contribution.select(limit=limit, offset=page*limit, order='amount desc')
334 return render.lob_contributions(c, limit)
335 class lob_pac:
336 def GET(self, pac_id):
337 limit = 50
338 i = web.input(page=0)
339 page = int(i.page)
340 if 'filing_id' in i:
341 p = [x.pac for x in schema.lob_pac_filings.select(where='filing_id=$i.filing_id',limit=limit, offset=page*limit, vars=locals())]
342 elif pac_id:
343 p = schema.lob_pac.select(where='id=$pac_id',limit=limit, offset=page*limit, vars=locals())
344 else:
345 p = schema.lob_pac.select(limit=limit, offset=page*limit)
346 return render.lob_pacs(p,limit)
347 class lob_org:
348 def GET(self, org_id):
349 limit = 50
350 i = web.input(page=0)
351 page = int(i.page)
352 if org_id:
353 o = schema.lob_organization.select(where='id=$org_id', limit=limit, offset=page*limit, order='name asc', vars=locals())
354 else:
355 o = schema.lob_organization.select(limit=limit, offset=page*limit, order='name asc')
356 return render.lob_orgs(o,limit)
357 class lob_person:
358 def GET(self, person_id):
359 limit = 50
360 i = web.input(page=0)
361 page = int(i.page)
362 if person_id:
363 p = schema.lob_person.select(where='id=$person_id', limit=limit, offset=page*limit, order='lastname asc', vars=locals())
364 else:
365 p = schema.lob_person.select(limit=limit, offset=page*limit, order='lastname asc')
366 return render.lob_person(p,limit)
367
670b7e4 @aaronsw add more links for bills, aligned groups
authored
368 class politician_introduced:
369 def GET(self, politician_id):
776fe4c @aaronsw get most important pages using smartersql
authored
370 pol = schema.Politician.where(id=politician_id)[0]
371 return render.politician_introduced(pol)
670b7e4 @aaronsw add more links for bills, aligned groups
authored
372
a04e88f @aaronsw List interest group alignment, bills introduced
authored
373 class politician_groups:
670b7e4 @aaronsw add more links for bills, aligned groups
authored
374 def GET(self, politician_id):
375 related = group_politician_similarity(politician_id, qmin=1)
57f54c0 @asldevi Don't autoreload in production mode;
asldevi authored
376 pol = schema.Politician.where(id=politician_id)[0]
377 return render.politician_groups(pol, related)
670b7e4 @aaronsw add more links for bills, aligned groups
authored
378
379 class politician_group:
a04e88f @aaronsw List interest group alignment, bills introduced
authored
380 def GET(self, politician_id, group_id):
3be04aa @aaronsw import rolls, allow staggered import of bills
authored
381 votes = db.select(['position', 'interest_group_bill_support', 'bill'],
382 where="interest_group_bill_support.bill_id = position.bill_id AND "
383 "position.bill_id = bill.id AND "
a04e88f @aaronsw List interest group alignment, bills introduced
authored
384 "politician_id = $politician_id AND group_id = $group_id",
385 order='vote = support desc',
386 vars=locals())
387
388 return render.politician_group(votes)
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
389
a04e88f @aaronsw List interest group alignment, bills introduced
authored
390
4eee6b0 add population, distribution pages for each, code and url cleanup
Aaron Swartz authored
391 r_safeproperty = re.compile('^[a-z0-9_]+$')
08827f0 @aaronsw add speech information to pol pages
authored
392 table_map = {'us': 'district', 'p': 'politician'}
4eee6b0 add population, distribution pages for each, code and url cleanup
Aaron Swartz authored
393
7c65867 more data, some first stabs at graphs
Aaron Swartz authored
394 class dproperty:
08827f0 @aaronsw add speech information to pol pages
authored
395 def GET(self, table, what):
396 try:
397 table = table_map[table]
398 except KeyError:
399 raise web.notfound
4eee6b0 add population, distribution pages for each, code and url cleanup
Aaron Swartz authored
400 if not r_safeproperty.match(what): raise web.notfound
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
401
14c0d2e @asldevi bug fixes
asldevi authored
402 #if `what` is not there in the `table` (provide available options rather than 404???)
403 try:
404 maxnum = float(db.select(table,
acaa337 Test-covered and reformatted more of webapp.py.
Kragen Javier Sitaker authored
405 what='max(%s) as m' % what,
406 vars=locals())[0].m)
14c0d2e @asldevi bug fixes
asldevi authored
407 except:
408 raise web.notfound
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
409
08827f0 @aaronsw add speech information to pol pages
authored
410 items = db.select(table,
acaa337 Test-covered and reformatted more of webapp.py.
Kragen Javier Sitaker authored
411 what="*, 100*(%s/$maxnum) as pct" % what,
412 order='%s desc' % what,
413 where='%s is not null' % what,
08827f0 @aaronsw add speech information to pol pages
authored
414 vars=locals()).list()
415 for item in items:
416 if table == 'district':
417 item.id = 'd' + item.name
418 item.path = '/us/' + item.name.lower()
419 elif table == 'politician':
67822ef @aaronsw typos and small fixes
authored
420 item.name = '%s %s (%s-%s)' % (item.firstname, item.lastname,
5d972e8 @aaronsw fix crasher
authored
421 (item.party or 'I')[0], item.district_id.split('-')[0])
08827f0 @aaronsw add speech information to pol pages
authored
422 item.path = '/p/' + item.id
423 return render.dproperty(items, what)
320eb4d add about, zip2rep
Aaron Swartz authored
424
f0292a2 @jdthomas Add sparkline numbers to district pages.
jdthomas authored
425 def sparkpos(table, what, id):
426 if table == 'district':
427 id_col = 'name'
428 id = id.upper()
429 elif table == 'politician':
430 id_col= 'id'
431 else: return 0
917d8a5 @aaronsw fix sql injection; show earmark recipients
authored
432 assert table in table_map.values()
433 if not r_safeproperty.match(what): raise web.notfound
434
435 item = db.query("select count(*) as position from %(table)s, \
436 (select * from %(table)s where %(id_col)s=$id) as a \
437 where %(table)s.%(what)s > a.%(what)s" %
438 {'table':table, 'what':what, 'id_col':id_col}, vars={'id': id})[0]
7445e5a @jdthomas Add number ranking to sparklines.
jdthomas authored
439 return item.position + 1 # '#1' looks better than '#0'
440
7c65867 more data, some first stabs at graphs
Aaron Swartz authored
441 class sparkdist:
08827f0 @aaronsw add speech information to pol pages
authored
442 def GET(self, table, what):
443 try:
444 table = table_map[table]
445 except KeyError:
446 raise web.notfound
4eee6b0 add population, distribution pages for each, code and url cleanup
Aaron Swartz authored
447 if not r_safeproperty.match(what): raise web.notfound
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
448
4eee6b0 add population, distribution pages for each, code and url cleanup
Aaron Swartz authored
449 inp = web.input(point=None)
dabdbd0 @aaronsw flip order of the sparklines to be less confusing
authored
450 points = db.select(table, what=what, order=what+' asc', where=what+' is not null')
4eee6b0 add population, distribution pages for each, code and url cleanup
Aaron Swartz authored
451 points = [x[what] for x in points.list()]
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
452
7c65867 more data, some first stabs at graphs
Aaron Swartz authored
453 web.header('Content-Type', 'image/png')
4eee6b0 add population, distribution pages for each, code and url cleanup
Aaron Swartz authored
454 return simplegraphs.sparkline(points, inp.point)
7c65867 more data, some first stabs at graphs
Aaron Swartz authored
455
798035f @aaronsw add support for photos
authored
456 class staticdata:
457 def GET(self, path):
458 if not web.config.debug:
459 raise web.notfound
460
461 assert '..' not in path, 'security'
462 return file('data/' + path).read()
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
463
d6e03b5 add web.py to REQUISITES
Aaron Swartz authored
464 app = web.application(urls, globals())
50572a0 webchick redesign
Rebecca Malamud authored
465 def notfound():
466 web.ctx.status = '404 Not Found'
467 return getattr(render, '404')()
468
469 app.notfound = notfound
2dba2db @asldevi using production mode from environment, use the same for writerep too
asldevi authored
470 if production_mode:
5858fbb @asldevi Send email on crashes - #67
asldevi authored
471 app.internalerror = web.emailerrors(config.send_errors_to, web.debugerror)
c3bc533 @simonbc Petition UI: require sign up to create a new petition, new petition page
simonbc authored
472
145202c add newlines; fix gmaps api key
Aaron Swartz authored
473 if __name__ == "__main__": app.run()
Something went wrong with that request. Please try again.