def site_search(request): query = request.GET.get("query") state = request.GET.get("state") bills = [] people = [] if query: bills = search_bills(state=state, query=query, sort="-latest_action") # pagination page_num = int(request.GET.get("page", 1)) bills_paginator = Paginator(bills, 20) try: bills = bills_paginator.page(page_num) except EmptyPage: raise Http404() # people search people = [] for p in Person.objects.search(query, state=state): pd = person_as_dict(p) pd["current_state"] = jid_to_abbr( p.current_jurisdiction_id).upper() people.append(pd) return render( request, "public/views/search.html", { "query": query, "state": state, "bills": bills, "people": people }, )
def _get_random_bills(): bills = (Bill.objects.all().filter( updated_at__gte=datetime.datetime.now() - datetime.timedelta(days=3)).select_related( "legislative_session", "legislative_session__jurisdiction", "billstatus").prefetch_related("sponsorships").order_by("?"))[:3] for bill in bills: bill.state = jid_to_abbr(bill.legislative_session.jurisdiction_id) return bills
def person(request, person_id): SPONSORED_BILLS_TO_SHOW = 4 RECENT_VOTES_TO_SHOW = 3 ocd_person_id = decode_uuid(person_id) person = get_object_or_404( PersonProxy.objects.prefetch_related("memberships__organization"), pk=ocd_person_id, ) # to display district in front of district name, or not? district_maybe = "" # canonicalize the URL canonical_url = person.pretty_url() if request.path != canonical_url: return redirect(canonical_url, permanent=True) state = person.current_role["state"] if not state: # this breaks if they held office in two states, but we don't really worry about that for m in person.memberships.all(): if m.organization.classification in ("upper", "lower", "legislature"): state = jid_to_abbr(m.organization.jurisdiction_id) retired = True else: retired = False # does it start with a number? if str(person.current_role["district"])[0] in "0123456789": district_maybe = "District" person.all_contact_details = person.contact_details.order_by("note") person.sponsored_bills = list(Bill.objects.all().select_related( "legislative_session", "legislative_session__jurisdiction", "billstatus").filter(sponsorships__person=person).order_by( "-created_at", "id")[:SPONSORED_BILLS_TO_SHOW]) votes = person.votes.all().select_related( "vote_event", "vote_event__bill")[:RECENT_VOTES_TO_SHOW] person.vote_events = [] for vote in votes: vote_event = vote.vote_event vote_event.legislator_vote = vote person.vote_events.append(vote_event) return render( request, "public/views/legislator.html", { "state": state, "person": person, "state_nav": "legislators", "retired": retired, "district_maybe": district_maybe, }, )
def convert_bill(b, include_votes): try: abstract = b.abstracts.all()[0].abstract except IndexError: abstract = "" chamber = b.from_organization.classification state = jid_to_abbr(b.legislative_session.jurisdiction_id) try: openstates_id = b.legacy_mapping.all()[0].legacy_id except IndexError: openstates_id = "" if include_votes: votes = [ convert_vote(v, chamber, state, openstates_id) for v in b.votes.all() ] else: votes = None return { "title": b.title, "summary": abstract, "created_at": b.created_at.strftime(DATE_FORMAT), "updated_at": b.updated_at.strftime(DATE_FORMAT), "id": openstates_id, "all_ids": [openstates_id], "chamber": chamber, "state": state, "session": b.legislative_session.identifier, "type": b.classification, "bill_id": b.identifier, "actions": [convert_action(a) for a in b.actions.all()], "sources": [{ "url": s.url } for s in b.sources.all()], "sponsors": [convert_sponsor(sp) for sp in b.sponsorships.all()], "versions": convert_versions(b.versions.all()), "documents": convert_versions(b.documents.all()), "alternate_titles": [alt.title for alt in b.other_titles.all()], "votes": votes, "action_dates": { "first": expand_date(b.first_action), "last": expand_date(b.last_action), # TODO - needed? "passed_upper": None, "passed_lower": None, "signed": None, }, "scraped_subjects": b.subject, "alternate_bill_ids": [], "subjects": [], "companions": [], }
def convert_post(post): abbr = jid_to_abbr(post.organization.jurisdiction_id) return { "division_id": post.division_id, "boundary_id": post.division_id, "name": post.label, "chamber": post.organization.classification, "abbr": abbr, "legislators": [], # TODO? "num_seats": 1, "id": f"{abbr}-{post.organization.classification}-{post.label}", }
def convert_post(post): abbr = jid_to_abbr(post.organization.jurisdiction_id) return { 'division_id': post.division_id, 'boundary_id': post.division_id, 'name': post.label, 'chamber': post.organization.classification, 'abbr': abbr, 'legislators': [], # TODO? 'num_seats': 1, 'id': f'{abbr}-{post.organization.classification}-{post.label}', }
def convert_bill(b, include_votes): try: abstract = b.abstracts.all()[0].abstract except IndexError: abstract = "" chamber = b.from_organization.classification state = jid_to_abbr(b.legislative_session.jurisdiction_id) try: openstates_id = b.legacy_mapping.all()[0].legacy_id except IndexError: openstates_id = '' if include_votes: votes = [convert_vote(v, chamber, state, openstates_id) for v in b.votes.all()] else: votes = None return { 'title': b.title, 'summary': abstract, 'created_at': b.created_at.strftime(DATE_FORMAT), 'updated_at': b.updated_at.strftime(DATE_FORMAT), 'id': openstates_id, 'all_ids': [openstates_id], 'chamber': chamber, 'state': state, 'session': b.legislative_session.identifier, 'type': b.classification, 'bill_id': b.identifier, 'actions': [convert_action(a) for a in b.actions.all()], 'sources': [{'url': s.url} for s in b.sources.all()], 'sponsors': [convert_sponsor(sp) for sp in b.sponsorships.all()], 'versions': convert_versions(b.versions.all()), 'documents': convert_versions(b.documents.all()), 'alternate_titles': [alt.title for alt in b.other_titles.all()], 'votes': votes, 'action_dates': { 'first': expand_date(b.first_action), 'last': expand_date(b.last_action), # TODO - needed? 'passed_upper': None, 'passed_lower': None, 'signed': None, }, 'scraped_subjects': b.subject, 'alternate_bill_ids': [], 'subjects': [], 'companions': [], }
def delta_set_to_pr(delta_set: DeltaSet): """ get a list of person IDs mapped to lists of DiffItem and generate a github PR """ person_deltas = {} states = set() for pd in delta_set.person_deltas.all(): person_deltas[pd.person_id] = pd.data_changes states.add(jid_to_abbr(pd.person.current_jurisdiction_id)) files_by_id = get_files(person_deltas.keys(), states=states) new_files = {} for person_id in person_deltas: file = files_by_id[person_id] new_files[file.path] = patch_file(file, person_deltas[person_id]) url = create_pr(f"people_admin_deltas/{delta_set.id}", delta_set.name, new_files) return url
def vote(request, vote_id): vote = get_object_or_404( VoteEvent.objects.all().select_related( "organization", "legislative_session", "bill", "bill__legislative_session", "bill__from_organization", "bill__legislative_session__jurisdiction", ), pk="ocd-vote/" + vote_id, ) state = jid_to_abbr(vote.organization.jurisdiction_id) vote_counts = sorted(vote.counts.all(), key=_vote_sort_key) person_votes = sorted(vote.votes.all().select_related("voter"), key=_vote_sort_key) # add percentages to vote_counts total = sum(vc.value for vc in vote_counts) if total: for vc in vote_counts: vc.percent = vc.value / total * 100 # aggregate voter ids into one query voter_ids_to_query = [pv.voter_id for pv in person_votes if pv.voter_id] voter_parties = defaultdict(list) # party -> option -> value party_votes = defaultdict(lambda: defaultdict(int)) for membership in Membership.objects.filter( person_id__in=voter_ids_to_query, organization__classification="party").select_related( "organization"): voter_parties[membership.person_id].append( membership.organization.name) # attach party to people & calculate party-option crosstab for pv in person_votes: # combine other options if pv.option not in ("yes", "no"): option = "other" else: option = pv.option if pv.voter_id: pv.party = voter_parties[pv.voter_id][0] party_votes[pv.party][option] += 1 else: party_votes["Unknown"][option] += 1 # only show party breakdown if most people are matched if not person_votes or (len(voter_parties) / len(person_votes) < 0.8): party_votes = None else: party_votes = sorted(dict(party_votes).items()) return render( request, "public/views/vote.html", { "state": state, "state_nav": "bills", "vote": vote, "vote_counts": vote_counts, "person_votes": person_votes, "party_votes": party_votes, }, )
def all_metadata(request): return JsonResponse([v1_metadata(jid_to_abbr(j.id), j) for j in jurisdictions_qs()], safe=False)
def test_jid_to_abbr(): assert jid_to_abbr( "ocd-jurisdiction/country:us/state:nc/government") == "nc"
def convert_legislator(leg): if leg.given_name and leg.family_name: first_name = leg.given_name last_name = leg.family_name suffixes = "" else: last_name = leg.name suffixes = first_name = "" legacy_ids = [ oid.identifier for oid in leg.identifiers.all() if oid.scheme == "legacy_openstates" ] if not legacy_ids: legacy_ids = ["~not available~"] party = leg.primary_party state = jid_to_abbr(leg.current_jurisdiction_id) chamber = None district = None if leg.current_role: chamber = leg.current_role["org_classification"] district = leg.current_role["district"] email = None offices = defaultdict(dict) for cd in leg.contact_details.all(): offices[cd.note][cd.type] = cd.value if cd.type == "email" and not email: email = cd.value active = bool(chamber and district) try: url = leg.links.all()[0].url except IndexError: url = "" return { "id": legacy_ids[0], "leg_id": legacy_ids[0], "all_ids": legacy_ids, "full_name": leg.name, "first_name": first_name, "last_name": last_name, "suffix": suffixes, "photo_url": leg.image, "url": url, "email": email, "party": party, "chamber": chamber, "district": district, "state": state, "sources": [{ "url": s.url } for s in leg.sources.all()], "active": active, "roles": [{ "term": static.TERMS[state][-1]["name"], "district": district, "chamber": chamber, "state": state, "party": party, "type": "member", "start_date": None, "end_date": None, }] if active else [], "offices": [{ "name": label, "fax": details.get("fax"), "phone": details.get("voice"), "email": details.get("email"), "address": details.get("address"), "type": "capitol" if "capitol" in label.lower() else "district", } for label, details in offices.items()], "old_roles": {}, "middle_name": "", "country": "us", "level": "state", "created_at": leg.created_at.strftime(DATE_FORMAT), "updated_at": leg.updated_at.strftime(DATE_FORMAT), }
def person(request, person_id): SPONSORED_BILLS_TO_SHOW = 4 RECENT_VOTES_TO_SHOW = 3 try: ocd_person_id = decode_uuid(person_id) except ValueError: ocd_person_id = ( person_id # will be invalid and raise 404, but useful in logging later ) person = get_object_or_404( Person.objects.prefetch_related("memberships__organization"), pk=ocd_person_id, ) # to display district in front of district name, or not? district_maybe = "" # canonicalize the URL canonical_url = pretty_url(person) if request.path != canonical_url: return redirect(canonical_url, permanent=True) if not person.current_jurisdiction_id: state = None retired = True elif not person.current_role: # this breaks if they held office in two states, but we don't really worry about that state = jid_to_abbr(person.current_jurisdiction_id) retired = True else: state = jid_to_abbr(person.current_jurisdiction_id) retired = False # does it start with a number? if str(person.current_role["district"])[0] in "0123456789": district_maybe = "District" person.all_links = list(person.links.all()) person.all_offices = list(person.offices.all()) person.sponsored_bills = list(Bill.objects.all().select_related( "legislative_session", "legislative_session__jurisdiction", ).filter(sponsorships__person=person).order_by( "-created_at", "id")[:SPONSORED_BILLS_TO_SHOW]) votes = (person.votes.all().select_related( "vote_event", "vote_event__bill").order_by("-vote_event__start__date") [:RECENT_VOTES_TO_SHOW]) person.vote_events = [] for vote in votes: vote_event = vote.vote_event vote_event.legislator_vote = vote person.vote_events.append(vote_event) return render( request, "public/views/legislator.html", { "state": state, "person": person, "state_nav": "legislators", "retired": retired, "district_maybe": district_maybe, }, )