def copy_dir(self, source, dest, level=0):
    '''Copies the static files from one directory to another.  If this command is run, we assume the user wants to overwrite any existing files.'''
    # ensure the destination exists
    if not os.path.exists(dest):
      os.mkdir(dest)
    # go through the files in this directory
    for fname in os.listdir(source):
      source_path = os.path.join(source, fname)
      dest_path = os.path.join(dest, fname)
      ext = os.path.splitext(fname)[1].lower()
    
      ###  EXPLICIT IGNORE  ###
      if self.ignore_file(fname):
        pass
    
      ###  DIRECTORIES  ###
      # ignore these directories
      elif os.path.isdir(source_path) and fname in ( 'templates', 'views', get_setting('TEMPLATES_CACHE_DIR'), '__pycache__' ):
        pass
        
      # if a directory, create it in the destination and recurse
      elif os.path.isdir(source_path):
        if not os.path.exists(dest_path):
          os.mkdir(dest_path)
        elif not os.path.isdir(dest_path):  # could be a file or link
          os.unlink(dest_path)
          os.mkdir(dest_path)
        self.copy_dir(source_path, dest_path, level+1)

      ###   FILES   ###
      # we don't do any regular files at the top level      
      elif level == 0:
        pass
        
      # ignore these files
      elif fname in ( '__init__.py', ):
        pass
      
      # ignore these extensions
      elif ext in ( '.cssm', '.jsm' ):
        pass
      
      # if a regular Javscript file, minify it
      elif ext == '.js' and get_setting('MINIFY_JS_CSS', False) and JSMIN:
        fin = open(source_path)
        fout = open(dest_path, 'w')
        fout.write(jsmin(fin.read()))
        fout.close()
        fin.close()
        
      elif ext == '.css' and get_setting('MINIFY_JS_CSS', False) and CSSMIN:
        fin = open(source_path)
        fout = open(dest_path, 'w')
        fout.write(cssmin(fin.read()))
        fout.close()
        fin.close()
      
      # if we get here, it's a binary file like an image, movie, pdf, etc.
      else:
        shutil.copy2(source_path, dest_path)
Esempio n. 2
0
  def __init__(self, template, cgi_id=None):
    # set up the directories so we can go through them fast on render
    self.template_dir, self.template_name = os.path.split(os.path.splitext(template.filename)[0])
    self.app_dir = os.path.dirname(self.template_dir)
    self.app = os.path.split(self.app_dir)[1]

    # ensure we have renderers for this template
    if self.app not in SCRIPT_RENDERERS:
      SCRIPT_RENDERERS[self.app] = MakoTemplateRenderer(self.app, 'scripts')
    if self.app not in STYLE_RENDERERS:
      STYLE_RENDERERS[self.app] = MakoTemplateRenderer(self.app, 'styles')

    # the static templatename.scss file
    try:
      scss_file = os.path.join(self.app_dir, 'styles', self.template_name + '.scss')
      scss_stat = os.stat(scss_file)
      try:
        css_file = os.path.join(self.app_dir, 'styles', self.template_name + '.css')
        css_stat = os.stat(css_file)
        # update the CSS file if the SCCS file is newer
        if scss_stat.st_mtime > css_stat.st_mtime:
          os.system(get_setting('SCCS_BINARY', '/usr/bin/env scss') + ' %s %s %s' % (get_setting('SCCS_ARGS', ''), scss_file, css_file))
      except OSError:
          # if no CSS file exists, create one
          os.system(get_setting('SCCS_BINARY', '/usr/bin/env scss') + ' %s %s %s' % (get_setting('SCCS_ARGS', ''), scss_file, css_file))
    except OSError:
        # no SCCS file exists .. continue as normal
        pass

    # the static templatename.css file
    try:
      fstat = os.stat(os.path.join(self.app_dir, 'styles', self.template_name + '.css'))
      self.css = '<link rel="stylesheet" type="text/css" href="%s?%s" />' % (os.path.join(settings.STATIC_URL, self.app, 'styles', self.template_name + '.css'), cgi_id if cgi_id != None else int(fstat.st_mtime))
    except OSError:
      self.css = None

    # the mako-rendered templatename.cssm file
    try:
      fstat = os.stat(os.path.join(self.app_dir, 'styles', self.template_name + '.cssm'))
      self.cssm = self.template_name + '.cssm'
    except OSError:
      self.cssm = None

    # the static templatename.js file
    try:
      fstat = os.stat(os.path.join(self.app_dir, 'scripts', self.template_name + '.js'))
      self.js = '<script src="%s?%s"></script>' % (os.path.join(settings.STATIC_URL, self.app, 'scripts', self.template_name + '.js'), cgi_id if cgi_id != None else int(fstat.st_mtime))
    except OSError:
      self.js = None

    # the mako-rendered templatename.jsm file
    try:
      fstat = os.stat(os.path.join(self.app_dir, 'scripts', self.template_name + '.jsm'))
      self.jsm = self.template_name + '.jsm'
    except OSError:
      self.jsm = None
Esempio n. 3
0
 def __init__(self, app_path, template_subdir='templates'):
   '''Creates a renderer to the given path (relateive to the project root where settings.STATIC_ROOT points to)'''
   project_path = os.path.normpath(settings.BASE_DIR)
   self.app_path = app_path
   template_dir = get_app_template_dir(app_path, template_subdir)  # raises ImproperlyConfigured if error
   self.template_search_dirs = [ template_dir ]
   if get_setting('TEMPLATES_DIRS', False):
     self.template_search_dirs.extend(get_setting('TEMPLATES_DIRS'))
   self.template_search_dirs.append(settings.BASE_DIR)
   self.cache_root = os.path.abspath(os.path.join(project_path, app_path, get_setting('TEMPLATES_CACHE_DIR'), template_subdir))
   self.tlookup = TemplateLookup(directories=self.template_search_dirs, imports=get_setting('DEFAULT_TEMPLATE_IMPORTS'), module_directory=self.cache_root, collection_size=2000, filesystem_checks=settings.DEBUG, input_encoding=get_setting('DEFAULT_TEMPLATE_ENCODING', 'utf-8'))
   # Use the default django engine (to get the list of context processors)
   self.engine = Engine.get_default()
