docker setup
This commit is contained in:
		| @ -0,0 +1,80 @@ | ||||
| from django.core.exceptions import ImproperlyConfigured, SuspiciousFileOperation | ||||
| from django.template.utils import get_app_template_dirs | ||||
| from django.utils._os import safe_join | ||||
| from django.utils.functional import cached_property | ||||
|  | ||||
|  | ||||
| class BaseEngine: | ||||
|     # Core methods: engines have to provide their own implementation | ||||
|     #               (except for from_string which is optional). | ||||
|  | ||||
|     def __init__(self, params): | ||||
|         """ | ||||
|         Initialize the template engine. | ||||
|  | ||||
|         `params` is a dict of configuration settings. | ||||
|         """ | ||||
|         params = params.copy() | ||||
|         self.name = params.pop("NAME") | ||||
|         self.dirs = list(params.pop("DIRS")) | ||||
|         self.app_dirs = params.pop("APP_DIRS") | ||||
|         if params: | ||||
|             raise ImproperlyConfigured( | ||||
|                 "Unknown parameters: {}".format(", ".join(params)) | ||||
|             ) | ||||
|  | ||||
|     @property | ||||
|     def app_dirname(self): | ||||
|         raise ImproperlyConfigured( | ||||
|             "{} doesn't support loading templates from installed " | ||||
|             "applications.".format(self.__class__.__name__) | ||||
|         ) | ||||
|  | ||||
|     def from_string(self, template_code): | ||||
|         """ | ||||
|         Create and return a template for the given source code. | ||||
|  | ||||
|         This method is optional. | ||||
|         """ | ||||
|         raise NotImplementedError( | ||||
|             "subclasses of BaseEngine should provide a from_string() method" | ||||
|         ) | ||||
|  | ||||
|     def get_template(self, template_name): | ||||
|         """ | ||||
|         Load and return a template for the given name. | ||||
|  | ||||
|         Raise TemplateDoesNotExist if no such template exists. | ||||
|         """ | ||||
|         raise NotImplementedError( | ||||
|             "subclasses of BaseEngine must provide a get_template() method" | ||||
|         ) | ||||
|  | ||||
|     # Utility methods: they are provided to minimize code duplication and | ||||
|     #                  security issues in third-party backends. | ||||
|  | ||||
|     @cached_property | ||||
|     def template_dirs(self): | ||||
|         """ | ||||
|         Return a list of directories to search for templates. | ||||
|         """ | ||||
|         # Immutable return value because it's cached and shared by callers. | ||||
|         template_dirs = tuple(self.dirs) | ||||
|         if self.app_dirs: | ||||
|             template_dirs += get_app_template_dirs(self.app_dirname) | ||||
|         return template_dirs | ||||
|  | ||||
|     def iter_template_filenames(self, template_name): | ||||
|         """ | ||||
|         Iterate over candidate files for template_name. | ||||
|  | ||||
|         Ignore files that don't lie inside configured template dirs to avoid | ||||
|         directory traversal attacks. | ||||
|         """ | ||||
|         for template_dir in self.template_dirs: | ||||
|             try: | ||||
|                 yield safe_join(template_dir, template_name) | ||||
|             except SuspiciousFileOperation: | ||||
|                 # The joined path was located outside of this template_dir | ||||
|                 # (it might be inside another one, so this isn't fatal). | ||||
|                 pass | ||||
| @ -0,0 +1,136 @@ | ||||
| from importlib import import_module | ||||
| from pkgutil import walk_packages | ||||
|  | ||||
| from django.apps import apps | ||||
| from django.conf import settings | ||||
| from django.template import TemplateDoesNotExist | ||||
| from django.template.context import make_context | ||||
| from django.template.engine import Engine | ||||
| from django.template.library import InvalidTemplateLibrary | ||||
|  | ||||
| from .base import BaseEngine | ||||
|  | ||||
|  | ||||
| class DjangoTemplates(BaseEngine): | ||||
|     app_dirname = "templates" | ||||
|  | ||||
|     def __init__(self, params): | ||||
|         params = params.copy() | ||||
|         options = params.pop("OPTIONS").copy() | ||||
|         options.setdefault("autoescape", True) | ||||
|         options.setdefault("debug", settings.DEBUG) | ||||
|         options.setdefault("file_charset", "utf-8") | ||||
|         libraries = options.get("libraries", {}) | ||||
|         options["libraries"] = self.get_templatetag_libraries(libraries) | ||||
|         super().__init__(params) | ||||
|         self.engine = Engine(self.dirs, self.app_dirs, **options) | ||||
|  | ||||
|     def from_string(self, template_code): | ||||
|         return Template(self.engine.from_string(template_code), self) | ||||
|  | ||||
|     def get_template(self, template_name): | ||||
|         try: | ||||
|             return Template(self.engine.get_template(template_name), self) | ||||
|         except TemplateDoesNotExist as exc: | ||||
|             reraise(exc, self) | ||||
|  | ||||
|     def get_templatetag_libraries(self, custom_libraries): | ||||
|         """ | ||||
|         Return a collation of template tag libraries from installed | ||||
|         applications and the supplied custom_libraries argument. | ||||
|         """ | ||||
|         libraries = get_installed_libraries() | ||||
|         libraries.update(custom_libraries) | ||||
|         return libraries | ||||
|  | ||||
|  | ||||
| class Template: | ||||
|     def __init__(self, template, backend): | ||||
|         self.template = template | ||||
|         self.backend = backend | ||||
|  | ||||
|     @property | ||||
|     def origin(self): | ||||
|         return self.template.origin | ||||
|  | ||||
|     def render(self, context=None, request=None): | ||||
|         context = make_context( | ||||
|             context, request, autoescape=self.backend.engine.autoescape | ||||
|         ) | ||||
|         try: | ||||
|             return self.template.render(context) | ||||
|         except TemplateDoesNotExist as exc: | ||||
|             reraise(exc, self.backend) | ||||
|  | ||||
|  | ||||
| def copy_exception(exc, backend=None): | ||||
|     """ | ||||
|     Create a new TemplateDoesNotExist. Preserve its declared attributes and | ||||
|     template debug data but discard __traceback__, __context__, and __cause__ | ||||
|     to make this object suitable for keeping around (in a cache, for example). | ||||
|     """ | ||||
|     backend = backend or exc.backend | ||||
|     new = exc.__class__(*exc.args, tried=exc.tried, backend=backend, chain=exc.chain) | ||||
|     if hasattr(exc, "template_debug"): | ||||
|         new.template_debug = exc.template_debug | ||||
|     return new | ||||
|  | ||||
|  | ||||
| def reraise(exc, backend): | ||||
|     """ | ||||
|     Reraise TemplateDoesNotExist while maintaining template debug information. | ||||
|     """ | ||||
|     new = copy_exception(exc, backend) | ||||
|     raise new from exc | ||||
|  | ||||
|  | ||||
| def get_template_tag_modules(): | ||||
|     """ | ||||
|     Yield (module_name, module_path) pairs for all installed template tag | ||||
|     libraries. | ||||
|     """ | ||||
|     candidates = ["django.templatetags"] | ||||
|     candidates.extend( | ||||
|         f"{app_config.name}.templatetags" for app_config in apps.get_app_configs() | ||||
|     ) | ||||
|  | ||||
|     for candidate in candidates: | ||||
|         try: | ||||
|             pkg = import_module(candidate) | ||||
|         except ImportError: | ||||
|             # No templatetags package defined. This is safe to ignore. | ||||
|             continue | ||||
|  | ||||
|         if hasattr(pkg, "__path__"): | ||||
|             for name in get_package_libraries(pkg): | ||||
|                 yield name[len(candidate) + 1 :], name | ||||
|  | ||||
|  | ||||
| def get_installed_libraries(): | ||||
|     """ | ||||
|     Return the built-in template tag libraries and those from installed | ||||
|     applications. Libraries are stored in a dictionary where keys are the | ||||
|     individual module names, not the full module paths. Example: | ||||
|     django.templatetags.i18n is stored as i18n. | ||||
|     """ | ||||
|     return { | ||||
|         module_name: full_name for module_name, full_name in get_template_tag_modules() | ||||
|     } | ||||
|  | ||||
|  | ||||
| def get_package_libraries(pkg): | ||||
|     """ | ||||
|     Recursively yield template tag libraries defined in submodules of a | ||||
|     package. | ||||
|     """ | ||||
|     for entry in walk_packages(pkg.__path__, pkg.__name__ + "."): | ||||
|         try: | ||||
|             module = import_module(entry[1]) | ||||
|         except ImportError as e: | ||||
|             raise InvalidTemplateLibrary( | ||||
|                 "Invalid template library specified. ImportError raised when " | ||||
|                 "trying to load '%s': %s" % (entry[1], e) | ||||
|             ) from e | ||||
|  | ||||
|         if hasattr(module, "register"): | ||||
|             yield entry[1] | ||||
| @ -0,0 +1,51 @@ | ||||
| import string | ||||
|  | ||||
| from django.core.exceptions import ImproperlyConfigured | ||||
| from django.template import Origin, TemplateDoesNotExist | ||||
| from django.utils.html import conditional_escape | ||||
|  | ||||
| from .base import BaseEngine | ||||
| from .utils import csrf_input_lazy, csrf_token_lazy | ||||
|  | ||||
|  | ||||
| class TemplateStrings(BaseEngine): | ||||
|     app_dirname = "template_strings" | ||||
|  | ||||
|     def __init__(self, params): | ||||
|         params = params.copy() | ||||
|         options = params.pop("OPTIONS").copy() | ||||
|         if options: | ||||
|             raise ImproperlyConfigured("Unknown options: {}".format(", ".join(options))) | ||||
|         super().__init__(params) | ||||
|  | ||||
|     def from_string(self, template_code): | ||||
|         return Template(template_code) | ||||
|  | ||||
|     def get_template(self, template_name): | ||||
|         tried = [] | ||||
|         for template_file in self.iter_template_filenames(template_name): | ||||
|             try: | ||||
|                 with open(template_file, encoding="utf-8") as fp: | ||||
|                     template_code = fp.read() | ||||
|             except FileNotFoundError: | ||||
|                 tried.append( | ||||
|                     ( | ||||
|                         Origin(template_file, template_name, self), | ||||
|                         "Source does not exist", | ||||
|                     ) | ||||
|                 ) | ||||
|             else: | ||||
|                 return Template(template_code) | ||||
|         raise TemplateDoesNotExist(template_name, tried=tried, backend=self) | ||||
|  | ||||
|  | ||||
| class Template(string.Template): | ||||
|     def render(self, context=None, request=None): | ||||
|         if context is None: | ||||
|             context = {} | ||||
|         else: | ||||
|             context = {k: conditional_escape(v) for k, v in context.items()} | ||||
|         if request is not None: | ||||
|             context["csrf_input"] = csrf_input_lazy(request) | ||||
|             context["csrf_token"] = csrf_token_lazy(request) | ||||
|         return self.safe_substitute(context) | ||||
| @ -0,0 +1,125 @@ | ||||
| from pathlib import Path | ||||
|  | ||||
| import jinja2 | ||||
|  | ||||
| from django.conf import settings | ||||
| from django.template import TemplateDoesNotExist, TemplateSyntaxError | ||||
| from django.utils.functional import cached_property | ||||
| from django.utils.module_loading import import_string | ||||
|  | ||||
| from .base import BaseEngine | ||||
| from .utils import csrf_input_lazy, csrf_token_lazy | ||||
|  | ||||
|  | ||||
| class Jinja2(BaseEngine): | ||||
|     app_dirname = "jinja2" | ||||
|  | ||||
|     def __init__(self, params): | ||||
|         params = params.copy() | ||||
|         options = params.pop("OPTIONS").copy() | ||||
|         super().__init__(params) | ||||
|  | ||||
|         self.context_processors = options.pop("context_processors", []) | ||||
|  | ||||
|         environment = options.pop("environment", "jinja2.Environment") | ||||
|         environment_cls = import_string(environment) | ||||
|  | ||||
|         if "loader" not in options: | ||||
|             options["loader"] = jinja2.FileSystemLoader(self.template_dirs) | ||||
|         options.setdefault("autoescape", True) | ||||
|         options.setdefault("auto_reload", settings.DEBUG) | ||||
|         options.setdefault( | ||||
|             "undefined", jinja2.DebugUndefined if settings.DEBUG else jinja2.Undefined | ||||
|         ) | ||||
|  | ||||
|         self.env = environment_cls(**options) | ||||
|  | ||||
|     def from_string(self, template_code): | ||||
|         return Template(self.env.from_string(template_code), self) | ||||
|  | ||||
|     def get_template(self, template_name): | ||||
|         try: | ||||
|             return Template(self.env.get_template(template_name), self) | ||||
|         except jinja2.TemplateNotFound as exc: | ||||
|             raise TemplateDoesNotExist(exc.name, backend=self) from exc | ||||
|         except jinja2.TemplateSyntaxError as exc: | ||||
|             new = TemplateSyntaxError(exc.args) | ||||
|             new.template_debug = get_exception_info(exc) | ||||
|             raise new from exc | ||||
|  | ||||
|     @cached_property | ||||
|     def template_context_processors(self): | ||||
|         return [import_string(path) for path in self.context_processors] | ||||
|  | ||||
|  | ||||
| class Template: | ||||
|     def __init__(self, template, backend): | ||||
|         self.template = template | ||||
|         self.backend = backend | ||||
|         self.origin = Origin( | ||||
|             name=template.filename, | ||||
|             template_name=template.name, | ||||
|         ) | ||||
|  | ||||
|     def render(self, context=None, request=None): | ||||
|         if context is None: | ||||
|             context = {} | ||||
|         if request is not None: | ||||
|             context["request"] = request | ||||
|             context["csrf_input"] = csrf_input_lazy(request) | ||||
|             context["csrf_token"] = csrf_token_lazy(request) | ||||
|             for context_processor in self.backend.template_context_processors: | ||||
|                 context.update(context_processor(request)) | ||||
|         try: | ||||
|             return self.template.render(context) | ||||
|         except jinja2.TemplateSyntaxError as exc: | ||||
|             new = TemplateSyntaxError(exc.args) | ||||
|             new.template_debug = get_exception_info(exc) | ||||
|             raise new from exc | ||||
|  | ||||
|  | ||||
| class Origin: | ||||
|     """ | ||||
|     A container to hold debug information as described in the template API | ||||
|     documentation. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self, name, template_name): | ||||
|         self.name = name | ||||
|         self.template_name = template_name | ||||
|  | ||||
|  | ||||
| def get_exception_info(exception): | ||||
|     """ | ||||
|     Format exception information for display on the debug page using the | ||||
|     structure described in the template API documentation. | ||||
|     """ | ||||
|     context_lines = 10 | ||||
|     lineno = exception.lineno | ||||
|     source = exception.source | ||||
|     if source is None: | ||||
|         exception_file = Path(exception.filename) | ||||
|         if exception_file.exists(): | ||||
|             source = exception_file.read_text() | ||||
|     if source is not None: | ||||
|         lines = list(enumerate(source.strip().split("\n"), start=1)) | ||||
|         during = lines[lineno - 1][1] | ||||
|         total = len(lines) | ||||
|         top = max(0, lineno - context_lines - 1) | ||||
|         bottom = min(total, lineno + context_lines) | ||||
|     else: | ||||
|         during = "" | ||||
|         lines = [] | ||||
|         total = top = bottom = 0 | ||||
|     return { | ||||
|         "name": exception.filename, | ||||
|         "message": exception.message, | ||||
|         "source_lines": lines[top:bottom], | ||||
|         "line": lineno, | ||||
|         "before": "", | ||||
|         "during": during, | ||||
|         "after": "", | ||||
|         "total": total, | ||||
|         "top": top, | ||||
|         "bottom": bottom, | ||||
|     } | ||||
| @ -0,0 +1,15 @@ | ||||
| from django.middleware.csrf import get_token | ||||
| from django.utils.functional import lazy | ||||
| from django.utils.html import format_html | ||||
| from django.utils.safestring import SafeString | ||||
|  | ||||
|  | ||||
| def csrf_input(request): | ||||
|     return format_html( | ||||
|         '<input type="hidden" name="csrfmiddlewaretoken" value="{}">', | ||||
|         get_token(request), | ||||
|     ) | ||||
|  | ||||
|  | ||||
| csrf_input_lazy = lazy(csrf_input, SafeString, str) | ||||
| csrf_token_lazy = lazy(get_token, str) | ||||
		Reference in New Issue
	
	Block a user