From d6b0ef5ee1625d511e12f1874d78a255e4f73502 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moraes?= Date: Wed, 5 Aug 2026 15:36:47 -0300 Subject: [PATCH] =?UTF-8?q?Remove=20limite=20de=20caracteres=20do=20campo?= =?UTF-8?q?=20Informa=C3=A7=C3=A3o=20Geral=20da=20Casa?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit O campo `CasaLegislativa.informacao_geral` é editado por editor de texto rico: `CasaLegislativaForm` aplica `attrs={'id': 'texto-rico'}` no widget e `frontend/src/__global/main.js` instancia o TinyMCE sobre esse id. O valor submetido, portanto, é HTML, e não texto puro. Com `max_length=100` no model, o MaxLengthValidator derivado pelo Django contava os caracteres do HTML, tags inclusive. Um endereço de três linhas com 87 caracteres visíveis vira 106 caracteres depois dos `

`, e o salvamento era recusado com "no máximo 100 caracteres (ele possui 106)" sem que o usuário tivesse digitado 100 caracteres. Quanto mais formatação o texto tem, mais cedo o erro aparece — e não há como o operador descobrir sozinho que o limite está sendo consumido por tags que ele não vê. O limite nunca teve efeito no banco: `TextField` gera coluna `text` no PostgreSQL, sem restrição de tamanho. A migration é um no-op em SQL e serve apenas para manter o state do Django coerente com o model. Adiciona teste que trava o comportamento e comentário no model registrando por que o campo não deve receber `max_length` de volta. OSTicket #824090 --- .../0061_casalegislativa_informacao_geral.py | 19 +++++++++++++ sapl/base/models.py | 4 ++- sapl/base/tests/test_form.py | 27 +++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 sapl/base/migrations/0061_casalegislativa_informacao_geral.py diff --git a/sapl/base/migrations/0061_casalegislativa_informacao_geral.py b/sapl/base/migrations/0061_casalegislativa_informacao_geral.py new file mode 100644 index 000000000..5fec68acd --- /dev/null +++ b/sapl/base/migrations/0061_casalegislativa_informacao_geral.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.28 on 2026-08-05 12:00 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0060_auto_20240812_1628'), + ] + + operations = [ + migrations.AlterField( + model_name='casalegislativa', + name='informacao_geral', + field=models.TextField(blank=True, + verbose_name='Informação Geral'), + ), + ] diff --git a/sapl/base/models.py b/sapl/base/models.py index 692c55138..b31c532ab 100644 --- a/sapl/base/models.py +++ b/sapl/base/models.py @@ -73,8 +73,10 @@ class CasaLegislativa(models.Model): max_length=100, blank=True, verbose_name=_('HomePage')) email = models.EmailField( max_length=100, blank=True, verbose_name=_('E-mail')) + # Campo editado via editor de texto rico (TinyMCE), portanto o valor + # armazenado é HTML. Não deve ter max_length: as tags consomem o limite + # e impedem o salvamento de textos curtos. informacao_geral = models.TextField( - max_length=100, blank=True, verbose_name=_('Informação Geral')) diff --git a/sapl/base/tests/test_form.py b/sapl/base/tests/test_form.py index 35f1c82bf..9464fe39e 100644 --- a/sapl/base/tests/test_form.py +++ b/sapl/base/tests/test_form.py @@ -39,3 +39,30 @@ def test_casa_legislativa_form_invalido(): }) assert not form.is_valid() + + +@pytest.mark.django_db(transaction=False) +def test_casa_legislativa_form_informacao_geral_sem_limite(): + # O campo é editado por editor de texto rico, então o valor submetido é + # HTML: as tags não podem consumir um limite de caracteres. + html = ''.join('

%s

' % linha for linha in + ['Câmara Municipal', 'Rua Osvaldo Cruz, 555 - Centro', + 'Expediente das 8h às 12h e das 13h30 às 17h30']) + assert len(html) > 100 + + form = CasaLegislativaForm(data={'codigo': 'codigo', + 'nome': 'nome', + 'sigla': 'sg', + 'endereco': 'endereco', + 'cep': '70000-000', + 'municipio': 'municipio', + 'uf': 'DF', + 'telefone': '33333333', + 'fax': '33333333', + 'endereco_web': '', + 'email': '', + 'informacao_geral': html + }) + + assert form.is_valid(), form.errors + assert form.cleaned_data['informacao_geral'] == html