def server_static(filepath): ''' Serves static files from the application's own internal static path, e.g. for its CSS/JS ''' response.add_header('Cache-Control', 'max-age=7200') return static_file(filepath, root=APPLICATION_PATH + STATIC_PATH)
def blog_editor_css(blog_id): blog = get_blog(blog_id) if blog.editor_css is None: from core import static template = static.editor_css else: template = blog.editor_css response.content_type = "text/css" response.add_header('Cache-Control', 'max-age=7200') return template
def blog_republish_batch(blog_id): user = auth.is_logged_in(request) blog = Blog.load(blog_id) permission = auth.is_blog_publisher(user, blog) pages_to_queue = request.forms.getall('check') pages_that_can_be_queued = blog.pages.published.select().where( Page.id << pages_to_queue) page_count = pages_that_can_be_queued.count() response.add_header('X-Page-Count', page_count) if page_count > 0: queue.queue_page_actions(pages_that_can_be_queued) msg = '<b>OK:</b> {} pages queued for publication.'.format(page_count) else: msg = '<b>NOTE:</b> No pages queued for publication.' return msg
def blog_new_page_save(blog_id): ''' UI for saving a newly created page. ''' user = auth.is_logged_in(request) blog = Blog.load(blog_id) permission = auth.is_blog_member(user, blog) tags = cms.save_page(None, user, blog) # TODO: move to model instance? logger.info("Page {} created by user {}.".format(tags.page.for_log, user.for_log)) response.add_header('X-Redirect', BASE_URL + '/page/{}/edit'.format(str(tags.page.id))) return response
def blog_new_page_save(blog_id): ''' UI for saving a newly created page. ''' user = auth.is_logged_in(request) blog = Blog.load(blog_id) permission = auth.is_blog_member(user, blog) tags = cms.save_page(None, user, blog) # TODO: move to model instance? logger.info("Page {} created by user {}.".format( tags.page.for_log, user.for_log)) response.add_header('X-Redirect', BASE_URL + '/page/{}/edit'.format(str(tags.page.id))) return response
def page_revision_restore_save(page_id): user = auth.is_logged_in(request) page = Page.load(page_id) permission = auth.is_page_editor(user, page) tags = save_page(page, user, page.blog) from core.cms import save_action_list tpl = template('edit/page_ajax', status_badge=status_badge, save_action=save_action, save_action_list=save_action_list, sidebar='', **tags.__dict__) response.add_header('X-Redirect', BASE_URL + '/page/{}/edit'.format(str(tags.page.id))) return tpl
def csrf_protection(): ''' Adds CSP headers to requests by default, and checks for the presence of CSRF protection in submitted forms. ''' response.add_header('Frame-Options', 'sameorigin') # response.add_header('Content-Security-Policy', "default-src 'self' 'unsafe-inline' 'unsafe-eval'") if request.method == "POST": raise_request_limit() try: user = auth.is_logged_in_core(request) except UserNotFound: csrf_code = csrf_hash(SECRET_KEY) user = None else: csrf_code = csrf_hash(user.last_login) if request.forms.getunicode('csrf') != csrf_code: raise CSRFTokenNotFound("Form submitted from {} did not have a valid CSRF protection token.".format( request.url))
def blog_editor_css(blog_id): ''' Route for a copy of the blog's editor CSS; this allows it to be cached browser-side ''' blog = Blog.load(blog_id) from core.models import Template, template_type try: editor_css_template = Template.get( Template.blog == blog, Template.title == 'HTML Editor CSS', Template.template_type == template_type.system) except: from core import static template = static.editor_css else: template = editor_css_template.body response.content_type = "text/css" response.add_header('Cache-Control', 'max-age=7200') return template
def csrf_protection(): ''' Adds CSP headers to requests by default, and checks for the presence of CSRF protection in submitted forms. ''' response.add_header('Frame-Options', 'sameorigin') # response.add_header('Content-Security-Policy', "default-src 'self' 'unsafe-inline' 'unsafe-eval'") if request.method == "POST": raise_request_limit() try: user = auth.is_logged_in_core(request) except UserNotFound: csrf_code = csrf_hash(SECRET_KEY) user = None else: csrf_code = csrf_hash(user.last_login) if request.forms.getunicode('csrf') != csrf_code: raise CSRFTokenNotFound( "Form submitted from {} did not have a valid CSRF protection token." .format(request.url))
def template_save(request, user, cms_template, blog=None): ''' Core logic for saving changes to a template. ''' # TODO: move the bulk of this into the actual model # the .getunicode stuff should be moved out, # make that part of the ui # we should just submit cms_template as self, # make whatever mods to it are needed in the ui func, # and perform the validation we did elsewhere, perhaps from core.cms import fileinfo, invalidate_cache from core.utils import is_blank from core.error import TemplateSaveException, PageNotChanged import datetime status = [] _forms = request.forms cms_template.title = _forms.getunicode('template_title') cms_template.body = _forms.getunicode('template_body') if is_blank(cms_template.title): cms_template.title = "New Template (#{})".format(cms_template.id) mode = _forms.getunicode('publishing_mode') if mode in publishing_mode.modes: cms_template.publishing_mode = mode else: raise TemplateSaveException("Invalid publishing mode selected.") cms_template.modified_date = datetime.datetime.utcnow() try: cms_template.save(user) except PageNotChanged as e: status.append("(Template unchanged.)") except Exception as e: raise e new_mappings = [] for n in _forms: if n.startswith('template_mapping_'): mapping_id = int(n[len('template_mapping_'):]) try: template_mapping = TemplateMapping.get( TemplateMapping.id == mapping_id) except TemplateMapping.DoesNotExist: raise TemplateSaveException( 'Template mapping with ID #{} does not exist.'.format( mapping_id)) else: if is_blank(_forms.getunicode(n)): raise TemplateSaveException( 'Template mapping #{} ({}) cannot be blank. Use None to specify no mapping.' .format(mapping_id, template_mapping.path_string)) else: if _forms.getunicode(n) != template_mapping.path_string: template_mapping.path_string = _forms.getunicode(n) new_mappings.append(template_mapping) for n in new_mappings: n.save() status.append("Mapping #{} ({}) rebuilt.".format(n.id, n.path_string)) if new_mappings: fileinfo.build_mapping_xrefs(new_mappings) build_action = "all" else: build_action = "fast" invalidate_cache() # TODO: eventually everything after this will be removed b/c of AJAX save # tags = template_tags(template_id=cms_template.id, user=user) save_action = _forms.getunicode('save') from core.libs.bottle import response from settings import BASE_URL from core.models import Queue x_open = False if int(save_action) in (2, 3): if cms_template.template_type == template_type.page: x_open = True response.add_header( 'X-Open', '{}/template/{}/queue/{}'.format(BASE_URL, cms_template.id, build_action)) if cms_template.template_type == template_type.archive: x_open = True response.add_header( 'X-Open', '{}/template/{}/queue/{}'.format(BASE_URL, cms_template.id, build_action)) if cms_template.template_type in (template_type.include, template_type.index): # I don't think this is needed anymore, we can remove it # TODO: test it # if new_mappings: # cms.build_archives_fileinfos_by_mappings(cms_template) for f in cms_template.fileinfos_published: Queue.push(job_type=f.template_mapping.template.template_type, blog=cms_template.blog, site=cms_template.blog.site, data_integer=f.id) status.append( "{} files regenerated from template and sent to publishing queue.". format(cms_template.fileinfos_published.count())) if blog is not None: blog.theme_modified = True blog.save() from core.log import logger logger.info("Template {} edited by user {}.".format( cms_template.for_log, user.for_log)) response.body = ' '.join(status) if x_open: return response else: return response.body