Esempio n. 4
0
 def __init__(self, app_path, template_subdir='templates'):
   '''Creates a renderer to the given path (relateive to the project root where settings.STATIC_ROOT points to)'''
   project_path = os.path.normpath(settings.BASE_DIR)
   self.app_path = app_path
   template_dir = get_app_template_dir(app_path, template_subdir)  # raises ImproperlyConfigured if error
   self.template_search_dirs = [ template_dir ]
   if get_setting('TEMPLATES_DIRS', False):
     self.template_search_dirs.extend(get_setting('TEMPLATES_DIRS'))
   self.template_search_dirs.append(settings.BASE_DIR)
   self.cache_root = os.path.abspath(os.path.join(project_path, app_path, get_setting('TEMPLATES_CACHE_DIR'), template_subdir))
   self.tlookup = TemplateLookup(directories=self.template_search_dirs, imports=get_setting('DEFAULT_TEMPLATE_IMPORTS'), module_directory=self.cache_root, collection_size=2000, filesystem_checks=settings.DEBUG, input_encoding=get_setting('DEFAULT_TEMPLATE_ENCODING', 'utf-8'))
   # Use the default django engine (to get the list of context processors)
   self.engine = Engine.get_default()
Esempio n. 5
0
 def get_template_js(self, request, context):
   '''Retrieves the static and mako_rendered CSS'''    
   ret = []
   for template in self.template_chain:
     ti = getattr(template, DMP_ATTR_NAME)
     if ti.js:
       ret.append(ti.js)  # the <script> was already created once in the constructor
     if ti.jsm:
       js_text = SCRIPT_RENDERERS[ti.app].render(request, ti.jsm, context.kwargs)
       if JSMIN and get_setting('MINIFY_JS_CSS', False):
         js_text = jsmin(js_text)
       ret.append('<script>%s</script>' % js_text)
   return '\n'.join(ret)
Esempio n. 6
0
 def get_template_css(self, request, context):
   '''Retrives the static and mako-rendered CSS'''
   ret = []
   for template in reversed(self.template_chain):  # reverse so lower CSS overrides higher CSS in the inheritance chain
     ti = getattr(template, DMP_ATTR_NAME)
     if ti.css:
       ret.append(ti.css)  # the <link> was already created once in the constructor
     if ti.cssm:
       css_text = STYLE_RENDERERS[ti.app].render(request, ti.cssm, context.kwargs)
       if JSMIN and get_setting('MINIFY_JS_CSS', False):
         css_text = cssmin(css_text)
       ret.append('<style type="text/css">%s</style>' % css_text) 
   return '\n'.join(ret)
Esempio n. 7
0
 def get_template_js(self, request, context):
     '''Retrieves the static and mako_rendered CSS'''
     ret = []
     for template in self.template_chain:
         ti = getattr(template, DMP_ATTR_NAME)
         if ti.js:
             ret.append(
                 ti.js
             )  # the <script> was already created once in the constructor
         if ti.jsm:
             js_text = SCRIPT_RENDERERS[ti.app].render(
                 request, ti.jsm, context.kwargs)
             if JSMIN and get_setting('MINIFY_JS_CSS', False):
                 js_text = jsmin(js_text)
             ret.append('<script>%s</script>' % js_text)
     return '\n'.join(ret)
Esempio n. 8
0
 def get_template_css(self, request, context):
     '''Retrives the static and mako-rendered CSS'''
     ret = []
     for template in reversed(
             self.template_chain
     ):  # reverse so lower CSS overrides higher CSS in the inheritance chain
         ti = getattr(template, DMP_ATTR_NAME)
         if ti.css:
             ret.append(
                 ti.css
             )  # the <link> was already created once in the constructor
         if ti.cssm:
             css_text = STYLE_RENDERERS[ti.app].render(
                 request, ti.cssm, context.kwargs)
             if JSMIN and get_setting('MINIFY_JS_CSS', False):
                 css_text = cssmin(css_text)
             ret.append('<style type="text/css">%s</style>' % css_text)
     return '\n'.join(ret)
Esempio n. 9
0
 def render_to_response(self, request, template, params={}, def_name=None):
   '''Runs a template and returns an HttpRequest object to it. 
   
      This method returns a django.http.Http404 exception if the template is not found.
      If the template raises a django_mako_plus.controller.RedirectException, the browser is redirected to
        the given page, and a new request from the browser restarts the entire DMP routing process.
      If the template raises a django_mako_plus.controller.InternalRedirectException, the entire DMP
        routing process is restarted internally (the browser doesn't see the redirect).
   
      The method throws two signals: 
        1. dmp_signal_pre_render_template: you can (optionally) return a new Mako Template object from a receiver to replace
           the normal template object that is used for the render operation.
        2. dmp_signal_post_render_template: you can (optionally) return a string to replace the string from the normal
           template object render.
   
      @request  The request context from Django.  If this is None, any TEMPLATE_CONTEXT_PROCESSORS defined in your settings
                file will be ignored but the template will otherwise render fine.
      @template The template file path to render.  This is relative to the app_path/controller_TEMPLATES_DIR/ directory.
                For example, to render app_path/templates/page1, set template="page1.html", assuming you have
                set up the variables as described in the documentation above.
      @params   A dictionary of name=value variables to send to the template page.
      @def_name Limits output to a specific top-level Mako <%block> or <%def> section within the template.
                If the section is a <%def>, it must have no parameters.  For example, def_name="foo" will call
                <%block name="foo"></%block> or <%def name="foo()"></def> within the template.
   '''
   try:
     content_type = mimetypes.types_map.get(os.path.splitext(template)[1].lower(), 'text/html')
     content = self.render(request, template, params, def_name)
     return HttpResponse(content.encode(settings.DEFAULT_CHARSET), content_type='%s; charset=%s' % (content_type, settings.DEFAULT_CHARSET))
   except TopLevelLookupException: # template file not found    
     log.debug('DMP :: template "%s" not found in search path: %s.' % (template, self.template_search_dirs))
     raise Http404()
   except RedirectException: # redirect to another page
     e = sys.exc_info()[1] # Py2.7 and Py3+ compliant
     log.debug('DMP :: view function %s.%s redirected processing to %s' % (request.dmp_router_module, request.dmp_router_function, e.redirect_to))
     # send the signal
     if get_setting('SIGNALS', False):
       signals.dmp_signal_redirect_exception.send(sender=sys.modules[__name__], request=request, exc=e)
     # send the browser the redirect command
     return e.get_response(request)
