Terminal Hacking Tool For Fallout 3

Recently I had to relax, was playing Fallout 3, and realized that when you hack terminals in the game, you follow the same algorithm. So I wrote a tiny tool that will walk you through hacking. It should get it every time. I think.

Terminal Hacking tool for Fallout 3

Conveniently Programming RSS Feeds in Drupal

Drupal feeds most of the content out of the box. If it doesn't do what you want, it allows you to use format_rss_item() and format_rss_channel(). This stuff is simple to use, but not very convenient by itself. There are two things that I like to do when building feeds:

  • Use theme functions to format items. (Makes designer happy.)
  • Make it as convenient as possible to program new types of RSS items (hello, PHP Metaprogramming).

I should mention that I'm working with Drupal 5.7, but any 5.x -6.x shouldn't be much different.

What's with that second point?

Yes, I like convenience. Well, say you're using a feed for getting updates on what your users do on your website. Sort of - an administration feed. Don't know about you, but I would like to have a nice little function that I can call anywhere in my module, give it all the data, and forget it. Say, on update of some certain content type I wanna post a notice to the admin feed. All I have to do is call one convenient function right there, and relax with Corona, or Guinness if it's winter.

Step 1. Preparing the RSS items to be published.

Let's create a table admin_feed that's gonna hold the feed items. We need 4 columns.

  • id - an integer (index)
  • type - a string (varchar possibly)
  • data - text
  • created - datetime/timestamp (should default to NOW)

Now let's open our module foo and add that single convenient function I was talking about. When I want to feed something, I want to specify what type of action is happening, and throw in some data as an object. This function will take my type, serialize my object, and save it to the db. Should be something like this:

<?php
   
function foo_feed_item($type, &$data = null) {
       
db_query("insert into admin_feed (type, data) values ('%s', '%s')", $type, serialize($data));
    }
?>

Alrighty. This was all the work necessary to get the feed items to save somewhere. Now the fun begins.

Step 2. Outputting feed.

Now it's time to display the feed. There should be a menu item that creates a path to our rss feed.

<?php
            $items
[] = array(    'path' => 'rss/admin',
                           
'title' => t('Admin Infostream'),
                           
'callback' => 'foo_feed_admin',
                           
'access' => true,
                           
'type' => MENU_CALLBACK
           
);
?>

This path expects the callback function foo_feed_admin() to exist, so lets create it. In the function we should take all of those saved items from admin_feed db table, and display them as a formatted feed. Here's my implementation, although you would probably want to make this feed private, and require a login:

<?php
   
function foo_feed_admin() {
       
$query = db_query('select * from admin_feed order by created desc');
       
$items = '';
       
        while (
$r = db_fetch_object($query))
           
$items .= theme('admin_feed', $r);
       
       
header(theme('feed_header'));
        echo
theme('feed_wrapper', $items);
    }
?>

I should mention two things about the above function. First of all, look at that loop. It goes through every item in the database, and passes it to the theme('admin_feed') function. We haven't written it yet, but getting there. Second of all, I have theme('feed_header') and theme('feed_wrapper') for my purposes, but you can make your own theme functions for that. It's important to see that I'm setting the header and using "echo" to output the result. This result is what you will see when you go to "rss/admin" path.

On to the theme now!

I will call my theme bar. So let's go to the sites/all/themes/bar directory. I have a template.php file there. Sometimes template.php grows too large with many theming functions for different things. This is why I prefer to split it into multiple files. Thus, for admin feed I created a file called theme_admin_feed.inc and included it into the template.php, but that's up to you. Now, let's create the first function - the one that will produce an RSS item.

<?php
   
function _make_item($title, $body, $link, $id) {
        return
format_rss_item(
           
$title,
           
$link,
           
$body,
            array(
               
'author' => 'nomail@something.com (admin)',
               
'guid' => $id
           
)
        );
    }
?>

This function returns a formatted item. Nothing to see here. You will see how we use it later.

The next function, however, will be interesting. This is the bar_admin_feed() function that we're calling from the module and passing the database rows to it. Here's what it looks like:

<?php
   
function bar_admin_feed( &$r ) {
        return
call_user_func_array('_af_'.$r->type, array( unserialize($r->data),  '['. strtoupper($r->type) .']', $r->id) );
    }
?>

This function uses php metaprogramming to call other functions in this file, depending on the type of the feed item. For example, if $r->type is "update", it will call _af_update() and pass those three parameters to it. I prefix '_af_' to prevent collisions with other functions in my template.php. It's up to you, but here "af" stands for "admin feed". Also I like to prefix all the titles of my admin feed with an uppercase type, wrapped into square brackets. So I would have something like "[UPDATE] User Johnny updated node 34". This helps if you want to apply coloring rules in your RSS reader later. So that's why I'm passing '['. strtoupper($r->type) .']' into my function. Now it's time to show how easy it has become to actually add those Update, Delete, Create notices to your program.

Step 3. Posting RSS items is now a piece of cake!

So now I want to post a feed item every time someone updates a node in Drupal, including the user who made the update, and whatever else I desire. I have my foo_nodeapi() where I catch the update action, the $node, etc. Here's what I'll do in there:

<?php
           
case 'update':
                global
$user;
               
$node->bywhom = $user;
               
foo_feed_item('update', $node);
                unset(
$node->bywhom);
            break;
?>

In this example I'm piggybacking the $user onto the $node, and passing it to foo_feed_item(). You could piggyback anything you want this way.

Now in our theme template.php (or in my case theme_admin_feed.inc) we have to write the theming function for this 'update' action. Here's how mine looks:

<?php
   
function _af_update(&$node, $title, $id) {
       
$title .= "$node->title was updated by $node->bywhom->name";
       
$body = "<a href='http://something.com/node/$node->nid/edit'>
                http://something.com/node/$node->nid/edit
                </a>
        "
;
       
$link = "http://something.com/node/$node->nid/edit";
       
        return
_make_item($title, $body, $link, $id);
    }
?>

As you can see, I have all the info conveniently provided to me. This is also the place where we're finally using that _make_item() function we wrote earlier. So I format my item anyway I want and pass it to _make_item(). I give myself some convenient links to the updated node, and the name of the person who made the update. All nice and tidy.

A few more words.

I'm sure there are tons of ways to accomplish this in a convenient way, and I would like to hear about them. If you see a better way to do something, a more clever technique, or anything, please let me know. I hope this is helpful. Any questions? Feel free to ask in the comments.

Scripteka 1.1 - Essential Updates

Yura and I have done some more work on Scripteka. Thus we brought version 1.1 to its completion, and will be deploying it today. The major changes are:

  • User Dashboard, where one can see all their scripts, and edit them.
  • Image upload for scripts. Finally, you can replace that default "empty page" image with your own.
  • Improved RSS feed with more useful information, and better formatting.
  • Improved communication and response to various actions. This includes:
    • Automated, token-based "claim script" feature. No more claiming script and not knowing what to do next.
    • More robust and informative feedback on script approval/rejection.
  • Small usability improvements.
  • Many bug fixes, polishing.

Hope you like it. We always appreciate feedbacks, suggestions, and bug submissions.

Syndicate content