def upload_file(request): selected_theme = request.GET.get("theme_edit", get_theme()) if not is_valid_theme(selected_theme): raise Http404(_('Specified theme does not exist')) if is_theme_read_only(selected_theme): raise Http403 if request.method == 'POST': form = UploadForm(request.POST, request.FILES) if form.is_valid(): file_dir = form.cleaned_data['file_dir'] overwrite = form.cleaned_data['overwrite'] def callback(file_path, uuid, selected_theme=selected_theme, file_dir=file_dir, overwrite=overwrite): theme_root = get_theme_root(selected_theme) file_name = os.path.basename(file_path) full_filename = os.path.join(file_dir, file_name) if (not is_valid_path(theme_root, file_dir) or not is_valid_path(theme_root, full_filename)): raise Http403 if os.path.isfile(os.path.join(theme_root, full_filename)) and not overwrite: msg_string = 'File %s already exists in that folder.' % (file_name) raise uploader.CallbackError(msg_string) copy_file_to_theme(file_path, selected_theme, file_dir, file_name) EventLog.objects.log() return uploader.post(request, callback) else: # not valid messages.add_message(request, messages.ERROR, form.errors) return HttpResponse('invalid', content_type="text/plain") return HttpResponseRedirect('/theme-editor/editor/')
def theme_rename(request, form_class=ThemeNameForm): if not request.user.profile.is_superuser: raise Http403 selected_theme = request.GET.get("theme_edit", get_theme()) if not is_valid_theme(selected_theme): raise Http404(_('Specified theme does not exist')) if is_theme_read_only(selected_theme): raise Http403 theme_root = get_theme_root(selected_theme) form = form_class(request.POST or None) ret_dict = {'success': False, 'err': ''} if form.is_valid(): new_theme_name = form.cleaned_data['theme_name'] if is_valid_theme(new_theme_name): ret_dict['err'] = _('Theme "%(name)s" already exists' % {'name': new_theme_name}) return HttpResponse(json.dumps(ret_dict)) if not is_valid_path(settings.ORIGINAL_THEMES_DIR, new_theme_name): raise Http403 new_theme_root = get_theme_root(new_theme_name) shutil.move(theme_root, new_theme_root) ret_dict['success'] = True EventLog.objects.log() #else: # ret_dict['err'] = form.errors.as_json() return HttpResponse(json.dumps(ret_dict))
def original_templates(request, template_name="theme_editor/original_templates.html"): selected_theme = request.GET.get("theme_edit", get_theme()) if not is_valid_theme(selected_theme): raise Http404(_('Specified theme does not exist')) if is_theme_read_only(selected_theme): raise Http403 app = request.GET.get("app", None) current_dir = request.GET.get("dir", '') if current_dir: current_dir = current_dir.replace('\\', '/') current_dir = current_dir.strip('/') current_dir = current_dir.replace('////', '/') current_dir = current_dir.replace('///', '/') current_dir = current_dir.replace('//', '/') # if current_dir is a directory then append the # trailing slash so we can get the dirname below # get the previous directory name and path prev_dir = '/' prev_dir_name = 'original templates' current_dir_split = current_dir.split('/') if len(current_dir_split) > 1: prev_dir_name = current_dir_split[-2] current_dir_split.pop() prev_dir = '/'.join(current_dir_split) elif not current_dir_split[0]: prev_dir = '' if app in app_templates: root = app_templates[app] elif is_valid_theme(app): root = os.path.join(get_theme_root(app), 'templates') else: if '/' in app and app.split('/')[0] == 'builtin': builtin_base_name = app.split('/')[1] root = os.path.join(settings.TENDENCI_ROOT, "themes/{}/templates".format(builtin_base_name)) else: raise Http404(_('Specified theme or app does not exist')) if not is_valid_path(root, current_dir): raise Http403 dirs = get_dir_list(root, current_dir) files, non_editable_files = get_file_list(root, current_dir) return render_to_resp(request=request, template_name=template_name, context={ 'current_theme': selected_theme, 'app': app, 'current_dir': current_dir, 'prev_dir_name': prev_dir_name, 'prev_dir': prev_dir, 'dirs': dirs, 'files': files, 'non_editable_files': non_editable_files, })
def copy_to_theme(request): selected_theme = request.GET.get("theme_edit", get_theme()) if not is_valid_theme(selected_theme): raise Http404(_('Specified theme does not exist')) if is_theme_read_only(selected_theme): raise Http403 app = request.GET.get("app", None) current_dir = request.GET.get("dir", '') if current_dir: current_dir = current_dir.replace('\\', '/') current_dir = current_dir.strip('/') current_dir = current_dir.replace('////', '/') current_dir = current_dir.replace('///', '/') current_dir = current_dir.replace('//', '/') chosen_file = request.GET.get("file", '') if chosen_file: chosen_file = chosen_file.replace('\\', '/') chosen_file = chosen_file.strip('/') chosen_file = chosen_file.replace('////', '/') chosen_file = chosen_file.replace('///', '/') chosen_file = chosen_file.replace('//', '/') if app in app_templates: root = app_templates[app] elif is_valid_theme(app): root = os.path.join(get_theme_root(app), 'templates') else: if '/' in app and app.split('/')[0] == 'builtin': builtin_base_name = app.split('/')[1] root = os.path.join( settings.TENDENCI_ROOT, "themes/{}/templates".format(builtin_base_name)) else: raise Http404(_('Specified theme or app does not exist')) if (not is_valid_path(root, current_dir) or not is_valid_path(root, os.path.join(current_dir, chosen_file))): raise Http403 full_filename = os.path.join(root, current_dir, chosen_file) if not os.path.isfile(full_filename): raise Http404 copy_file_to_theme(full_filename, selected_theme, os.path.join('templates', current_dir), chosen_file) msg_string = 'Successfully copied %s/%s to theme' % (current_dir, chosen_file) messages.add_message(request, messages.SUCCESS, _(msg_string)) EventLog.objects.log() return redirect('theme_editor.editor')
def delete_file(request): # if no permission; raise 403 exception if not has_perm(request.user, 'theme_editor.change_themefileversion'): raise Http403 current_dir = request.GET.get("dir", '') if current_dir: current_dir = current_dir.replace('\\', '/') current_dir = current_dir.strip('/') current_dir = current_dir.replace('////', '/') current_dir = current_dir.replace('///', '/') current_dir = current_dir.replace('//', '/') if current_dir.startswith('plugins.'): current_dir = current_dir.split('plugins.')[1] chosen_file = request.GET.get("file", '') if chosen_file: chosen_file = chosen_file.replace('\\', '/') chosen_file = chosen_file.strip('/') chosen_file = chosen_file.replace('////', '/') chosen_file = chosen_file.replace('///', '/') chosen_file = chosen_file.replace('//', '/') full_filename = os.path.join(settings.PROJECT_ROOT, "themes", get_theme(), current_dir, chosen_file) if not os.path.isfile(full_filename): raise Http404 os.remove(full_filename) if settings.USE_S3_STORAGE: delete_file_from_s3(file=settings.AWS_LOCATION + '/' + 'themes/' + get_theme() + '/' + current_dir + chosen_file) msg_string = 'Successfully deleted %s/%s.' % (current_dir, chosen_file) messages.add_message(request, messages.SUCCESS, _(msg_string)) EventLog.objects.log() return redirect('theme_editor.editor')
def save(self, request, file_relative_path, ROOT_DIR=THEME_ROOT, ORIG_ROOT_DIR=THEME_ROOT): content = self.cleaned_data["content"] file_path = (os.path.join(ROOT_DIR, file_relative_path)).replace("\\", "/") if settings.USE_S3_THEME: file_path = (os.path.join(ORIG_ROOT_DIR, file_relative_path)).replace("\\", "/") # write the theme file locally in case it was wiped by a restart if settings.USE_S3_THEME and not os.path.isfile(file_path): file_dir = os.path.dirname(file_path) if not os.path.isdir(file_dir): # if directory does not exist, create it os.makedirs(file_dir) new_file = open(file_path, 'w') new_file.write('') new_file.close() if os.path.isfile(file_path) and content != "": archive_file(request, file_relative_path, ROOT_DIR=ORIG_ROOT_DIR) # Save the file locally no matter the theme location. # The save to S3 reads from the local file, so we need to save it first. f = codecs.open(file_path, 'w', 'utf-8', 'replace') file = File(f) file.write(content) file.close() if settings.USE_S3_THEME: # copy to s3 storage if os.path.splitext(file_path)[1] == '.html': public = False else: public = True save_file_to_s3(file_path, public=public) cache_key = ".".join([ settings.SITE_CACHE_KEY, 'theme', "%s/%s" % (get_theme(), file_relative_path) ]) cache.delete(cache_key) if hasattr(settings, 'REMOTE_DEPLOY_URL') and settings.REMOTE_DEPLOY_URL: urllib.urlopen(settings.REMOTE_DEPLOY_URL) return True else: return False
def get_template_sources(self, template_name, template_dirs=None): """ Return possible absolute paths to "template_name" in the current theme and any themes it inherits from. Any paths that don't lie inside one of the template dirs are excluded from the result set for security reasons. """ request = get_current_request() mobile = (request and request.mobile) active_theme = get_active_theme() theme = get_theme(active_theme) cached_theme, theme_search_info = self.cached_theme_search_info # If the theme changed or the user is previewing a different theme, # recalculate theme_search_info. # Note that this Loader instance may be shared between multiple threads, # so you must be careful when reading/writing # self.cached_theme_search_info to ensure that writes in one thread # cannot cause unexpected behavior in another thread that is # reading/writing self.cached_theme_search_info at the same time. if cached_theme != theme: theme_search_info = [] for cur_theme in get_theme_search_order(theme): if is_builtin_theme(cur_theme) or not settings.USE_S3_THEME: theme_search_info.append( (cur_theme, get_theme_root(cur_theme), False)) else: theme_search_info.append((cur_theme, cur_theme, True)) if theme == active_theme: self.cached_theme_search_info = (theme, theme_search_info) for cur_theme, cur_theme_root, use_s3_theme in theme_search_info: for template_path in (['mobile', 'templates'] if mobile else ['templates']): if not use_s3_theme: try: template_file = safe_join(cur_theme_root, template_path, template_name) except SuspiciousFileOperation: # The joined path was located outside of template_path, # although it might be inside another one, so this isn't # fatal. continue else: template_file = os.path.join(cur_theme_root, template_path, template_name) origin = Origin(name=template_file, template_name=template_name, loader=self) origin.theme = cur_theme origin.use_s3_theme = use_s3_theme yield origin
def delete_file(request): selected_theme = request.GET.get("theme_edit", get_theme()) if not is_valid_theme(selected_theme): raise Http404(_('Specified theme does not exist')) if is_theme_read_only(selected_theme): raise Http403 current_dir = request.GET.get("dir", '') if current_dir: current_dir = current_dir.replace('\\', '/') current_dir = current_dir.strip('/') current_dir = current_dir.replace('////', '/') current_dir = current_dir.replace('///', '/') current_dir = current_dir.replace('//', '/') if current_dir.startswith('plugins.'): current_dir = current_dir.split('plugins.')[1] chosen_file = request.GET.get("file", '') if chosen_file: chosen_file = chosen_file.replace('\\', '/') chosen_file = chosen_file.strip('/') chosen_file = chosen_file.replace('////', '/') chosen_file = chosen_file.replace('///', '/') chosen_file = chosen_file.replace('//', '/') theme_root = get_theme_root(selected_theme) if (not is_valid_path(theme_root, current_dir) or not is_valid_path( theme_root, os.path.join(current_dir, chosen_file))): raise Http403 full_filename = os.path.join(theme_root, current_dir, chosen_file) if not os.path.isfile(full_filename): raise Http404 os.remove(full_filename) if settings.USE_S3_STORAGE: s3_path = selected_theme + '/' + current_dir + chosen_file s3_full_path = settings.AWS_LOCATION + '/' + settings.THEME_S3_PATH + '/' + s3_path delete_file_from_s3(file=s3_full_path) cache_key = ".".join([settings.SITE_CACHE_KEY, 'theme', s3_path]) cache.delete(cache_key) msg_string = 'Successfully deleted %s/%s.' % (current_dir, chosen_file) messages.add_message(request, messages.SUCCESS, _(msg_string)) EventLog.objects.log() return redirect('theme_editor.editor')
def create_new_template(request, form_class=AddTemplateForm): """ Create a new blank template for a given template name """ selected_theme = request.GET.get("theme_edit", get_theme()) if not is_valid_theme(selected_theme): raise Http404(_('Specified theme does not exist')) if is_theme_read_only(selected_theme): raise Http403 form = form_class(request.POST or None) ret_dict = {'created': False, 'err': ''} if form.is_valid(): template_name = form.cleaned_data['template_name'].strip() template_full_name = 'default-%s.html' % template_name existing_templates = [t[0] for t in get_template_list()] if template_full_name not in existing_templates: # create a new template and assign default content theme_root = get_theme_root(selected_theme) template_dir = os.path.join(theme_root, 'templates') template_full_path = os.path.join(template_dir, template_full_name) # grab the content from the new-default-template.html # first check if there is a customized one on the site default_template_name = 'new-default-template.html' default_template_path = os.path.join(template_dir, 'theme_editor', default_template_name) if not os.path.isfile(default_template_path): # no customized one found, use the default one default_template_path = os.path.join( os.path.abspath(os.path.dirname(__file__)), 'templates/theme_editor', default_template_name) if os.path.isfile(default_template_path): default_content = open(default_template_path).read() else: default_content = '' with open(template_full_path, 'w') as f: f.write(default_content) if settings.USE_S3_STORAGE: s3_path = os.path.join(settings.THEME_S3_PATH, selected_theme, 'templates', template_full_name) save_file_to_s3(template_full_path, dest_path=s3_path, public=False) ret_dict['created'] = True ret_dict['template_name'] = template_full_name else: ret_dict['err'] = _('Template "%(name)s" already exists' % {'name': template_full_name}) return HttpResponse(json.dumps(ret_dict))
def app_list(request, template_name="theme_editor/app_list.html"): selected_theme = request.GET.get("theme_edit", get_theme()) if not is_valid_theme(selected_theme): raise Http404(_('Specified theme does not exist')) if is_theme_read_only(selected_theme): raise Http403 theme_list = get_theme_search_order(selected_theme)[1:] app_list = app_templates.keys() return render_to_resp(request=request, template_name=template_name, context={ 'current_theme': selected_theme, 'apps': theme_list + sorted(app_list, key=lambda app: app[0]), })
def save(self, request, file_relative_path, ROOT_DIR=THEME_ROOT, ORIG_ROOT_DIR=THEME_ROOT): content = self.cleaned_data["content"] file_path = (os.path.join(ROOT_DIR, file_relative_path)).replace("\\", "/") if settings.USE_S3_THEME: file_path = (os.path.join(ORIG_ROOT_DIR, file_relative_path)).replace("\\", "/") # write the theme file locally in case it was wiped by a restart if settings.USE_S3_THEME and not os.path.isfile(file_path): file_dir = os.path.dirname(file_path) if not os.path.isdir(file_dir): # if directory does not exist, create it os.makedirs(file_dir) new_file = open(file_path, 'w') new_file.write('') new_file.close() if os.path.isfile(file_path) and content != "": archive_file(request, file_relative_path, ROOT_DIR=ORIG_ROOT_DIR) # Save the file locally no matter the theme location. # The save to S3 reads from the local file, so we need to save it first. f = codecs.open(file_path, 'w', 'utf-8', 'replace') file = File(f) file.write(content) file.close() if settings.USE_S3_THEME: # copy to s3 storage if os.path.splitext(file_path)[1] == '.html': public = False else: public = True save_file_to_s3(file_path, public=public) cache_key = ".".join([settings.SITE_CACHE_KEY, 'theme', "%s/%s" % (get_theme(), file_relative_path)]) cache.delete(cache_key) if hasattr(settings, 'REMOTE_DEPLOY_URL') and settings.REMOTE_DEPLOY_URL: urllib.urlopen(settings.REMOTE_DEPLOY_URL) return True else: return False
def theme(request): context = {} if 'theme' in request.GET and request.user.profile.is_superuser: theme = request.GET.get('theme') if theme: request.session['theme'] = theme elif 'theme' in request.session: del request.session['theme'] context['ACTIVE_THEME'] = get_active_theme() context['THEME'] = theme = get_theme(context['ACTIVE_THEME']) context['THEME_INFO'] = get_theme_info(theme) # Backward compatibility for old themes def warn_theme_urls(value): warn("{{ THEME_URL }}media/<path> is deprecated, use {% static '<path>' %} instead", DeprecationWarning) return value if is_builtin_theme(theme): theme_url = '%sthemes/%s/'%(settings.STATIC_URL, get_builtin_theme_dir(theme)) def warn_theme_url(value=theme_url): # noqa: E306 return warn_theme_urls(value) context['THEME_URL'] = warn_theme_url elif settings.USE_S3_STORAGE: theme_url = '%s/%s/%s/themes/%s/'%( settings.S3_ROOT_URL, settings.AWS_STORAGE_BUCKET_NAME, settings.AWS_LOCATION, theme) def warn_theme_url(value=theme_url): # noqa: E306 return warn_theme_urls(value) context['THEME_URL'] = warn_theme_url else: theme_url = '/themes/'+theme+'/' def warn_theme_url(value=theme_url): # noqa: E306 return warn_theme_urls(value) context['THEME_URL'] = warn_theme_url local_theme_url = '/themes/'+theme+'/' def warn_local_theme_url(value=local_theme_url): # noqa: E306 warn("{{ LOCAL_THEME_URL }}media/<path> is deprecated, use {% local_static '<path>' %} instead", DeprecationWarning) return value context['LOCAL_THEME_URL'] = warn_local_theme_url return context
def theme_delete(request): if not request.user.profile.is_superuser: raise Http403 selected_theme = request.GET.get("theme_edit", get_theme()) if not is_valid_theme(selected_theme): raise Http404(_('Specified theme does not exist')) if is_theme_read_only(selected_theme): raise Http403 shutil.rmtree(get_theme_root(selected_theme)) if settings.USE_S3_STORAGE: delete_file_from_s3(file=settings.AWS_LOCATION + '/' + settings.THEME_S3_PATH + '/' + selected_theme) msg_string = 'Successfully deleted %s.' % (selected_theme) messages.add_message(request, messages.SUCCESS, _(msg_string)) EventLog.objects.log() return redirect('theme_editor.editor')
def get_file_content(file, ROOT_DIR=THEME_ROOT): """ Get the content from the file that selected from the navigation """ content = '' if settings.USE_S3_THEME: try: theme = get_theme() content = read_theme_file_from_s3(os.path.join(theme, file)) except: pass if not content: current_file = os.path.join(ROOT_DIR, file) if os.path.isfile(current_file): fd = open(current_file, 'r') content = fd.read() fd.close() return content
def edit_file(request, form_class=FileForm, template_name="theme_editor/index.html"): if not has_perm(request.user, 'theme_editor.view_themefileversion'): raise Http403 selected_theme = request.GET.get("theme_edit", get_theme()) original_theme_root = os.path.join(settings.ORIGINAL_THEMES_DIR, selected_theme) if settings.USE_S3_THEME: theme_root = os.path.join(settings.THEME_S3_PATH, selected_theme) else: theme_root = os.path.join(settings.ORIGINAL_THEMES_DIR, selected_theme) # get the default file and clean up any input default_file = request.GET.get("file", DEFAULT_FILE) if default_file: default_file = default_file.replace('\\', '/') default_file = default_file.strip('/') default_file = default_file.replace('////', '/') default_file = default_file.replace('///', '/') default_file = default_file.replace('//', '/') is_file = qstr_is_file(default_file, ROOT_DIR=theme_root) is_dir = qstr_is_dir(default_file, ROOT_DIR=theme_root) if is_file: pass elif is_dir: # if default_file is a directory then append the # trailing slash so we can get the dirname below default_file = '%s/' % default_file else: # if the default_file is not a directory or file within # the themes folder then return a 404 raise Http404( _("Custom template not found. Make sure you've copied over the themes to the THEME_DIR." )) # get the current file name current_file = os.path.basename(default_file) # get file ext name = current_file.split('/')[-1] ext = name.split('.')[-1] stylesheets = ['css', 'less'] # get the present working directory # and make sure they cannot list root pwd = os.path.dirname(default_file) if pwd == '/': pwd = '' current_file_path = os.path.join(pwd, current_file) # get the previous directory name and path prev_dir = '/' prev_dir_name = 'theme base' pwd_split = pwd.split('/') if len(pwd_split) > 1: prev_dir_name = pwd_split[-2] pwd_split.pop() prev_dir = '/'.join(pwd_split) elif not pwd_split[0]: prev_dir = '' # get the direcory list dirs = get_dir_list(pwd, ROOT_DIR=theme_root) # get the file list files, non_editable_files = get_file_list(pwd, ROOT_DIR=theme_root) all_files_folders = get_all_files_list(ROOT_DIR=theme_root) # non-deletable files non_deletable_files = [ 'homepage.html', 'default.html', 'footer.html', 'header.html', 'sidebar.html', 'nav.html', 'styles.less', 'styles.css' ] # get the number of themes in the themes directory on the site theme_choices = [i for i in theme_choice_list()] theme_count = len(theme_choices) # get a list of revisions archives = ThemeFileVersion.objects.filter( relative_file_path=default_file).order_by("-create_dt") if request.is_ajax() and request.method == "POST": file_form = form_class(request.POST) response_status = 'FAIL' response_message = _('Cannot update file.') if file_form.is_valid(): if file_form.save(request, default_file, ROOT_DIR=theme_root, ORIG_ROOT_DIR=original_theme_root): response_status = 'SUCCESS' response_message = unicode(_('Your changes have been saved.')) EventLog.objects.log() response = json.dumps({ 'status': response_status, 'message': response_message }) return HttpResponse(response, content_type="application/json") content = get_file_content(default_file, ROOT_DIR=theme_root) file_form = form_class({"content": content, "rf_path": default_file}) theme_form = ThemeSelectForm(initial={'theme_edit': selected_theme}) return render_to_response(template_name, { 'file_form': file_form, 'theme_form': theme_form, 'current_theme': selected_theme, 'current_file_path': current_file_path, 'current_file': current_file, 'prev_dir_name': prev_dir_name, 'prev_dir': prev_dir, 'pwd': pwd, 'dirs': dirs, 'files': files, 'non_editable_files': non_editable_files, 'non_deletable_files': non_deletable_files, 'theme_count': theme_count, 'archives': archives, 'is_file': is_file, 'is_dir': is_dir, 'all_files_folders': all_files_folders, 'ext': ext, 'stylesheets': stylesheets }, context_instance=RequestContext(request))
def edit_file(request, form_class=FileForm, template_name="theme_editor/index.html"): selected_theme = request.GET.get("theme_edit", get_theme()) if not is_valid_theme(selected_theme): raise Http404(_('Specified theme does not exist')) # get the default file and clean up any input default_file = request.GET.get("file", DEFAULT_FILE) if default_file: default_file = default_file.replace('\\', '/') default_file = default_file.strip('/') default_file = default_file.replace('////', '/') default_file = default_file.replace('///', '/') default_file = default_file.replace('//', '/') theme_root = get_theme_root(selected_theme) if not is_valid_path(theme_root, default_file): raise Http403 theme_read_only = is_theme_read_only(selected_theme) if request.is_ajax() and request.method == "POST": if theme_read_only: raise Http403 file_form = form_class(request.POST) response_status = 'FAIL' response_message = _('Cannot update file.') if file_form.is_valid(): if file_form.save(theme_root, selected_theme, default_file, request): response_status = 'SUCCESS' response_message = str(_('Your changes have been saved.')) EventLog.objects.log() response = json.dumps({ 'status': response_status, 'message': response_message }) return HttpResponse(response, content_type='application/json') is_file = os.path.isfile(os.path.join(theme_root, default_file)) is_dir = os.path.isdir(os.path.join(theme_root, default_file)) if is_file: pass elif is_dir: # if default_file is a directory then append the # trailing slash so we can get the dirname below default_file = '%s/' % default_file else: # if the default_file is not a directory or file within # the themes folder then return a 404 raise Http404( _("Custom template not found. Make sure you've copied over the themes to the THEME_DIR." )) # get the current file name current_file = os.path.basename(default_file) # get file ext name = current_file.split('/')[-1] ext = name.split('.')[-1] stylesheets = ['css', 'less'] # get the present working directory # and make sure they cannot list root pwd = os.path.dirname(default_file) if pwd == '/': pwd = '' # make sure the path is still valid after stripping off the file name if not is_valid_path(theme_root, pwd): raise Http403 current_file_path = os.path.join(pwd, current_file) # get the previous directory name and path prev_dir = '/' prev_dir_name = 'theme base' pwd_split = pwd.split('/') if len(pwd_split) > 1: prev_dir_name = pwd_split[-2] pwd_split.pop() prev_dir = '/'.join(pwd_split) elif not pwd_split[0]: prev_dir = '' # get the directory list dirs = get_dir_list(theme_root, pwd) # get the file list files, non_editable_files = get_file_list(theme_root, pwd) all_files_folders = get_all_files_list(theme_root, selected_theme) # non-deletable files non_deletable_files = [ 'homepage.html', 'default.html', 'footer.html', 'header.html', 'sidebar.html', 'nav.html', 'styles.less', 'styles.css' ] # get the number of themes in the themes directory on the site theme_count = len([i for i in theme_choices()]) # get a list of revisions archives = ThemeFileVersion.objects.filter( relative_file_path=current_file_path).order_by("-create_dt") # New templates created by clicking the New Template" button are blank. # Add a space for the blank template to make it editable. content = get_file_content(theme_root, selected_theme, current_file_path) or ' ' file_form = form_class({'content': content}) theme_form = ThemeSelectForm(initial={'theme_edit': selected_theme}) return render_to_resp(request=request, template_name=template_name, context={ 'file_form': file_form, 'theme_form': theme_form, 'current_theme': selected_theme, 'current_file_path': current_file_path, 'current_file': current_file, 'prev_dir_name': prev_dir_name, 'prev_dir': prev_dir, 'pwd': pwd, 'dirs': dirs, 'files': files, 'non_editable_files': non_editable_files, 'non_deletable_files': non_deletable_files, 'theme_count': theme_count, 'archives': archives, 'is_file': is_file, 'is_dir': is_dir, 'theme_read_only': theme_read_only, 'can_copy_theme': (not is_base_theme(selected_theme)), 'all_files_folders': all_files_folders, 'ext': ext, 'stylesheets': stylesheets, })
def get_all_files_list(ROOT_DIR=THEME_ROOT): """ Get a list of files and folders from within the theme folder """ files_folders = {} root_dir = os.path.join(ROOT_DIR) start = root_dir.rfind(os.sep) + 1 for path, dirs, files in os.walk(root_dir): subdir = {'contents': []} folders = path[start:].split(os.sep) for f in files: editable = False if os.path.splitext(os.path.join(path, f))[1] in ALLOWED_EXTENSIONS: editable = True # Hide hidden folders if not f.startswith('.'): subdir['contents'].append({'name': f, 'path': os.path.join(path[len(root_dir) + 1:], f), 'editable': editable}) subdir['contents'] = sorted(subdir['contents'], key=itemgetter('name')) parent = reduce(dict.get, folders[:-1], files_folders) # Hide hidden folders if not folders[-1].startswith('.'): parent[folders[-1]] = subdir for parent in files_folders: # Hide hidden folders if not path.split(os.sep)[-1].startswith('.'): subdir['contents'].append({'folder_path': path}) if settings.USE_S3_THEME: s3_files_folders = {'contents': []} theme_folder = "%s/%s" % (settings.THEME_S3_PATH, get_theme()) conn = boto.connect_s3(settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY) bucket = conn.get_bucket(settings.AWS_STORAGE_BUCKET_NAME) for item in bucket.list(prefix=theme_folder): editable = False if os.path.splitext(item.name)[1] in ALLOWED_EXTENSIONS: editable = True file_path = item.name.replace(theme_folder, '').lstrip('/') path_split = file_path.split('/') splits = len(path_split) if splits == 1: s3_files_folders['contents'].append({ 'name': path_split[0], 'path': file_path, 'editable': editable}) elif splits == 2: if not path_split[0] in s3_files_folders: s3_files_folders[path_split[0]] = {'contents': [{'folder_path': "/".join(path_split[:-1])}]} s3_files_folders[path_split[0]]['contents'].append({ 'name': path_split[1], 'path': file_path, 'editable': editable}) elif splits == 3: if not path_split[0] in s3_files_folders: s3_files_folders[path_split[0]] = {'contents': [{'folder_path': "/".join(path_split[:-1])}]} if not path_split[1] in s3_files_folders[path_split[0]]: s3_files_folders[path_split[0]][path_split[1]] = {'contents': [{'folder_path': "/".join(path_split[:-1])}]} s3_files_folders[path_split[0]][path_split[1]]['contents'].append({ 'name': path_split[2], 'path': file_path, 'editable': editable}) elif splits == 4: if not path_split[0] in s3_files_folders: s3_files_folders[path_split[0]] = {'contents': [{'folder_path': "/".join(path_split[:-1])}]} if not path_split[1] in s3_files_folders[path_split[0]]: s3_files_folders[path_split[0]][path_split[1]] = {'contents': [{'folder_path': "/".join(path_split[:-1])}]} if not path_split[2] in s3_files_folders[path_split[0]][path_split[1]]: s3_files_folders[path_split[0]][path_split[1]][path_split[2]] = {'contents': [{'folder_path': "/".join(path_split[:-1])}]} s3_files_folders[path_split[0]][path_split[1]][path_split[2]]['contents'].append({ 'name': path_split[3], 'path': file_path, 'editable': editable}) return {get_theme(): s3_files_folders} return files_folders
def get_all_files_list(ROOT_DIR=THEME_ROOT): """ Get a list of files and folders from within the theme folder """ files_folders = {} root_dir = os.path.join(ROOT_DIR) start = root_dir.rfind(os.sep) + 1 for path, dirs, files in os.walk(root_dir): folders = path[start:].split(os.sep) # Hide hidden folders and folders within hidden folders if any(folder.startswith('.') for folder in folders): continue subdir = {'contents': []} for f in files: editable = False if os.path.splitext(os.path.join(path, f))[1] in ALLOWED_EXTENSIONS: editable = True # Hide hidden files if not f.startswith('.'): subdir['contents'].append({ 'name': f, 'path': os.path.join(path[len(root_dir) + 1:], f), 'editable': editable }) subdir['contents'] = sorted(subdir['contents'], key=itemgetter('name')) subdir['contents'].append({'folder_path': path}) parent = reduce(dict.get, folders[:-1], files_folders) parent[folders[-1]] = subdir if settings.USE_S3_THEME: s3_files_folders = {'contents': []} theme_folder = "%s/%s" % (settings.THEME_S3_PATH, get_theme()) conn = boto.connect_s3(settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY) bucket = conn.get_bucket(settings.AWS_STORAGE_BUCKET_NAME) for item in bucket.list(prefix=theme_folder): editable = False if os.path.splitext(item.name)[1] in ALLOWED_EXTENSIONS: editable = True file_path = item.name.replace(theme_folder, '').lstrip('/') path_split = file_path.split('/') splits = len(path_split) if splits == 1: s3_files_folders['contents'].append({ 'name': path_split[0], 'path': file_path, 'editable': editable }) elif splits == 2: if not path_split[0] in s3_files_folders: s3_files_folders[path_split[0]] = { 'contents': [{ 'folder_path': "/".join(path_split[:-1]) }] } s3_files_folders[path_split[0]]['contents'].append({ 'name': path_split[1], 'path': file_path, 'editable': editable }) elif splits == 3: if not path_split[0] in s3_files_folders: s3_files_folders[path_split[0]] = { 'contents': [{ 'folder_path': "/".join(path_split[:-1]) }] } if not path_split[1] in s3_files_folders[path_split[0]]: s3_files_folders[path_split[0]][path_split[1]] = { 'contents': [{ 'folder_path': "/".join(path_split[:-1]) }] } s3_files_folders[path_split[0]][ path_split[1]]['contents'].append({ 'name': path_split[2], 'path': file_path, 'editable': editable }) elif splits == 4: if not path_split[0] in s3_files_folders: s3_files_folders[path_split[0]] = { 'contents': [{ 'folder_path': "/".join(path_split[:-1]) }] } if not path_split[1] in s3_files_folders[path_split[0]]: s3_files_folders[path_split[0]][path_split[1]] = { 'contents': [{ 'folder_path': "/".join(path_split[:-1]) }] } if not path_split[2] in s3_files_folders[path_split[0]][ path_split[1]]: s3_files_folders[path_split[0]][path_split[1]][ path_split[2]] = { 'contents': [{ 'folder_path': "/".join(path_split[:-1]) }] } s3_files_folders[path_split[0]][path_split[1]][ path_split[2]]['contents'].append({ 'name': path_split[3], 'path': file_path, 'editable': editable }) return {get_theme(): s3_files_folders} return files_folders
def handle_simple(cls, path, local_only, template=None, theme=None): active_theme = get_active_theme() theme = get_theme(active_theme) global _cached_theme_search_info cached_theme, theme_search_info = _cached_theme_search_info # If the theme changed or the user is previewing a different theme, # update _cached_theme_search_info. # Note that _cached_theme_search_info may be shared between multiple # threads, so you must be careful when reading/writing # _cached_theme_search_info to ensure that writes in one thread cannot # cause unexpected behavior in another thread that is reading/writing # _cached_theme_search_info at the same time. if cached_theme != theme: theme_search_info = [] for cur_theme in get_theme_search_order(theme): if is_builtin_theme(cur_theme): cur_theme_dir = get_builtin_theme_dir(cur_theme) static_path = os.path.join(settings.STATIC_ROOT, 'themes', cur_theme_dir) if not os.path.isdir(static_path): continue local_static_url = '%sthemes/%s/' % ( settings.LOCAL_STATIC_URL, cur_theme_dir) static_url = '%sthemes/%s/' % (settings.STATIC_URL, cur_theme_dir) theme_search_info.append( (static_path, local_static_url, static_url)) else: cur_theme_root = get_theme_root(cur_theme) for static_dir in ['media', 'static']: static_path = os.path.join(cur_theme_root, static_dir) if not os.path.isdir(static_path): continue local_static_url = static_url = '/themes/' + cur_theme + '/' + static_dir + '/' if settings.USE_S3_STORAGE: static_url = '%s/%s/%s/themes/%s/%s/' % ( settings.S3_ROOT_URL, settings.AWS_STORAGE_BUCKET_NAME, settings.AWS_LOCATION, cur_theme, static_dir) theme_search_info.append( (static_path, local_static_url, static_url)) if theme == active_theme: _cached_theme_search_info = (theme, theme_search_info) # Search for static file in themes for static_path, local_static_url, static_url in theme_search_info: if not os.path.exists(os.path.join(static_path, path)): continue return urljoin((local_static_url if local_only else static_url), quote(path)) # Warn about static files that don't exist in either a theme or # STATIC_ROOT if not os.path.exists(os.path.join(settings.STATIC_ROOT, path)): if not template: call = ('local_static' if local_only else 'static') warn('%s() call references non-existent static path "%s"' % (call, path)) else: tag = ('{% local_static %}' if local_only else '{% static %}') theme_str = ('theme "%s"' % (theme) if theme else 'an installed Django app') warn( '%s in template "%s" in %s references non-existent static path "%s"' % (tag, template, theme_str, path)) # Handle {% local_static %} for files not found in a theme if local_only: return urljoin(settings.LOCAL_STATIC_URL, quote(path)) # Default to standard Django {% static %} behavior return super(ThemeStaticNode, cls).handle_simple(path)
def edit_file(request, form_class=FileForm, template_name="theme_editor/index.html"): if not has_perm(request.user, 'theme_editor.view_themefileversion'): raise Http403 selected_theme = request.GET.get("theme_edit", get_theme()) original_theme_root = os.path.join(settings.ORIGINAL_THEMES_DIR, selected_theme) if settings.USE_S3_THEME: theme_root = os.path.join(settings.THEME_S3_PATH, selected_theme) else: theme_root = os.path.join(settings.ORIGINAL_THEMES_DIR, selected_theme) # get the default file and clean up any input default_file = request.GET.get("file", DEFAULT_FILE) if default_file: default_file = default_file.replace('\\', '/') default_file = default_file.strip('/') default_file = default_file.replace('////', '/') default_file = default_file.replace('///', '/') default_file = default_file.replace('//', '/') is_file = qstr_is_file(default_file, ROOT_DIR=theme_root) is_dir = qstr_is_dir(default_file, ROOT_DIR=theme_root) if is_file: pass elif is_dir: # if default_file is a directory then append the # trailing slash so we can get the dirname below default_file = '%s/' % default_file else: # if the default_file is not a directory or file within # the themes folder then return a 404 raise Http404(_("Custom template not found. Make sure you've copied over the themes to the THEME_DIR.")) # get the current file name current_file = os.path.basename(default_file) # get file ext name = current_file.split('/')[-1] ext = name.split('.')[-1] stylesheets = ['css', 'less'] # get the present working directory # and make sure they cannot list root pwd = os.path.dirname(default_file) if pwd == '/': pwd = '' current_file_path = os.path.join(pwd, current_file) # get the previous directory name and path prev_dir = '/' prev_dir_name = 'theme base' pwd_split = pwd.split('/') if len(pwd_split) > 1: prev_dir_name = pwd_split[-2] pwd_split.pop() prev_dir = '/'.join(pwd_split) elif not pwd_split[0]: prev_dir = '' # get the direcory list dirs = get_dir_list(pwd, ROOT_DIR=theme_root) # get the file list files, non_editable_files = get_file_list(pwd, ROOT_DIR=theme_root) all_files_folders = get_all_files_list(ROOT_DIR=theme_root) # non-deletable files non_deletable_files = ['homepage.html', 'default.html', 'footer.html', 'header.html', 'sidebar.html', 'nav.html', 'styles.less', 'styles.css'] # get the number of themes in the themes directory on the site theme_choices = [ i for i in theme_choice_list()] theme_count = len(theme_choices) # get a list of revisions archives = ThemeFileVersion.objects.filter(relative_file_path=default_file).order_by("-create_dt") if request.is_ajax() and request.method == "POST": file_form = form_class(request.POST) response_status = 'FAIL' response_message = _('Cannot update file.') if file_form.is_valid(): if file_form.save(request, default_file, ROOT_DIR=theme_root, ORIG_ROOT_DIR=original_theme_root): response_status = 'SUCCESS' response_message = unicode(_('Your changes have been saved.')) EventLog.objects.log() response = json.dumps({'status':response_status, 'message':response_message}) return HttpResponse(response, content_type="application/json") content = get_file_content(default_file, ROOT_DIR=theme_root) file_form = form_class({"content": content, "rf_path": default_file}) theme_form = ThemeSelectForm(initial={'theme_edit': selected_theme}) return render_to_response(template_name, { 'file_form': file_form, 'theme_form': theme_form, 'current_theme': selected_theme, 'current_file_path': current_file_path, 'current_file': current_file, 'prev_dir_name': prev_dir_name, 'prev_dir': prev_dir, 'pwd': pwd, 'dirs': dirs, 'files': files, 'non_editable_files': non_editable_files, 'non_deletable_files': non_deletable_files, 'theme_count': theme_count, 'archives': archives, 'is_file': is_file, 'is_dir': is_dir, 'all_files_folders': all_files_folders, 'ext' : ext, 'stylesheets' : stylesheets }, context_instance=RequestContext(request))