Esempio n. 1
0
def elections(request, office, cycle, state=None, district=None):
    cycle = int(cycle)

    # Get all cycles up until the cycle from the URL if it's beyond the current cycle
    # this fixes the issue of an election page not showing user-provided cycle
    # in the cycle select
    max_cycle = cycle if cycle > utils.current_cycle(
    ) else utils.current_cycle()
    cycles = utils.get_cycles(max_cycle)

    if office.lower() == 'president':
        cycles = [each for each in cycles if each % 4 == 0]
    elif office.lower() == 'senate':
        cycles = api_caller.get_all_senate_cycles(state)

    if office.lower() not in ['president', 'senate', 'house']:
        raise Http404()
    if state and state.upper() not in constants.states:
        raise Http404()

    return render(
        request, 'elections.jinja', {
            'office': office,
            'office_code': office[0],
            'parent': 'data',
            'cycle': cycle,
            'cycles': cycles,
            'state': state,
            'state_full': constants.states[state.upper()] if state else None,
            'district': district,
            'title': utils.election_title(cycle, office, state, district),
        })
Esempio n. 2
0
def elections(request, office, cycle, state=None, district=None):
    cycle = int(cycle)

    # Get all cycles up until the cycle from the URL if it's beyond the current cycle
    # this fixes the issue of an election page not showing user-provided cycle
    # in the cycle select
    max_cycle = cycle if cycle > utils.current_cycle(
    ) else utils.current_cycle()
    cycles = utils.get_cycles(max_cycle)

    if office.lower() == 'president':
        cycles = [each for each in cycles if each % 4 == 0]
    elif office.lower() == 'senate':
        cycles = api_caller.get_all_senate_cycles(state)

    if office.lower() not in ['president', 'senate', 'house']:
        raise Http404()
    if (state is not None) and (state
                                and state.upper() not in constants.states):
        raise Http404()

    #map/redirect legacy tab names to correct anchor
    tab = request.GET.get('tab', '').replace('/', '')
    legacy_tabs = {
        'contributions': '#individual-contributions',
        'totals': '#candidate-financial-totals',
        'spending-by-others': '#independent-expenditures'
    }

    if tab in legacy_tabs.keys():
        if office == 'senate' or office == 'house':
            return redirect(
                reverse('elections-state-district',
                        args=(office, state, district, cycle)) +
                legacy_tabs[tab])
        if office == 'president':
            return redirect(
                reverse('elections-president', args=(office, cycle)) +
                legacy_tabs[tab])

    return render(
        request, 'elections.jinja', {
            'office': office,
            'office_code': office[0],
            'parent': 'data',
            'cycle': cycle,
            'cycles': cycles,
            'state': state,
            'state_full': constants.states[state.upper()] if state else None,
            'district': district,
            'title': utils.election_title(cycle, office, state, district),
        })
Esempio n. 3
0
def elections_lookup(request):
    cycles = utils.get_cycles(utils.current_cycle())

    return render(request, 'election-lookup.jinja', {
        'parent': 'data',
        'cycles': cycles
    })
Esempio n. 4
0
def raising_spending(request):
    office = request.GET.get('office', 'P')

    election_year = int(request.GET.get('election_year', constants.DEFAULT_ELECTION_YEAR))

    max_election_year = utils.current_cycle() + 4
    election_years = utils.get_cycles(max_election_year)

    FEATURES = settings.FEATURES

    return {
        'name_field': 'name',
        'id_field:': 'candidate_id',
        'candidate': 'candidate_id',
        'action': 'raised',
        'title': 'Raising: by the numbers',
        'election_years': election_years,
        'election_year': election_year,
        'office': office,
        'FEATURES': FEATURES
    }
Esempio n. 5
0
def spending(request):
    office = request.GET.get("office", "P")

    election_year = int(
        request.GET.get("election_year", constants.DEFAULT_ELECTION_YEAR))

    max_election_year = utils.current_cycle() + 4
    election_years = utils.get_cycles(max_election_year)

    return render(
        request,
        "spending-bythenumbers.jinja",
        {
            "parent": "data",
            "title": "Spending: by the numbers",
            "election_years": election_years,
            "election_year": election_year,
            "office": office,
            "social_image_identifier": "data",
        },
    )
