Browse Source

Merge branch '3.1.x' into evita-anexada-ciclica

pull/2670/head
João Rodrigues 7 years ago
committed by GitHub
parent
commit
f4576d4306
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      docker-compose.yml
  2. 58
      docs/solr.rst
  3. 16
      sapl/api/views.py
  4. 3
      sapl/comissoes/views.py
  5. 27
      sapl/materia/views.py
  6. 3
      sapl/norma/forms.py
  7. 17
      sapl/norma/models.py
  8. 19
      sapl/parlamentares/forms.py
  9. 15
      sapl/parlamentares/tests/test_parlamentares.py
  10. 21
      sapl/sessao/models.py
  11. 2
      sapl/settings.py
  12. 2
      sapl/templates/base.html
  13. 3
      sapl/templates/menu_tabelas_auxiliares.yaml
  14. 1
      sapl/templates/norma/normajuridica_form.html
  15. 3
      sapl/templates/sessao/blocos_ata/identificacao_basica.html
  16. 6
      sapl/templates/sessao/blocos_ata/lista_presenca.html
  17. 3
      sapl/templates/sessao/blocos_ata/lista_presenca_ordem_dia.html
  18. 37
      sapl/templates/sessao/blocos_ata/materias_expediente.html
  19. 31
      sapl/templates/sessao/blocos_ata/materias_ordem_dia.html
  20. 3
      sapl/templates/sessao/blocos_ata/mesa_diretora.html
  21. 7
      sapl/templates/sessao/blocos_ata/oradores_expediente.html
  22. 5
      sapl/templates/sessao/blocos_ata/oradores_explicacoes.html
  23. 2
      setup.py
  24. 2
      solr/docker-compose.yml

2
docker-compose.yml

@ -11,7 +11,7 @@ sapldb:
ports:
- "5432:5432"
sapl:
image: interlegis/sapl:3.1.152
image: interlegis/sapl:3.1.153
restart: always
environment:
ADMIN_PASSWORD: interlegis

58
docs/solr.rst

@ -1,27 +1,55 @@
**ESTAS INSTRUÇÕES ESTÃO DEFASADAS. EM BREVE IREMOS DISPONIBILIZAR UM TUTORIAL MAIS ATUALIZADO DE COMO INTEGRAR O SOLR AO SAPL**
================================
Instruções para instalar o Solr
================================
Solr é a ferramenta utilizada pelo SAPL 3.1 para indexar documentos para que possa ser feita
a Pesquisa Textual.
Solr é uma plataforma open source de indexação e busca textual utilizada pelo SAPL 3.1 para indexar documentos (normas jurídicas, matérias legislativas e documentos acessórios).
Observação: Se a execução do SAPL for mediante containers Docker então use o arquivo *docker-compose.yml* disponível em
*https://github.com/interlegis/sapl/blob/3.1.x/solr/docker-compose.yml* (verifique os mapeamentos de volume estão corretos, a verso do SAPL referenciada no arquivo docker-compose.yml, e realize o backup de seu BD **antes** de qualquer tentativa de substituição do arquivo *docker-compose.yml* em uso corrente);
1) Faça o download da distribuição *binária* do Apache Solr do site oficial do projeto **http://lucene.apache.org/solr**
As instalações Solr suportadas até o momento vão da 7.4 à 8;
2) Descompacte o arquivo em uma pasta do diretório (referenciada neste tutorial como $SOLR_HOME)
3) Inicie o Solr com o comando:
**$SOLR_HOME/bin/solr start -c**
4) Por meio do browser, acesse a URL **http://localhost:8983** (ou informe o endereço da máquina onde o Solr foi instalado)
5) Pare o servidor do SAPL;
6) Edite o arquivo .env adicionando as seguintes linhas:
USE_SOLR = True
SOLR_COLLECTION = sapl
SOLR_URL = http://localhost:8983
Adicione ao arquivo ``.env`` o seguinte atributo:
(o valor do campo SOLR_URL deve corresponder à URL acessada no item 3)
``SOLR_URL = 'http://127.0.0.1:8983/solr'``
7) Entre no diretório raiz do SAPL e digite o comando: **python3 solr_api.py -c sapl -u http://localhost:8983`**
Dentro do diretório principal siga os seguintes passos::
(a URL informada acima deve ser a mesma dos itens 3 e 6)
curl -LO https://archive.apache.org/dist/lucene/solr/4.10.2/solr-4.10.2.tgz
tar xvzf solr-4.10.2.tgz
cd solr-4.10.2
cd example
java -jar start.jar
./manage.py build_solr_schema --filename solr-4.10.2/example/solr/collection1/conf/schema.xml
8) Enquanto o Solr realiza a indexação da base de dados do SAPL, inicie em uma outra tela o SAPL;
9) Após realizados os passos com sucesso, nas telas de busca de Matéria Legislativa e Normas deverá aparecer um botão
de 'Busca Textual' próximo ao botão de busca tradicional.
Após isso, deve-se parar o servidor do Solr e restartar com ``java -jar start.jar``
**Observações:**
* Para parar o Solr execute o comando **$SOLR_HOME/bin/solr stop**
**OBS: Toda vez que o código da pesquisa textual for modificado, os comandos de build_solr_schema e start.jar devem ser rodados, nessa mesma ordem.**
* Para reindexar os dados do SAPL execute o comando **python3 manage.py rebuild_index** (isso irá apagar todos os dados
do Solr e indexar tudo novamente).

