OpenX Upgrade Page Full of Errors

20 August 2010

I was moving and upgrading OpenX for a client (v2.8.5). I changed some things in the config file, then went in to the admin interface (install page).

I got a screen full of baffling error messages starting:

MESSAGE: Undefined variable: imgPath
TYPE: Notice
FILE: /home/nice/public_html/www/admin/install.php
LINE: 75
DEBUG INFO:

70 $oMenu->add(new OA_Admin_Menu_Section('install', '', ''));
71
72 if ($oController->hasLayout()) {
73 //layout
74 $oPageHeader = $oController->getModelProperty('pageHeader');
75 phpAds_PageHeader('install', $oPageHeader, $imgPath, false, true, false);

76 }
77 if ($view) {
78 $view->display();
79 }
80 echo $actionContent;

MESSAGE: Only variable references should be returned by reference
TYPE: Notice
FILE: /home/nice/public_html/lib/OA/Admin/Menu/Section.php
LINE: 354
DEBUG INFO:

349 {
350 if ($this->type == $type) {
351 return $this;
352 }
353 else {
354 return $this->parentSection != null ? $this->parentSection->getParentOrSelf($type) : null;

355 }
356 }
357
358
359 /**

MESSAGE: Only variable references should be returned by reference
TYPE: Notice
FILE: /home/nice/public_html/lib/OA/Admin/Menu/Section.php
LINE: 354
DEBUG INFO:

349 {
350 if ($this->type == $type) {
351 return $this;
352 }
353 else {
354 return $this->parentSection != null ? $this->parentSection->getParentOrSelf($type) : null;

355 }
356 }
357
358
359 /**

MESSAGE: Undefined index: PREF
TYPE: Notice

Undefined variables. Something’s wrong with reading the config file.

I had to edit the code to find out what the problem was. In the init-parse.php file, look for $conf = @parse_ini_file. Remove that @ sign – it’s suppressing the error message. Try again and you should see an error saying can’t parse ini file on line X.

In my case, it’s because I put a dollar sign in the database password. Seems that’s not valid in the ini file. I changed the password and it’s working.

Pretty obscure, no?

Filed under: Uncategorized — Scott @ 11:29 am

Porting MooTools to jQuery

8 July 2010

Last night I ported some JavaScript code that used MooTools to use jQuery instead. In many ways I prefer MooTools to jQuery, but jQuery is easier to integrate in code that uses other libraries (e.g. Prototype).

Here’s a few quick hints for things you need to change if you’re doing the same.

$(‘element_id’)

You need a leading hash: $('#element_id')

No need for two dollars to use selectors: $('#element_id form input.special') works.

There’s a difference of approach to what happens when you use $(...): MooTools adds stuff to the DOM element. jQuery gives you a new object which wraps the element. This means you can’t just call DOM stuff on the object jQuery gives you. e.g.

MooTools:
$$('a.special_link').href – access the normal DOM properties

jQuery
$('a.special_link').attr('href') – ask the jQuery object to access the underlying DOM element

A jQuery object can represent a list of elements, not just a single one. You can access the underlying element using index zero: $('a.special_link')[0].href

Class

jQuery doesn’t do classes. There’s code and plugins around, or you can use a standard JavaScript approach like:

var MyClass = function(blah) {
    // this is your constructor
    this.blah = blah;
};
MyClass.prototype.doStuff = function(name) {
    // this is a member function
    return this.blah + name;
}

// instantiate and call like normal
var thing = new MyClass('hello');
thing.doStuff('monty');

bind(this)

Oh this one hurts. When you have a function, perhaps a callback, that you want to reference your class instance as “this“, in MooTools you use something like:

new Request.JSON({url: '...', onSuccess: function(data){
    this.doStuff(data.name);
}.bind(this));

The equivalent is to use JavaScripts apply method which lets you pass an object to use for “this“. You might also want “arguments” which is an array of all arguments passed to the function. e.g.

var self = this;
$.getJSON('...', function(){return function(data){
    this.doStuff(data.name);
}.apply(self, arguments)});

addEvent

This is what jQuery calls bind. e.g.

$('#element_id a').bind('click', function(e){..});

each

Instead of MooTools’ $$('a.special').each(function(elem){...})

Try $.each($('a.special'), function(index, elem){...}). Note the first param to your function is index, not the element.

Request.JSON

As above, try $.getJSON(url, func). You can also use $.post if it’s a POST request (seems to decode the JSON response automatically).

get and set

Instead of elem.get('href') try elem.attr('href'). Instead of elem.set('text', 'blah') there’s elem.text('blah').

That’s my braindump for now.

Filed under: JavaScript — Scott @ 10:49 am

Staplefish joins Red Robot Studios

18 March 2010

I’ve been working as a freelancer under the Staplefish business name for over four years now. Since mid-2008, I’ve also be working with Andrew at our Red Robot Studios business.

I’m moving all my Staplefish work under the Red Robot Studios brand. The aim is to simplify some business things (accounting, tax, invoicing, etc) and offer better service by teaming up with Andrew (e.g. one of us can cover while the other goes on holiday). It also marks our decision to focus on Red Robot Studios and offer great Django development and mobile development services.

To all Staplefish clients: Please be assured Scott is still working for you, just under a different business name and your websites will not be affected. Feel free to contact me with any questions or concerns.

Filed under: Business — Scott @ 12:58 pm

Emulating Django blocks with Smarty capture

2 January 2010

Django blocks considered addictive

I do Django development for Red Robot Studios and one of the many great things about the Django web framework is the template system.

Using blocks and inheritance, repetitive html is kept to a minimum. For example you can do:

base.html

...
<title>{% block title %}Default Title{% endblock %}</title>
...
<div id="content">
{% block content %}{% endblock %}
</div>
...

home.html

{% extends 'base.html' %}{% block title %}Home Page Title{% endblock %}
{% block content %}
Home page content here
{% endblock %}

The content of the blocks in home.html are plugged in to the block placeholders in base.html.

Smarty doesn’t have blocks like Django

Update: Wait a minute. I’m wrong. Smarty does have blocks, as Richard pointed out in the comments. Uh, how did I miss that?

Smarty is a template system for php. I was using it recently for a client and wished I could use Django-style blocks. Smarty doesn’t have blocks and inheritance, but does have capture and include. Here’s how I was able to achieve a similar result.

Using Smarty capture to emulate blocks

Using Smarty’s capture and include functions, here’s how the templates look:

header.tpl

...
<title>{if $smarty.capture.title}{$smarty.capture.title}{else}Default Title{/if}</title>
...
<div id="content">
{$smarty.capture.content}
</div>
...

home.tpl

{capture name='title'}Home Page Title{/capture}
{capture name='content'}
Home page content here
{/capture}

{include file='header.tpl'}

Simple, no? Remember to do these captures before including the file.

It’s not as powerful as Django template inheritance, but it’s a reasonable attempt to use Django-style blocks in Smarty templates.

Filed under: Web Development — Scott @ 12:34 am

Migrating Postgresql Databases the Easy Way

23 June 2009

When you upgrade Postgresl to a new major version (e.g. 8.1 to 8.3), all databases need to be dumped from the old version and loaded in to the new version. It’s not difficult, but on Debian there’s a really easy way.

Debian has pg_createcluster, pg_dropcluster and pg_upgradecluster (plus a few others). The one I’m referring to here is pg_upgradecluster.

It takes the version and cluster name of the databases you want to upgrade.

e.g. if you’ve installed Postgresql 8.3 and have databases in 8.1, just run:

# pg_upgradecluster 8.1 main

This upgrades the databases in the “main” cluster under version 8.1 and puts them under “main” in version 8.3. If you already have a “main” cluster in 8.3, you’ll need to drop it first.

This little tool not only dumps and loads the database, but it also changes the config so 8.3 runs on the standard port previously used by 8.1 (or whatever your older version). A painless way to upgrade.

Filed under: Postgresql — Scott @ 11:45 am

Gvim menu bar missing

9 March 2009

I just opened gvim on my Ubuntu (Hardy Heron) box and found there was no menu bar (File, Edit, etc).

After messing with some guioptions and getting nowhere I ran gvim as root (using sudo) and the menu bar was there. The answer came from a forum post by “Marko”:

Delete the file ~/.gnome2/Vim

It will be recreated when you run gvim again. With luck, the menu will be displayed again.

Filed under: Uncategorized — Scott @ 4:04 am

Layoff Talent – Django project just launched

11 December 2008

Andrew and I spent a few days this week putting together a new Django project.

It’s called Layoff Talent and it’s a place for people in the tech industry who have been laid off and are looking for a new job. They can add a simple profile and then hopefully be picked up by employers looking for new talent.

It’s similar in some ways to Django People or the Djangogigs developer listings, but specifically for people who have been laid off and not restricted to Django developers.

There’s nothing ground breaking from a development point of view, but it’s another example of how Django makes it easy to put out a full-featured site in a short time. Of course, we’ll be adding more features as the site gets popular.

If you know someone who has been laid off, please tell them about layofftalent.com.

Filed under: Uncategorized — Scott @ 6:05 pm

Get User from session key in Django

4 December 2008

Error emails contain session key

When you get an error email from your Django app telling you someone got a server error, it’s not always easy to tell which user had a problem. It might help your debugging to know or you might want to contact the user to tell them you have fixed the problem.

Assuming the user is logged in when they get the error, the email will contain the session key for that user’s session. The relevant part of the email looks like:

<WSGIRequest
GET:<QueryDict: {}>,
POST:<QueryDict: {}>,
COOKIES:{ 'sessionid': '8cae76c505f15432b48c8292a7dd0e54'},
...

Finding the user from the session

If the session still exists we can find it, unpickle the data it contains and get the user id. Here’s a short script to do just that:

from django.contrib.sessions.models import Session
from django.contrib.auth.models import User

session_key = '8cae76c505f15432b48c8292a7dd0e54'

session = Session.objects.get(session_key=session_key)
uid = session.get_decoded().get('_auth_user_id')
user = User.objects.get(pk=uid)

print user.username, user.get_full_name(), user.email

There it is. Pass in the session key (sessionid cookie) and get back the user’s name and email address.

Plug: Get your own job board at Fuselagejobs

Filed under: Django — Scott @ 9:43 pm

Dynamic upload paths in Django

25 August 2008

For a while I’ve been using the CustomImageField as a way to specify an upload path for images. It’s a hack that lets you use ids or slugs from your models in the upload path, e.g.:

/path/to/media/photos/1234/flowers.jpg
or
/path/to/media/photos/scotland-trip/castle.jpg

CustomImageField no more

Since the FileStorageRefactor was merged in to trunk r8244, it’s no longer necessary to use the custom field. Other recent changes to trunk mean that it doesn’t work any more in its current state, so this is a good time to retire it.

Pass a callable in upload_to

It is now possible for the upload_to parameter of the FileField or ImageField to be a callable, instead of a string. The callable is passed the current model instance and uploaded file name and must return a path. That sounds ideal.

Here’s an example:

import os
from django.db import models

def get_image_path(instance, filename):
    return os.path.join('photos', str(instance.id), filename)

class Photo(models.Model):
    image = models.ImageField(upload_to=get_image_path)

get_image_path is the callable (in this case a function). It simply gets the id from the instance of Photo and uses that in the upload path. Images will be uploaded to paths like:

photos/1/kitty.jpg

You can use whatever fields are in the instance (slugs, etc), or fields in related models. For example, if Photo models are associated with an Album model, the upload path for a Photo could include the Album slug.

Note that if you are using the id, you need to make sure the model instance was saved before you upload the file. Otherwise, the id hasn’t been set at that point and can’t be used.

For reference, here’s what the main part of the view might look like:

...
    if request.method == 'POST':
        form = PhotoForm(request.POST, request.FILES)
        if form.is_valid():
            photo = Photo.objects.create()
            image_file = request.FILES['image']
            photo.image.save(image_file.name, image_file)
...

This is much simpler than the hacks used in CustomImageField and provides a nice flexible way to specify file or image upload paths per-model instance.

Note: If you are using ModelForm, when you call form.save() it will save the file – no need to do it yourself as in the example above.

Update: Using the id of the instance doesn’t work any more because it’s probably not set when your function is called. Try using a field such as a slug instead, or the id of a parent object (e.g. if the Photo is in an Album, use the Album‘s id.

Filed under: Django — Scott @ 10:38 pm

Extending the Django User model with inheritance

21 August 2008

Update March 2013:
Django 1.5 includes a configurable custom user model that makes all this obsolete.

Extra fields for Users

Most of the Django projects I’ve worked on need to store information about each user in addition to the standard name and email address held by the contrib.auth.models.User model.

The old way: User Profiles

The solution in the past was to create a “user profile” model which is associated 1-to-1 with the user. Something like:

the model

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True, related_name='profile')
    timezone = models.CharField(max_length=50, default='Europe/London')

config in settings.py

AUTH_PROFILE_MODULE = 'accounts.UserProfile'

usage

profile = request.user.get_profile()
print profile.timezone

It works ok, but it’s an extra database query for each request that uses the profile (it’s cached during the request so each call to get_profile() is not a query). Also, the information about the user is stored in two separate models, so you need to display and update fields from both the User and the UserProfile models.

The new way: Model Inheritance

As part of the great work done on the queryset-refactor by Malcolm et al, Django now has model inheritance.

If you’re using trunk as of revision 7477 (26th April 2008), your model classes can inherit from an existing model class. Additional fields are stored in a separate table which is linked to the table of the base model. When you retrieve your model, the query uses a join to get the fields from it and the base model.

Inheriting from User

Instead of creating a User Profile class, why don’t we inherit from the normal User class and add some fields?

from django.contrib.auth.models import User, UserManager

class CustomUser(User):
    """User with app settings."""
    timezone = models.CharField(max_length=50, default='Europe/London')

    # Use UserManager to get the create_user method, etc.
    objects = UserManager()

Now each instance of CustomUser will have the normal User fields and methods, as well as our additional fields and methods. Pretty handy, no?

We add UserManager as the default manager so that the standard methods are available. In particular, to create a user, we really want to say:

user = CustomUser.objects.create(...)

If we just created the user from the User class, we wouldn’t get a row in the CustomUser table. Creation needs to be done in the derived class.

You can still get and update the underlying User model, no problem, but it won’t have the additional fields and methods found in our CustomUser class.

Getting the CustomUser class by default

So far, there’s one problem. When you get request.user, it’s an instance of User, not an instance of CustomUser, so you don’t get the extra fields and methods.

What we want is for Django to retrieve the CustomUser instance transparently. It turns out to be quite easy.

Users come from authentication backends

The default authentication backend gets the User model from the database, checks the password is correct then returns the User. You can write your own authentication backend, for example to check the username and password against some other data source or to use the email address instead of username.

In our case, we can use an authentication backend to return an instance of CustomUser instead of User.

the authentication backend in auth_backends.py

from django.conf import settings
from django.contrib.auth.backends import ModelBackend
from django.core.exceptions import ImproperlyConfigured
from django.db.models import get_model

class CustomUserModelBackend(ModelBackend):
    def authenticate(self, username=None, password=None):
        try:
            user = self.user_class.objects.get(username=username)
            if user.check_password(password):
                return user
        except self.user_class.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return self.user_class.objects.get(pk=user_id)
        except self.user_class.DoesNotExist:
            return None

    @property
    def user_class(self):
        if not hasattr(self, '_user_class'):
            self._user_class = get_model(*settings.CUSTOM_USER_MODEL.split('.', 2))
            if not self._user_class:
                raise ImproperlyConfigured('Could not get custom user model')
        return self._user_class

config in settings.py

AUTHENTICATION_BACKENDS = (
    'myproject.auth_backends.CustomUserModelBackend',
)
...

CUSTOM_USER_MODEL = 'accounts.CustomUser'

That’s it. Now when you get request.user, it’s an instance of the CustomUser class with whatever additional fields or methods you have added.

P.S. Looking for Django hosting? I’d recommend WebFaction for shared hosting and Slicehost for a VPS.

Filed under: Django — Scott @ 8:40 pm
« Previous PageNext Page »