Esempio n. 6
0
def raising(request):
    top_category = request.GET.get('top_category', 'P')
    cycles = utils.get_cycles(utils.current_cycle())
    cycle = request.GET.get('cycle', constants.DEFAULT_TIME_PERIOD)

    if top_category in ['pac']:
        top_raisers = api_caller.load_top_pacs('-receipts',
                                               cycle=cycle,
                                               per_page=10)
    elif top_category in ['party']:
        top_raisers = api_caller.load_top_parties('-receipts',
                                                  cycle=cycle,
                                                  per_page=10)
    else:
        top_raisers = api_caller.load_top_candidates('-receipts',
                                                     office=top_category,
                                                     cycle=cycle,
                                                     per_page=10)

    if cycle == datetime.datetime.today().year:
        coverage_end_date = datetime.datetime.today()
    else:
        coverage_end_date = datetime.date(cycle, 12, 31)

    page_info = top_raisers['pagination']

    return render(
        request, 'raising-breakdown.jinja', {
            'parent': 'data',
            'title': 'Raising breakdown',
            'top_category': top_category,
            'coverage_start_date': datetime.date(cycle - 1, 1, 1),
            'coverage_end_date': coverage_end_date,
            'cycles': cycles,
            'cycle': cycle,
            'top_raisers': top_raisers['results'],
            'page_info': utils.page_info(top_raisers['pagination'])
        })
Esempio n. 7
0
def aggregate_totals(request):
    office = request.GET.get("office", "P")

    election_year = int(
        request.GET.get("election_year", constants.DEFAULT_ELECTION_YEAR))

    max_election_year = utils.current_cycle() + 4
    election_years = utils.get_cycles(max_election_year)

    FEATURES = settings.FEATURES

    return render(
        request,
        "widgets/aggregate-totals.jinja",
        {
            "title": "Aggregate Totals",
            "election_years": election_years,
            "election_year": election_year,
            "office": office,
            "FEATURES": FEATURES,
            "social_image_identifier": "data",
        },
    )