16
sapl/api/views.py

@ -27,7 +27,7 @@ from sapl.materia.models import Proposicao, TipoMateriaLegislativa,\
from sapl.parlamentares.models import Parlamentar
from sapl.protocoloadm.models import DocumentoAdministrativo,\
DocumentoAcessorioAdministrativo, TramitacaoAdministrativo
from sapl.sessao.models import SessaoPlenaria
from sapl.sessao.models import SessaoPlenaria, ExpedienteSessao
from sapl.utils import models_with_gr_for_model, choice_anos_com_sessaoplenaria
@ -498,3 +498,17 @@ class _SessaoPlenariaViewSet:
serializer = ChoiceSerializer(years, many=True)
return Response(serializer.data)
@action(detail=True)
def expedientes(self, request, *args, **kwargs):
sessao = self.get_object()
page = self.paginate_queryset(sessao.expedientesessao_set.all())
if page is not None:
serializer = SaplApiViewSetConstrutor.get_class_for_model(
ExpedienteSessao).serializer_class(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(page, many=True)
return Response(serializer.data)

3
sapl/comissoes/views.py

@ -197,7 +197,8 @@ class ReuniaoCrud(MasterDetailCrud):
public = [RP_LIST, RP_DETAIL, ]
class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['data', 'nome', 'tema']
list_field_names = ['data', 'nome', 'tema', 'upload_ata']
ordering = '-data'
class ListView(MasterDetailCrud.ListView):
logger = logging.getLogger(__name__)

27
sapl/materia/views.py

@ -14,7 +14,7 @@ from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, ValidationError
from django.core.urlresolvers import reverse
from django.db.models import Max, Q
from django.http import HttpResponse, JsonResponse
@ -1945,6 +1945,7 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
filterset_class = AcessorioEmLoteFilterSet
template_name = 'materia/em_lote/acessorio.html'
permission_required = ('materia.add_documentoacessorio',)
logger = logging.getLogger(__name__)
def get_context_data(self, **kwargs):
context = super(DocumentoAcessorioEmLoteView,
@ -1966,6 +1967,7 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
return context
def post(self, request, *args, **kwargs):
username = request.user.username
marcadas = request.POST.getlist('materia_id')
if len(marcadas) == 0:
@ -1982,13 +1984,20 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
tmp_name = os.path.join(tempfile.gettempdir(), request.FILES['arquivo'].name)
tmp_name = os.path.join(MEDIA_ROOT, request.FILES['arquivo'].name)
with open(tmp_name, 'wb') as destination:
for chunk in request.FILES['arquivo'].chunks():
destination.write(chunk)
try:
doc_data = tz.localize(datetime.strptime(
request.POST['data'], "%d/%m/%Y"))
except Exception as e:
msg = _('Formato da data incorreto. O formato deve ser da forma dd/mm/aaaa.')
messages.add_message(request, messages.ERROR, msg)
self.logger.error("User={}. {}. Data inserida: {}".format(username, str(msg), request.POST['data']))
os.remove(tmp_name)
return self.get(request, self.kwargs)
for materia_id in marcadas:
doc = DocumentoAcessorio()
doc.materia_id = materia_id
@ -1997,6 +2006,18 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
doc.data = doc_data
doc.autor = request.POST['autor']
doc.ementa = request.POST['ementa']
doc.arquivo.name = tmp_name
try:
doc.clean_fields()
except ValidationError as e:
for m in [ '%s: %s' % (DocumentoAcessorio()._meta.get_field(k).verbose_name, '</br>'.join(v))
for k,v in e.message_dict.items() ]:
# Insere as mensagens de erro no formato:
# 'verbose_name do nome do campo': 'mensagem de erro'
messages.add_message(request, messages.ERROR, m)
self.logger.error("User={}. {}. Nome do arquivo: {}.".format(username, str(msg), request.FILES['arquivo'].name))
os.remove(tmp_name)
return self.get(request, self.kwargs)
doc.save()
diretorio = os.path.join(MEDIA_ROOT,
'sapl/public/documentoacessorio',

3
sapl/norma/forms.py

@ -298,11 +298,10 @@ class AnexoNormaJuridicaForm(FileFieldCheckMixin, ModelForm):
def save(self, commit=False):
anexo = self.instance
anexo.ano = self.cleaned_data['norma'].ano
anexo = super(AnexoNormaJuridicaForm, self).save(commit=True)
anexo.norma = self.cleaned_data['norma']
anexo.assunto_anexo = self.cleaned_data['assunto_anexo']
anexo.anexo_arquivo = self.cleaned_data['anexo_arquivo']
anexo.save()
anexo = super(AnexoNormaJuridicaForm, self).save(commit=True)
return anexo

17
sapl/norma/models.py

@ -351,3 +351,20 @@ class AnexoNormaJuridica(models.Model):
def __str__(self):
return _('Anexo: %(anexo)s da norma %(norma)s') % {
'anexo': self.anexo_arquivo, 'norma': self.norma}
def save(self, force_insert=False, force_update=False, using=None,
update_fields=None):
if not self.pk and self.anexo_arquivo:
anexo_arquivo = self.anexo_arquivo
self.anexo_arquivo = None
models.Model.save(self, force_insert=force_insert,
force_update=force_update,
using=using,
update_fields=update_fields)
self.anexo_arquivo = anexo_arquivo
return models.Model.save(self, force_insert=force_insert,
force_update=force_update,
using=using,
update_fields=update_fields)

19
sapl/parlamentares/forms.py

@ -236,18 +236,6 @@ class ParlamentarFilterSet(django_filters.FilterSet):
class ParlamentarCreateForm(ParlamentarForm):
legislatura = forms.ModelChoiceField(
label=_('Legislatura'),
required=True,
queryset=Legislatura.objects.all().order_by('-data_inicio'),
empty_label='----------',
)
data_expedicao_diploma = forms.DateField(
label=_('Expedição do Diploma'),
required=True,
)
class Meta(ParlamentarForm.Meta):
widgets = {
'fotografia': forms.ClearableFileInput(),
@ -258,13 +246,6 @@ class ParlamentarCreateForm(ParlamentarForm):
@transaction.atomic
def save(self, commit=True):
parlamentar = super(ParlamentarCreateForm, self).save(commit)
legislatura = self.cleaned_data['legislatura']
Mandato.objects.create(
parlamentar=parlamentar,
legislatura=legislatura,
data_inicio_mandato=legislatura.data_inicio,
data_fim_mandato=legislatura.data_fim,
data_expedicao_diploma=self.cleaned_data['data_expedicao_diploma'])
content_type = ContentType.objects.get_for_model(Parlamentar)
object_id = parlamentar.pk
tipo = TipoAutor.objects.get(content_type=content_type)

15
sapl/parlamentares/tests/test_parlamentares.py

@ -11,7 +11,6 @@ from sapl.parlamentares.models import (Dependente, Filiacao, Legislatura,
@pytest.mark.django_db(transaction=False)
def test_cadastro_parlamentar(admin_client):
legislatura = mommy.make(Legislatura)
url = reverse('sapl.parlamentares:parlamentar_create')
response = admin_client.get(url)
@ -20,21 +19,13 @@ def test_cadastro_parlamentar(admin_client):
response = admin_client.post(url, {'nome_completo': 'Teresa Barbosa',
'nome_parlamentar': 'Terezinha',
'sexo': 'F',
'ativo': 'True',
'legislatura': legislatura.id,
'data_expedicao_diploma': '2001-01-01'},
'ativo': 'True'},
follow=True)
[parlamentar] = Parlamentar.objects.all()
assert parlamentar.nome_parlamentar == 'Terezinha'
assert parlamentar.sexo == 'F'
assert parlamentar.ativo is True
# o primeiro mandato é criado
[mandato] = Mandato.objects.all()
assert mandato.parlamentar == parlamentar
assert str(mandato.data_expedicao_diploma) == '2001-01-01'
assert mandato.legislatura == legislatura
assert mandato.data_fim_mandato == legislatura.data_fim
@pytest.mark.django_db(transaction=False)
@ -42,9 +33,7 @@ def test_incluir_parlamentar_errors(admin_client):
url = reverse('sapl.parlamentares:parlamentar_create')
response = admin_client.post(url)
erros_esperados = {campo: ['Este campo é obrigatório.']
for campo in ['legislatura',
'data_expedicao_diploma',
'nome_parlamentar',
for campo in ['nome_parlamentar',
'nome_completo',
'sexo',
]}

21
sapl/sessao/models.py

@ -290,8 +290,11 @@ class TipoExpediente(models.Model):
@reversion.register()
class ExpedienteSessao(models.Model): # ExpedienteSessaoPlenaria
sessao_plenaria = models.ForeignKey(SessaoPlenaria,
on_delete=models.CASCADE)
sessao_plenaria = models.ForeignKey(
SessaoPlenaria,
on_delete=models.CASCADE,
related_name='expedientesessao_set'
)
tipo = models.ForeignKey(TipoExpediente, on_delete=models.PROTECT)
conteudo = models.TextField(
blank=True, verbose_name=_('Conteúdo do expediente'))
@ -584,10 +587,14 @@ class ResumoOrdenacao(models.Model):
oitavo = models.CharField(max_length=30)
nono = models.CharField(max_length=30)
decimo = models.CharField(max_length=30)
decimo_primeiro = models.CharField(max_length=30,default="Ocorrências da Sessão")
decimo_segundo = models.CharField(max_length=30, default="Votos Nominais Mat Expediente")
decimo_terceiro = models.CharField(max_length=30, default="Votos Nominais Mat Ordem Dia")
decimo_quarto = models.CharField(max_length=30, default="Oradores da Ordem do Dia")
decimo_primeiro = models.CharField(
max_length=30, default="Ocorrências da Sessão")
decimo_segundo = models.CharField(
max_length=30, default="Votos Nominais Mat Expediente")
decimo_terceiro = models.CharField(
max_length=30, default="Votos Nominais Mat Ordem Dia")
decimo_quarto = models.CharField(
max_length=30, default="Oradores da Ordem do Dia")
class Meta:
verbose_name = _('Ordenação do Resumo de uma Sessão')
@ -596,6 +603,7 @@ class ResumoOrdenacao(models.Model):
def __str__(self):
return 'Ordenação do Resumo de uma Sessão'
@reversion.register()
class TipoRetiradaPauta(models.Model):
descricao = models.CharField(max_length=150, verbose_name=_('Descrição'))
@ -687,6 +695,7 @@ class JustificativaAusencia(models.Model):
using=using,
update_fields=update_fields)
class RetiradaPauta(models.Model):
materia = models.ForeignKey(MateriaLegislativa,
on_delete=models.CASCADE,

2
sapl/settings.py

@ -41,7 +41,7 @@ ALLOWED_HOSTS = ['*']
LOGIN_REDIRECT_URL = '/'
LOGIN_URL = '/login/?next='
SAPL_VERSION = '3.1.152'
SAPL_VERSION = '3.1.153'
if DEBUG:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

2
sapl/templates/base.html

@ -179,7 +179,7 @@
<small>
Desenvolvido pelo <a href="http://www.interlegis.leg.br/">Interlegis</a> em software livre e aberto.
</small>
<span>Release: 3.1.152</span>
<span>Release: 3.1.153</span>
</p>
</div>
<div class="col-md-4">

3
sapl/templates/menu_tabelas_auxiliares.yaml

@ -20,6 +20,9 @@
- title: {% trans 'Pesquisar Parlamentar' %}
url: sapl.parlamentares:pesquisar_parlamentar
css_class: btn btn-link
- title: {% trans 'Adicionar Parlamentar' %}
url: sapl.parlamentares:parlamentar_create
css_class: btn btn-link
- title: {% trans 'Legislatura' %}
url: sapl.parlamentares:legislatura_list
css_class: btn btn-link

1
sapl/templates/norma/normajuridica_form.html

@ -30,7 +30,6 @@
for (i = 0; i < fields.length; i++) {
$(fields[i]).change(recuperar_materia);
}
recuperar_materia();
function recuperar_norma() {
var tipo = $("#id_tipo").val();

3
sapl/templates/sessao/blocos_ata/identificacao_basica.html

@ -2,7 +2,8 @@
<p align="justify">
<strong>Identificação Básica: </strong>
{% for b in basica %}
{{b}} ;
{{b}}
{% if not forloop.last %} ; {% endif %}
{% endfor %}
</p>
</fieldset>

6
sapl/templates/sessao/blocos_ata/lista_presenca.html

@ -5,7 +5,8 @@
{% if presenca_sessao %}
<strong>Lista de Presença na Sessão: </strong>
{% for p in presenca_sessao %}
{{p.nome_completo}} / {{ p|filiacao_data_filter:object.data_inicio }} ;
{{p.nome_completo}} / {{ p|filiacao_data_filter:object.data_inicio }}
{% if not forloop.last %} ; {% endif %}
{% endfor %}
{% endif %}
</p>
@ -13,7 +14,8 @@
{% if justificativa_ausencia %}
<strong>Justificativas de Ausências na Sessão: </strong>
{% for j in justificativa_ausencia %}
{{j.parlamentar.nome_completo}} / {{ j.tipo_ausencia }} ;
{{j.parlamentar.nome_completo}} / {{ j.tipo_ausencia }}
{% if not forloop.last %} ; {% endif %}
{% endfor %}
{% endif %}
</p>

3
sapl/templates/sessao/blocos_ata/lista_presenca_ordem_dia.html

@ -5,7 +5,8 @@
{% if presenca_ordem %}
<strong>Lista de Presença na Ordem do Dia: </strong>
{% for p in presenca_ordem %}
{{p.nome_completo}} / {{ p|filiacao_data_filter:object.data_inicio }} ;
{{p.nome_completo}} / {{ p|filiacao_data_filter:object.data_inicio }}
{% if not forloop.last %} ; {% endif %}
{% endfor %}
{% endif %}
</p>

37
sapl/templates/sessao/blocos_ata/materias_expediente.html

@ -3,24 +3,33 @@
{% if materia_expediente %}
<strong>Matérias do Expediente: </strong>
{% for m in materia_expediente %}
<b>{{m.numero}} - {{m.titulo}}</b>
{% if m.turno %}
Turno: {{m.turno}}
{% endif %}
Autor{{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }}
<b>{{m.numero}} - {{m.titulo}}</b>,
{{m.ementa|safe}}
Autor{{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }},
{% if m.numero_protocolo %}
Número de Protocolo: {{ m.numero_protocolo }}
Número de Protocolo: {{ m.numero_protocolo }},
{% endif %}
{% if m.numero_processo %}
Processo: {{ m.numero_processo }}
Processo: {{ m.numero_processo }},
{% endif %}
{%if m.turno %}
Turno: {{m.turno}},
{%endif %}
{%if m.tipo_votacao %}
Tipo: {{m.tipo_votacao}},
Sim: {{ m.voto_sim }},
Não: {{ m.voto_nao }},
Abstenções: {{m.voto_abstencoes}},
{% endif %}
Resultado:</b> {{m.resultado}}
{% if m.resultado_observacao %} - {{m.resultado_observacao}} {% endif %}
{% if m.voto_nominal%}
<b>Votos Nominais :</b>
{% for voto in m.voto_nominal %}
{{voto.0}} - {{voto.1}}
{% if not forloop.last %} ; {% endif %}
{% endfor %}
{% endif %}
{{m.ementa|safe}}
{{m.resultado}} {{m.resultado_observacao}}</td>
{% endfor %}
{% endif %}
</p>

31
sapl/templates/sessao/blocos_ata/materias_ordem_dia.html

@ -2,29 +2,32 @@
<p align="justify">
<strong>Matérias da Ordem do Dia: </strong>
{% for m in materias_ordem %}
<b>{{m.numero}} - {{m.titulo}}</b>
Descrição: {{m.ementa|safe}}
Autor{{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }}
<b>{{m.numero}} - {{m.titulo}}</b>,
{{m.ementa|safe}}
Autor{{ m.autor|length|pluralize:"es" }}: {{ m.autor|join:', ' }},
{% if m.numero_protocolo %}
Número de Protocolo: {{ m.numero_protocolo }}
Número de Protocolo: {{ m.numero_protocolo }},
{% endif %}
{% if m.numero_processo %}
Processo:{{ m.numero_processo }}
Processo: {{ m.numero_processo }},
{% endif %}
{%if m.turno %}
Turno: {{m.turno}}
Turno: {{m.turno}},
{%endif %}
Tipo: {{m.tipo_votacao}}
Sim:{{m.voto_sim}}
Não:{{m.voto_nao}}
Abstenções:{{m.voto_abstencoes}}
Resultado:</b> {{m.resultado}} {{m.resultado_observacao}}
{%if m.tipo_votacao %}
Tipo: {{m.tipo_votacao}},
Sim: {{ m.voto_sim }},
Não: {{ m.voto_nao }},
Abstenções: {{m.voto_abstencoes}},
{% endif %}
Resultado:</b> {{m.resultado}}
{% if m.resultado_observacao %} - {{m.resultado_observacao}} {% endif %}
{% if m.voto_nominal%}
<b>Votos Nominais :</b>
{% for voto in m.voto_nominal %}
/ {{voto.0}} - {{voto.1}}
{% endfor %};
{{voto.0}} - {{voto.1}}
{% if not forloop.last %} ; {% endif %}
{% endfor %}
{% endif %}
{% endfor %}
</p>
</fieldset>

3
sapl/templates/sessao/blocos_ata/mesa_diretora.html

@ -4,7 +4,8 @@
<strong>Mesa Diretora: </strong>
{% for m in mesa %}
{{m.cargo}}:
{{m.parlamentar.nome_completo}} / {{ m.parlamentar.filiacao_atual }} ;
{{m.parlamentar.nome_completo}} / {{ m.parlamentar.filiacao_atual }}
{% if not forloop.last %} ; {% endif %}
{% endfor %}
{% endif %}
</p>

7
sapl/templates/sessao/blocos_ata/oradores_expediente.html

@ -3,10 +3,9 @@
{% if oradores %}
<strong>Oradores do Expediente: </strong>
{% for o in oradores %}
<div><b>{{o.numero_ordem}}</b> - {{o.parlamentar.nome_completo}}</div>
<div>{{o.url_discurso}}</div>
<div>{{o.observacao}}</div>
</br>
<b>{{o.numero_ordem}}</b> - {{o.parlamentar.nome_completo}} / {{ o.parlamentar.filiacao_atual }}
{% if o.observacao %} - {{o.observacao}} {% endif %}
{% if not forloop.last %} ; {% endif %}
{% endfor %}
{% endif %}
</p>

5
sapl/templates/sessao/blocos_ata/oradores_explicacoes.html

@ -3,8 +3,9 @@
{% if oradores_explicacoes %}
<strong>Oradores das Explicações Pessoais: </strong>
{% for o in oradores_explicacoes %}
<b>{{o.numero_ordem}}</b> - {{o.parlamentar.nome_completo}} / {{ o.parlamentar.filiacao_atual }} ;
{{o.url_discurso}}
<b>{{o.numero_ordem}}</b> - {{o.parlamentar.nome_completo}} / {{ o.parlamentar.filiacao_atual }}
{% if o.observacao %} - {{o.observacao}} {% endif %}
{% if not forloop.last %} ; {% endif %}
{% endfor %}
{% endif %}
</p>

2
setup.py

@ -43,7 +43,7 @@ install_requires = [
]
setup(
name='interlegis-sapl',
version='3.1.152',
version='3.1.153',
packages=find_packages(),
include_package_data=True,
license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007',

2
solr/docker-compose.yml

@ -24,7 +24,7 @@ services:
- "8983:8983"
sapl:
image: interlegis/sapl:3.1.144
image: interlegis/sapl:3.1.152
# build: .
restart: always
environment:

Loading…
Cancel
Save