Exemple #1
0
def popular():
    '''Show all bills in the database for a given year,
       and how many people are tracking each one.
       This requires login, only because it seems rude to show information
       about our users to someone who can't be bothered to register.
    '''
    year = billutils.current_leg_year()
    yearstr = billutils.year_to_2digit(year)
    bills = Bill.query.all()
    # allbills.html expects a list of
    # [ [billno, title, link, fulltext_link, num_tracking ] ]
    bill_list = []
    for bill in bills:
        if bill.year != yearstr:
            continue
        num_tracking = bill.num_tracking()
        if num_tracking:
            bill_list.append( [ bill.billno, bill.title,
                                bill.bill_url(), bill.contentslink,
                                num_tracking ] )

    # Now sort by num_tracking, column 4:
    bill_list.sort(reverse=True, key=lambda l: l[4])
    bill_lists = [ { 'thelist': bill_list,
                     'header': "",
                     'alt': "Nobody seems to be tracking anything" } ]

    verb = 'are' if year >= billutils.current_leg_year() else 'were'

    return render_template('allbills.html', user=current_user,
                           title="%s Bills People %s Tracking" % (year, verb),
                           leg_year=year,
                           returnpage="popular",
                           bill_lists=bill_lists)
Exemple #2
0
def index():
    values = request.values.to_dict()
    if "year" in values:
        year = values['year']
    else:
        year = billutils.current_leg_year()
    return render_template('index.html', title='Home', sortby='status',
                           year=year)
Exemple #3
0
    def tracking(self, billno, leg_year=None):
        '''Convenience routine to help with laying out the allbills page
        '''
        if not leg_year:
            leg_year = billutils.current_leg_year()
        yearstr = billutils.year_to_2digit(leg_year)

        bill = Bill.query.filter_by(billno=billno, year=yearstr).first()
        if not bill:
            return False
        return (bill in self.bills)
Exemple #4
0
def bills_by_update_date():
    '''Return a list of bills in the current legislative year,
       sorted by how recently they've been updated, oldest first.
       No key required.
    '''
    year = request.values.get('year')
    if not year:
        year = billutils.current_leg_year()
    yearstr = billutils.year_to_2digit(year)

    bill_list = Bill.query.filter_by(year=yearstr) \
                          .order_by(Bill.update_date).all()
    return ','.join([ bill.billno for bill in bill_list])
Exemple #5
0
def appinfo(key):
    '''Display info about the app and the database.
    '''
    if key != billtracker.config["SECRET_KEY"]:
        return "FAIL Bad key\n"

    infostr = "<br>\nBillTracker at " + str(datetime.now())

    infostr += "<p>\nSQLALCHEMY_DATABASE_URI: " \
        + billtracker.config["SQLALCHEMY_DATABASE_URI"]
    infostr += '<br>\nDatabase: ' + str(db.session.get_bind())

    allusers = User.query.all()
    infostr += "<p>\n%d users registered." % len(allusers)

    # How active are the users?
    now = datetime.now(timezone.utc)
    curyear2d = billutils.year_to_2digit(billutils.current_leg_year())
    checked_in_last_day = 0
    never_checked = 0
    has_current_year_bills = 0
    totbills = 0
    spacer = '&nbsp;&nbsp;&nbsp;&nbsp;'
    for user in allusers:
        if not user.last_check:
            never_checked += 1
        elif now - user.last_check < timedelta(days=1):
            checked_in_last_day += 1
        totbills += len(user.bills)
        for bill in user.bills:
            if bill.year == curyear2d:
                has_current_year_bills += 1
                break

    infostr += "<br>\n%swith bills from this year: %d" % (spacer,
                                                      has_current_year_bills)
    infostr += "<br>\n%schecked in past day: %d" % (spacer,
                                                    checked_in_last_day)
    infostr += "<br>\n%snever checked: %d" % (spacer, never_checked)

    infostr += "<br>\nAverage bills per user: %d" % (totbills / len(allusers))

    return "OK " + infostr