Esempio n. 8
0
def candidate(request, candidate_id):
    # grab url query string parameters
    cycle = request.GET.get('cycle', None)
    election_full = request.GET.get('election_full', True)

    if cycle is not None:
        cycle = int(cycle)

    # set election_full to boolean from passed string variable
    election_full = bool(strtobool(str(election_full)))

    candidate, committees, cycle = api_caller.load_with_nested(
        'candidate',
        candidate_id,
        'committees',
        cycle=cycle,
        cycle_key='two_year_period',
        election_full=election_full,
    )

    if election_full and cycle and cycle not in candidate['election_years']:

        next_cycle = next(
            (year
             for year in sorted(candidate['election_years']) if year > cycle),
            max(candidate['election_years']),
        )

        # If the next_cycle is odd set it to whatever the cycle value was
        # and then set election_full to false
        # This solves an issue with special elections
        if next_cycle % 2 > 0:
            next_cycle = cycle
            election_full = False

        candidate, committees, cycle = api_caller.load_with_nested(
            'candidate',
            candidate_id,
            'committees',
            cycle=next_cycle,
            cycle_key='two_year_period',
            election_full=election_full,
        )

    election_year = next(
        (year
         for year in sorted(candidate['election_years']) if year >= cycle),
        None,
    )

    result_type = 'candidates'
    duration = election_durations.get(candidate['office'], 2)
    min_cycle = cycle - duration if election_full else cycle
    report_type = report_types.get(candidate['office'])

    # For JavaScript
    context_vars = {
        'cycles': candidate['cycles'],
        'name': candidate['name'],
        'cycle': cycle,
        'electionFull': election_full,
        'candidateID': candidate['candidate_id']
    }

    # In the case of when a presidential or senate candidate has filed
    # for a future year that's beyond the current cycle,
    # set a max_cycle var to the current cycle we're in
    # and when calling the API for totals, set election_full to False.
    # The max_cycle value is also referenced in the templates for setting
    # the cycle for itemized tables. Because these are only in 2-year chunks,
    # the cycle should never be beyond the one we're in.
    cycles = [
        cycle for cycle in candidate['cycles']
        if cycle <= utils.current_cycle()
    ]
    max_cycle = cycle if cycle <= utils.current_cycle(
    ) else utils.current_cycle()
    show_full_election = election_full if cycle <= utils.current_cycle(
    ) else False

    # Annotate committees with most recent available cycle
    aggregate_cycles = (list(range(cycle, cycle - duration, -2))
                        if election_full else [cycle])
    for committee in committees:
        committee['related_cycle'] = (max(
            cycle for cycle in aggregate_cycles
            if cycle in committee['cycles']) if election_full else
                                      candidate['two_year_period'])

    # Group the committees by designation
    committee_groups = groupby(committees, lambda each: each['designation'])
    committees_authorized = committee_groups.get(
        'P', []) + committee_groups.get('A', [])

    committee_groups = committee_groups
    committees_authorized = committees_authorized
    committee_ids = [
        committee['committee_id'] for committee in committees_authorized
    ]

    # Get aggregate totals for the financial summary
    # And pass through the data processing utils
    aggregate = api_caller.load_candidate_totals(
        candidate['candidate_id'],
        cycle=max_cycle,
        election_full=show_full_election,
    )
    if aggregate:
        raising_summary = utils.process_raising_data(aggregate)
        spending_summary = utils.process_spending_data(aggregate)
        cash_summary = utils.process_cash_data(aggregate)
    else:
        raising_summary = None
        spending_summary = None
        cash_summary = None

    aggregate = aggregate

    # Get totals for the last two-year period of a cycle for showing on
    # raising and spending tabs
    two_year_totals = api_caller.load_candidate_totals(
        candidate['candidate_id'], cycle=max_cycle, election_full=False)

    # Get the statements of candidacy
    statement_of_candidacy = api_caller.load_candidate_statement_of_candidacy(
        candidate['candidate_id'], cycle=cycle)

    if statement_of_candidacy:
        for statement in statement_of_candidacy:
            # convert string to python datetime and parse for readable output
            statement['receipt_date'] = datetime.datetime.strptime(
                statement['receipt_date'], '%Y-%m-%dT%H:%M:%S')
            statement['receipt_date'] = statement['receipt_date'].strftime(
                '%m/%d/%Y')

    # Get all the elections
    elections = sorted(
        zip(candidate['election_years'], candidate['election_districts']),
        key=lambda pair: pair[0],
        reverse=True,
    )

    return render(
        request, 'candidates-single.jinja', {
            'name': candidate['name'],
            'cycle': int(cycle),
            'office': candidate['office'],
            'office_full': candidate['office_full'],
            'state': candidate['state'],
            'district': candidate['district'],
            'candidate_id': candidate_id,
            'party_full': candidate['party_full'],
            'incumbent_challenge_full': candidate['incumbent_challenge_full'],
            'election_year': election_year,
            'election_years': candidate['election_years'],
            'result_type': result_type,
            'duration': duration,
            'min_cycle': min_cycle,
            'report_type': report_type,
            'cycles': cycles,
            'max_cycle': max_cycle,
            'show_full_election': show_full_election,
            'committee_groups': committee_groups,
            'committees_authorized': committees_authorized,
            'committee_ids': committee_ids,
            'raising_summary': raising_summary,
            'spending_summary': spending_summary,
            'cash_summary': cash_summary,
            'aggregate': aggregate,
            'two_year_totals': two_year_totals,
            'statement_of_candidacy': statement_of_candidacy,
            'elections': elections,
            'candidate': candidate,
            'context_vars': context_vars
        })
