Skip to content

HTTPS clone URL

Subversion checkout URL

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