Drupal, Grassroots Political Activism and the Ron Paul Campaign

There is a battle going on for the control of information. The powers that be (traditional news outlets) are increasingly being challenged by widespread independent media sources including bloggers and journalism-enabling sites like NowPublic. It is the difference between "Good evening. This is what the news is." and "What is going on in the world? I'll find out." The change from one to the other is inevitable.

In politics, this is an important change. Instead of politicians claiming that this or that is "the will of the American people", that will can actually be tested by listening to the people because the people now have a voice. The first real example of this was the Howard Dean campaign in 2004. Dean used DeanSpace, a community CMS based on Drupal, to raise massive internet support.

In the current U.S. presidential election, the candidate who is using the internet most effectively is Ron Paul. Like Howard Dean, Ron Paul's support on the internet is massive. While his main website does not run Drupal, the Daily Paul is a popular site about the campaign. It's managed by Michael Nystrom and it runs on Drupal.

What I find interesting about Ron Paul's campaign is that while Howard Dean had support from the mainstream media (representing the traditional "we will tell you what is important" position), Ron Paul seems to be virtually ignored by the mainstream media; only the Washington Post has covered him. Thus, he represents the first test of how well grassroots internet campaigns can fare when they are pitted against, and not supplemented by, traditional media.

Perhaps the Long Tail, while effective economically, is ineffective politically at the present time. When Ron Paul, a pro-life Christian obstetrician and ten-time Taxpayer's Friend awardee was excluded from a forum put on by the Iowa Christian Alliance and Iowans for Tax Relief in Iowa, eyebrows were raised and his supporters on the internet were quick to unearth the fact that the forum's organizer, Ed Failor, is a senior advisor to the McCain campaign and otherwise involved in Big Politics. But can they convince Iowans to vote for Ron Paul in the Iowa Straw Poll? They have until August 11. That remains to be seen, and would take a tremendous logistical and monetary effort.

While all that is interesting, times are not static. The young people who make up a significant portion (though not by any means all) of Ron Paul's support have grown up with the internet. They do not go to the television Evening News for their news. They do not have landline telephones that are called by pollsters. They are used to using news aggregators, where media bias is apparent. They're savvy. And -- here's the key -- they are making up an increasing percentage of the public.

So while Ron Paul's campaign may not succeed, the battle between old and new media, between the powers that be and the widespread dissatisfaction with those powers, between corporate power and individual power -- that battle will become increasingly heated.

For myself, I'm glad to be involved in an open source project like Drupal, which, in addition to being a platform for individual voices, is in itself a microcosm of individuals working together to achieve a communal goal.

[ Submitted by John on Sat, 2007-06-23 15:43. | | ]

Writing an action for Drupal 6

Note: this applies to the development version of Drupal 6 as of June 12, 2007 with the actions patch applied.

Actions are atomic functions that can be assigned to run at different times during runtime. For example, you could have an action that emails a user and have that run when a node is inserted. Or when a comment is deleted. Or when a user logs in.

When writing an action, you first need to decide whether or not your action will need to know anything beyond the context in which it runs. For example, an action that prefixes the title of a node with "New! " does not need any other information; it just needs the node. Let's actually create that action a moment.

First, we need to describe the action to Drupal. We do that with hook_action_info.

<?php
 
function modulename_action_info {
  return array(
   
'modulename_prepend_new_action' => array(
       
'type' => 'node',
       
'description' => t('Prepend "New! " to the title of a node'),
       
'configurable' => FALSE,
       
'hooks' => array(
         
'nodeapi' => array('presave''insert''update''view'),
         
'comment' => array('insert'),
       )
    )
  );
}/
?>

The array returned is keyed by function name. So later on we'll create a function called modulename_prepend_new_action(), probably not the best name but let's roll with it.

The 'type' key declares what object type this action will work on. It will work on nodes, so it's a 'node' type of action, or a node action.

The 'description' will appear in the UI when the administrator is assigning actions to hooks on the "Assign actions" screen.

The 'configurable' key declares whether or not the action needs additional information to run. This action doesn't; it simply modifies the node it's been given. More about configurable actions in a minute.

The 'hooks' key determines where this action may be assigned. For example, this action running during the 'register' op of the user hook would make no sense. But running in the 'presave' op of the nodeapi hook, where it can modify the node object just before it is saved, makes perfect sense.