Esempio n. 9
0
def committee(request, committee_id):
    # grab url query string parameters
    cycle = request.GET.get('cycle', None)

    redirect_to_previous = False if cycle else True
    committee, candidates, cycle = api_caller.load_with_nested(
        'committee', committee_id, 'candidates', cycle)

    parent = 'data'
    cycle = int(cycle)
    year = to_date(committee, cycle)
    result_type = 'committees'

    # Link to current cycle if candidate has a corresponding page, else link
    # without cycle query parameter
    # See https://github.com/18F/openFEC/issues/1536
    for candidate in candidates:
        election_years = [
            election_year for election_year in candidate['election_years']
            if election_year -
            election_durations[candidate['office']] < cycle <= election_year
        ]
        candidate['related_cycle'] = max(
            election_years) if election_years else None

    # add related candidates a level below
    financials = api_caller.load_cmte_financials(committee_id, cycle=cycle)

    report_type = report_types.get(committee['committee_type'], 'pac-party')
    reports = financials['reports']
    totals = financials['totals']

    context_vars = {
        'cycle': cycle,
        'timePeriod': str(int(cycle) - 1) + '–' + str(cycle),
        'name': committee['name'],
    }

    template_variables = {
        'name': committee['name'],
        'committee': committee,
        'committee_id': committee_id,
        'committee_type_full': committee['committee_type_full'],
        'committee_type': committee['committee_type'],
        'designation_full': committee['designation_full'],
        'street_1': committee['street_1'],
        'city': committee['city'],
        'state': committee['state'],
        'zip': committee['zip'],
        'treasurer_name': committee['treasurer_name'],
        'parent': parent,
        'cycle': cycle,
        'cycles': committee['cycles'],
        'year': year,
        'result_type': result_type,
        'report_type': report_type,
        'reports': reports,
        'totals': totals,
        'min_receipt_date': utils.three_days_ago(),
        'context_vars': context_vars,
        'party_full': committee['party_full']
    }

    if financials['reports'] and financials['totals']:
        # Format the current two-year-period's totals using the process utilities
        if committee['committee_type'] == 'I':
            # IE-only committees have very little data, so they just get this one
            template_variables['ie_summary'] = utils.process_ie_data(
                financials['totals'][0])
        else:
            # All other committees have three tables
            template_variables['raising_summary'] = utils.process_raising_data(
                financials['totals'][0])
            template_variables[
                'spending_summary'] = utils.process_spending_data(
                    financials['totals'][0])
            template_variables['cash_summary'] = utils.process_cash_data(
                financials['totals'][0])

    if redirect_to_previous and not financials['reports']:
        # If there's no reports, find the first year with reports and redirect there
        for c in sorted(committee['cycles'], reverse=True):
            financials = api_caller.load_cmte_financials(
                committee['committee_id'], cycle=c)
            if financials['reports']:
                return redirect(
                    reverse('committee-by-id',
                            kwargs={'committee_id': committee['committee_id']})
                    + '?cycle=' + str(c))

    # If it's not a senate committee and we're in the current cycle
    # check if there's any raw filings in the last three days
    if committee['committee_type'] != 'S' and cycle == utils.current_cycle():
        raw_filings = api_caller._call_api(
            'efile',
            'filings',
            cycle=cycle,
            committee_id=committee['committee_id'],
            min_receipt_date=template_variables['min_receipt_date'])
        if len(raw_filings.get('results')) > 0:
            template_variables['has_raw_filings'] = True
    else:
        template_variables['has_raw_filings'] = False

    return render(request, 'committees-single.jinja', template_variables)