Exemple #6
0
def make_new_bill(billno, leg_year=None):
    '''Create a new Bill object, not previously in the database,
       by fetching and parsing its page.
       Don't actually add it to the database, just return the Bill object.
    '''
    if not leg_year:
        leg_year = billutils.current_leg_year()

    b = nmlegisbill.parse_bill_page(billno, leg_year,
                                    cache_locally=True)

    if b:
        bill = Bill()
        bill.set_from_parsed_page(b)
    else:
        bill = None
        flash("Couldn't fetch information for %s" % billno)

    return bill
Exemple #7
0
    def bills_by_year(self, year=None):
        # XXX There has got to be a clever way to do this from the db,
        # but userbills only has user_id and bill_id.
        # thebills = db.session.query(userbills).filter_by(user_id=self.id, ).count()

        if not year:
            year = billutils.current_leg_year()

        elif type(year) is int and year < 0:
            return self.bills

        yearstr = billutils.year_to_2digit(year)

        bill_list = []
        for bill in self.bills:
            if bill.year == yearstr:
                bill_list.append(bill)

        return bill_list
Exemple #8
0
def allbills():
    '''Show all bills that have been filed, with titles and links,
       whether or not they're in our database or any user is tracking them.
       New bills the user hasn't seen before are listed first.
       By default, though, only show the current session.
    '''
    leg_year = billutils.current_leg_year()

    # Do the slow part first, before any database accesses.
    # This can fail, e.g. if nmlegis isn't answering.
    try:
        allbills = nmlegisbill.all_bills(leg_year)
        # This is an OrderedDict, { billno: [title, url] }
    except:
        allbills = None

    bills_seen = []
    if current_user and not current_user.is_anonymous:
        user = User.query.filter_by(username=current_user.username).first()

        if user.bills_seen:
            bills_seen = user.bills_seen.split(',')
    else:
        user = None

    if not allbills:
        flash("Problem fetching the list of all bills."
              "The legislative website my be overloaded.")
        return render_template('allbills.html', user=user,
                      title="NM Bill Tracker: Problem Fetching %d Bills"
                               % leg_year,
                               leg_year=leg_year,
                               bill_lists=None)

    newbills = []
    oldbills = []

    # allbills.html expects a list of
    # [ [billno, title, link, fulltext_link, num_tracking ] ]
    for billno in allbills:
        contentsurls = nmlegisbill.contents_url_for_billno(billno)
        if contentsurls:
            contents = contentsurls[0]
        else:
            contents = ''
        args = [ billno, allbills[billno][0], allbills[billno][1],
                 contents, Bill.num_tracking_billno(billno, leg_year) ]

        if user and billno not in bills_seen:
            newbills.append(args)
        else:
            oldbills.append(args)

    # Update user
    if user:
        user.bills_seen = ','.join(allbills.keys())
        db.session.add(user)
        db.session.commit()

    bill_lists = [ { 'thelist': newbills,
                     'header': """<h2>Recently Filed Bills:</h2>
<p>
These are the bills filed since the last time you checked this page.
<br />
(Warning: that means that if you leave this page and come back,
or reload the page, these bills will no longer be there!
So check them now.)""",
                     'alt': "Nothing new since you last looked."
                   },
                   { 'thelist': oldbills,
                     'header': "<h2>Older bills</h2>",
                     'alt': ""
                   } ]

    return render_template('allbills.html', user=user,
                           title="NM Bill Tracker: All %d Bills" \
                                 % billutils.current_leg_year(),
                           leg_year=leg_year,
                           bill_lists=bill_lists)
