Andreas Blixt

Not tagged photo

This is a filtered list of entries. To see all of them, go back to the home page.

The Name of the Wind

Monday, February 16th 2009 — Random Stuff3 comments

Today I finished reading a book called The Name of the Wind by Patrick Rothfuss. I really liked it! Read more about it on its homepage.

Noughts and Crosses

Thursday, February 12th 2009 — Programming, Gaming142 comments

You might have seen my MoNKey! game. Well, a guy called Andrejus has taken up the torch and is continuing the project under the name PlayTicTac. Check it out! There is also a Lithuanian version available, called Kryžiukai–Nuliukai.

Pagination

Wednesday, February 11th 2009 — Programming2 comments

I decided to add paging to my blog the other day, and considered the different ways one could do so. The most common way is just to start at page 1, then after every X entries start a new page until you have pages for all your entries. I didn't like this option because it would mean that every time I added an entry, all the older entries would be "pushed down" one step on the pages, so the last entry on page 1 would then be the first entry on page 2. Why is this bad? Well, imagine if you searched for something on Google, and it linked to page 5 on a blog. So you go there and you find that the content you searched for isn't there; it's been pushed down to page 7. This can be a nuisance. And so I wanted to come up with an alternative solution.

One way to do it would be to categorize the entries by date, and browse one month at a time or some such. The problem with this is that it will result in an uneven distribution of entries across the pages. Instead, I decided to go with a variation of the solution I mentioned first.

My solution was to reverse the order of the pages. So page 1 would hold the X oldest entries; page 2 the subsequent X entries, and so forth. This way, page 5 will always hold the same entries, no matter how many entries you add. But there is one more thing to think of when doing this: you can't just show the last page by default. Say the last page is page 6, and it already has X entries. Now, if I add an entry, it will be on page 7, by itself. If I were to show page 7 by default, the front page would look pretty empty. So I added another, "magic" page (default if no page is specified) that shows the X most recent entries. And there you have it. Search-safe pagination.

P.S. It's worth mentioning that another reasonable option would be to turn off search-engine indexing of the pages through robots.txt or the robots meta tag, which would ensure that only results linking directly to the blog entry would show up.

Importing your Flickr photos with Django

Friday, February 6th 2009 — Programming, Python, Django1 comment

Recently, I made my blog import updates from Flickr automatically. Since this is a pretty neat feature that is nice to have on your blog, I figured I'd share my code with you. There are a few prerequisites to using this code:

Additionally, you need Python programming experience and a basic understanding of the Django framework.

First of all, let's go through what my blog models look like.

class Entry(models.Model):
    title = models.CharField(max_length=50)
    slug = models.SlugField(max_length=50, unique_for_date='published')
    published = models.DateTimeField(auto_now_add=True)
    tags = models.ManyToManyField('Tag')
    content = models.TextField()

    class Meta:
        get_latest_by = 'published'
        ordering = ['-published']
        verbose_name_plural = 'entries'

    def __unicode__(self):
        return self.title

    def get_absolute_url(self):
        return '/%s/%s' % (self.published.strftime('%Y/%m/%d'), self.slug)

class Tag(models.Model):
    name = models.CharField(max_length=30, unique=True)
    display_name = models.CharField(max_length=50)

    def __unicode__(self):
        return self.display_name

    def get_absolute_url(self):
        return '/tagged/%s' % self.name

As you can see, they're pretty straight-forward, and shouldn't be too dissimilar to your blog models. Now, let's go through the code that does the actual work!

