Lets take a moment to review this line of code.
The
style=none part tells the widget not to
apply any styling as you are going to apply styling yourself.
Any value other than "none" (lowercase) is ignored and you will
get the styled widget above if you make a typo.
Next, the
items=15 parameter
tells the widget how many items you want to display.
If you leave it out, you will get the default which is 10.
Minumum is 1 and maximum is 100. Any non integer values
will be ignored and you will get the default. Any values
below 1 will simply be treated as a 1 and likewise values
above 100 will be treated as 100.
Finally, the
title_chars=20
part of the code snippet tells the muti widget how many characters
should be displayed before the link title is truncated.
If the actual link title is longer than the number of characters
specified then the title is appended with '...' to indicate this.
The code above, will result in a raw unstyled widget, you need
to apply your own styles, either in a stylesheet, or inline in
your html to actually style the widget.
Lets take a look at how we can do this. We are going to
produce a styled widget which looks like this:
The muti widget consists of three div elements. The first
one has an id of
muti_widget_raw.
So to style the widget you
will need to add code similar to the following:
<style type="text/css">
div#muti_widget_raw
{
border:1px solid gray;
font-family: Georgia;
width: 180px;
}
</style>
Of course if you are using a stylesheet then you
will not need the
<style>
opening and closing tags. From here on the examples will
omit these tags.
The
muti_widget_raw div is the outer
enclosing div for all content in the widget.
Within this div there are two other div elements, these
are the
muti_widget_header div
and the
muti_widget_links div.
You can style each of those as follows:
div#muti_widget_header
{
color: blue;
font-weight: bold;
background: yellow;
text-align:center;
}
div#muti_widget_links
{
color: yellow;
background: blue;
padding-left: 5px;
padding-bottom: 5px;
font-size: 8pt;
line-height: 16pt;
}
Whithin the
muti_widget_header div there is
the "Muti Hot" url element which has an
id of
muti_widget_header_link.
It can be styled as follows:
a#muti_widget_header_link
{
text-decoration:none;
}
The final items that you can style are the item
urls themselves. These are all defined with a
CLASS
of
muti_widget_link.
It is important to note where
a class is used and where an id is used because this
makes a difference in the syntax of your CSS.
The links can be styled as follows
a.muti_widget_link /* Note the class syntax here! */
{
color:yellow;
text-decoration: none;
}
a.muti_widget_link:hover
{
text-decoration: underline;
}
And thats it! You are free to apply any styling you like.
Muti Hooks
A while ago Charl van Niekerk authored an item
entitled
Twitter and Muti. (For those who don't know
Charl, he is one of the brightest young minds on the
continent right now and has recently been selected to
paticipate in Google's Summer of Code program)
This piece by Charl really got me thinking, essentially he
was saying that in todays modern web2.0 world, we
need to be thinking about realtime messaging instead
of the older rss based messaging which we are now all
accustomed too. After brainstorming and bouncing
ideas off a few people, including
Erik Hersman,
Gerhard Venter,
Stii,
Colin Daniels and
of course Charl, I have decided to introduce Muti Hooks.
Muti hooks are small pieces of python code, written
by users or third parties, that are called by the muti
engine when certain events occur. They can be used to
customize the muti engine to perform any imagineable task.
Here are a few examples of what muti hooks could be used for:
- Notification about topics of interest - Supposing
you would like to be notified whenever
an article about Ubuntu, for example, is posted to
muti. You could write a hook that checks the title
and tags of the submission and if either of them contain
the word 'ubuntu' you could be notified by email, sms,
skype, irc, twitter or any other service.
- Be notified when an item from your blog or website is posted.
If you are a blogger, or website owner, you may want to be notified when
someone else posts an item from your blog or website to muti.
A muti hook could easily accomplish this task.
- Cross-post to del.icio.us - Supposing that you would like
everything you post to muti, to also be posted to del.icio.us.
Of course you could do that manually but a better way would be
to write a hook that does the job for you. Fortunately del.icio.us
has a rather nice api which is callable from python so wht not
use a muti hook to do the hard work for you?
- Synchronise tags on your blog with tags on muti -
Supposing you blog about something and tag your piece as
'ubuntu' and 'opensource'. Now someone submits your
item to muti and tags it with 'linux', wouldnt it be
nice to have that tag ALSO appear on your blog?
If your blogging platform had an api or other means
to recieve notifications then a muti hook could
accomplish this task for you.
- Amatomu and
Afrigator both allow voting of items. Suppose that these services wanted
to count muti votes in the total vote count as well, they could write
a muti hook that notifies a listener on their respective services whenever
an item on muti is voted on.
- Cross-post to other muti instances. There has
been some talk recently of perhaps running country based
instances of muti in interested countries such as Kenya and
Nigeria. Suppose posts on these services wanted any item posted
to also appear on the main muti site, a muti hook could
be used to achieve this.
- Cross-post to Blik all items that you
tag as 'Afrikaans'. This is similar to other cross-posting
examples. In all Cross-posting situations the receiving
site would need to have some sort of api to accept
the post, but remember even if it accepts only by
form, http is fully programmable in Python.
These examples should give you an idea about the flexibility and
power of muti hooks. In many of them I have used the example of
email notification, but its important to understand that 'notification'
could be by ANY possible method that is programmable.
There are four types of muti hooks planned, two are
immediately available and more may be coming.
They are:
- Submit hooks - triggered whenever there is a new
item posted to muti.
- Tag hooks - triggered whenever there is a change
in tags to an item ie either a new tag or a tag is deleted.
- Comment hooks - triggered whenever a comment is posted
- Vote hooks - triggered whenever an item is voted upon
So how does one create a muti hook?
Muti hooks are created by writing a small piece of python
which subclasses one of the Muti hook classes. The example
below will demonstrate this. We will look at a very simple
hook which sends an email to you whenever an item tagged
with 'ubuntu' is posted.
Here is the code:
import muti_hooks
import smtplib
class MyHook(muti_hooks.Submit_hook):
# This is a simple submit hook which
# demonstrates the hook capabilities
# of muti''
author = 'Neville Newey'
email = 'me@mymaildomain.com'
def __init__(self):
self.register()
def process_submission(self, post):
if 'ubuntu' in post.get('tags'):
self.notify(post)
def notify(self, post):
mailmsg = []
cons = mailmsg.append
cons('From: noreply@muti.co.za')
cons('To: me@mymaildomain.com')
cons('Subject: Item about Ubuntu posted on muti')
cons('\n')
mailmsg = '\n'.join(mailmsg)
all_recipients = ['me@mymaildomain.com']
server = smtplib.SMTP('my.smtpserver.com', 25)
# some smtp servers require login...
server.login('name','password')
args = ('me@mymaildomain.com', all_recipients, mailmsg)
server.sendmail(*args)
server.close()
And thats it! A few things to take note of here:
The code imports the muti_hooks module. It then
defines a class called 'MyHook' but you may call it anything.
The only requirement is
that it subclasses Submit_hook. (For a tag hook
you subclass Tag_hook). Your class can contain any methods
you like but the important one is
process_submission.
This is the method that will actually get called from the
muti engine by the hooks process once it is registered.
The email class variable is also important. If you omit your
email address here then you will not be notified of any errors
in your code.
So how do you develop and test a muti hook? This is a good
question since you do not have a muti instance to test
your hook with. Fear not, Python's unit test module to
the rescue!
Here is an example of some test code that you could write
and execute to test your hook before submitting it to muti:
import unittest
from my_hook import *
class TestMutiHooks(unittest.TestCase):
def setUp(self):
post = dict(title='This is the title of the post.')
post['url'] = 'http://thisistheurl.com'
post['submitter'] = 'anyname'
post['tags'] = ['tags','come','as','a','list','ubuntu']
self.post = post
def test_my_hook(self):
my_hook = MyHook()
my_hook.process_submission(self.post)
if __name__ == '__main__':
unittest.main()
Save this test code in a file and run it from the
same directory as your hook. This emulates exactly
what will happen on the muti server once your code
has been registered.
Of course since you are importing the muti_hooks module
you will also need that. You can download it from
here. This is what it looks like:
# Copyright 2006, 2007 Neville Newey
class Submit_hook:
def __init__(self):
self.register()
def register(self):
# Make sure your subclassed hook makes a
# call to self.register() and do NOT override
# this method. This method is for future use
# all you have to remember is to simply make
# a call to it for now.
pass
def process_submission(self, post):
# This is the guts of your hook and you
# should override this method with whatever
# code you want to. The post argument is
# a dict that has the following keys:
# 'title', 'submitter', 'url', 'comment' and 'tags'.
# The first four are strings while 'tags'
# is a list of 0 or more strings.
# post['comment'] may be the empty string or None.
pass
def get_smtp_server():
# This function will return the internal muti
# smtp server. You may use this smtp server for
# outgoing mail if you do not have access to
# your own smtp server. If you do use this function
# in your hooks then when testing you need to
# overide it in your own hook.
pass
Believe it or not this is the actual code used
for the muti_hook class! Isnt python beautiful?
There is a good reason it is the language of choice
for Web 2.0 applications. Of course you may be
wondering how such a small amount of code could
result in your muti hook being called at the right
time with the right information supplied to it.
The trick and really neat thing here is that the
'engine' that loads and runs the muti hooks, is
itself just a hook! Yes, thats right, it
is a hook that subclasses the muti_hook class and implements
a process_submission method just like any other hook,
the only difference is that it has a special status in
the muti engine, and that is that it is the first
(and only!) hook that is called by muti. It then proceeds to
load and execute other hooks. Nevertheless Captain
Hook itself consists of less than 80 lines of code
and much of that is taken up with logging errors!
A few more technical details:
Since the primary muti hook (actually called
'Captain Hook') has to load and exceute
'untrusted' code, some security precautions need
to be taken. Firstly the code is execed without
a copy of any local variables. Secondly the code
is run through a sanitizer before it is executed
and certain operations are not allowed for obvious
secureity reasons. These are things such as file
system access, access to arbitrary tcp ports etc.
So lines such as 'import sys' will not work in
your code and in fact your hook will be rejected if
it contains such lines. Other items rejected by
the sanitizer are access to any module that touches
the file system such as pickle, os, system etc.
And finally, any submitted hook code will be
thoroughly tested and inspected before being deployed
on the production muti server.