Esempio n. 10
0
  def render_to_response(self, request, template, params={}, def_name=None):
    '''Runs a template and returns an HttpRequest object to it.

       This method returns a django.http.Http404 exception if the template is not found.
       If the template raises a django_mako_plus.controller.RedirectException, the browser is redirected to
         the given page, and a new request from the browser restarts the entire DMP routing process.
       If the template raises a django_mako_plus.controller.InternalRedirectException, the entire DMP
         routing process is restarted internally (the browser doesn't see the redirect).

       The method throws two signals:
         1. dmp_signal_pre_render_template: you can (optionally) return a new Mako Template object from a receiver to replace
            the normal template object that is used for the render operation.
         2. dmp_signal_post_render_template: you can (optionally) return a string to replace the string from the normal
            template object render.

       @request  The request context from Django.  If this is None, any TEMPLATE_CONTEXT_PROCESSORS defined in your settings
                 file will be ignored but the template will otherwise render fine.
       @template The template file path to render.  This is relative to the app_path/controller_TEMPLATES_DIR/ directory.
                 For example, to render app_path/templates/page1, set template="page1.html", assuming you have
                 set up the variables as described in the documentation above.
       @params   A dictionary of name=value variables to send to the template page.
       @def_name Limits output to a specific top-level Mako <%block> or <%def> section within the template.
                 If the section is a <%def>, it must have no parameters.  For example, def_name="foo" will call
                 <%block name="foo"></%block> or <%def name="foo()"></def> within the template.
    '''
    try:
      content_type = mimetypes.types_map.get(os.path.splitext(template)[1].lower(), 'text/html')
      content = self.render(request, template, params, def_name)
      return HttpResponse(content.encode(settings.DEFAULT_CHARSET), content_type='%s; charset=%s' % (content_type, settings.DEFAULT_CHARSET))
    except TopLevelLookupException: # template file not found
      log.debug('DMP :: template "%s" not found in search path: %s.' % (template, self.template_search_dirs))
      raise Http404()
    except RedirectException: # redirect to another page
      e = sys.exc_info()[1] # Py2.7 and Py3+ compliant
      log.debug('DMP :: view function %s.%s redirected processing to %s' % (request.dmp_router_module, request.dmp_router_function, e.redirect_to))
      # send the signal
      if get_setting('SIGNALS', False):
        signals.dmp_signal_redirect_exception.send(sender=sys.modules[__name__], request=request, exc=e)
      # send the browser the redirect command
      return e.get_response(request)
Esempio n. 11
0
def route_request(request):
    '''The main router for all calls coming in to the system.'''
    # output the variables so the programmer can debug where this is routing
    log.debug('DMP :: processing: app=%s, page=%s, func=%s, urlparams=%s' % (request.dmp_router_app, request.dmp_router_page, request.dmp_router_function, request.urlparams))

    # set the full function location
    request.dmp_router_module = '.'.join([ request.dmp_router_app, 'views', request.dmp_router_page ])
    
    # first try going to the view function for this request
    # we look for a views/name.py file where name is the same name as the HTML file
    response = None
    
    while True: # enables the InternalRedirectExceptions to loop around
      full_module_filename = os.path.normpath(os.path.join(settings.BASE_DIR, request.dmp_router_module.replace('.', '/') + '.py'))
      try:
        # look for the module, and if not found go straight to template
        if not os.path.exists(full_module_filename):
          log.debug('DMP :: module %s not found; sending processing directly to template %s.html' % (request.dmp_router_module, request.dmp_router_page_full))
          try:
            dmp_renderer = get_renderer(request.dmp_router_app)
          except ImproperlyConfigured as e: 
            log.debug('DMP :: %s' % (e))
            raise Http404
          return dmp_renderer.render_to_response(request, '%s.html' % request.dmp_router_page_full)
        
        # find the function
        module_obj = import_module(request.dmp_router_module)
        if not hasattr(module_obj, request.dmp_router_function):
          log.debug('DMP :: view function/class %s not in module %s; returning 404 not found.' % (request.dmp_router_function, request.dmp_router_module))
          raise Http404
        func_obj = getattr(module_obj, request.dmp_router_function)
        
        # see if the func_obj is actually a class -- we might be doing class-based views here
        if isinstance(func_obj, type):
          request.dmp_router_class = request.dmp_router_function
          request.dmp_router_function = request.method.lower()
          if not hasattr(func_obj, request.dmp_router_function):
            log.debug('DMP :: view class %s.%s has no method named %s; returning 404 not found.' % (request.dmp_router_module, request.dmp_router_class, request.dmp_router_function))
            raise Http404
          func_obj = getattr(func_obj(), request.dmp_router_function)  # move to the class.get(), class.post(), etc. method

        # ensure it is decorated with @view_function - this is for security so only certain functions can be called
        if getattr(func_obj, 'dmp_view_function', False) != True: 
          log.debug('DMP :: view function/class %s found successfully, but it is not decorated with @view_function; returning 404 not found.  Note that if you have multiple decorators on a function, the @view_function decorator must be listed first.' % (request.dmp_router_function))
          raise Http404

        # send the pre-signal
        if get_setting('SIGNALS', False):
          for receiver, ret_response in signals.dmp_signal_pre_process_request.send(sender=sys.modules[__name__], request=request):
            if isinstance(ret_response, (HttpResponse, StreamingHttpResponse)):
              return ret_response

        # call view function
        if request.dmp_router_class == None:
          log.debug('DMP :: calling view function %s.%s' % (request.dmp_router_module, request.dmp_router_function))
        else:
          log.debug('DMP :: calling class-based view function %s.%s.%s' % (request.dmp_router_module, request.dmp_router_class, request.dmp_router_function))
        response = func_obj(request)
              
        # send the post-signal
        if get_setting('SIGNALS', False):
          for receiver, ret_response in signals.dmp_signal_post_process_request.send(sender=sys.modules[__name__], request=request, response=response):
            if ret_response != None:
              response = ret_response # sets it to the last non-None in the signal receiver chain
            
        # if we didn't get a correct response back, send a 404
        if not isinstance(response, (HttpResponse, StreamingHttpResponse)):
          if request.dmp_router_class == None:
            log.debug('DMP :: view function %s.%s failed to return an HttpResponse (or the post-signal overwrote it).  Returning Http404.' % (request.dmp_router_module, request.dmp_router_function))
          else:
            log.debug('DMP :: class-based view function %s.%s.%s failed to return an HttpResponse (or the post-signal overwrote it).  Returning Http404.' % (request.dmp_router_module, request.dmp_router_class, request.dmp_router_function))
          raise Http404
              
        # return the response
        return response
        
      except InternalRedirectException:
        ivr = sys.exc_info()[1] # Py2.7 and Py3+ compliant
        # send the signal
        if get_setting('SIGNALS', False):
          signals.dmp_signal_internal_redirect_exception.send(sender=sys.modules[__name__], request=request, exc=ivr)
        # do the internal redirect
        request.dmp_router_module = ivr.redirect_module
        request.dmp_router_function = ivr.redirect_function
        full_module_filename = os.path.normpath(os.path.join(settings.BASE_DIR, request.dmp_router_module.replace('.', '/') + '.py'))
        log.debug('DMP :: received an InternalViewRedirect to %s -> %s' % (full_module_filename, request.dmp_router_function))
      
      except RedirectException: # redirect to another page
        e = sys.exc_info()[1] # Py2.7 and Py3+ compliant
        if request.dmp_router_class == None:
          log.debug('DMP :: view function %s.%s redirected processing to %s' % (request.dmp_router_module, request.dmp_router_function, e.redirect_to))
        else:
          log.debug('DMP :: class-based view function %s.%s.%s redirected processing to %s' % (request.dmp_router_module, request.dmp_router_class, request.dmp_router_function, e.redirect_to))
        # send the signal
        if get_setting('SIGNALS', False):
          signals.dmp_signal_redirect_exception.send(sender=sys.modules[__name__], request=request, exc=e)
        # send the browser the redirect command
        return e.get_response(request)

    # the code should never get here
    raise Exception("Django-Mako-Plus router error: The route_request() function should not have been able to get to this point.  Please notify the owner of the DMP project.  Thanks.")
