Move get_jinja_loader to init submodule.
[mediagoblin.git] / mediagoblin / util.py
index a0a09adf5c601a7cce307c5deaae8da9e4aa5e94..ab219df034e9c0d0ee0c36e8330d3512fa94108f 100644 (file)
@@ -18,7 +18,6 @@ from email.MIMEText import MIMEText
 import gettext
 import pkg_resources
 import smtplib
-import os
 import sys
 import re
 import urllib
@@ -28,13 +27,14 @@ import copy
 from babel.localedata import exists
 import jinja2
 import translitcodec
-from paste.deploy.loadwsgi import NicerConfigParser
 from webob import Response, exc
+from lxml.html.clean import Cleaner
+import markdown
 
-from mediagoblin import globals as mgoblin_globals
+from mediagoblin import mg_globals
+from mediagoblin import messages
 from mediagoblin.db.util import ObjectId
 
-
 TESTS_ENABLED = False
 def _activate_testing():
     """
@@ -44,20 +44,24 @@ def _activate_testing():
     TESTS_ENABLED = True
 
 
-def get_jinja_loader(user_template_path=None):
+def clear_test_buckets():
     """
-    Set up the Jinja template loaders, possibly allowing for user
-    overridden templates.
+    We store some things for testing purposes that should be cleared
+    when we want a "clean slate" of information for our next round of
+    tests.  Call this function to wipe all that stuff clean.
 
-    (In the future we may have another system for providing theming;
-    for now this is good enough.)
+    Also wipes out some other things we might redefine during testing,
+    like the jinja envs.
     """
-    if user_template_path:
-        return jinja2.ChoiceLoader(
-            [jinja2.FileSystemLoader(user_template_path),
-             jinja2.PackageLoader('mediagoblin', 'templates')])
-    else:
-        return jinja2.PackageLoader('mediagoblin', 'templates')
+    global SETUP_JINJA_ENVS
+    SETUP_JINJA_ENVS = {}
+
+    global EMAIL_TEST_INBOX
+    global EMAIL_TEST_MBOX_INBOX
+    EMAIL_TEST_INBOX = []
+    EMAIL_TEST_MBOX_INBOX = []
+
+    clear_test_template_context()
 
 
 SETUP_JINJA_ENVS = {}
@@ -79,11 +83,15 @@ def get_jinja_env(template_loader, locale):
 
     template_env = jinja2.Environment(
         loader=template_loader, autoescape=True,
-        extensions=['jinja2.ext.i18n'])
+        extensions=['jinja2.ext.i18n', 'jinja2.ext.autoescape'])
 
     template_env.install_gettext_callables(
-        mgoblin_globals.translations.gettext,
-        mgoblin_globals.translations.ngettext)
+        mg_globals.translations.gettext,
+        mg_globals.translations.ngettext)
+
+    # All templates will know how to ...
+    # ... fetch all waiting messages and remove them from the queue
+    template_env.globals['fetch_messages'] = messages.fetch_messages
 
     if exists(locale):
         SETUP_JINJA_ENVS[locale] = template_env
@@ -95,7 +103,7 @@ def get_jinja_env(template_loader, locale):
 TEMPLATE_TEST_CONTEXT = {}
 
 
-def render_template(request, template, context):
+def render_template(request, template_path, context):
     """
     Render a template with context.
 
@@ -103,12 +111,12 @@ def render_template(request, template, context):
     Also stores the context if we're doing unit tests.  Helpful!
     """
     template = request.template_env.get_template(
-        template)
+        template_path)
     context['request'] = request
     rendered = template.render(context)
 
     if TESTS_ENABLED:
-        TEMPLATE_TEST_CONTEXT[template] = context
+        TEMPLATE_TEST_CONTEXT[template_path] = context
 
     return rendered
 
@@ -244,9 +252,9 @@ def send_email(from_addr, to_addrs, subject, message_body):
      - message_body: email body text
     """
     # TODO: make a mock mhost if testing is enabled
-    if TESTS_ENABLED or mgoblin_globals.email_debug_mode:
+    if TESTS_ENABLED or mg_globals.email_debug_mode:
         mhost = FakeMhost()
-    elif not mgoblin_globals.email_debug_mode:
+    elif not mg_globals.email_debug_mode:
         mhost = smtplib.SMTP()
 
     mhost.connect()
@@ -259,7 +267,7 @@ def send_email(from_addr, to_addrs, subject, message_body):
     if TESTS_ENABLED:
         EMAIL_TEST_INBOX.append(message)
 
-    if getattr(mgoblin_globals, 'email_debug_mode', False):
+    if getattr(mg_globals, 'email_debug_mode', False):
         print u"===== Email ====="
         print u"From address: %s" % message['From']
         print u"To addresses: %s" % message['To']
@@ -331,26 +339,49 @@ def get_locale_from_request(request):
     return locale_to_lower_upper(target_lang)
 
 
-def read_config_file(conf_file):
-    """
-    Read a paste deploy style config file and process it.
-    """
-    if not os.path.exists(conf_file):
-        raise IOError(
-            "MEDIAGOBLIN_CONFIG not set or file does not exist")
+# A super strict version of the lxml.html cleaner class
+HTML_CLEANER = Cleaner(
+    scripts=True,
+    javascript=True,
+    comments=True,
+    style=True,
+    links=True,
+    page_structure=True,
+    processing_instructions=True,
+    embedded=True,
+    frames=True,
+    forms=True,
+    annoying_tags=True,
+    allow_tags=[
+        'div', 'b', 'i', 'em', 'strong', 'p', 'ul', 'ol', 'li', 'a', 'br'],
+    remove_unknown_tags=False, # can't be used with allow_tags
+    safe_attrs_only=True,
+    add_nofollow=True, # for now
+    host_whitelist=(),
+    whitelist_tags=set([]))
+
+
+def clean_html(html):
+    # clean_html barfs on an empty string
+    if not html:
+        return u''
 
-    parser = NicerConfigParser(conf_file)
-    parser.read(conf_file)
-    parser._defaults.setdefault(
-        'here', os.path.dirname(os.path.abspath(conf_file)))
-    parser._defaults.setdefault(
-        '__file__', os.path.abspath(conf_file))
+    return HTML_CLEANER.clean_html(html)
 
-    mgoblin_conf = dict(
-        [(section_name, dict(parser.items(section_name)))
-         for section_name in parser.sections()])
 
-    return mgoblin_conf
+MARKDOWN_INSTANCE = markdown.Markdown(safe_mode='escape')
+
+
+def cleaned_markdown_conversion(text):
+    """
+    Take a block of text, run it through MarkDown, and clean its HTML.
+    """
+    # Markdown will do nothing with and clean_html can do nothing with
+    # an empty string :)
+    if not text:
+        return u''
+
+    return clean_html(MARKDOWN_INSTANCE.convert(text))
 
 
 SETUP_GETTEXTS = {}
@@ -373,7 +404,7 @@ def setup_gettext(locale):
         if exists(locale):
             SETUP_GETTEXTS[locale] = this_gettext
 
-    mgoblin_globals.setup_globals(
+    mg_globals.setup_globals(
         translations=this_gettext)