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 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 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 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)