Now for the action itself. It's dead simple.

<?php
 
function modulename_prepend_new_action(&$node$context) {
 
$node->title t('New!') . ' ' $node->title;

?>

What's in $context? Well, that's where Drupal puts any information that it thinks the action might want to use. Suppose we wanted this action to run when a comment is added. That's great. But internally, the comment is the object being worked with during the comment hook. So the actions module looks at the comment, finds the nid, loads the node, and passes that to the action (because it's a node action it expects a node). But since Drupal already has a copy of the comment object on hand, it puts it into the $context so that if the action wants to, it can look at it and make decisions based on that. So that's what $context is.

Now for the second kind of an action, a configurable action. That's like a stored procedure. For this we'll look at a comment action called Unpublish comment containing keyword(s). Obviously the action needs to know which keywords to compare with the comment body so it can figure out whether to unpublish the action or not. So it is a configurable action. Note that we don't use configurable actions directly; we make instances of them. We could make multiple action instances with descriptions like this:

Unpublish comment containing 'butter'
Unpublish comment containing 'blubber'
Unpublish comment containing 'flubber' or 'moose'

We would create these "action instances" on the "Manage actions" screen that the actions module provides. Here's the action_info() hook:

<?php
 
function comment_action_info() {
  return array(
   
'comment_unpublish_by_keyword_action' => array(
     
'description' => t('Unpublish comment containing keyword(s)'),
     
'type' => 'comment',
     
'configurable' => TRUE,
     
'hooks' => array(
       
'comment' => array('insert''update'),
      )
    )
  );

?>

Now we need to provide a way for the user to input which keywords to look for. So we create a comment_unpublish_by_keyword_action_form() function. Note we just append _form to the action function name. Here's the function, simplified:

<?php
 
function comment_unpublish_by_keyword_action_form($context) {
 
$form['keywords'] = array(
   
'#title' => t('Keywords'),
   
'#type' => 'textfield',
   
'#description' => t('The comment will be unpublished if it contains any of the keywords above. Use a comma-separated list of keywords. Example: funny, bungee jumping, "Company, Inc.".'),
   
'#default_value' => isset($context['keywords']) ? implode(','$context['keywords']) : '',
  );
  return 
$form;

?>

We could make a validation function (comment_unpublish_by_keyword_action_form_validate()) if we wanted to, but let's skip that and go right to the submission function. The taxonomy module already has a great implementation of turning comma-delimited keywords into an array, so we'll just use that. Code reuse!

<?php
 
function comment_unpublish_by_keyword_action_submit($form$form_state) {
  return array(
'keywords' => taxonomy_explode_tags($form_state['values']['keywords']));

?>

Note that we return a keyed array of parameters needed by the action. These parameters will be available inside $context. So the action will need to look for $context['keywords'] and that's exactly what it does:

<?php
 
function comment_unpublish_by_keyword_action($comment$context) {
  foreach (
$context['keywords'] as $keyword) {
    if (
strstr($comment->comment$keyword)) {
     
db_query('UPDATE {comments} SET status = 'COMMENT_NOT_PUBLISHED .' WHERE cid = %d'$comment->cid);
     
watchdog('action''Unpublished comment %subject.', array('%subject' => $comment->subject));
      break;
    }
  }

?>

There you have it. Try writing an action of your own!

[ Submitted by John on Mon, 2007-06-04 16:59. | | ]

It's shipping!

The book is finally making its way into hands of eager developers. Time for a bit of reflection. Writing this book was like one long code sprint. Because many topics couldn't be written about until the Drupal 5 codebase was frozen, we stacked a lot of the writing towards the end of the cycle. That meant that often we were each writing a new chapter, soliciting informal reviews from experts in a topic area from within the Drupal community, reviewing a chapter in the technical edit phase, and reviewing a chapter in the copy edit phase simultaneously. Towards the end, we added production-ready proof reviews to the menu.

Like a software project, the scope of the book had to be firmly enforced or it would not be in your hands today. But I'm glad it is. I'm also really happy that Matt agreed to be coauthor. Often his work would spur mine on (and, I think, vice versa). chx was amazing too, often turning around code reviews in a matter of hours. The Drupal community is, in short, amazing.

I'll just summarize by saying: whew.

And in case you've read the author info, here are some photos of a Bell & Howell Apple ][.

[ Submitted by John on Tue, 2007-04-17 22:46. | | ]

Drupal book printed

A box arrived today. Inside...copies of Pro Drupal Development hot off the press!

In the picture I'm holding my youngest son. He's in the picture to show what an optimist I am. I assured my wife that writing a book would be no problem. Why, it would be done long before the baby was born. Er. We'll celebrate his first birthday in a few weeks.

[ Submitted by John on Thu, 2007-04-12 20:01. | | ]

InfoWorld stops print publication

The only print publication on the subject of technology that I read is InfoWorld. I've read it since Stewart Alsop was editor.

It was clear that the print publication was going away when they did a format change from a large format to a slick magazine format, laid off the columnists that wrote nearly all of the parts of the magazine that I read, and started adding inscrutable technobabble articles aimed at C*O's.

I'm sad about the change, because though I follow a gaggle of online news sources, InfoWorld was something I that I read offline. Now I'll have to make polite conversation instead.

[ Submitted by John on Fri, 2007-04-06 13:17. | ]

Transparent bridging firewall

I had occasion today to set up a transparent bridging firewall. It's basically a computer that sits on the wire and silently drops packets matching certain rules.

In my case I wanted to restrict traffic to certain subnets without disturbing anything. So I took an Pentium Pro based HP Vectra (I'm telling you, those old HPs never die!) and put in two PCI-based ethernet cards, an Intel card and a trusty 3Com 905. It was nice that I had two different cards lying around, since they can be easily identified within FreeBSD by their separate interfaces (fxp0 and xl0, respectively). I installed FreeBSD 6.2 from a CD with minimal settings -- in particular, I declined to configure the network interface cards.

After install, I added the following line to /boot/loader.conf:

if_bridge_load="YES"

Added the following lines to /etc/rc.conf to force the two ethernet interfaces up and set up the bridge.

ifconfig_fxp0="up"
ifconfig_xl0="up"
cloned_interfaces="bridge0"
ifconfig_bridge0="addm fxp0 addm xl0 up"
firewall_enable="YES"
firewall_type="/etc/rc.firewall.local"
firewall_quiet="YES"
firewall_logging="YES"

Added the following to /etc/sysctl.conf:

net.link.bridge.ipfw=1
net.link.bridge.ipfw_arp=0

Then I added ipfw rules to /etc/rc.firewall.local.

Note that I did not assign an IP address to either network card. That means the only way into the machine is through the console, and the only way to tell that it's there on the wire is to guess because response time is a tiny bit longer.

So far it looks like even a Pentium Pro is overkill.

[ Submitted by John on Mon, 2007-04-02 16:34. | | ]

Off to the Printer

As we were writing the Drupal book, Matt and I frequently wondered how many pages it would come out to. We estimated about 300 pages.

When the book went to the printer, the total page count was just above 450.

[ Submitted by John on Mon, 2007-04-02 09:51. | | ]

Online/Offline Applications

Joyent is a company that offers shared and virtual hosting. I was able to get an opinion of their approach from some people whose opinions I respect at the recent OSCMS conference, and have pretty much decided not to go with them for my hosting needs (I'm currently looking for a hosting service).

However, their recent announcement of Joyent Slingshot is interesting: Joyent Slingshot allows developers to deploy Rails applications that work the same online and offline (with synchronization) and with drag into and out of the application just like a standard desktop application.

Radio Userland pioneered the idea of the local/remote web application and it's something for the Drupal community to consider. Drupal applications running locally and remotely. Syncing together (I know, I know, the publish and subscribe modules need a little love and a 5.0 release), maybe doing peer-to-peer. Hooking into iPhoto. Offline mirroring. There's so much to do!

[ Submitted by John on Tue, 2007-03-27 22:37. | | ]

OSCMS 2007

Back from Sunnyvale, where I had an enjoyable time at the 2007 OSCMS conference. I spent time hawking the book, geeking out, and hanging out with Adrian.

Unfortunately my return flight was badly timed (reminder: book flights earlier next time!) and I nearly missed it because I was talking to Dries about the actions module. Wish I could have been there for the whole hack session.

Judging by the buzz at the conference, Drupal has a bright future.

As for the conference itself, there was only one thing missing.

[ Submitted by John on Tue, 2007-03-27 20:41. | | ]