Esempio n. 10
0
def elections(request, office, cycle, state=None, district=None):
    cycle = int(cycle)

    max_cycle = utils.current_cycle() + 4
    cycles = utils.get_cycles(max_cycle)

    if office.lower() == "president":
        cycles = [each for each in cycles if each % 4 == 0]
    elif office.lower() == "senate":
        cycles = api_caller.get_all_senate_cycles(state)

    if office.lower() not in ["president", "senate", "house"]:
        raise Http404()
    if (state is not None) and (state
                                and state.upper() not in constants.states):
        raise Http404()

    election_duration = election_durations.get(office[0].upper(), 2)
    # Puerto Rico house/resident commissioners have 4-year cycles
    if state and state.upper() == "PR":
        election_duration = 4

    # map/redirect legacy tab names to correct anchor
    tab = request.GET.get("tab", "").replace("/", "")
    legacy_tabs = {
        "contributions": "#individual-contributions",
        "totals": "#candidate-financial-totals",
        "spending-by-others": "#independent-expenditures",
    }

    if tab in legacy_tabs:
        if office == "house":
            return redirect(
                reverse("elections-house",
                        args=(office, state, district, cycle)) +
                legacy_tabs[tab])
        elif office == "senate":
            return redirect(
                reverse("elections-senate", args=(office, state, cycle)) +
                legacy_tabs[tab])
        elif office == "president":
            return redirect(
                reverse("elections-president", args=(office, cycle)) +
                legacy_tabs[tab])

    return render(
        request,
        "elections.jinja",
        {
            "office": office,
            "office_code": office[0],
            "parent": "data",
            "cycle": cycle,
            "election_duration": election_duration,
            "cycles": cycles,
            "state": state,
            "state_full": constants.states[state.upper()] if state else None,
            "district": district,
            "title": utils.election_title(cycle, office, state, district),
            "social_image_identifier": "data",
        },
    )
