Hi all,
Don't want to detract from the current thread on template refactoring, as it's the biggest area in need at the moment, but I've pushed up some new changes that I'd love some feedback on.
A quick one to first get out of the way, I've added a setting that controls the filtering level on RichTextField instances. Filtering was hastily added to fix the possible XSS issue described recently. This has the downside of filtering out potentially dangerous yet useful/required HTML, particular for embedding videos. What I've done is provided a setting with 3 levels of filtering, high (filter all dangerous tags), low (allows some extra tags, like those for video, plus we'll add more to this over time), and None (disables filtering entirely - a valid option with only one or few trusted admin users).
To support this I've also added a "choices" arg to the register_setting function, to provide a fixed set of choices for an editable setting. Format is a sequences of name/value pairs, just like choices for Django form/model fields.
Now for the biggie: multi-tenancy. We now have the ability to host multiple sites (django.contrib.sites) on a single running instance. This is the change I'm most keen on feedback for, particularly around actually running it, testing it, and trying to break it, as its approach is unorthodox at worst, by way of introducing threadlocals and a "current request". Here's the gist of how it works:
All site related models previously made use of django.contrib.sites's CurrentSiteManager which is where the tie to the SITE_ID setting occurred. These models now use Mezzanine's CurrentSiteManager, which uses a series of checks in looking for the site ID, the main one being matching the host of the current request to the domain of the site record. To support this, a new middleware is used that assigns and removes the request object to a threadlocal variable, which gives us global access to the current request. If this approach turns out fine, which I believe it will, it will lead the way for a clean implementation of multi-lingual content support, as well as some great refactoring around the multi-device support.
The series of checks in order looks like this:
- Check for a "site_id" in the session. This is first, and is used for bypassing the domain check, so that say in the admin for example, we can include a feature for flipping between sites, without leaving the domain the admin is running on.
- Check for the host in the current request against a site record's domain, as described above.
- Check for an environment variable MEZZANINE_SITE_ID. This allows you to specify a site to use when a current request wouldn't be available, for instance with management commands. I've also modified manage.py to look for (and remove) a --site=ID setting which will take care of this.
- Final fallback is the SITE_ID setting.
While fairly time consuming, this turned out to be quite an easy change thanks to the initial sites work that Eduardo Gutierrez did way back over a year ago, and all the tests he wrote still pass and are still very applicable to this new approach, so big thanks to him. Here's the implementation, would be very happy to have any flaws pointed out: