Automating mailman with ruby mechanize

One of the things I’ve found is that people forget events quite often, so I try to make it easy for people to know when and what the next MHVLUG meeting is.  One of the ways I’ve been doing this by setting the footer on our mailing list to list the next couple of meetings.  This has worked out well, except for when I forget to go and update it.

Mailman doesn’t have an API, but you can get past that by using ruby’s excellent mechanize package, which lets you nicely script complex interactions with websites.  With an hour of time I pulled together this script which now runs every night and automatically syncs from our icalendar feed and updates the mailing list footer appropriately.

#!/usr/bin/ruby

require "pp"
require "rubygems"
require "mechanize"
require "tzinfo"
require "icalendar"
require "open-uri"

@@upcoming =<<END
Upcoming Meetings (6pm - 8pm)                         MHVLS Auditorium
END

def next_meetings()
    open("http://mhvlug.org/calendar/ical") do |file|
        cal = Icalendar.parse(file)
        # ruby collections are sometimes quite compact, so here is the
        # short hand:
        #   Icalendar returns an array, so get the first element
        #   then get the events array
        #   then filter that by only events in the future, and Wed at 6pm
        #   then only get the first 3 ([0..2] is an array slice)
        events = cal.first.events.
            select { |a|
                (a.dtend > Date.today) and
                (a.dtstart.wday == 3) and
                (a.dtstart.hour == 18)
            }[0..2]

        events.each do |e|
            str = e.dtstart.strftime("%b %e - ") + e.summary
            str.gsub!(/  /, " ")
            @@upcoming += "  " + str + "n"
        end
    end
end

def update_mailman
    a = WWW::Mechanize.new

    # this is the page we want to go, but we aren't logged in yet, so it will give
    # us a login form
    login_page = a.get("http://mhvlug.org/cgi-bin/mailman/admin/mhvlug/nondigest")

    # find the form that gets us back to where we want to go, and set the adminpw field
    nondigest_page = login_page.form_with(
                         :action => "/cgi-bin/mailman/admin/mhvlug/nondigest"
                     ) do |f|
        # set your password here
        f.adminpw = "XXXXXXX"
    end.submit

    # we only care about updating 1 field, name=msg_footer, so find the right form
    # update the field, and submit
    p = nondigest_page.form_with(:action => "../../admin/mhvlug/nondigest") do |f|
        footer = f.msg_footer
        footer = footer.split("MHVLS Auditorium")[0]
        footer.gsub!(/Upcoming Meetings.*/, @@upcoming)
        puts footer
        f.msg_footer = footer
    end.submit
end

# pull from ical
next_meetings

# push to mailman
update_mailman

And now, one more manual task is being done by agents automatically for me.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s