Esempio n. 11
0
def get_committee(committee_id, cycle):
    """
    Given a committee_id and cycle, call the API and get the committee
    and committee financial data needed to render the committee profile page
    """

    committee, all_candidates, cycle = load_committee_history(
        committee_id, cycle)
    # When there are multiple candidate records of various offices (H, S, P)
    # linked to a single committee ID,
    # associate the candidate record with the matching committee type
    candidates = [
        candidate for candidate in all_candidates
        if committee["committee_type"] == candidate["office"]
    ]

    parent = "data"
    result_type = "committees"
    cycle = int(cycle)
    year = to_date(committee, cycle)

    # Link to current cycle if candidate has a corresponding page, else link
    # without cycle query parameter
    # See https://github.com/fecgov/openFEC/issues/1536
    for candidate in candidates:
        election_years = []
        for election_year in candidate["election_years"]:
            start_of_election_period = (
                election_year - election_durations[candidate["office"]])
            if start_of_election_period < cycle and cycle <= election_year:
                election_years.append(election_year)
        # For each candidate, set related_cycle to the candidate's time period
        # relative to the selected cycle.
        candidate["related_cycle"] = cycle if election_years else None

    report_type = report_types.get(committee["committee_type"], "pac-party")

    cycle_out_of_range, fallback_cycle, cycles = load_cycle_data(
        committee, cycle)

    reports, totals = load_reports_and_totals(committee_id, cycle,
                                              cycle_out_of_range,
                                              fallback_cycle)

    # Check organization types to determine SSF status
    is_ssf = committee.get("organization_type") in [
        "W", "C", "L", "V", "M", "T"
    ]

    # if cycles_has_activity's options are more than cycles_has_financial's,
    # when clicking back to financial summary/raising/spending,
    # reset cycle=fallback_cycle and timePeriod and.
    # to make sure missing message page show correct timePeriod.
    time_period_js = str(int(cycle) - 1) + "–" + str(cycle)
    cycle_js = cycle
    if cycle_out_of_range:
        cycle_js = fallback_cycle
        time_period_js = str(int(cycle_js) - 1) + "–" + str(cycle_js)

    context_vars = {
        "cycle": cycle_js,
        "timePeriod": time_period_js,
        "name": committee["name"],
        "cycleOutOfRange": cycle_out_of_range,
        "lastCycleHasFinancial": fallback_cycle,
    }

    template_variables = {
        "candidates": candidates,
        "committee": committee,
        "committee_id": committee_id,
        "committee_type": committee["committee_type"],
        "context_vars": context_vars,
        "cycle": cycle,
        "cycles": cycles,
        "is_SSF": is_ssf,
        "cycle_out_of_range": cycle_out_of_range,
        "parent": parent,
        "result_type": result_type,
        "report_type": report_type,
        "reports": reports,
        "totals": totals,
        "min_receipt_date": utils.three_days_ago(),
        "context_vars": context_vars,
        "party_full": committee["party_full"],
        "candidates": candidates,
        "social_image_identifier": "data",
        "year": year,
        "timePeriod": time_period_js,
    }
    # Format the current two-year-period's totals
    if reports and totals:
        # IE-only committees
        if committee["committee_type"] == "I":
            template_variables["ie_summary"] = utils.process_ie_data(totals)
        # Inaugural Committees
        elif committee["organization_type"] == "I":
            template_variables[
                "inaugural_summary"] = utils.process_inaugural_data(totals)
        # Host Committees that file on Form 4
        elif committee["organization_type"] == "H" and reports[
                "form_type"] == "F4":
            template_variables[
                "raising_summary"] = utils.process_host_raising_data(totals)
            template_variables[
                "spending_summary"] = utils.process_host_spending_data(totals)
            template_variables["cash_summary"] = utils.process_cash_data(
                totals)
        else:
            # All other committees have three tables
            template_variables["raising_summary"] = utils.process_raising_data(
                totals)
            template_variables[
                "spending_summary"] = utils.process_spending_data(totals)
            template_variables["cash_summary"] = utils.process_cash_data(
                totals)

    # If in the current cycle, check for raw filings in the last three days
    if cycle == utils.current_cycle():
        # (4)call efile/filings under tag: efiling
        path = "/efile/filings/"
        filters = {}
        filters["cycle"] = cycle
        filters["committee_id"] = committee["committee_id"]
        filters["min_receipt_date"] = template_variables["min_receipt_date"]
        raw_filings = api_caller.load_endpoint_results(path, **filters)

        template_variables["has_raw_filings"] = True if raw_filings else False
    else:
        template_variables["has_raw_filings"] = False

    # Needed for filings tab
    template_variables["filings_lookup"] = {
        "reports": ["F3", "F3X", "F3P", "F3L", "F4", "F5", "F7", "F13"],
        "notices": ["F5", "F24", "F6", "F9", "F10", "F11"],
        "statements": ["F1"],
        "other": ["F1M", "F8", "F99", "F12"],
    }

    # Call /filings?committee_id=C00693234&form_type=F1
    # Get the statements of organization
    statement_of_organization = api_caller.load_committee_statement_of_organization(
        committee_id)

    if statement_of_organization:
        statement_of_organization["receipt_date"] = format_receipt_date(
            statement_of_organization["receipt_date"])

    template_variables["statement_of_organization"] = statement_of_organization

    # Add message for a committee that was formerly an authorized candidate committee.
    # These committees are now unauthorized committees.
    converted_committee_id = None
    former_committee_name = None
    former_authorized_candidate_id = None
    former_authorized_candidate_name = None

    if cycle == 2020 and committee_to_candidate_linkage.get(committee_id):
        # Call /candidate/{candidate_id}/history/
        converted_committee_id = committee.get('committee_id')
        former_authorized_candidate_id = committee_to_candidate_linkage.get(
            converted_committee_id)
        path = "/candidate/" + str(
            former_authorized_candidate_id) + "/history/"
        filters = {}
        filters["per_page"] = 1
        candidate = api_caller.load_first_row_data(path, **filters)
        # Get the converted committee's former name and candidate name
        former_committee_name = former_committee_names.get(
            converted_committee_id)
        former_authorized_candidate_name = candidate.get('name')

    template_variables["former_committee_name"] = former_committee_name
    template_variables[
        "former_authorized_candidate_name"] = former_authorized_candidate_name
    template_variables[
        "former_authorized_candidate_id"] = former_authorized_candidate_id

    return template_variables