def testAvailableThemes(self): """ Check that the ThemeController says we have the themes we expect to have. """ tc = ThemeController() names_ref = ['barebones', 'circles', 'floaty', 'fruitsalad'] names_tc = tc.get_theme_names() self.assertEqual(set(names_ref), set(names_tc))
def landing(request): context = {} tc = ThemeController() context['theme_name'] = tc.get_current_theme() context['last_customization_name'] = Tag.getTag('prev_theme_customization', default='None') return render_to_response('themes/landing.html', request, context)
def testAvailableThemes(self): """ Check that the ThemeController says we have the themes we expect to have. """ tc = ThemeController() names_ref = ['generic1', 'generic2', 'chicago', 'mit'] names_tc = tc.get_theme_names() self.assertEqual(set(names_ref), set(names_tc))
def landing(request): if settings.LOCAL_THEME: raise ESPError(THEME_ERROR_STRING, log=False) context = {} tc = ThemeController() context['theme_name'] = tc.get_current_theme() context['last_customization_name'] = tc.get_current_customization() return render_to_response('themes/landing.html', request, context)
def load_from_tag(cls, theme_name=None, just_selected=False): data = json.loads(Tag.getTag('theme_template_control', default='{}')) if theme_name is None: tc = ThemeController() theme_name = tc.get_current_theme() data['theme'] = theme_name form_temp = cls(initial=data) data = form_temp.recover_from_serialization(data) data['just_selected'] = just_selected form = cls(initial=data) return form
def get_nav_category(path): tc = ThemeController() settings = tc.get_template_settings() # Search for current nav category based on request path first_level = ''.join(path.lstrip('/').split('/')[:1]) for category in settings['nav_structure']: if category['header_link'].lstrip('/').startswith(first_level): return category # Search failed - use default nav category default_nav_category = 'learn' for category in settings['nav_structure']: if category['header_link'].lstrip('/').startswith(default_nav_category): return category
def get_nav_category(path): tc = ThemeController() settings = tc.get_template_settings() # Search for current nav category based on request path first_level = ''.join(path.lstrip('/').split('/')[:1]) for category in settings['nav_structure']: if category['header_link'].lstrip('/').startswith(first_level): return category # Search failed - use default nav category default_nav_category = 'learn' for category in settings['nav_structure']: if category['header_link'].lstrip('/').startswith( default_nav_category): return category
def testEditor(self): """ Check that the theme editor backend functionality is working. """ """ TODO: - Check that theme specific properties show up on the form - Check load, save, delete modes as well as test """ # Log in as administrator and load the theme editor self.client.login(username=self.admin.username, password='******') response = self.client.get('/themes/customize/') self.assertEqual(response.status_code, 200) # Check that the "advanced" properties for all themes show up in the form # (using ThemeController directly for theme switching, since testSelector() # covers the Web interface) tc = ThemeController() theme_names = tc.get_theme_names() for theme_name in theme_names: variables_filename = os.path.join(settings.MEDIA_ROOT, 'esp', 'themes', 'theme_data', theme_name, 'variables.less') if os.path.exists(variables_filename): tc.clear_theme() tc.load_theme(theme_name) response = self.client.get('/themes/customize/') self.assertEqual(response.status_code, 200) variables = re.findall(r'@(\S+):\s+?(\S+);', open(variables_filename).read()) for (varname, value) in variables: self.assertTrue(len(re.findall(r'<input.*?name="%s".*?value="%s".*?>', response.content, flags=re.I)) > 0) # Test that we can change a parameter and the right value appears in the stylesheet def verify_linkcolor(color_str): css_filename = os.path.join(settings.MEDIA_ROOT, 'styles', themes_settings.COMPILED_CSS_FILE) regexp = r'\n\s*?a\s*?{.*?color:\s*?%s;.*?}' % color_str self.assertTrue(len(re.findall(regexp, open(css_filename).read(), flags=(re.DOTALL | re.I))) == 1) color_str1 = '#%06X' % random.randint(0, 1 << 24) config_dict = {'apply': True, 'linkColor': color_str1} response = self.client.post('/themes/customize/', config_dict) self.assertEqual(response.status_code, 200) verify_linkcolor(color_str1) # Test that we can save this setting, change it and re-load config_dict = {'save': True, 'linkColor': color_str1, 'saveThemeName': 'save_test'} response = self.client.post('/themes/customize/', config_dict) self.assertEqual(response.status_code, 200) color_str2 = '#%06X' % random.randint(0, 1 << 24) config_dict = {'apply': True, 'linkColor': color_str2} response = self.client.post('/themes/customize/', config_dict) self.assertEqual(response.status_code, 200) verify_linkcolor(color_str2) config_dict = {'load': True, 'loadThemeName': 'save_test'} response = self.client.post('/themes/customize/', config_dict) self.assertEqual(response.status_code, 200) verify_linkcolor(color_str1) # We're done. Log out. self.client.logout()
def extract_theme(url): # Get the appropriate color scheme out of the Tag that controls nav structure # (specific to MIT theme) tab_index = 0 tc = ThemeController() settings = tc.get_template_settings() max_chars_matched = 0 for category in settings['nav_structure']: num_chars_matched = count_matching_chars(url, category['header_link']) if num_chars_matched > max_chars_matched: max_chars_matched = num_chars_matched tab_index = 0 i = 1 for item in category['links']: num_chars_matched = count_matching_chars(url, item['link']) if num_chars_matched > max_chars_matched: max_chars_matched = num_chars_matched tab_index = i i += 1 return 'tabcolor%d' % tab_index
def extract_theme(str): # Get the appropriate color scheme out of the Tag that controls nav structure # (specific to MIT theme) tab_index = 0 tc = ThemeController() settings = tc.get_template_settings() for category in settings['nav_structure']: if category['header_link'][:5] == str[:5]: i = 1 for item in category['links']: if str == item['link']: tab_index = i break path_current = os.path.dirname(str) path_tab = os.path.dirname(item['link']) if len(path_current) > len( path_tab) and path_current.startswith(path_tab): tab_index = i break i += 1 return 'tabcolor%d' % tab_index
def confirm_overwrite(request, current_theme=None, differences=None, orig_view=None): """ Display a form asking the user which local modified files they would like to keep, and which they would like to overwrite with the ones from the theme data. """ if settings.LOCAL_THEME: raise ESPError(THEME_ERROR_STRING, log=False) context = {} tc = ThemeController() if current_theme is None: current_theme = request.POST.get('theme', '') if request.method == 'POST' and request.POST.get('confirm_overwrite', '0') == '1': files_to_keep = [] diffs_current = tc.check_local_modifications(current_theme) # Build a list of filenames that we are not supposed to overwrite. for entry in diffs_current: post_key = 'overwrite_%s' % entry['filename_hash'] post_val = request.POST.get(post_key, None) if post_val is not None: if post_val != 'overwrite': files_to_keep.append(entry['filename']) # Continue with the original view (typically the theme selector). view_func = selector if request.POST.get('orig_view', '') == 'recompile': view_func = recompile return view_func(request, keep_files=files_to_keep) # Display the form asking the user which files to keep/overwrite. if differences is None: differences = tc.check_local_modifications(current_theme) context['theme_name'] = current_theme context['differences'] = differences context['orig_view'] = orig_view return render_to_response('themes/confirm_overwrite.html', request, context)
def render_to_response(template, request, context, prog=None, auto_per_program_templates=True, mimetype=None, use_request_context=True): from esp.web.views.navBar import makeNavBar if isinstance(template, (basestring, )): template = [template] if isinstance(prog, (list, tuple)) and auto_per_program_templates: template = [_per_program_template_name(prog[0], t) for t in template] + template section = request.path.split('/')[1] tc = ThemeController() context['theme'] = tc.get_template_settings() context['settings'] = settings # create nav bar list if not context.has_key('navbar_list'): category = None if context.has_key('nav_category'): category = context['nav_category'] context['navbar_list'] = makeNavBar(section, category) if not use_request_context: context['request'] = request response = django.shortcuts.render_to_response(template, context, mimetype=mimetype) return response else: return render_response(request, template, context, mimetype=mimetype)
def render_to_response(template, request, context, content_type=None, use_request_context=True): from esp.web.views.navBar import makeNavBar if isinstance(template, (basestring,)): template = [ template ] section = request.path.split('/')[1] tc = ThemeController() context['theme'] = tc.get_template_settings() context['settings'] = settings # create nav bar list if not 'navbar_list' in context: category = None if 'nav_category' in context: category = context['nav_category'] context['navbar_list'] = makeNavBar(section, category, path=request.path[1:]) if not use_request_context: context['request'] = request response = django.shortcuts.render_to_response(template, context, content_type=content_type) return response else: return render_response(request, template, context, content_type=content_type)
def recompile(request, keep_files=None): if settings.LOCAL_THEME: raise ESPError(THEME_ERROR_STRING, log=False) tc = ThemeController() # Check for differences between the theme's files and those in the working copy. # If there are differences, require a confirmation from the user for each file. theme_name = tc.get_current_theme() differences = tc.check_local_modifications(theme_name) if len(differences) > 0 and keep_files is None: return confirm_overwrite(request, current_theme=theme_name, differences=differences, orig_view='recompile') tc.recompile_theme(keep_files=keep_files) return HttpResponseRedirect('/themes/')
def landing(request): context = {} tc = ThemeController() context['theme_name'] = tc.get_current_theme() context['last_customization_name'] = tc.get_current_customization() return render_to_response('themes/landing.html', request, context)
def save_to_tag(self): tc = ThemeController() data = self.prepare_for_serialization(self.cleaned_data.copy()) tc.set_template_settings(data)
def selector(request, keep_files=None): if settings.LOCAL_THEME: raise ESPError(THEME_ERROR_STRING, log=False) context = {} tc = ThemeController() if request.method == 'POST' and 'action' in request.POST: if request.POST['action'] == 'select': theme_name = request.POST['theme'].replace(' (current)', '') # Check for differences between the theme's files and those in the working copy. # If there are differences, require a confirmation from the user for each file. differences = tc.check_local_modifications(theme_name) if len(differences) > 0 and keep_files is None: return confirm_overwrite(request, current_theme=theme_name, differences=differences, orig_view='selector') # Display configuration form if one is provided for the selected theme if tc.get_config_form_class(theme_name) is not None: return configure(request, current_theme=theme_name, force_display=True, keep_files=keep_files) tc.save_customizations('%s-last' % tc.get_current_theme()) backup_info = tc.clear_theme(keep_files=keep_files) tc.load_theme(theme_name, backup_info=backup_info) elif request.POST['action'] == 'clear': tc.save_customizations('%s-last' % tc.get_current_theme()) tc.clear_theme() context['theme_name'] = tc.get_current_theme() context['themes'] = tc.get_theme_names() return render_to_response('themes/selector.html', request, context)
def testSelector(self): """ Check that theme selector functionality is working. """ self.client.login(username=self.admin.username, password='******') # Get a ThemeController for identifying available themes. tc = ThemeController() # Get the home page (this is a fresh site) and make sure it has a link to the theme landing. response = self.client.get('/') self.assertTrue(len(re.findall(r'<a href="/themes.*?Configure site appearance.*?</a>', response.content, flags=re.DOTALL)) == 1) # Go to the themes landing page and theme selector, make sure neither errors out. response = self.client.get('/themes/') self.assertEqual(response.status_code, 200) response = self.client.get('/themes/select/') self.assertEqual(response.status_code, 200) # Test each theme that is available. for theme_name in tc.get_theme_names(): # print 'Testing theme: %s' % theme_name # Delete the theme_compiled.css file so we force a new one to be generated. css_filename = os.path.join(settings.MEDIA_ROOT, 'styles', themes_settings.COMPILED_CSS_FILE) if os.path.exists(css_filename): os.remove(css_filename) # POST to the theme selector with our choice of theme response = self.client.post('/themes/select/', {'action': 'select', 'theme': theme_name}) self.assertEqual(response.status_code, 200) # Supply more settings if the theme asks for them. if '<form id="theme_setup_form"' in response.content: field_matches = re.findall(r'<(input type="\S+"|textarea).*?name="(\S+)".*?>', response.content, flags=re.DOTALL) settings_dict = { 'theme': theme_name, 'just_selected': 'True', 'nav_structure': '[{"header": "header", "header_link": "/header_link/", "links": [{"link": "link1", "text": "text1"}]}]', } for entry in field_matches: if entry[1] not in settings_dict: # Supply value = key if we do not already know what to say settings_dict[entry[1]] = entry[1] # If theme setup succeeded, we will be redirected to the landing page. response = self.client.post('/themes/setup/', settings_dict, follow=True) self.assertTrue(('http://testserver/themes/', 302) in response.redirect_chain) # Check that the CSS stylesheet has been included in the page. self.assertTrue('/media/styles/theme_compiled.css' in response.content) # Check that the CSS stylesheet has been compiled. self.assertTrue(os.path.exists(css_filename)) self.assertTrue(len(open(css_filename).read()) > 1000) # Hacky way to check that content is substantial """ # The following code would validate the CSS syntax, but cssutils doesn't seem to # support the fancy CSS techniques used by Bootstrap and LESS. parser = cssutils.CSSParser(raiseExceptions=True) parser.parseFile(css_filename) """ # Check that the template override is marked with the theme name. self.assertTrue(('{%% comment %%} Theme: %s {%% endcomment %%}' % theme_name) in response.content) # Test that the theme can be cleared and the home page reverts. response = self.client.post('/themes/select/', {'action': 'clear'}) response = self.client.get('/') self.assertTrue(len(re.findall(r'<a href="/themes.*?Configure site appearance.*?</a>', response.content, flags=re.DOTALL)) == 1) self.client.logout()
def editor(request): if settings.LOCAL_THEME: raise ESPError(THEME_ERROR_STRING, log=False) tc = ThemeController() if request.method == 'POST': # Handle form submission vars = None palette = None if 'save' in request.POST: if request.POST['saveThemeName'] == '': theme_name = tc.get_current_customization() if theme_name == 'None': # Generate a temporary theme name random_slug = ''.join(random.choice(string.lowercase) for i in range(4)) theme_name = 'theme-%s-%s' % (datetime.now().strftime('%Y%m%d'), random_slug) else: theme_name = request.POST['saveThemeName'] vars = request.POST.dict() palette = request.POST.getlist('palette') tc.save_customizations(theme_name, vars=vars, palette=palette) tc.set_current_customization(theme_name) elif 'load' in request.POST: (vars, palette) = tc.load_customizations(request.POST['loadThemeName']) elif 'delete' in request.POST: tc.delete_customizations(request.POST['loadThemeName']) elif 'apply' in request.POST: vars = request.POST.dict() palette = request.POST.getlist('palette') # Re-generate the CSS for the current theme given the supplied settings if vars: tc.customize_theme(vars) if palette: tc.set_palette(palette) # Get current theme and customization settings current_theme = tc.get_current_theme() context = tc.find_less_variables(flat=True) context.update(tc.get_current_params()) context['palette'] = tc.get_palette() # Get list of available customizations context['available_themes'] = tc.get_customization_names() context['last_used_setting'] = tc.get_current_customization() # Load a bunch of preset fonts context['sans_fonts'] = sorted(themes_settings.sans_serif_fonts.iteritems()) # Load the theme-specific options adv_vars = tc.find_less_variables(current_theme, theme_only=True) context['adv_vars'] = {} for filename in adv_vars: category_name = os.path.basename(filename)[:-5] category_vars = [] keys = adv_vars[filename].keys() keys.sort() for key in keys: # Detect type of variable based on default value initial_val = adv_vars[filename][key] if key in context: initial_val = context[key] if initial_val.startswith('#'): category_vars.append((key, 'color', initial_val)) elif 'color' in key: # This is a nontrivial color value. However, we only allow overriding # these variables with specific colors. category_vars.append((key, 'color', '')) elif initial_val.endswith('px') or initial_val.endswith('em'): category_vars.append((key, 'length', initial_val)) else: category_vars.append((key, 'text', initial_val)) context['adv_vars'][category_name] = category_vars return render_to_response('themes/editor.html', request, context)
def configure(request, current_theme=None, force_display=False, keep_files=None): if settings.LOCAL_THEME: raise ESPError(THEME_ERROR_STRING, log=False) context = {} tc = ThemeController() if current_theme is None: current_theme = request.POST.get('theme', None) or tc.get_current_theme() context['theme_name'] = current_theme form_class = tc.get_config_form_class(current_theme) if form_class is None: form = None return render_to_response('themes/configure_form.html', request, context) if request.method == 'POST' and not force_display: form = form_class(request.POST.copy()) if form.is_valid(): # Done; save results and go back to landing page. if form.cleaned_data['theme'] != tc.get_current_theme(): tc.save_customizations('%s-last' % tc.get_current_theme()) if form.cleaned_data['just_selected']: # Detect which files (in the active media directories) are being preserved, # and use this information when reloading the theme. keep_files = request.POST.getlist('keep_files', []) backup_info = tc.clear_theme(keep_files=keep_files) tc.load_theme(form.cleaned_data['theme'], backup_info=backup_info) form.save_to_tag() return HttpResponseRedirect('/themes/') else: form = form_class.load_from_tag(theme_name=current_theme, just_selected=force_display) context['form'] = form context['keep_files'] = keep_files context['confirm_overwrite'] = request.POST.get('confirm_overwrite', '0') return render_to_response('themes/configure_form.html', request, context)
def configure(request, current_theme=None, force_display=False): context = {} tc = ThemeController() if current_theme is None: current_theme = request.POST.get('theme', None) or tc.get_current_theme() context['theme_name'] = current_theme form_class = tc.get_config_form_class(current_theme) if form_class is None: form = None return render_to_response('themes/configure_form.html', request, context) if request.method == 'POST' and not force_display: form = form_class(request.POST.copy()) if form.is_valid(): # Done; save results and go back to landing page. if form.cleaned_data['theme'] != tc.get_current_theme(): tc.save_customizations('%s-last' % tc.get_current_theme()) if form.cleaned_data['just_selected']: tc.clear_theme() tc.load_theme(form.cleaned_data['theme']) form.save_to_tag() return HttpResponseRedirect('/themes/') else: form = form_class.load_from_tag(theme_name=current_theme, just_selected=force_display) context['form'] = form return render_to_response('themes/configure_form.html', request, context)
def testSelector(self): """ Check that theme selector functionality is working. """ self.client.login(username=self.admin.username, password='******') # Get a ThemeController for identifying available themes. tc = ThemeController() # Get the home page (this is a fresh site) and make sure it has a link to the theme landing. response = self.client.get('/') self.assertTrue(len(re.findall(r'<a href="/themes.*?Configure site appearance.*?</a>', response.content, flags=re.DOTALL)) == 1) # Go to the themes landing page and theme selector, make sure neither errors out. response = self.client.get('/themes/') self.assertEqual(response.status_code, 200) response = self.client.get('/themes/select/') self.assertEqual(response.status_code, 200) # Move the existing images dir out of the way, so we don't conflict # with it (either what the user has there, or between themes). # TODO(benkraft): Do the same for styles and scripts, although in # practice conflicts there are less likely. # TODO(benkraft): This is a super hacky way to do things! Instead we # should be doing all these tests in some sort of tmpdir to avoid # touching anything of the user's. images_dir = os.path.join(settings.MEDIA_ROOT, 'images', 'theme') # Really we should use a tempdir, but on vagrant it may be on a # different file system, which causes problems, so we do a hackier # thing instead. images_backup_dir = os.path.join(settings.MEDIA_ROOT, 'images', 'theme_backup_for_tests') if os.path.exists(images_dir): os.rename(images_dir, images_backup_dir) try: # Test each theme that is available. for theme_name in tc.get_theme_names(): # Delete the theme_compiled.css file so we force a new one to be generated. css_filename = os.path.join(settings.MEDIA_ROOT, 'styles', themes_settings.COMPILED_CSS_FILE) if os.path.exists(css_filename): os.remove(css_filename) # Clobber any stray theme images dir, to avoid conflicts. # Note that we've already backed up any one the user had # created, above. if os.path.exists(images_dir): shutil.rmtree(images_dir) # Make sure there won't be any conflicts between this theme and # existing files -- since they would cause harder-to-understand # errors later on. self.assertFalse(tc.check_local_modifications(theme_name)) # POST to the theme selector with our choice of theme response = self.client.post('/themes/select/', {'action': 'select', 'theme': theme_name}) self.assertEqual(response.status_code, 200) # Supply more settings if the theme asks for them. if '<form id="theme_setup_form"' in response.content: field_matches = re.findall(r'<(input id="\S+"|textarea).*?name="(\S+)".*?>', response.content, flags=re.DOTALL) # This is the union of all the theme configuration settings that # have a non-trivial form (e.g. key = value fails validation). settings_dict = { 'theme': theme_name, 'just_selected': 'True', 'front_page_style': 'bubblesfront.html', 'facebook_link': 'http://somehost.net', 'nav_structure': '[{"header": "header", "header_link": "/header_link/", "links": [{"link": "link1", "text": "text1"}]}]', } for entry in field_matches: if entry[1] not in settings_dict: # Supply value = key if we do not already know what to say settings_dict[entry[1]] = entry[1] # If theme setup succeeded, we will be redirected to the landing page. response = self.client.post('/themes/setup/', settings_dict, follow=True) self.assertTrue(('http://testserver/themes/', 302) in response.redirect_chain) # Check that the CSS stylesheet has been included in the page. self.assertTrue('/media/styles/theme_compiled.css' in response.content) # Check that the CSS stylesheet has been compiled. self.assertTrue(os.path.exists(css_filename)) self.assertTrue(len(open(css_filename).read()) > 1000) # Hacky way to check that content is substantial # Check that the template override is marked with the theme name. self.assertTrue(('<!-- Theme: %s -->' % theme_name) in response.content) # Test that the theme can be cleared and the home page reverts. response = self.client.post('/themes/select/', {'action': 'clear'}) response = self.client.get('/') self.assertTrue(len(re.findall(r'<a href="/themes.*?Configure site appearance.*?</a>', response.content, flags=re.DOTALL)) == 1) self.client.logout() finally: # Restore the backed up images dir. if os.path.exists(images_dir): shutil.rmtree(images_dir) if os.path.exists(images_backup_dir): os.rename(images_backup_dir, images_dir)
def recompile(request): tc = ThemeController() tc.recompile_theme() return HttpResponseRedirect('/themes/')
def selector(request): context = {} tc = ThemeController() if request.method == 'POST' and 'action' in request.POST: if request.POST['action'] == 'select': theme_name = request.POST['theme'].replace(' (current)', '') # Display configuration form if one is provided for the selected theme if tc.get_config_form_class(theme_name) is not None: return configure(request, current_theme=theme_name, force_display=True) tc.save_customizations('%s-last' % tc.get_current_theme()) tc.clear_theme() tc.load_theme(theme_name) elif request.POST['action'] == 'clear': tc.save_customizations('%s-last' % tc.get_current_theme()) tc.clear_theme() context['theme_name'] = tc.get_current_theme() context['themes'] = tc.get_theme_names() return render_to_response('themes/selector.html', request, context)
def testSelector(self): """ Check that theme selector functionality is working. """ self.client.login(username=self.admin.username, password='******') # Get a ThemeController for identifying available themes. tc = ThemeController() # Get the home page (this is a fresh site) and make sure it has a link to the theme landing. response = self.client.get('/') self.assertTrue(len(re.findall(r'<a href="/themes.*?Configure site appearance.*?</a>', response.content, flags=re.DOTALL)) == 1) # Go to the themes landing page and theme selector, make sure neither errors out. response = self.client.get('/themes/') self.assertEqual(response.status_code, 200) response = self.client.get('/themes/select/') self.assertEqual(response.status_code, 200) # Test each theme that is available. for theme_name in tc.get_theme_names(): # Delete the theme_compiled.css file so we force a new one to be generated. css_filename = os.path.join(settings.MEDIA_ROOT, 'styles', themes_settings.COMPILED_CSS_FILE) if os.path.exists(css_filename): os.remove(css_filename) # POST to the theme selector with our choice of theme response = self.client.post('/themes/select/', {'action': 'select', 'theme': theme_name}) self.assertEqual(response.status_code, 200) # Supply more settings if the theme asks for them. if '<form id="theme_setup_form"' in response.content: field_matches = re.findall(r'<(input id="\S+"|textarea).*?name="(\S+)".*?>', response.content, flags=re.DOTALL) # This is the union of all the theme configuration settings that # have a non-trivial form (e.g. key = value fails validation). settings_dict = { 'theme': theme_name, 'just_selected': 'True', 'front_page_style': 'bubblesfront.html', 'facebook_link': 'http://somehost.net', 'nav_structure': '[{"header": "header", "header_link": "/header_link/", "links": [{"link": "link1", "text": "text1"}]}]', } for entry in field_matches: if entry[1] not in settings_dict: # Supply value = key if we do not already know what to say settings_dict[entry[1]] = entry[1] # If theme setup succeeded, we will be redirected to the landing page. response = self.client.post('/themes/setup/', settings_dict, follow=True) self.assertTrue(('http://testserver/themes/', 302) in response.redirect_chain) # Check that the CSS stylesheet has been included in the page. self.assertTrue('/media/styles/theme_compiled.css' in response.content) # Check that the CSS stylesheet has been compiled. self.assertTrue(os.path.exists(css_filename)) self.assertTrue(len(open(css_filename).read()) > 1000) # Hacky way to check that content is substantial # Check that the template override is marked with the theme name. self.assertTrue(('<!-- Theme: %s -->' % theme_name) in response.content) # Test that the theme can be cleared and the home page reverts. response = self.client.post('/themes/select/', {'action': 'clear'}) response = self.client.get('/') self.assertTrue(len(re.findall(r'<a href="/themes.*?Configure site appearance.*?</a>', response.content, flags=re.DOTALL)) == 1) self.client.logout()