edx/edx-platform — pull request #36 by natehardison (2013-06-01 22:04:56+00:00)
Title: LMS template theming for Stanford 6/11/13 launch

For @cpennington @ormsbee @frrrances @talbs @markchang @sefk @jinpa @caesar2164

Overview
------------
This is based on [last week's conversation](https://github.com/edx/edx-platform-pre-clean/pull/2135), and it is the branch that I'd like to be pulled into master. This is a companion to @caesar2164's changes in #28 in that both are needed for Stanford's 6/11/13 launch.

As we talked about in the RFC PR in the pre-clean repo, this PR is not a work of art. There are a number of ugly conditionals and hacks that are both Stanford- and edX-specific. However, the idea is that a compromise for now will get us living on `master` and better able to turn this into a full-blown theming layer in the near future. I have tried to pull things out into the settings where possible, but there are a few places (e.g., the `lms/templates/emails/`) where some Stanford-specific hacking was needed to get the desired language in place.

Installation
--------------
First, you'll need to grab our theme files, located in a public repo at https://github.com/Stanford-Online/edx-theme. We've established a convention that theme files will live outside of the main edx-platform repository, in the `edx_base/themes/` (or `mitx_all/themes/`) directory. To grab the Stanford theme, assuming you're inside your repository dir (`edx-platform/`), run:

$ cd ..
$ mkdir themes
$ git clone git://github.com/Stanford-Online/edx-theme.git themes/stanford

Probably the most obnoxious part of themes is that *both* Django and Rake need to know:

1. whether or not a theme is enabled
2. what the theme's name is (since that tells them where to look for templates, static files, etc.)

Django needs to know for obvious reasons (adjusting settings like `STATICFILES_DIRS`, `MAKO_TEMPLATES`, etc. and for rendering templates appropriately), and Rake needs to know because it controls static asset compilation. If a theme is enabled, we need to conditionally import the theme's Sass overrides into the main LMS Sass files (`lms/static/sass/{application,course}.scss`), and we need to set the Sass compiler's load and watch paths appropriately so that the theme's Sass files are included in compilation. Unfortunately, [Sass does not support conditional imports](http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#import), so we instead turn the main LMS Sass files into Mako templates, and use Mako to control the conditional theme import. This Mako invocation is something that must also be done by the Rakefile, since it must be done before the Sass compiler runs. Right now, this is one nasty hack in `assets.rake`, but #5 does this in a much better fashion.

Anyway, the long and the short of all this is that *we cannot just turn a theme on and off with Django settings*, since Rake cannot parse a Django settings file. Therefore, as is done in production environments, we use a JSON file located in the `ENV_ROOT` (the parent dir of your repo dir) to set the theme settings. The JSON file in dev environments is simply called `env.json`; in production, it's named slightly differently. If you want to turn a theme on, then you *must* have this file (or Rake won't invoke Mako and set up Sass properly), and if you want to disable the theme, then you either *cannot* have this file (or else Rake will invoke Mako and set up Sass to load the theme's Sass) or you have to edit out its theme setting. For simplicity, I use `mv env.json{,.bak}` and `mv env.json{.bak,}` to "disable" and "enable" this file (respectively) as needed.

My `env.json` looks like this:

{
"PLATFORM_NAME": "Stanford Online",
"SITE_NAME": "class.stanford.edu",
"BUGS_EMAIL": "bugs@class.stanford.edu",
"CONTACT_EMAIL": "contact@class.stanford.edu",
"TECH_SUPPORT_EMAIL": "techsupport@class.stanford.edu",
"THEME_NAME": "stanford",
"UNUSED_MKTG_URLS": [
"CONTACT",
"FAQ",
"HONOR",
"PRIVACY"
]
}

The `THEME_NAME` setting is the important one, as it's the `themes/` directory that Rake looks for when compiling assets (Django will also reference it too). The others are standard overrides that you could just as well specify in your custom `lms/envs/.py` file. All of the other settings, however, with the exception of `SITE_NAME`, are *new in this PR*.

My Django settings file mimics `lms/envs/aws.py` closely, since I wanted to test that my changes to `aws.py` worked. Here's what it looks like, in case you want to copy it in for testing this PR:

# lms/envs/dev_stanford.py
import json

from .dev import *

with open(ENV_ROOT / "env.json") as env_file:
ENV_TOKENS = json.load(env_file)

PLATFORM_NAME = ENV_TOKENS['PLATFORM_NAME']
SITE_NAME = ENV_TOKENS['SITE_NAME']

#Theme overrides
THEME_NAME = ENV_TOKENS.get('THEME_NAME', None)
if not THEME_NAME is None:
enable_theme(THEME_NAME)
FAVICON_PATH = 'themes/%s/images/favicon.ico' % THEME_NAME

TECH_SUPPORT_EMAIL = ENV_TOKENS.get('TECH_SUPPORT_EMAIL', TECH_SUPPORT_EMAIL)
CONTACT_EMAIL = ENV_TOKENS.get('CONTACT_EMAIL', CONTACT_EMAIL)
BUGS_EMAIL = ENV_TOKENS.get('BUGS_EMAIL', BUGS_EMAIL)

# Allow environments to remove unused marketing URLs. These need to
# match *exactly* with the keys listed in the default dict (in
# common.py)
# TODO: decide on a better way to allow themes to override these
for url in ENV_TOKENS.get('UNUSED_MKTG_URLS', UNUSED_MKTG_URLS):
del MKTG_URL_LINK_MAP[url]

Therefore, I boot up my LMS with `rake lms[dev_stanford]`, and life is good.

Settings changes
----------------------
I added a few new settings in this PR that folks who deploy should know about, in case they want to override them in the `*_vars.yml` files (looking at you guys, @jbau, @e0d, and @jarv). Here they are:

* `PLATFORM_NAME` is the display name of the platform (e.g., "edX" or "Stanford Online")
* `UNUSED_MKTG_URLS` allows environments to disable unwanted URLs in the `MKTG_URL_LINK_MAP` (e.g., themes don't want a `JOBS` page)
* `TECH_SUPPORT_EMAIL` is what it says (e.g., "technical@edx.org"). Likewise, we also have:
* `BUGS_EMAIL` (e.g., "bugs@edx.org")
* `CONTACT_EMAIL` (e.g., "info@edx.org")

There's also a `FAVICON_PATH` setting, but that'll be automatically overridden [when a theme is turned on](https://github.com/edx/edx-platform/blob/nate/template-theming/lms/envs/aws.py#L126).

The appropriate defaults for all of these settings should be set in `lms/envs/common.py`, and I added overriding code to `lms/envs/aws.py`. Please let me know if I missed anything.

TODO
--------
As mentioned above, this PR does leave something to be desired in terms of a better theming layer. I put comments in the code where I think the hacks are particularly heinous. Hopefully we'll have time to revisit this soon.

Additionally, there are still a couple of things I see that we have to do in order to get this ready for 6/11:

* Theme the Django templates (e.g., `lms/templates/registration/password_reset_{confirm,email}.html`, `lms/templates/main_django.html`). I would appreciate advice on how to do this, as from what I can tell, the `settings` are not made available to these templates' contexts. And since arbitrary Python in Django templates isn't possible by default (I think? Unfamiliar here...), I think we have to do something like [this](https://docs.djangoproject.com/en/dev/howto/custom-template-tags/). The `main_django.html` template *is blocking*, since that's the base template for the wiki.
* Theme some of the CMS (basically, set the appropriate contact information so that folks don't come to the Stanford Studio and wind up posting for help, filing bugs, etc. on the standard edX forums/email inboxes). I'll do this soon.