The following code is basically just a function that will request all the recent photos of a user (specified in your settings.py file, see further below.) The photos that have not been added to your blog will be added automatically as a blog entry. I call the function whenever the front page is requested, at a maximum rate of once per hour (I used the cache module to store a global variable for one hour and only fetched the images when the variable didn't exist.)

I'm assuming you have some Python and Django experience, so the code shouldn't be too hard to customize. Feel free to contact me if you have any questions.

from datetime import datetime
from django.utils.dateformat import format
from django.utils.html import escape
from blixt import settings
from blixt.blog.models import Entry, Tag
import flickrapi

def sync_flickr():
    flickr = flickrapi.FlickrAPI(settings.FLICKR_API_KEY)

    cur_date = None
    entry = None
    page = 1
    pages = 1

    # Get/create a tag to use for Flickr update entries.
    tag, created = Tag.objects.get_or_create(
        name='photo', display_name='Photography')

    # Try to get the most recent Flickr update entry.
    try:
        flickr_updates = Entry.objects.filter(slug='flickr-update')
        most_recent = flickr_updates[0].published
    except:
        most_recent = None

    # Start a loop that will get all public photos of the user specified in the
    # settings.
    while page <= pages:
        res = flickr.people_getPublicPhotos(user_id=settings.FLICKR_USER_ID,
                                            extras='date_upload',
                                            per_page=10, page=page)
        page += 1
        pages = int(res.find('photos').get('pages'))

        # Get all <photo> elements and handle them one by one.
        photos = res.findall('photos/photo')
        for photo in photos:
            # Determine the date/time that the current photo was uploaded.
            photo_uploaded = datetime.fromtimestamp(
                int(photo.get('dateupload')))

            # If the most recently added entry is more recent than the current
            # photo, there is no need to continue because all older photos have
            # already been added.
            if most_recent and photo_uploaded <= most_recent:
                pages = 0
                break

            # Create a new entry for every unique upload date.
            if photo_uploaded.date() != cur_date:
                if entry: entry.save()
                cur_date = photo_uploaded.date()
                entry = Entry(
                    title=format(photo_uploaded, r'\F\l\i\c\k\r: M j, Y'),
                    slug='flickr-update',
                    content='')
                entry.save()
                entry.published = photo_uploaded
                entry.tags = [tag]

            # Build the HTML content for the entry.
            entry.content += settings.FLICKR_IMAGE_HTML % {
                'src': settings.FLICKR_IMAGE_SRC % photo.attrib,
                'title': escape(photo.get('title')),
                'url': settings.FLICKR_IMAGE_URL % photo.attrib
            }
    if entry: entry.save()

The following code is a snippet from my settings.py file. You'll need to replace the API key and user ID values with your own. You can customize the HTML of the generated blog entry here as well.

FLICKR_API_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
FLICKR_USER_ID = '12345678@N00'
FLICKR_IMAGE_HTML = \
'<div class="thumb"><p class="image"><a href="%(url)s" title="%(title)s">' \
'<img src="%(src)s" width="75" height="75" alt="%(title)s" /></a></p>' \
'<p class="title"><a href="%(url)s" title="%(title)s">%(title)s</a></p></div>'
FLICKR_IMAGE_SRC = \
'http://farm%(farm)s.static.flickr.com/%(server)s/%(id)s_%(secret)s_s.jpg'
FLICKR_IMAGE_URL = 'http://www.flickr.com/photos/%(owner)s/%(id)s'

Passwords in Databases

Thursday, January 29th 2009 — Programming2 comments

Why? Two or three times now, I've gotten an e-mail from the admin of a site that I was registered to:

"Something terrible has happened. Hackers have managed to get access to our databases..." Well, that's not too terrible is it? It only had my name, some information that was public anyways and maybe a list of people I was connected to on the site. "...we recommend that you change your password wherever you used it, and have generated new, random passwords for you." Wait... what?!

Why would my password be stored in their database in a form that could be usable by the hackers? These things happen to big sites. People see it as a sport to hack these kinds of sites. And no matter how much security you've got, you need to make sure that once they do get through, they get as little information as possible.

Securing the passwords of your users is very easy, and there's no reason not to do it. Even if you have a completely impenetrable security setup, all it takes is for an administrator to go rogue and the worst things could happen. So, how would you secure the passwords?

Hashes! Hashes are good for a lot of things, and they're great for user authentication. A hash is basically the result of a very complex algorithm that takes a string as its input. It's a "lossy" conversion, so to speak, because you can't get the original string by reversing the algorithm. You can't even figure out the length of the original string (and these hashes are always the same length, no matter if you make one from an eight-character password or from a 1 GB file.) Which means mr. Hacker wouldn't be able to do much with the hashes of the passwords.

The next thing to do would be the authentication. It's very easy. The user enters their username and password, then on the server you make a hash from the password and compare this hash with the one in the database. If they match, let the user in.

There are several algorithms to choose from. Some of the most common ones are MD5 and SHA-1, but I generally use SHA-256, as there are computers holding so-called "rainbow tables" that consist of several terabytes of hash→value mappings. SHA-256 is better because it's much harder to make these tables for it. Partly because it's bigger and partly because the algorithm is more secure.

So there you have it. Spread the word and let's make the internet a more secure place!

If you still want more security, there is one more thing you could do. Adding a random string (known as a "salt") to the password before hashing it ensures that even if there is a rainbow table for the algorithm you used, it will most likely not work for your hashes. Let the salt be pretty long because rainbow tables generally have the hashes for all alphanumeric combinations up to eight characters long. Adding a salt to a password that is already eight characters long will dramatically improve the chances that it's not included in the rainbow table.