Exemple #9
0
def track_untrack():
    '''Called when the user marks bills for tracking or untracking
       via checkboxes, from either the addbills or allbills page.
    '''
    if request.method == 'POST' or request.method == 'GET':
        # request contains form (for POST), args (for GET),
        # and values (combined); the first two are ImmutableMultiDict,
        # values is CombinedMultiDict.
        # I've found no way to iterate through
        # either ImmutableMultiDict or CombinedMultiDict;
        # to_dict() is the only way I've found of accessing the contents.

        track = []
        untrack = []

        values = request.values.to_dict()

        if 'returnpage' in values:
            returnpage = values['returnpage']
        else:
            returnpage = 'addbills'

        if 'leg_year' in values:
            leg_year = values['leg_year']
        else:
            leg_year = billutils.current_leg_year()

        yearstr = billutils.year_to_2digit(leg_year)

        for billno in values:
            if values[billno] == 'on':
                # Untrack buttons may be u_BILLNO.YEAR or just BILLNO.YEAR;
                # track buttons will be f_BILLNO.YEAR.
                if billno.startswith('f_'):
                    track.append(billno[2:])
                elif billno.startswith('u_'):
                    untrack.append(billno[2:])
                else:
                    untrack.append(billno)

        print("track:", track, file=sys.stderr)
        print("untrack:", untrack, file=sys.stderr)

        if not track and not untrack:
            return redirect(url_for(returnpage))

        # Was querying the user here. Why? current_user is already set.
        # It's better not to do any database queries until we can batch
        # them all together.
        # user = User.query.filter_by(username=current_user.username).first()

        will_untrack = []
        not_tracking = []
        will_track = []
        already_tracking = []
        for billno in untrack:
            if current_user.tracking(billno, yearstr):
                will_untrack.append(billno)
            else:
                not_tracking.append(billno)
        for billno in track:
            if current_user.tracking(billno, yearstr):
                already_tracking.append(billno)
            else:
                will_track.append(billno)

        if already_tracking:
            flash("Already tracking %s" % ', '.join(already_tracking))

        if not_tracking:
            flash("Can't untrack %s; you weren't tracking them"
                  % ', '.join(not_tracking))

        if will_untrack:
            for b in current_user.bills_by_year(yearstr):
                if b.billno in will_untrack:
                    current_user.bills.remove(b)
            flash("You are no longer tracking %s" % ', '.join(will_untrack))

        # The hard (and slow) part: make new bills as needed.
        # Can't really do this asynchronously (unless it's with AJAX)
        # since the user is waiting.
        # However, querying Bill.query.filter_by apparently holds
        # the database locked open, keeping anyone else from writing it
        # while make_new_bill fetches info.

        if will_track:
            # Figure out which bills will need to be fetched:
            # Bills the user wants to track that don't exist yet in the db:
            new_billnos = []
            # Bills that the user will start tracking:
            bills_to_track = []
            for billno in will_track:
                b = db.session.query(Bill).filter(Bill.billno == billno).first()
                if b:
                    bills_to_track.append(b)
                else:
                    new_billnos.append(billno)

            # The session is open because of having done read queries.
            # Want to close it so it won't stay locked during the next part.
            # Does commit() close it? Not clear.
            db.session.commit()

            # Now, do the slow part: fetch the bills that need to be fetched.
            new_bills = []
            for billno in new_billnos:
                print("Needed to make a new bill for", billno, yearstr,
                      "in track_untrack", file=sys.stderr)
                bill = make_new_bill(billno, leg_year)
                new_bills.append(bill)
            flash("You are now tracking %s" % ', '.join(will_track))

            # Now add all the bills to track to the user's list
            # (hitting the database):
            for bill in bills_to_track:
                current_user.bills.append(bill)
            for bill in new_bills:
                print("Adding new bill", bill, "to the db", file=sys.stderr)
                db.session.add(bill)
                current_user.bills.append(bill)

        if will_track or will_untrack:
            # We changed something. Finish up and commit.
            db.session.add(current_user)
            db.session.commit()

    return redirect(url_for(returnpage))