fix: change pattern detail view
CI / test (push) Successful in 1m17s
CI / build (push) Successful in 27s

This commit is contained in:
2026-07-21 15:01:28 +02:00
parent 1ecca9362f
commit 2839d60923
7 changed files with 39 additions and 27 deletions
+5 -3
View File
@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: crochet\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-21 12:09+0000\n"
"POT-Creation-Date: 2026-07-21 12:32+0000\n"
"Language: en\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -46,9 +46,10 @@ msgstr "More information"
#: crochet/templates/crochet/_cookie_banner.html:11
msgid "Entendido"
msgstr "Got it"
msgstr "Agree"
#: crochet/templates/crochet/account_home.html:4
#: crochet/templates/crochet/pattern_detail.html:43
msgid "Mis patrones"
msgstr "My patterns"
@@ -110,6 +111,7 @@ msgstr "Log out"
#: crochet/templates/crochet/base.html:62
#: crochet/templates/crochet/home.html:24
#: crochet/templates/crochet/password_reset_complete.html:18
#: crochet/templates/crochet/pattern_detail.html:45
#: crochet/templates/registration/login.html:4
#: crochet/templates/registration/login.html:14
msgid "Iniciar sesión"
@@ -634,7 +636,7 @@ msgstr ""
msgid "Añade una sección para ver aquí el resultado."
msgstr "Add a section to see the result here."
#: crochet/templates/crochet/pattern_detail.html:26
#: crochet/templates/crochet/pattern_detail.html:31
msgid "Descargar PDF"
msgstr "Download PDF"
+4 -2
View File
@@ -2,7 +2,7 @@ msgid ""
msgstr ""
"Project-Id-Version: crochet\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-21 12:09+0000\n"
"POT-Creation-Date: 2026-07-21 12:32+0000\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -47,6 +47,7 @@ msgid "Entendido"
msgstr ""
#: crochet/templates/crochet/account_home.html:4
#: crochet/templates/crochet/pattern_detail.html:43
msgid "Mis patrones"
msgstr ""
@@ -108,6 +109,7 @@ msgstr ""
#: crochet/templates/crochet/base.html:62
#: crochet/templates/crochet/home.html:24
#: crochet/templates/crochet/password_reset_complete.html:18
#: crochet/templates/crochet/pattern_detail.html:45
#: crochet/templates/registration/login.html:4
#: crochet/templates/registration/login.html:14
msgid "Iniciar sesión"
@@ -604,7 +606,7 @@ msgstr ""
msgid "Añade una sección para ver aquí el resultado."
msgstr ""
#: crochet/templates/crochet/pattern_detail.html:26
#: crochet/templates/crochet/pattern_detail.html:31
msgid "Descargar PDF"
msgstr ""
@@ -59,7 +59,13 @@ class Command(BaseCommand):
INPUT_CSS.parent.mkdir(parents=True, exist_ok=True)
sources = '\n'.join(f'@source "{path}";' for path in SOURCES)
INPUT_CSS.write_text(f'@import "tailwindcss";\n{sources}\n')
# source(none): sin esto, Tailwind v4 escanea IGUALMENTE todo el
# proyecto en busca de clases por su cuenta (detección automática de
# contenido), además de los @source de abajo; el resultado deja de
# estar acotado a SOURCES y arrastra clases de cualquier otra
# plantilla (pattern.html, home.html...), justo lo que este comando
# existe para evitar.
INPUT_CSS.write_text(f'@import "tailwindcss" source(none);\n{sources}\n')
self.stdout.write(f'Compilando {OUTPUT_CSS.relative_to(settings.BASE_DIR)}...')
result = subprocess.run(
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
{% load static django_htmx %}
{# Un comentario Django de una sola línea (su lexer no cruza saltos de línea al buscar el cierre, y tampoco admite el propio delimitador de comentario dentro del texto). #}
{# Incluido por cada plantilla con look de "plataforma" (editor, cuenta): daisyUI + Tailwind vía CDN + el tema propio "crochet" (ver theme.css) + htmx. pattern_detail.html NO lo incluye a propósito (ver ese archivo). #}
{# Incluido por cada plantilla con look de "plataforma" (editor, cuenta, y también pattern_detail.html para tener el mismo navbar/cabecera): daisyUI + Tailwind vía CDN + el tema propio "crochet" (ver theme.css) + htmx. #}
<link href="https://cdn.jsdelivr.net/npm/daisyui@5" rel="stylesheet" type="text/css" />
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<link rel="stylesheet" href="{% static 'css/theme.css' %}">
+7 -14
View File
@@ -4,6 +4,13 @@
{% block title %}{{ page_settings.title|default:"Crochet" }}{% endblock %}
{% block extra_css %}
<!-- El navbar real (ver base.html) usa clases de daisyUI, así que aquí
hace falta cargarlo igual que en el resto del sitio (ver
_platform_assets.html), aunque esta vista se genere también como
HTML de entrada para el PDF: al ser no-print, no se imprime, pero
WeasyPrint sí llega a pedir por red su CSS (daisyUI, Google Fonts)
para construirlo, aunque el resultado no se vea nunca en el PDF. -->
{% include 'crochet/_platform_assets.html' %}
<link rel="stylesheet" href="{% static 'css/pattern-detail.css' %}">
<style>
:root {
@@ -14,26 +21,12 @@
</style>
{% endblock %}
<!-- Sin daisyUI aquí (ver arriba), así que el navbar de base.html no tiene
ningún estilo que aplicarle: se deja vacío a propósito. Lo mismo con
el aviso de cookies: es una vista de solo lectura sin JS propio. -->
{% block navbar %}{% endblock %}
{% block cookie_banner %}{% endblock %}
{% block content %}
<main class="p-4">
<div class="flex justify-end gap-2 mb-4 no-print">
<a href="{% url 'crochet:pattern_pdf' pattern.uuid %}" class="detail-btn">{% trans 'Descargar PDF' %}</a>
{% if lang != 'es' %}
{% language 'es' %}
<a href="{% url 'crochet:pattern_detail' pattern.uuid %}" class="detail-btn">Español</a>
{% endlanguage %}
{% endif %}
{% if lang != 'en' %}
{% language 'en' %}
<a href="{% url 'crochet:pattern_detail' pattern.uuid %}" class="detail-btn">English</a>
{% endlanguage %}
{% endif %}
</div>
<div id="panel-output" class="border border-gray-300 rounded-2xl p-4 max-w-3xl mx-auto"
+13 -4
View File
@@ -12,6 +12,7 @@ from crochet.models import Pattern, PatternImage, StitchType
from crochet.tests.test_models import make_test_image_file
NO_HTML_COMMENTS_RE = re.compile(r'<!--.*?-->', re.S)
NAV_RE = re.compile(r'<nav[ >].*?</nav>', re.S)
class HomeViewTests(TestCase):
@@ -286,15 +287,23 @@ class PatternDetailViewTests(TestCase):
self.assertLess(body.index('Ampharos'), body.index(self.pattern.cover_image_large.url))
def test_page_has_no_editable_elements(self):
# El navbar compartido (ver base.html) sí trae sus propios <button>
# (desplegable de idioma/cuenta): no editan el patrón, así que se
# descarta antes de comprobar esto. La regla real es que el PATRÓN
# en sí -lo que hay fuera del navbar- no debe traer ningún control
# de edición, ni siquiera oculto con CSS: cualquiera podría
# revelarlo desde las herramientas de desarrollador del navegador y
# guardar cambios reales (esta vista comparte uuid con la de editar).
with translation.override('es'):
url = reverse('crochet:pattern_detail', args=[self.pattern.uuid])
response = self.client.get(url)
body_without_comments = NO_HTML_COMMENTS_RE.sub('', response.content.decode())
body_without_nav = NAV_RE.sub('', body_without_comments)
self.assertNotRegex(body_without_comments, r'<input[ >]')
self.assertNotRegex(body_without_comments, r'<button[ >]')
self.assertNotRegex(body_without_comments, r'<select[ >]')
self.assertNotIn('csrf-token', body_without_comments)
self.assertNotRegex(body_without_nav, r'<input[ >]')
self.assertNotRegex(body_without_nav, r'<button[ >]')
self.assertNotRegex(body_without_nav, r'<select[ >]')
self.assertNotIn('csrf-token', body_without_nav)
def test_malicious_text_is_escaped(self):
pattern = Pattern.objects.create(sections=[