from django.core.management.base import BaseCommand, CommandError
from django.utils.importlib import import_module
from django.conf import settings
from django_mako_plus.controller import router, get_setting
from optparse import make_option
import os, os.path, shutil, fnmatch

# import minification if requested
if get_setting('MINIFY_JS_CSS', False):
  try:
    from rjsmin import jsmin
    JSMIN = True
  except ImportError:
    JSMIN = False
  try:
    from rcssmin import cssmin
    CSSMIN = True
  except ImportError:
    CSSMIN = False


class Command(BaseCommand):
  args = ''
  help = 'Collects static files, such as media, scripts, and styles, to a common directory root. This is done to prepare for deployment.'
  can_import_settings = True
  option_list = BaseCommand.option_list + (
          make_option(
            '--overwrite', 
            action='store_true',
            dest='overwrite',
            default=False,
Esempio n. 13
0
    def copy_dir(self, source, dest, level=0):
        '''Copies the static files from one directory to another.  If this command is run, we assume the user wants to overwrite any existing files.'''
        # ensure the destination exists
        if not os.path.exists(dest):
            os.mkdir(dest)
        # go through the files in this directory
        for fname in os.listdir(source):
            source_path = os.path.join(source, fname)
            dest_path = os.path.join(dest, fname)
            ext = os.path.splitext(fname)[1].lower()

            ###  EXPLICIT IGNORE  ###
            if self.ignore_file(fname):
                pass

            ###  DIRECTORIES  ###
            # ignore these directories
            elif os.path.isdir(source_path) and fname in (
                    'templates', 'views', get_setting('TEMPLATES_CACHE_DIR'),
                    '__pycache__'):
                pass

            # if a directory, create it in the destination and recurse
            elif os.path.isdir(source_path):
                if not os.path.exists(dest_path):
                    os.mkdir(dest_path)
                elif not os.path.isdir(dest_path):  # could be a file or link
                    os.unlink(dest_path)
                    os.mkdir(dest_path)
                self.copy_dir(source_path, dest_path, level + 1)

            ###   FILES   ###
            # we don't do any regular files at the top level
            elif level == 0:
                pass

            # ignore these files
            elif fname in ('__init__.py', ):
                pass

            # ignore these extensions
            elif ext in ('.cssm', '.jsm'):
                pass

            # if a regular Javscript file, minify it
            elif ext == '.js' and get_setting('MINIFY_JS_CSS',
                                              False) and JSMIN:
                fin = open(source_path)
                fout = open(dest_path, 'w')
                fout.write(jsmin(fin.read()))
                fout.close()
                fin.close()

            elif ext == '.css' and get_setting('MINIFY_JS_CSS',
                                               False) and CSSMIN:
                fin = open(source_path)
                fout = open(dest_path, 'w')
                fout.write(cssmin(fin.read()))
                fout.close()
                fin.close()

            # if we get here, it's a binary file like an image, movie, pdf, etc.
            else:
                shutil.copy2(source_path, dest_path)
Esempio n. 14
0
from django.core.management.base import BaseCommand, CommandError
from django.utils.importlib import import_module
from django.conf import settings
from django_mako_plus.controller import router, get_setting
from optparse import make_option
import os, os.path, shutil, fnmatch

# import minification if requested
if get_setting('MINIFY_JS_CSS', False):
    try:
        from rjsmin import jsmin
        JSMIN = True
    except ImportError:
        JSMIN = False
    try:
        from rcssmin import cssmin
        CSSMIN = True
    except ImportError:
        CSSMIN = False


class Command(BaseCommand):
    args = ''
    help = 'Collects static files, such as media, scripts, and styles, to a common directory root. This is done to prepare for deployment.'
    can_import_settings = True
    option_list = BaseCommand.option_list + (
        make_option(
            '--overwrite',
            action='store_true',
            dest='overwrite',
            default=False,
Esempio n. 15
0
  def render(self, request, template, params={}, def_name=None):
    '''Runs a template and returns a string.  Normally, you probably want to call render_to_response instead
       because it gives a full HttpResponse or Http404.

       This method raises a mako.exceptions.TopLevelLookupException if the template is not found.

       The method throws two signals:
         1. dmp_signal_pre_render_template: you can (optionally) return a new Mako Template object from a receiver to replace
            the normal template object that is used for the render operation.
         2. dmp_signal_post_render_template: you can (optionally) return a string to replace the string from the normal
            template object render.

       @request  The request context from Django.  If this is None, 1) any TEMPLATE_CONTEXT_PROCESSORS defined in your settings
                 file will be ignored and 2) DMP signals will not be sent, but the template will otherwise render fine.
       @template The template file path to render.  This is relative to the app_path/controller_TEMPLATES_DIR/ directory.
                 For example, to render app_path/templates/page1, set template="page1.html", assuming you have
                 set up the variables as described in the documentation above.
       @params   A dictionary of name=value variables to send to the template page.
       @def_name Limits output to a specific top-level Mako <%block> or <%def> section within the template.
                 If the section is a <%def>, it must have no parameters.  For example, def_name="foo" will call
                 <%block name="foo"></%block> or <%def name="foo()"></def> within the template.
                 The block/def must be defined in the exact template.  DMP does not support calling defs from
                 super-templates.
    '''
    # must convert the request context to a real dict to use the ** below
    context_dict = {}
    context_dict['request'] = request
    context_dict['settings'] = settings
    try:
      context_dict['STATIC_URL'] = settings.STATIC_URL  # this is used so much in templates, it's useful to have it always available
    except AttributeError:
      pass
    context = Context(params) if request == None else RequestContext(request, params)  # Django's RequestContext automatically runs all the TEMPLATE_CONTEXT_PROCESSORS and populates with variables
    with context.bind_template(self):
      for d in context:
        context_dict.update(d)

    # get the template
    template_obj = self.get_template(template)

    # send the pre-render signal
    if get_setting('SIGNALS', False) and request != None:
      for receiver, ret_template_obj in signals.dmp_signal_pre_render_template.send(sender=self, request=request, context=context, template=template_obj):
        if ret_template_obj != None:  # changes the template object to the received
          template_obj = ret_template_obj

    # do we need to limit down to a specific def?
    # this only finds within the exact template (won't go up the inheritance tree)
    # I wish I could make it do so, but can't figure this out
    render_obj = template_obj
    if def_name:  # do we need to limit to just a def?
      render_obj = template_obj.get_def(def_name)

    # PRIMARY FUNCTION: render the template
    log.debug('DMP :: rendering template %s' % template_obj.filename)
    if settings.DEBUG:
      try:
        content = render_obj.render_unicode(**context_dict)
      except:
        content = html_error_template().render_unicode()
    else:  # this is outside the above "try" loop because in non-DEBUG mode, we want to let the exception throw out of here (without having to re-raise it)
      content = render_obj.render_unicode(**context_dict)

    # send the post-render signal
    if get_setting('SIGNALS', False) and request != None:
      for receiver, ret_content in signals.dmp_signal_post_render_template.send(sender=self, request=request, context=context, template=template_obj, content=content):
        if ret_content != None:
          content = ret_content  # sets it to the last non-None return in the signal receiver chain

    # return
    return content
Esempio n. 16
0
    def __init__(self, template, cgi_id=None):
        # set up the directories so we can go through them fast on render
        self.template_dir, self.template_name = os.path.split(
            os.path.splitext(template.filename)[0])
        self.app_dir = os.path.dirname(self.template_dir)
        self.app = os.path.split(self.app_dir)[1]

        # ensure we have renderers for this template
        if self.app not in SCRIPT_RENDERERS:
            SCRIPT_RENDERERS[self.app] = MakoTemplateRenderer(
                self.app, 'scripts')
        if self.app not in STYLE_RENDERERS:
            STYLE_RENDERERS[self.app] = MakoTemplateRenderer(
                self.app, 'styles')

        # the static templatename.scss file
        try:
            scss_file = os.path.join(self.app_dir, 'styles',
                                     self.template_name + '.scss')
            scss_stat = os.stat(scss_file)
            try:
                css_file = os.path.join(self.app_dir, 'styles',
                                        self.template_name + '.css')
                css_stat = os.stat(css_file)
                # update the CSS file if the SCCS file is newer
                if scss_stat.st_mtime > css_stat.st_mtime:
                    os.system(
                        get_setting('SCCS_BINARY', '/usr/bin/env scss') +
                        ' %s %s %s' %
                        (get_setting('SCCS_ARGS', ''), scss_file, css_file))
            except OSError:
                # if no CSS file exists, create one
                os.system(
                    get_setting('SCCS_BINARY', '/usr/bin/env scss') +
                    ' %s %s %s' %
                    (get_setting('SCCS_ARGS', ''), scss_file, css_file))
        except OSError:
            # no SCCS file exists .. continue as normal
            pass

        # the static templatename.css file
        try:
            fstat = os.stat(
                os.path.join(self.app_dir, 'styles',
                             self.template_name + '.css'))
            self.css = '<link rel="stylesheet" type="text/css" href="%s?%s" />' % (
                os.path.join(settings.STATIC_URL, self.app, 'styles',
                             self.template_name + '.css'),
                cgi_id if cgi_id != None else int(fstat.st_mtime))
        except OSError:
            self.css = None

        # the mako-rendered templatename.cssm file
        try:
            fstat = os.stat(
                os.path.join(self.app_dir, 'styles',
                             self.template_name + '.cssm'))
            self.cssm = self.template_name + '.cssm'
        except OSError:
            self.cssm = None

        # the static templatename.js file
        try:
            fstat = os.stat(
                os.path.join(self.app_dir, 'scripts',
                             self.template_name + '.js'))
            self.js = '<script src="%s?%s"></script>' % (os.path.join(
                settings.STATIC_URL, self.app, 'scripts', self.template_name +
                '.js'), cgi_id if cgi_id != None else int(fstat.st_mtime))
        except OSError:
            self.js = None

        # the mako-rendered templatename.jsm file
        try:
            fstat = os.stat(
                os.path.join(self.app_dir, 'scripts',
                             self.template_name + '.jsm'))
            self.jsm = self.template_name + '.jsm'
        except OSError:
            self.jsm = None
Esempio n. 17
0
  objects in a dict or other type of cache.  This isn't done here to keep things simpler.
'''

from django.conf import settings
from django_mako_plus.controller.router import MakoTemplateRenderer
from django_mako_plus.controller import get_setting
import os, os.path, time


DMP_ATTR_NAME = 'dmp_templateinfo'  # used to attach TemplateInfo objects to Mako templates


# Import minification if requested
JSMIN = False
CSSMIN = False
if get_setting('MINIFY_JS_CSS', False) and not settings.DEBUG:
  try:
    from rjsmin import jsmin
    JSMIN = True
  except ImportError:
    pass
  try:
    from rcssmin import cssmin
    CSSMIN = True
  except ImportError:
    pass


#######################################################################
###   A dict of template renderers for scripts and styles in our apps.
###   These are created as needed in TemplateInfo below and cached here.
Esempio n. 18
0
  def process_request(self, request):
    '''Called for each browser request.  This adds the following fields to the request object:
    
       request.dmp_router_app       The Django application (such as "calculator").
       request.dmp_router_page      The view module (such as "calc" for calc.py).
       request.dmp_router_page_full The view module as specified in the URL, including the function name if specified.
       request.dmp_router_function  The function within the view module to be called (usually "process_request").
       request.dmp_router_module    The module path in Python terms, such as calculator.views.calc.
       request.urlparams            A list of the remaining url parts (see the calc.py example).
       
       This method is run as part of the middleware processing, so it runs long
       before the route_request() method at the top of this file.
    '''
    # split the path
    path_parts = request.path[1:].split('/') # [1:] to remove the leading /
    
    # splice the list if the settings need it
    start_index = get_setting('URL_START_INDEX', 0)
    if start_index > 0:
      path_parts = path_parts[start_index:]
      
    # ensure that we have at least 2 path_parts to work with
    # by adding the default app and/or page as needed
    if len(path_parts) == 0:
      path_parts.append(get_setting('DEFAULT_APP', 'homepage'))
      path_parts.append(get_setting('DEFAULT_PAGE', 'index'))
      
    elif len(path_parts) == 1: # /app or /page
      if path_parts[0] in TEMPLATE_RENDERERS:  # one of our apps specified, so insert the default page
        path_parts.append(get_setting('DEFAULT_PAGE', 'index'))
      else:  # not one of our apps, so insert the app and assume path_parts[0] is a page in that app
        path_parts.insert(0, get_setting('DEFAULT_APP', 'homepage'))
        if not path_parts[1]: # was the page empty?
          path_parts[1] = get_setting('DEFAULT_PAGE', 'index')
    
    else: # at this point in the elif, we know len(path_parts) >= 2
      if path_parts[0] not in TEMPLATE_RENDERERS: # the first part was not one of our apps, so insert the default app
        path_parts.insert(0, get_setting('DEFAULT_APP', 'homepage'))
      if not path_parts[1]:  # is the page empty?
        path_parts[1] = get_setting('DEFAULT_PAGE', 'index')
            
    # set the app and page in the request
    request.dmp_router_app = path_parts[0]
    request.dmp_router_page = path_parts[1]
    request.dmp_router_page_full = path_parts[1]  # might be different from dmp_router_page when split by '.' below
    
    # see if a function is specified with the page (the . separates a function name)
    du_pos = request.dmp_router_page.find('.')
    if du_pos >= 0:
      request.dmp_router_function = request.dmp_router_page[du_pos+1:]
      request.dmp_router_function = request.dmp_router_function.replace('.', '_')  # python methods can't have dot, so replace with an underscore if in the name
      request.dmp_router_page = request.dmp_router_page[:du_pos]
    else:  # the . not found, and the __ not found, so go to default function name
      request.dmp_router_function = 'process_request'

    # set the class to be None (it is set later if we find a class-based view)
    request.dmp_router_class = None

    # set up the urlparams with the reamining path parts
    # note that I'm not using unquote_plus because the + switches to a space *after* the question mark (in the regular parameters)
    # in the normal url, spaces have to be quoted with %20.  Thanks Rosie for the tip.
    request.urlparams = URLParamList([ unquote(s) for s in path_parts[2:] ])
Esempio n. 19
0
  def render(self, request, template, params={}, def_name=None):
    '''Runs a template and returns a string.  Normally, you probably want to call render_to_response instead
       because it gives a full HttpResponse or Http404.
       
       This method raises a mako.exceptions.TopLevelLookupException if the template is not found.
    
       The method throws two signals: 
         1. dmp_signal_pre_render_template: you can (optionally) return a new Mako Template object from a receiver to replace
            the normal template object that is used for the render operation.
         2. dmp_signal_post_render_template: you can (optionally) return a string to replace the string from the normal
            template object render.
    
       @request  The request context from Django.  If this is None, 1) any TEMPLATE_CONTEXT_PROCESSORS defined in your settings
                 file will be ignored and 2) DMP signals will not be sent, but the template will otherwise render fine.
       @template The template file path to render.  This is relative to the app_path/controller_TEMPLATES_DIR/ directory.
                 For example, to render app_path/templates/page1, set template="page1.html", assuming you have
                 set up the variables as described in the documentation above.
       @params   A dictionary of name=value variables to send to the template page.
       @def_name Limits output to a specific top-level Mako <%block> or <%def> section within the template.
                 If the section is a <%def>, it must have no parameters.  For example, def_name="foo" will call
                 <%block name="foo"></%block> or <%def name="foo()"></def> within the template.
                 The block/def must be defined in the exact template.  DMP does not support calling defs from 
                 super-templates.
    '''
    # must convert the request context to a real dict to use the ** below
    context_dict = {}
    context_dict['request'] = request
    context_dict['settings'] = settings
    try:
      context_dict['STATIC_URL'] = settings.STATIC_URL  # this is used so much in templates, it's useful to have it always available
    except AttributeError:
      pass
    context = Context(params) if request == None else RequestContext(request, params)  # Django's RequestContext automatically runs all the TEMPLATE_CONTEXT_PROCESSORS and populates with variables
    with context.bind_template(self):
      for d in context:
        context_dict.update(d)

    # get the template
    template_obj = self.get_template(template)

    # send the pre-render signal
    if get_setting('SIGNALS', False) and request != None:
      for receiver, ret_template_obj in signals.dmp_signal_pre_render_template.send(sender=self, request=request, context=context, template=template_obj):
        if ret_template_obj != None:  # changes the template object to the received
          template_obj = ret_template_obj

    # do we need to limit down to a specific def?
    # this only finds within the exact template (won't go up the inheritance tree)
    # I wish I could make it do so, but can't figure this out
    render_obj = template_obj  
    if def_name:  # do we need to limit to just a def?
      render_obj = template_obj.get_def(def_name)

    # PRIMARY FUNCTION: render the template
    log.debug('DMP :: rendering template %s' % template_obj.filename)
    if settings.DEBUG:
      try:
        content = render_obj.render_unicode(**context_dict)
      except:
        content = html_error_template().render_unicode()
    else:  # this is outside the above "try" loop because in non-DEBUG mode, we want to let the exception throw out of here (without having to re-raise it)
      content = render_obj.render_unicode(**context_dict)
      
    # send the post-render signal
    if get_setting('SIGNALS', False) and request != None:
      for receiver, ret_content in signals.dmp_signal_post_render_template.send(sender=self, request=request, context=context, template=template_obj, content=content):
        if ret_content != None:
          content = ret_content  # sets it to the last non-None return in the signal receiver chain
          
    # return
    return content
Esempio n. 20
0
  Note that with this Django starter kit, we recreate the static renderer each time.
  At deployment, it would speed things up considerably to cache these StaticRenderer
  objects in a dict or other type of cache.  This isn't done here to keep things simpler.
'''

from django.conf import settings
from django_mako_plus.controller.router import MakoTemplateRenderer
from django_mako_plus.controller import get_setting
import os, os.path, time

DMP_ATTR_NAME = 'dmp_templateinfo'  # used to attach TemplateInfo objects to Mako templates

# Import minification if requested
JSMIN = False
CSSMIN = False
if get_setting('MINIFY_JS_CSS', False) and not settings.DEBUG:
    try:
        from rjsmin import jsmin
        JSMIN = True
    except ImportError:
        pass
    try:
        from rcssmin import cssmin
        CSSMIN = True
    except ImportError:
        pass

#######################################################################
###   A dict of template renderers for scripts and styles in our apps.
###   These are created as needed in TemplateInfo below and cached here.
###   One for each app is created in each dict.
Esempio n. 21
0
  def process_request(self, request):
    '''Called for each browser request.  This adds the following fields to the request object:

       request.dmp_router_app       The Django application (such as "calculator").
       request.dmp_router_page      The view module (such as "calc" for calc.py).
       request.dmp_router_page_full The view module as specified in the URL, including the function name if specified.
       request.dmp_router_function  The function within the view module to be called (usually "process_request").
       request.dmp_router_module    The module path in Python terms, such as calculator.views.calc.
       request.urlparams            A list of the remaining url parts (see the calc.py example).

       This method is run as part of the middleware processing, so it runs long
       before the route_request() method at the top of this file.
    '''
    # split the path
    path_parts = request.path[1:].split('/') # [1:] to remove the leading /

    # splice the list if the settings need it
    start_index = get_setting('URL_START_INDEX', 0)
    if start_index > 0:
      path_parts = path_parts[start_index:]

    # ensure that we have at least 2 path_parts to work with
    # by adding the default app and/or page as needed
    if len(path_parts) == 0:
      path_parts.append(get_setting('DEFAULT_APP', 'homepage'))
      path_parts.append(get_setting('DEFAULT_PAGE', 'index'))

    elif len(path_parts) == 1: # /app or /page
      if path_parts[0] in TEMPLATE_RENDERERS:  # one of our apps specified, so insert the default page
        path_parts.append(get_setting('DEFAULT_PAGE', 'index'))
      else:  # not one of our apps, so insert the app and assume path_parts[0] is a page in that app
        path_parts.insert(0, get_setting('DEFAULT_APP', 'homepage'))
        if not path_parts[1]: # was the page empty?
          path_parts[1] = get_setting('DEFAULT_PAGE', 'index')

    else: # at this point in the elif, we know len(path_parts) >= 2
      if path_parts[0] not in TEMPLATE_RENDERERS: # the first part was not one of our apps, so insert the default app
        path_parts.insert(0, get_setting('DEFAULT_APP', 'homepage'))
      if not path_parts[1]:  # is the page empty?
        path_parts[1] = get_setting('DEFAULT_PAGE', 'index')

    # set the app and page in the request
    request.dmp_router_app = path_parts[0]
    request.dmp_router_page = path_parts[1]
    request.dmp_router_page_full = path_parts[1]  # might be different from dmp_router_page when split by '.' below

    # see if a function is specified with the page (the . separates a function name)
    du_pos = request.dmp_router_page.find('.')
    if du_pos >= 0:
      request.dmp_router_function = request.dmp_router_page[du_pos+1:]
      request.dmp_router_function = request.dmp_router_function.replace('.', '_')  # python methods can't have dot, so replace with an underscore if in the name
      request.dmp_router_page = request.dmp_router_page[:du_pos]
    else:  # the . not found, and the __ not found, so go to default function name
      request.dmp_router_function = 'process_request'

    # set the class to be None (it is set later if we find a class-based view)
    request.dmp_router_class = None

    # set up the urlparams with the reamining path parts
    # note that I'm not using unquote_plus because the + switches to a space *after* the question mark (in the regular parameters)
    # in the normal url, spaces have to be quoted with %20.  Thanks Rosie for the tip.
    request.urlparams = URLParamList([ unquote(s) for s in path_parts[2:] ])
Esempio n. 22
0
def route_request(request):
    '''The main router for all calls coming in to the system.'''
    # output the variables so the programmer can debug where this is routing
    log.debug('DMP :: processing: app=%s, page=%s, func=%s, urlparams=%s' % (request.dmp_router_app, request.dmp_router_page, request.dmp_router_function, request.urlparams))

    # set the full function location
    request.dmp_router_module = '.'.join([ request.dmp_router_app, 'views', request.dmp_router_page ])

    # first try going to the view function for this request
    # we look for a views/name.py file where name is the same name as the HTML file
    response = None

    while True: # enables the InternalRedirectExceptions to loop around
      full_module_filename = os.path.normpath(os.path.join(settings.BASE_DIR, request.dmp_router_module.replace('.', '/') + '.py'))
      try:
        # look for the module, and if not found go straight to template
        if not os.path.exists(full_module_filename):
          log.debug('DMP :: module %s not found; sending processing directly to template %s.html' % (request.dmp_router_module, request.dmp_router_page_full))
          try:
            dmp_renderer = get_renderer(request.dmp_router_app)
          except ImproperlyConfigured as e:
            log.debug('DMP :: %s' % (e))
            raise Http404
          return dmp_renderer.render_to_response(request, '%s.html' % request.dmp_router_page_full)

        # find the function
        module_obj = import_module(request.dmp_router_module)
        if not hasattr(module_obj, request.dmp_router_function):
          log.debug('DMP :: view function/class %s not in module %s; returning 404 not found.' % (request.dmp_router_function, request.dmp_router_module))
          raise Http404
        func_obj = getattr(module_obj, request.dmp_router_function)

        # see if the func_obj is actually a class -- we might be doing class-based views here
        if isinstance(func_obj, type):
          request.dmp_router_class = request.dmp_router_function
          request.dmp_router_function = request.method.lower()
          if not hasattr(func_obj, request.dmp_router_function):
            log.debug('DMP :: view class %s.%s has no method named %s; returning 404 not found.' % (request.dmp_router_module, request.dmp_router_class, request.dmp_router_function))
            raise Http404
          func_obj = getattr(func_obj(), request.dmp_router_function)  # move to the class.get(), class.post(), etc. method

        # ensure it is decorated with @view_function - this is for security so only certain functions can be called
        if getattr(func_obj, 'dmp_view_function', False) != True:
          log.debug('DMP :: view function/class %s found successfully, but it is not decorated with @view_function; returning 404 not found.  Note that if you have multiple decorators on a function, the @view_function decorator must be listed first.' % (request.dmp_router_function))
          raise Http404

        # send the pre-signal
        if get_setting('SIGNALS', False):
          for receiver, ret_response in signals.dmp_signal_pre_process_request.send(sender=sys.modules[__name__], request=request):
            if isinstance(ret_response, (HttpResponse, StreamingHttpResponse)):
              return ret_response

        # call view function
        if request.dmp_router_class == None:
          log.debug('DMP :: calling view function %s.%s' % (request.dmp_router_module, request.dmp_router_function))
        else:
          log.debug('DMP :: calling class-based view function %s.%s.%s' % (request.dmp_router_module, request.dmp_router_class, request.dmp_router_function))
        response = func_obj(request)

        # send the post-signal
        if get_setting('SIGNALS', False):
          for receiver, ret_response in signals.dmp_signal_post_process_request.send(sender=sys.modules[__name__], request=request, response=response):
            if ret_response != None:
              response = ret_response # sets it to the last non-None in the signal receiver chain

        # if we didn't get a correct response back, send a 404
        if not isinstance(response, (HttpResponse, StreamingHttpResponse)):
          if request.dmp_router_class == None:
            log.debug('DMP :: view function %s.%s failed to return an HttpResponse (or the post-signal overwrote it).  Returning Http404.' % (request.dmp_router_module, request.dmp_router_function))
          else:
            log.debug('DMP :: class-based view function %s.%s.%s failed to return an HttpResponse (or the post-signal overwrote it).  Returning Http404.' % (request.dmp_router_module, request.dmp_router_class, request.dmp_router_function))
          raise Http404

        # return the response
        return response

      except InternalRedirectException:
        ivr = sys.exc_info()[1] # Py2.7 and Py3+ compliant
        # send the signal
        if get_setting('SIGNALS', False):
          signals.dmp_signal_internal_redirect_exception.send(sender=sys.modules[__name__], request=request, exc=ivr)
        # do the internal redirect
        request.dmp_router_module = ivr.redirect_module
        request.dmp_router_function = ivr.redirect_function
        full_module_filename = os.path.normpath(os.path.join(settings.BASE_DIR, request.dmp_router_module.replace('.', '/') + '.py'))
        log.debug('DMP :: received an InternalViewRedirect to %s -> %s' % (full_module_filename, request.dmp_router_function))

      except RedirectException: # redirect to another page
        e = sys.exc_info()[1] # Py2.7 and Py3+ compliant
        if request.dmp_router_class == None:
          log.debug('DMP :: view function %s.%s redirected processing to %s' % (request.dmp_router_module, request.dmp_router_function, e.redirect_to))
        else:
          log.debug('DMP :: class-based view function %s.%s.%s redirected processing to %s' % (request.dmp_router_module, request.dmp_router_class, request.dmp_router_function, e.redirect_to))
        # send the signal
        if get_setting('SIGNALS', False):
          signals.dmp_signal_redirect_exception.send(sender=sys.modules[__name__], request=request, exc=e)
        # send the browser the redirect command
        return e.get_response(request)

    # the code should never get here
    raise Exception("Django-Mako-Plus router error: The route_request() function should not have been able to get to this point.  Please notify the owner of the DMP project.  Thanks.")