Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed #34343 -- Moved built-in templates to filesystem. #16562

Merged
merged 1 commit into from
Feb 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
**/*.min.js
**/vendor/**/*.js
django/contrib/gis/templates/**/*.js
django/views/templates/*.js
docs/_build/**/*.js
node_modules/**.js
tests/**/*.js
99 changes: 13 additions & 86 deletions django/views/csrf.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from pathlib import Path

from django.conf import settings
from django.http import HttpResponseForbidden
from django.template import Context, Engine, TemplateDoesNotExist, loader
Expand All @@ -12,93 +14,17 @@
# tags cannot be used with this inline templates as makemessages would not be
# able to discover the strings.

CSRF_FAILURE_TEMPLATE = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="robots" content="NONE,NOARCHIVE">
<title>403 Forbidden</title>
<style type="text/css">
html * { padding:0; margin:0; }
body * { padding:10px 20px; }
body * * { padding:0; }
body { font:small sans-serif; background:#eee; color:#000; }
body>div { border-bottom:1px solid #ddd; }
h1 { font-weight:normal; margin-bottom:.4em; }
h1 span { font-size:60%; color:#666; font-weight:normal; }
#info { background:#f6f6f6; }
#info ul { margin: 0.5em 4em; }
#info p, #summary p { padding-top:10px; }
#summary { background: #ffc; }
#explanation { background:#eee; border-bottom: 0px none; }
</style>
</head>
<body>
<div id="summary">
<h1>{{ title }} <span>(403)</span></h1>
<p>{{ main }}</p>
{% if no_referer %}
<p>{{ no_referer1 }}</p>
<p>{{ no_referer2 }}</p>
<p>{{ no_referer3 }}</p>
{% endif %}
{% if no_cookie %}
<p>{{ no_cookie1 }}</p>
<p>{{ no_cookie2 }}</p>
{% endif %}
</div>
{% if DEBUG %}
<div id="info">
<h2>Help</h2>
{% if reason %}
<p>Reason given for failure:</p>
<pre>
{{ reason }}
</pre>
{% endif %}

<p>In general, this can occur when there is a genuine Cross Site Request Forgery, or when
<a
href="https://docs.djangoproject.com/en/{{ docs_version }}/ref/csrf/">Django’s
CSRF mechanism</a> has not been used correctly. For POST forms, you need to
ensure:</p>

<ul>
<li>Your browser is accepting cookies.</li>

<li>The view function passes a <code>request</code> to the template’s <a
href="https://docs.djangoproject.com/en/dev/topics/templates/#django.template.backends.base.Template.render"><code>render</code></a>
method.</li>

<li>In the template, there is a <code>{% templatetag openblock %} csrf_token
{% templatetag closeblock %}</code> template tag inside each POST form that
targets an internal URL.</li>

<li>If you are not using <code>CsrfViewMiddleware</code>, then you must use
<code>csrf_protect</code> on any views that use the <code>csrf_token</code>
template tag, as well as those that accept the POST data.</li>
CSRF_FAILURE_TEMPLATE_NAME = "403_csrf.html"

<li>The form has a valid CSRF token. After logging in in another browser
tab or hitting the back button after a login, you may need to reload the
page with the form, because the token is rotated after a login.</li>
</ul>

<p>You’re seeing the help section of this page because you have <code>DEBUG =
True</code> in your Django settings file. Change that to <code>False</code>,
and only the initial error message will be displayed. </p>
def builtin_template_path(name):
"""
Return a path to a builtin template.

<p>You can customize this page using the CSRF_FAILURE_VIEW setting.</p>
</div>
{% else %}
<div id="explanation">
<p><small>{{ more }}</small></p>
</div>
{% endif %}
</body>
</html>
""" # NOQA
CSRF_FAILURE_TEMPLATE_NAME = "403_csrf.html"
Avoid calling this function at the module level or in a class-definition
because __file__ may not exist, e.g. in frozen environments.
"""
return Path(__file__).parent / "templates" / name


def csrf_failure(request, reason="", template_name=CSRF_FAILURE_TEMPLATE_NAME):
Expand Down Expand Up @@ -151,8 +77,9 @@ def csrf_failure(request, reason="", template_name=CSRF_FAILURE_TEMPLATE_NAME):
t = loader.get_template(template_name)
except TemplateDoesNotExist:
if template_name == CSRF_FAILURE_TEMPLATE_NAME:
# If the default template doesn't exist, use the string template.
t = Engine().from_string(CSRF_FAILURE_TEMPLATE)
# If the default template doesn't exist, use the fallback template.
with builtin_template_path("csrf_403.html").open(encoding="utf-8") as fh:
t = Engine().from_string(fh.read())
c = Context(c)
else:
# Raise if a developer-specified template doesn't exist.
Expand Down
120 changes: 13 additions & 107 deletions django/views/i18n.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import json
import os
import re
from pathlib import Path

from django.apps import apps
from django.conf import settings
Expand All @@ -16,6 +17,16 @@
LANGUAGE_QUERY_PARAMETER = "language"


def builtin_template_path(name):
"""
Return a path to a builtin template.

Avoid calling this function at the module level or in a class-definition
because __file__ may not exist, e.g. in frozen environments.
"""
return Path(__file__).parent / "templates" / name


def set_language(request):
"""
Redirect to a given URL while setting the chosen language in the session
Expand Down Expand Up @@ -84,112 +95,6 @@ def get_formats():
return {attr: get_format(attr) for attr in FORMAT_SETTINGS}


js_catalog_template = r"""
{% autoescape off %}
'use strict';
{
const globals = this;
const django = globals.django || (globals.django = {});

{% if plural %}
django.pluralidx = function(n) {
const v = {{ plural }};
if (typeof v === 'boolean') {
return v ? 1 : 0;
} else {
return v;
}
};
{% else %}
django.pluralidx = function(count) { return (count == 1) ? 0 : 1; };
{% endif %}

/* gettext library */

django.catalog = django.catalog || {};
{% if catalog_str %}
const newcatalog = {{ catalog_str }};
for (const key in newcatalog) {
django.catalog[key] = newcatalog[key];
}
{% endif %}

if (!django.jsi18n_initialized) {
django.gettext = function(msgid) {
const value = django.catalog[msgid];
if (typeof value === 'undefined') {
return msgid;
} else {
return (typeof value === 'string') ? value : value[0];
}
};

django.ngettext = function(singular, plural, count) {
const value = django.catalog[singular];
if (typeof value === 'undefined') {
return (count == 1) ? singular : plural;
} else {
return value.constructor === Array ? value[django.pluralidx(count)] : value;
}
};

django.gettext_noop = function(msgid) { return msgid; };

django.pgettext = function(context, msgid) {
let value = django.gettext(context + '\x04' + msgid);
if (value.includes('\x04')) {
value = msgid;
}
return value;
};

django.npgettext = function(context, singular, plural, count) {
let value = django.ngettext(context + '\x04' + singular, context + '\x04' + plural, count);
if (value.includes('\x04')) {
value = django.ngettext(singular, plural, count);
}
return value;
};

django.interpolate = function(fmt, obj, named) {
if (named) {
return fmt.replace(/%\(\w+\)s/g, function(match){return String(obj[match.slice(2,-2)])});
} else {
return fmt.replace(/%s/g, function(match){return String(obj.shift())});
}
};


/* formatting library */

django.formats = {{ formats_str }};

django.get_format = function(format_type) {
const value = django.formats[format_type];
if (typeof value === 'undefined') {
return format_type;
} else {
return value;
}
};

/* add to global namespace */
globals.pluralidx = django.pluralidx;
globals.gettext = django.gettext;
globals.ngettext = django.ngettext;
globals.gettext_noop = django.gettext_noop;
globals.pgettext = django.pgettext;
globals.npgettext = django.npgettext;
globals.interpolate = django.interpolate;
globals.get_format = django.get_format;

django.jsi18n_initialized = true;
}
};
{% endautoescape %}
""" # NOQA


class JavaScriptCatalog(View):
"""
Return the selected language catalog as a JavaScript library.
Expand Down Expand Up @@ -308,7 +213,8 @@ def render_to_response(self, context, **response_kwargs):
def indent(s):
return s.replace("\n", "\n ")

template = Engine().from_string(js_catalog_template)
with builtin_template_path("i18n_catalog.js").open(encoding="utf-8") as fh:
template = Engine().from_string(fh.read())
context["catalog_str"] = (
indent(json.dumps(context["catalog"], sort_keys=True, indent=2))
if context["catalog"]
Expand Down
41 changes: 15 additions & 26 deletions django/views/static.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@
from django.utils.translation import gettext_lazy


def builtin_template_path(name):
"""
Return a path to a builtin template.

Avoid calling this function at the module level or in a class-definition
because __file__ may not exist, e.g. in frozen environments.
"""
return Path(__file__).parent / "templates" / name


def serve(request, path, document_root=None, show_indexes=False):
"""
Serve static files below a given point in the directory structure.
Expand Down Expand Up @@ -53,29 +63,7 @@ def serve(request, path, document_root=None, show_indexes=False):
return response


DEFAULT_DIRECTORY_INDEX_TEMPLATE = """
{% load i18n %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<meta http-equiv="Content-Language" content="en-us">
<meta name="robots" content="NONE,NOARCHIVE">
<title>{% blocktranslate %}Index of {{ directory }}{% endblocktranslate %}</title>
</head>
<body>
<h1>{% blocktranslate %}Index of {{ directory }}{% endblocktranslate %}</h1>
<ul>
{% if directory != "/" %}
<li><a href="../">../</a></li>
{% endif %}
{% for f in file_list %}
<li><a href="{{ f|urlencode }}">{{ f }}</a></li>
{% endfor %}
</ul>
</body>
</html>
"""
# Translatable string for static directory index template title.
template_translatable = gettext_lazy("Index of %(directory)s")


Expand All @@ -88,9 +76,10 @@ def directory_index(path, fullpath):
]
)
except TemplateDoesNotExist:
t = Engine(libraries={"i18n": "django.templatetags.i18n"}).from_string(
DEFAULT_DIRECTORY_INDEX_TEMPLATE
)
with builtin_template_path("directory_index.html").open(encoding="utf-8") as fh:
t = Engine(libraries={"i18n": "django.templatetags.i18n"}).from_string(
fh.read()
)
c = Context()
else:
c = {}
Expand Down