Browse Source

Merge tag '3.1.147' into migracao

migracao
Marcio Mazza 6 years ago
parent
commit
1c6e32f8a9
  1. 2
      docker-compose.yml
  2. 7
      docs/deploy.rst
  3. 24
      docs/instalacao31.rst
  4. 4
      docs/solr.rst
  5. 1
      requirements/requirements.txt
  6. 59
      sapl/base/forms.py
  7. 13
      sapl/base/templatetags/common_tags.py
  8. 2
      sapl/base/tests/test_login.py
  9. 20
      sapl/base/urls.py
  10. 168
      sapl/base/views.py
  11. 12
      sapl/compilacao/views.py
  12. 1
      sapl/crispy_layout_mixin.py
  13. 61
      sapl/lexml/OAIServer.py
  14. 6
      sapl/lexml/models.py
  15. 6
      sapl/lexml/urls.py
  16. 22
      sapl/lexml/views.py
  17. 48
      sapl/materia/forms.py
  18. 3
      sapl/materia/urls.py
  19. 145
      sapl/materia/views.py
  20. 24
      sapl/parlamentares/forms.py
  21. 8
      sapl/parlamentares/urls.py
  22. 79
      sapl/parlamentares/views.py
  23. 10
      sapl/protocoloadm/forms.py
  24. 39
      sapl/protocoloadm/views.py
  25. 85
      sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py
  26. 53
      sapl/relatorios/views.py
  27. 15
      sapl/sessao/forms.py
  28. 25
      sapl/sessao/migrations/0033_auto_20190228_1803.py
  29. 2
      sapl/sessao/models.py
  30. 127
      sapl/sessao/views.py
  31. 4
      sapl/settings.py
  32. BIN
      sapl/static/sapl/css/chunk-vendors.81e1a0b9.css.gz
  33. 1
      sapl/static/sapl/css/compilacao.3372b760.css
  34. BIN
      sapl/static/sapl/css/compilacao.3372b760.css.gz
  35. 1
      sapl/static/sapl/css/sessao_online.ddd218af.css
  36. BIN
      sapl/static/sapl/css/sessao_online.ddd218af.css.gz
  37. 0
      sapl/static/sapl/frontend/audio/ring.mp3
  38. 2
      sapl/static/sapl/frontend/css/chunk-vendors.3c9fe6b4.css
  39. BIN
      sapl/static/sapl/frontend/css/chunk-vendors.3c9fe6b4.css.gz
  40. 1
      sapl/static/sapl/frontend/css/compilacao.1f5fb8cf.css
  41. BIN
      sapl/static/sapl/frontend/css/compilacao.1f5fb8cf.css.gz
  42. 2
      sapl/static/sapl/frontend/css/global.83a4a89d.css
  43. BIN
      sapl/static/sapl/frontend/css/global.83a4a89d.css.gz
  44. 0
      sapl/static/sapl/frontend/css/painel.baa845ab.css
  45. 0
      sapl/static/sapl/frontend/css/painel.baa845ab.css.gz
  46. 0
      sapl/static/sapl/frontend/fonts/fa-brands-400.4b115e11.woff2
  47. 0
      sapl/static/sapl/frontend/fonts/fa-brands-400.b90365bc.woff
  48. 0
      sapl/static/sapl/frontend/fonts/fa-brands-400.c39278f7.ttf
  49. 0
      sapl/static/sapl/frontend/fonts/fa-brands-400.c39278f7.ttf.gz
  50. 0
      sapl/static/sapl/frontend/fonts/fa-brands-400.d9d17590.eot
  51. 0
      sapl/static/sapl/frontend/fonts/fa-brands-400.d9d17590.eot.gz
  52. 0
      sapl/static/sapl/frontend/fonts/fa-regular-400.414ff5da.eot
  53. 0
      sapl/static/sapl/frontend/fonts/fa-regular-400.414ff5da.eot.gz
  54. 0
      sapl/static/sapl/frontend/fonts/fa-regular-400.5dd3976c.woff
  55. 0
      sapl/static/sapl/frontend/fonts/fa-regular-400.65779ebc.woff2
  56. 0
      sapl/static/sapl/frontend/fonts/fa-regular-400.f6c6f6c8.ttf
  57. 0
      sapl/static/sapl/frontend/fonts/fa-regular-400.f6c6f6c8.ttf.gz
  58. 0
      sapl/static/sapl/frontend/fonts/fa-solid-900.46280631.woff2
  59. 0
      sapl/static/sapl/frontend/fonts/fa-solid-900.61969d43.woff
  60. 0
      sapl/static/sapl/frontend/fonts/fa-solid-900.b5596f4d.eot
  61. 0
      sapl/static/sapl/frontend/fonts/fa-solid-900.b5596f4d.eot.gz
  62. 0
      sapl/static/sapl/frontend/fonts/fa-solid-900.b70cea03.ttf
  63. 0
      sapl/static/sapl/frontend/fonts/fa-solid-900.b70cea03.ttf.gz
  64. 0
      sapl/static/sapl/frontend/img/arrow.png
  65. 0
      sapl/static/sapl/frontend/img/authenticated.png
  66. 0
      sapl/static/sapl/frontend/img/avatar.png
  67. 0
      sapl/static/sapl/frontend/img/beta.png
  68. 0
      sapl/static/sapl/frontend/img/brasao_transp.gif
  69. 0
      sapl/static/sapl/frontend/img/down_arrow_select.jpg
  70. 0
      sapl/static/sapl/frontend/img/down_arrow_select.jpg.gz
  71. 0
      sapl/static/sapl/frontend/img/etiqueta.png
  72. 0
      sapl/static/sapl/frontend/img/fa-brands-400.80533988.svg
  73. 0
      sapl/static/sapl/frontend/img/fa-brands-400.80533988.svg.gz
  74. 0
      sapl/static/sapl/frontend/img/fa-regular-400.e7e957c8.svg
  75. 0
      sapl/static/sapl/frontend/img/fa-regular-400.e7e957c8.svg.gz
  76. 0
      sapl/static/sapl/frontend/img/fa-solid-900.82905d8d.svg
  77. 0
      sapl/static/sapl/frontend/img/fa-solid-900.82905d8d.svg.gz
  78. 0
      sapl/static/sapl/frontend/img/favicon.ico
  79. 0
      sapl/static/sapl/frontend/img/file.png
  80. 0
      sapl/static/sapl/frontend/img/hand-note.png
  81. 0
      sapl/static/sapl/frontend/img/icon_comissoes.png
  82. 0
      sapl/static/sapl/frontend/img/icon_delete_white.png
  83. 0
      sapl/static/sapl/frontend/img/icon_materia_legislativa.png
  84. 0
      sapl/static/sapl/frontend/img/icon_mesa_diretora.png
  85. 0
      sapl/static/sapl/frontend/img/icon_normas_juridicas.png
  86. 0
      sapl/static/sapl/frontend/img/icon_parlamentares.png
  87. 0
      sapl/static/sapl/frontend/img/icon_pautas.png
  88. 0
      sapl/static/sapl/frontend/img/icon_plenarias.png
  89. 0
      sapl/static/sapl/frontend/img/icon_relatorios.png
  90. 0
      sapl/static/sapl/frontend/img/icon_save_white.png
  91. 0
      sapl/static/sapl/frontend/img/lexml.gif
  92. 0
      sapl/static/sapl/frontend/img/logo.png
  93. 0
      sapl/static/sapl/frontend/img/logo_cc.png
  94. 0
      sapl/static/sapl/frontend/img/logo_interlegis.png
  95. 0
      sapl/static/sapl/frontend/img/manual.png
  96. 0
      sapl/static/sapl/frontend/img/pdflogo.png
  97. 0
      sapl/static/sapl/frontend/img/perfil.png
  98. 0
      sapl/static/sapl/frontend/img/search-gray.png
  99. 0
      sapl/static/sapl/frontend/img/search.png
  100. 0
      sapl/static/sapl/frontend/img/ui-icons_2694e8_256x240.274157b3.png

2
docker-compose.yml

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

7
docs/deploy.rst

@ -24,11 +24,8 @@ Entrar no ambiente virtual::
Arquivos Estáticos
------------------
Com o ambiente em produção, os arquivos estáticos devem ser servidos pelo web service, em nosso caso o `NGINX`, logo para ter acesso aos arquivos primeiro devemos rodar o seguinte comando::
./manage.py compilescss
para que os arquivos SASS/SCSS sejam compilados em arquivos .css em ambiente de produção, e em seguida rode::
Com o ambiente em produção, os arquivos estáticos devem ser servidos pelo web service, em nosso caso o `NGINX`,
em ambiente de produção, para tanto, rode::
./manage.py collectstatic --no-input --clear

24
docs/instalacao31.rst

@ -39,14 +39,14 @@ Instalar o virtualenv usando python 3 para o projeto.
sudo mkdir -p /var/interlegis/.virtualenvs
* Ajustar as permissões - onde ``sapl31`` trocar por usuario::
* Ajustar as permissões::
sudo chown -R sapl31:sapl31 /var/interlegis/
sudo chown -R $USER:$USER /var/interlegis/
* Edite o arquivo ``.bashrc`` e adicione ao seu final as configurações abaixo para o virtualenvwrapper::
nano /home/sapl31/.bashrc
nano /home/$USER/.bashrc
export VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3
export WORKON_HOME=/var/interlegis/.virtualenvs
@ -56,7 +56,7 @@ Instalar o virtualenv usando python 3 para o projeto.
* Carregue as configurações do virtualenvwrapper::
source /home/sapl31/.bashrc
source /home/$USER/.bashrc
@ -116,7 +116,7 @@ Instalação e configuração das dependências do projeto
* (caso você já possua uma instalação do postrgresql anterior ao processo de instalação do ambiente de desenvolvimento do SAPL em sua máquina e sábia como fazer, esteja livre para proceder como desejar, porém, ao configurar o arquivo ``.env`` no próximo passo, as mesmas definições deverão ser usadas)
* **Ajustar as permissões - onde $USER trocar por usuario**::
* **Ajustar as permissões - onde $USER trocar por usuário**::
eval $(echo "sudo chown -R $USER:$USER /var/interlegis/")
@ -225,6 +225,7 @@ Preparação do ambiente::
* **Instalação do NodeJs LTS 10.15.x**::
sudo apt-get install curl
curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt-get install -y nodejs
@ -281,4 +282,15 @@ Feito isso, e você ativando a variável de ambiente FRONTEND_CUSTOM=True (vide
**Deste ponto em diante, é exigido o conhecimento que você pode adquirir em https://cli.vuejs.org/guide/ e em https://vuejs.org/v2/guide/ para colaborar com sapl-frontend**
**OBS: após a separação do sapl para o sapl-frontend, o conteúdo da pasta static é compilado e minificado. É gerado pelo build do sapl-frontend e não deve-se tentar customizar ou criar elementos manipulando diretamente informações na pasta static.**
Sobre a pasta static
--------------------
Após a separação do sapl em sapl e sapl-frontend, o conteúdo da pasta sapl/static/sapl/frontend é compilado e minificado. É gerado pelo build do sapl-frontend e não deve-se tentar customizar ou criar elementos manipulando diretamente informações na pasta sapl/static/sapl/frontend.
Para aplicar css e javascript sem sapl-frontend:
1) Não altere diretamente o conteúdo da pasta sapl/static/sapl/frontend. Isso deve ser feito no projeto sapl-frontend. Você perderá qualquer manipulação dentro desta pasta.
2) Caso venha a criar algum código css/js diretamente no django, crie seus arquivos na pasta sapl/static/sapl.
3) Não crie nenhum novo conteúdo na pasta sapl/static. Projetos Django podem ser usados como app de outro projeto. É o que ocorre com o Sapl, que é usado como uma app em outros projetos. Qualquer conteúdo colocado dentro sapl/static e não em sapl/static/sapl, pode estar causando erro no uso do Sapl como app em outro projeto.

4
docs/solr.rst

@ -1,3 +1,5 @@
**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
================================
@ -22,4 +24,4 @@ Dentro do diretório principal siga os seguintes passos::
Após isso, deve-se parar o servidor do Solr e restartar com ``java -jar start.jar``
**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.**
**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.**

1
requirements/requirements.txt

@ -24,6 +24,7 @@ rtyaml==0.0.5
python-magic==0.4.15
unipath==1.1
WeasyPrint==44
Pillow==5.1.0
gunicorn==19.9.0
textract==1.5.0

59
sapl/base/forms.py

@ -64,19 +64,46 @@ def get_roles():
class UsuarioCreateForm(ModelForm):
logger = logging.getLogger(__name__)
username = forms.CharField(required=True, label="Nome de usuário",
max_length=30)
firstname = forms.CharField(required=True, label="Nome", max_length=30)
lastname = forms.CharField(required=True, label="Sobrenome", max_length=30)
password1 = forms.CharField(required=True, widget=forms.PasswordInput,
label='Senha', max_length=128)
password2 = forms.CharField(required=True, widget=forms.PasswordInput,
label='Confirmar senha', max_length=128)
user_active = forms.ChoiceField(required=False, choices=YES_NO_CHOICES,
label="Usuário ativo?", initial='True')
username = forms.CharField(
required=True,
label="Nome de usuário",
max_length=30
)
firstname = forms.CharField(
required=True,
label="Nome",
max_length=30
)
lastname = forms.CharField(
required=True,
label="Sobrenome",
max_length=30
)
password1 = forms.CharField(
required=True,
widget=forms.PasswordInput,
label='Senha',
min_length=6,
max_length=128
)
password2 = forms.CharField(
required=True,
widget=forms.PasswordInput,
label='Confirmar senha',
min_length=6,
max_length=128
)
user_active = forms.ChoiceField(
required=True,
choices=YES_NO_CHOICES,
label="Usuário ativo?",
initial='True'
)
roles = forms.MultipleChoiceField(
required=True, widget=forms.CheckboxSelectMultiple(), choices=get_roles)
required=True,
widget=forms.CheckboxSelectMultiple(),
choices=get_roles
)
class Meta:
model = get_user_model()
@ -84,7 +111,7 @@ class UsuarioCreateForm(ModelForm):
'password1', 'password2', 'user_active', 'roles']
def clean(self):
super(UsuarioCreateForm, self).clean()
super().clean()
if not self.is_valid():
return self.cleaned_data
@ -99,7 +126,7 @@ class UsuarioCreateForm(ModelForm):
def __init__(self, *args, **kwargs):
super(UsuarioCreateForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
row0 = to_row([('username', 12)])
@ -916,7 +943,9 @@ class RelatorioDataFimPrazoTramitacaoFilterSet(django_filters.FilterSet):
*args, **kwargs)
self.filters['tipo'].label = 'Tipo de Matéria'
self.filters['tramitacao__unidade_tramitacao_local'].label = 'Unidade de tramitação local'
self.filters['tramitacao__status'].label = 'Status de tramitação'
row1 = to_row([('tramitacao__data_fim_prazo', 12)])
row2 = to_row(
[('tipo', 4),

13
sapl/base/templatetags/common_tags.py

@ -1,3 +1,6 @@
from _functools import reduce
import re
from django import template
from django.template.defaultfilters import stringfilter
from django.utils.safestring import mark_safe
@ -9,7 +12,6 @@ from sapl.norma.models import NormaJuridica
from sapl.parlamentares.models import Filiacao
from sapl.utils import filiacao_data, SEPARADOR_HASH_PROPOSICAO
register = template.Library()
@ -286,3 +288,12 @@ def render_chunk_vendors(extension=None):
return mark_safe('\n'.join(tags))
except:
return ''
@register.filter(is_safe=True)
@stringfilter
def dont_break_out(value):
_safe = '<div class="dont-break-out">{}</div>'.format(value)
_safe = mark_safe(_safe)
return _safe

2
sapl/base/tests/test_login.py

@ -13,7 +13,7 @@ def user():
def test_login_aparece_na_barra_para_usuario_nao_logado(client):
response = client.get('/')
assert '<a class="nav-link" href="/login/"><img src="/static/sapl/img/user.png"></a>' in str(
assert '<a class="nav-link" href="/login/"><img src="/static/sapl/frontend/img/user.png"></a>' in str(
response.content)

20
sapl/base/urls.py

@ -8,7 +8,7 @@ from django.contrib.auth.views import (password_reset, password_reset_complete,
password_reset_done)
from django.views.generic.base import RedirectView, TemplateView
from sapl.base.views import AutorCrud, ConfirmarEmailView, TipoAutorCrud
from sapl.base.views import AutorCrud, ConfirmarEmailView, TipoAutorCrud, get_data_ultima_atualizacao
from sapl.settings import EMAIL_SEND_USER, MEDIA_URL
from .apps import AppConfig
@ -31,11 +31,14 @@ from .views import (AlterarSenha, AppConfigCrud, CasaLegislativaCrud,
ListarInconsistenciasView, ListarProtocolosDuplicadosView,
ListarProtocolosComMateriasView,
ListarMatProtocoloInexistenteView,
ListarParlamentaresDuplicadosView,
ListarFiliacoesSemDataFiliacaoView,
ListarMandatoSemDataInicioView,
ListarParlMandatosIntersecaoView,
ListarParlFiliacoesIntersecaoView,
ListarAutoresDuplicadosView,
ListarBancadaComissaoAutorExternoView,
ListarLegislaturaInfindavelView,
ListarMandatoSemDataInicioView)
ListarLegislaturaInfindavelView)
app_name = AppConfig.name
@ -148,12 +151,21 @@ urlpatterns = [
url(r'^sistema/inconsistencias/materias_protocolo_inexistente$',
ListarMatProtocoloInexistenteView.as_view(),
name='lista_materias_protocolo_inexistente'),
url(r'^sistema/inconsistencias/filiacoes_sem_data_filiacao$',
ListarFiliacoesSemDataFiliacaoView.as_view(),
name='lista_filiacoes_sem_data_filiacao'),
url(r'^sistema/inconsistencias/mandato_sem_data_inicio',
ListarMandatoSemDataInicioView.as_view(),
name='lista_mandato_sem_data_inicio'),
url(r'^sistema/inconsistencias/parlamentares_duplicados$',
ListarParlamentaresDuplicadosView.as_view(),
name='lista_parlamentares_duplicados'),
url(r'^sistema/inconsistencias/parlamentares_mandatos_intersecao$',
ListarParlMandatosIntersecaoView.as_view(),
name='lista_parlamentares_mandatos_intersecao'),
url(r'^sistema/inconsistencias/parlamentares_filiacoes_intersecao$',
ListarParlFiliacoesIntersecaoView.as_view(),
name='lista_parlamentares_filiacoes_intersecao'),
url(r'^sistema/inconsistencias/autores_duplicados$',
ListarAutoresDuplicadosView.as_view(),
name='lista_autores_duplicados'),
@ -164,6 +176,8 @@ urlpatterns = [
ListarLegislaturaInfindavelView.as_view(),
name='lista_legislatura_infindavel'),
url(r'^sistema/data_ultima_atualizacao', get_data_ultima_atualizacao),
# todos os sublinks de sistema devem vir acima deste
url(r'^sistema/$', permission_required('base.view_tabelas_auxiliares')
(TemplateView.as_view(template_name='sistema.html')),

168
sapl/base/views.py

@ -14,7 +14,7 @@ from django.core.mail import send_mail
from django.core.urlresolvers import reverse, reverse_lazy
from django.db import connection
from django.db.models import Count, Q, ProtectedError
from django.http import Http404, HttpResponseRedirect
from django.http import Http404, HttpResponseRedirect, JsonResponse
from django.template import TemplateDoesNotExist
from django.template.loader import get_template
from django.utils import timezone
@ -37,7 +37,7 @@ from sapl.crud.base import CrudAux, make_pagination
from sapl.materia.models import (Autoria, MateriaLegislativa, Proposicao,
TipoMateriaLegislativa, StatusTramitacao, UnidadeTramitacao)
from sapl.norma.models import (NormaJuridica, NormaEstatisticas)
from sapl.parlamentares.models import Parlamentar, Legislatura, Mandato
from sapl.parlamentares.models import Parlamentar, Legislatura, Mandato, Filiacao
from sapl.protocoloadm.models import Protocolo
from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria,
SessaoPlenariaPresenca, Bancada)
@ -949,18 +949,36 @@ class ListarInconsistenciasView(PermissionRequiredMixin, ListView):
len(materias_protocolo_inexistente())
)
)
tabela.append(
('filiacoes_sem_data_filiacao',
'Filiações sem data filiação',
len(filiacoes_sem_data_filiacao())
)
)
tabela.append(
('mandato_sem_data_inicio',
'Mandatos sem data inicial',
len(mandato_sem_data_inicio())
)
)
tabela.append(
('parlamentares_duplicados',
'Parlamentares duplicados',
len(parlamentares_duplicados())
)
)
tabela.append(
('parlamentares_mandatos_intersecao',
'Parlamentares com mandatos com interseção',
'Parlamentares com mandatos em interseção',
len(parlamentares_mandatos_intersecao())
)
)
tabela.append(
('parlamentares_filiacoes_intersecao',
'Parlamentares com filiações em interseção',
len(parlamentares_filiacoes_intersecao())
)
)
tabela.append(
('autores_duplicados',
'Autores duplicados',
@ -1057,12 +1075,14 @@ class ListarBancadaComissaoAutorExternoView(PermissionRequiredMixin, ListView):
page_obj.number, paginator.num_pages)
context[
'NO_ENTRIES_MSG'
] = 'Nenhum encontrado.'
] = 'Nenhuma encontrada.'
return context
def autores_duplicados():
return [autor.values() for autor in Autor.objects.values('nome', 'tipo__descricao').annotate(count=Count('nome')).filter(count__gt=1)]
return [autor.values() for autor in Autor.objects.values(
'nome', 'tipo__descricao').order_by(
"nome").annotate(count=Count('nome')).filter(count__gt=1)]
class ListarAutoresDuplicadosView(PermissionRequiredMixin, ListView):
@ -1088,10 +1108,56 @@ class ListarAutoresDuplicadosView(PermissionRequiredMixin, ListView):
return context
def parlamentares_filiacoes_intersecao():
intersecoes = []
for parlamentar in Parlamentar.objects.all().order_by('nome_parlamentar'):
filiacoes = parlamentar.filiacao_set.all()
combinacoes = itertools.combinations(filiacoes, 2)
for c in combinacoes:
data_filiacao1 = c[0].data
data_desfiliacao1 = c[0].data_desfiliacao if c[0].data_desfiliacao else timezone.now().date()
data_filiacao2 = c[1].data
data_desfiliacao2 = c[1].data_desfiliacao if c[1].data_desfiliacao else timezone.now().date()
if data_filiacao1 and data_filiacao2:
exists = intervalos_tem_intersecao(
data_filiacao1, data_desfiliacao1,
data_filiacao2, data_desfiliacao2)
if exists:
intersecoes.append((parlamentar, c[0], c[1]))
return intersecoes
class ListarParlFiliacoesIntersecaoView(PermissionRequiredMixin, ListView):
model = get_user_model()
template_name = 'base/parlamentares_filiacoes_intersecao.html'
context_object_name = 'parlamentares_filiacoes_intersecao'
permission_required = ('base.list_appconfig',)
paginate_by = 10
def get_queryset(self):
return parlamentares_filiacoes_intersecao()
def get_context_data(self, **kwargs):
context = super(
ListarParlFiliacoesIntersecaoView, self).get_context_data(**kwargs)
paginator = context['paginator']
page_obj = context['page_obj']
context['page_range'] = make_pagination(
page_obj.number, paginator.num_pages)
context[
'NO_ENTRIES_MSG'
] = 'Nenhum encontrado.'
return context
def parlamentares_mandatos_intersecao():
intersecoes = []
for parlamentar in Parlamentar.objects.all().order_by('nome_completo'):
for parlamentar in Parlamentar.objects.all().order_by('nome_parlamentar'):
mandatos = parlamentar.mandato_set.all()
combinacoes = itertools.combinations(mandatos, 2)
@ -1135,10 +1201,59 @@ class ListarParlMandatosIntersecaoView(PermissionRequiredMixin, ListView):
return context
def parlamentares_duplicados():
return [parlamentar.values() for parlamentar in Parlamentar.objects.values(
'nome_parlamentar').order_by('nome_parlamentar').annotate(count=Count(
'nome_parlamentar')).filter(count__gt=1)]
class ListarParlamentaresDuplicadosView(PermissionRequiredMixin, ListView):
model = get_user_model()
template_name = 'base/parlamentares_duplicados.html'
context_object_name = 'parlamentares_duplicados'
permission_required = ('base.list_appconfig',)
paginate_by = 10
def get_queryset(self):
return parlamentares_duplicados()
def get_context_data(self, **kwargs):
context = super(
ListarParlamentaresDuplicadosView, self).get_context_data(**kwargs)
paginator = context['paginator']
page_obj = context['page_obj']
context['page_range'] = make_pagination(
page_obj.number, paginator.num_pages)
context[
'NO_ENTRIES_MSG'
] = 'Nenhum encontrado.'
return context
def mandato_sem_data_inicio():
return Mandato.objects.filter(data_inicio_mandato__isnull=True).order_by('parlamentar')
def get_data_ultima_atualizacao(request):
datas = [MateriaLegislativa.objects.all().
order_by('-data_ultima_atualizacao').
values_list('data_ultima_atualizacao', flat=True).
first(),
NormaJuridica.objects.all().
order_by('-data_ultima_atualizacao').
values_list('data_ultima_atualizacao', flat=True).
first()]
max_data = ''
if datas[0] and datas[1]:
max_data = max(datas)
else:
max_data = next([i for i in datas if i is not None], '')
return JsonResponse({'data_ultima_atualizacao': max_data})
class ListarMandatoSemDataInicioView(PermissionRequiredMixin, ListView):
model = get_user_model()
template_name = 'base/mandato_sem_data_inicio.html'
@ -1159,7 +1274,35 @@ class ListarMandatoSemDataInicioView(PermissionRequiredMixin, ListView):
page_obj.number, paginator.num_pages)
context[
'NO_ENTRIES_MSG'
] = 'Nenhum encontrada.'
] = 'Nenhum encontrado.'
return context
def filiacoes_sem_data_filiacao():
return Filiacao.objects.filter(data__isnull=True).order_by('parlamentar')
class ListarFiliacoesSemDataFiliacaoView(PermissionRequiredMixin, ListView):
model = get_user_model()
template_name = 'base/filiacoes_sem_data_filiacao.html'
context_object_name = 'filiacoes_sem_data_filiacao'
permission_required = ('base.list_appconfig',)
paginate_by = 10
def get_queryset(self):
return filiacoes_sem_data_filiacao()
def get_context_data(self, **kwargs):
context = super(
ListarFiliacoesSemDataFiliacaoView, self
).get_context_data(**kwargs)
paginator = context['paginator']
page_obj = context['page_obj']
context['page_range'] = make_pagination(
page_obj.number, paginator.num_pages)
context[
'NO_ENTRIES_MSG'
] = 'Nenhuma encontrada.'
return context
@ -1244,6 +1387,7 @@ def protocolos_duplicados():
return [(v[0], len(v)) for (k, v) in protocolos.items() if len(v) > 1]
class ListarProtocolosDuplicadosView(PermissionRequiredMixin, ListView):
model = get_user_model()
template_name = 'base/protocolos_duplicados.html'
@ -1329,17 +1473,19 @@ class CreateUsuarioView(PermissionRequiredMixin, CreateView):
model = get_user_model()
form_class = UsuarioCreateForm
success_message = 'Usuário criado com sucesso!'
fail_message = 'Usuário não criado!'
permission_required = ('base.add_appconfig',)
def get_success_url(self):
return reverse('sapl.base:usuario')
def form_valid(self, form):
data = form.cleaned_data
new_user = get_user_model().objects.create(
username=data['username'], email=data['email'])
username=data['username'],
email=data['email']
)
new_user.first_name = data['firstname']
new_user.last_name = data['lastname']
new_user.set_password(data['password1'])
@ -1354,6 +1500,10 @@ class CreateUsuarioView(PermissionRequiredMixin, CreateView):
messages.success(self.request, self.success_message)
return HttpResponseRedirect(self.get_success_url())
def form_invalid(self, form):
messages.error(self.request, self.fail_message)
return super().form_invalid(form)
class DeleteUsuarioView(PermissionRequiredMixin, DeleteView):
model = get_user_model()

12
sapl/compilacao/views.py

@ -2933,6 +2933,7 @@ class DispositivoDinamicEditView(
class DispositivoSearchFragmentFormView(ListView):
template_name = 'compilacao/dispositivo_form_search_fragment.html'
logger = logging.getLogger(__name__)
def get(self, request, *args, **kwargs):
@ -2955,14 +2956,20 @@ class DispositivoSearchFragmentFormView(ListView):
messages.info(
request, _('Não foram encontrados resultados '
'com seus critérios de busca!'))
username = self.request.user.username
self.logger.error("user=" + username + ". Não foram encontrados "
"resultados com esses critérios de busca. "
"id_tipo_ta=".format(request.GET['tipo_ta']))
try:
r = response.render()
return response
except Exception as e:
messages.error(request, "Erro - %s" % e)
messages.error(request, "Erro - %s" % str(e))
context = {}
self.template_name = 'compilacao/messages.html'
username = self.request.user.username
self.logger.error("user=" + username + ". " + str(e))
return self.render_to_response(context)
def get_queryset(self):
@ -3134,7 +3141,8 @@ class DispositivoSearchFragmentFormView(ListView):
return r
except Exception as e:
print(e)
username = self.request.user.username
self.logger.error("user=" + username + ". " + str(e))
class DispositivoSearchModalView(FormView):

1
sapl/crispy_layout_mixin.py

@ -166,6 +166,7 @@ def get_field_display(obj, fieldname):
value)
elif 'TextField' in str_type_from_field:
display = value.replace('\n', '<br/>')
display = '<div class="dont-break-out">{}</div>'.format(display)
else:
display = str(value)
return verbose_name, display

61
sapl/lexml/OAIServer.py

@ -9,7 +9,7 @@ from lxml import etree
from lxml.builder import ElementMaker
from sapl.base.models import AppConfig, CasaLegislativa
from sapl.lexml.models import LexmlPublicador
from sapl.lexml.models import LexmlPublicador, LexmlProvedor
from sapl.norma.models import NormaJuridica
@ -26,8 +26,9 @@ class OAILEXML:
def __call__(self, element, metadata):
data = metadata.record
value = etree.XML(data['metadata'])
element.append(value)
if data['metadata']:
value = etree.XML(data['metadata'])
element.append(value)
class OAIServer:
@ -54,7 +55,7 @@ class OAIServer:
granularity='YYYY-MM-DDThh:mm:ssZ',
compression=['identity'],
toolkit_description=False)
if not self.config['descricao']:
if self.config['descricao']:
result.add_description(self.config['descricao'])
return result
@ -64,22 +65,22 @@ class OAIServer:
metadata.record = record
return header, metadata
def list_query(self, from_date=None, until_date=None, offset=0, batch_size=10, identifier=None):
def list_query(self, from_=None, until=None, offset=0, batch_size=10, identifier=None):
if identifier:
identifier = int(identifier.split('/')[-1]) # Get internal id
else:
identifier = ''
until_date = datetime.now() if not until_date or until_date > datetime.now() else until_date
return self.oai_query(offset=offset, batch_size=batch_size, from_date=from_date, until_date=until_date,
until = datetime.now() if not until or until > datetime.now() else until
return self.oai_query(offset=offset, batch_size=batch_size, from_=from_, until=until,
identifier=identifier)
def check_metadata_prefix(self, metadata_prefix):
if not metadata_prefix in self.config['metadata_prefixes']:
raise oaipmh.error.CannotDisseminateFormatError
def listRecords(self, metadataPrefix, from_date=None, until_date=None, cursor=0, batch_size=10):
def listRecords(self, metadataPrefix, from_=None, until=None, cursor=0, batch_size=10):
self.check_metadata_prefix(metadataPrefix)
for record in self.list_query(from_date, until_date, cursor, batch_size):
for record in self.list_query(from_, until, cursor, batch_size):
header, metadata = self.create_header_and_metadata(record)
yield header, metadata, None # None?
@ -98,10 +99,10 @@ class OAIServer:
appconfig = AppConfig.objects.first()
return appconfig.esfera_federacao
def recupera_norma(self, offset, batch_size, from_date, until_date, identifier, esfera):
kwargs = {'data__lte': until_date}
if from_date:
kwargs['data__gte'] = from_date
def recupera_norma(self, offset, batch_size, from_, until, identifier, esfera):
kwargs = {'data__lte': until}
if from_:
kwargs['data__gte'] = from_
if identifier:
kwargs['numero'] = identifier
if esfera:
@ -144,9 +145,9 @@ class OAIServer:
else:
urn += '{};'.format(norma.data.isoformat())
if norma.tipo.equivalente_lexml == 'lei.organica' or norma.tipo.equivalente_lexml == 'constituicao':
urn += norma.ano
urn += str(norma.ano)
else:
urn += norma.numero
urn += str(norma.numero)
if norma.data_vigencia and norma.data_publicacao:
urn += '@{};publicacao;{}'.format(norma.data_vigencia.isoformat(), norma.data_publicacao.isoformat())
elif norma.data_publicacao:
@ -213,12 +214,12 @@ class OAIServer:
else:
return None
def oai_query(self, offset=0, batch_size=10, from_date=None, until_date=None, identifier=None):
def oai_query(self, offset=0, batch_size=10, from_=None, until=None, identifier=None):
esfera = self.get_esfera_federacao()
offset = 0 if offset < 0 else offset
batch_size = 10 if batch_size < 0 else batch_size
until_date = datetime.now() if not until_date or until_date > datetime.now() else until_date
normas = self.recupera_norma(offset, batch_size, from_date, until_date, identifier, esfera)
until = datetime.now() if not until or until > datetime.now() else until
normas = self.recupera_norma(offset, batch_size, from_, until, identifier, esfera)
for norma in normas:
resultado = {}
identificador = self.monta_id(norma)
@ -257,16 +258,28 @@ def casa_legislativa():
return casa if casa else CasaLegislativa() # retorna objeto dummy
def get_xml_provedor():
""" antigo get_descricao_casa() """
descricao = ''
provedor = LexmlProvedor.objects.first()
if provedor:
descricao = provedor.xml
if descricao:
descricao = descricao.encode('utf-8')
return descricao
def get_config(url, batch_size):
config = {'content_type': None,
'delay': 0,
'base_asset_path': None,
'metadata_prefixes': ['oai_lexml']}
config.update({'titulo': casa_legislativa().nome, # Inicializa variável global casa
'email': casa.email,
'base_url': url[:url.find('/', 8)],
'descricao': casa.informacao_geral,
'batch_size': batch_size})
'metadata_prefixes': ['oai_lexml'],
'titulo': casa_legislativa().nome, # Inicializa variável global casa
'email': [casa.email], # lista de e-mails, antigo `def get_email()`
'base_url': url[:url.find('/', 8)] + reverse('sapl.lexml:lexml_endpoint')[:-4], # remove '/oai' suffix
'descricao': get_xml_provedor(),
'batch_size': batch_size
}
return config

6
sapl/lexml/models.py

@ -23,6 +23,12 @@ class LexmlProvedor(models.Model): # LexmlRegistroProvedor
blank=True,
verbose_name=_('XML fornecido pela equipe do LexML:'))
@property
def pretty_xml(self):
import html
safe_xml = html.escape(self.xml)
return safe_xml.replace('\n', '<br/>').replace(' ', '&nbsp;')
class Meta:
verbose_name = _('Provedor Lexml')
verbose_name_plural = _('Provedores Lexml')

6
sapl/lexml/urls.py

@ -1,6 +1,6 @@
from django.conf.urls import include, url
from sapl.lexml.views import LexmlProvedorCrud, LexmlPublicadorCrud, lexml_request
from sapl.lexml.views import LexmlProvedorCrud, LexmlPublicadorCrud, lexml_request, request_search
from .apps import AppConfig
@ -11,5 +11,7 @@ urlpatterns = [
include(LexmlProvedorCrud.get_urls())),
url(r'^sistema/lexml/publicador/',
include(LexmlPublicadorCrud.get_urls())),
url(r'^sistema/lexml', lexml_request, name='lexml_endpoint')
url(r'^sistema/lexml/request_search/(?P<keyword>[\w\-]+)/', request_search, name='lexml_search'),
url(r'^sistema/lexml/oai', lexml_request, name='lexml_endpoint'),
]

22
sapl/lexml/views.py

@ -1,18 +1,30 @@
from django.http import HttpResponse
from django.shortcuts import render
from sapl.crud.base import CrudAux
from sapl.crud.base import CrudAux, Crud
from sapl.lexml.OAIServer import OAIServerFactory, get_config
from sapl.rules import RP_DETAIL, RP_LIST
from .models import LexmlProvedor, LexmlPublicador
LexmlProvedorCrud = CrudAux.build(LexmlProvedor, 'lexml_provedor')
LexmlPublicadorCrud = CrudAux.build(LexmlPublicador, 'lexml_publicador')
class LexmlProvedorCrud(Crud):
model = LexmlProvedor
help_topic = 'lexml_provedor'
public = [RP_LIST, RP_DETAIL]
class DetailView(Crud.DetailView):
layout_key = 'LexmlProvedorDetail'
def lexml_request(request):
config = get_config(request.get_raw_uri(), int(request.GET.get('batch_size', 10)))
config = get_config(request.get_raw_uri(), int(request.GET.get('batch_size', '10')))
oai_server = OAIServerFactory(config)
r = oai_server.handleRequest({'verb': request.GET.get('verb', 'ListRecords'),
'metadataPrefix': request.GET.get('metadataPrefix', 'oai_lexml')})
r = oai_server.handleRequest(request.GET)
response = r.decode('UTF-8')
return HttpResponse(response, content_type='text/xml')
def request_search(request, keyword):
return render(request, "lexml/resultado-pesquisa.html", {"keyword": keyword})

48
sapl/materia/forms.py

@ -26,7 +26,7 @@ import django_filters
import sapl
from sapl.base.models import AppConfig, Autor, TipoAutor
from sapl.comissoes.models import Comissao
from sapl.comissoes.models import Comissao, Participacao
from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_PUBLIC,
STATUS_TA_PRIVATE)
from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column,
@ -204,7 +204,7 @@ class MateriaLegislativaForm(FileFieldCheckMixin, ModelForm):
widget=forms.HiddenInput())
self.fields['autor'] = forms.CharField(required=False,
widget=forms.HiddenInput())
if kwargs['instance'].numero_protocolo:
if kwargs['instance'].numero_protocolo and Protocolo.objects.filter(numero=kwargs['instance'].numero_protocolo, ano=kwargs['instance'].ano).exists():
self.fields['numero_protocolo'].widget.attrs['readonly'] = True
def clean(self):
@ -340,16 +340,14 @@ class AcompanhamentoMateriaForm(ModelForm):
def __init__(self, *args, **kwargs):
row1 = to_row([('email', 10)])
row1.append(
Column(form_actions(label='Cadastrar'), css_class='col-md-2')
)
row1 = to_row([('email', 12)])
self.helper = SaplFormHelper()
self.helper.layout = Layout(
Fieldset(
_('Acompanhamento de Matéria por e-mail'), row1
_('Acompanhamento de Matéria por e-mail'),
row1,
form_actions(label='Cadastrar')
)
)
super(AcompanhamentoMateriaForm, self).__init__(*args, **kwargs)
@ -375,7 +373,7 @@ class RelatoriaForm(ModelForm):
widgets = {'comissao': forms.Select(attrs={'disabled': 'disabled'})}
def __init__(self, *args, **kwargs):
super(RelatoriaForm, self).__init__(*args, **kwargs)
super().__init__(*args, **kwargs)
def clean(self):
super(RelatoriaForm, self).clean()
@ -425,7 +423,7 @@ class TramitacaoForm(ModelForm):
super(TramitacaoForm, self).__init__(*args, **kwargs)
self.fields['data_tramitacao'].initial = timezone.now().date()
ust = UnidadeTramitacao.objects.select_related().all()
unidade_tramitacao_destino = [(ut.pk, ut) for ut in ust if ut.comissao and ut.comissao.ativa]
unidade_tramitacao_destino = [('', '---------')]+[(ut.pk, ut) for ut in ust if ut.comissao and ut.comissao.ativa]
unidade_tramitacao_destino.extend([(ut.pk, ut) for ut in ust if ut.orgao])
unidade_tramitacao_destino.extend([(ut.pk, ut) for ut in ust if ut.parlamentar])
self.fields['unidade_tramitacao_destino'].choices = unidade_tramitacao_destino
@ -1142,6 +1140,29 @@ class AcessorioEmLoteFilterSet(django_filters.FilterSet):
Fieldset(_('Documentos Acessórios em Lote'),
row1, row2, form_actions(label='Pesquisar')))
class AnexadaEmLoteFilterSet(django_filters.FilterSet):
class Meta(FilterOverridesMetaMixin):
model = MateriaLegislativa
fields = ['tipo', 'data_apresentacao']
def __init__(self, *args, **kwargs):
super(AnexadaEmLoteFilterSet, self).__init__(*args, **kwargs)
self.filters['tipo'].label = 'Tipo de Matéria'
self.filters['data_apresentacao'].label = 'Data (Inicial - Final)'
self.form.fields['tipo'].required = True
self.form.fields['data_apresentacao'].required = True
row1 = to_row([('tipo', 12)])
row2 = to_row([('data_apresentacao', 12)])
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Matéria Anexada em Lote'),
row1, row2, form_actions(label='Pesquisar')))
class PrimeiraTramitacaoEmLoteFilterSet(django_filters.FilterSet):
@ -1700,9 +1721,6 @@ class ConfirmarProposicaoForm(ProposicaoForm):
attrs={'readonly': 'readonly', 'rows': 4}),
'data_envio': widgets.DateTimeInput(
attrs={'readonly': 'readonly'}),
'numero_materia_futuro': widgets.NumberInput(
attrs={'readonly': 'readonly', 'rows': 1}),
}
def __init__(self, *args, **kwargs):
@ -1739,9 +1757,7 @@ class ConfirmarProposicaoForm(ProposicaoForm):
self._meta.fields.remove('regime_tramitacao')
# esta chamada isola o __init__ de ProposicaoForm
super(ProposicaoForm, self).__init__(*args, **kwargs)
self.fields['numero_materia_futuro'].widget.attrs['readonly'] = True
super(ProposicaoForm, self).__init__(*args, **kwargs)
fields = [
Fieldset(

3
sapl/materia/urls.py

@ -8,6 +8,7 @@ from sapl.materia.views import (AcompanhamentoConfirmarView,
CriarProtocoloMateriaView, DespachoInicialCrud,
DocumentoAcessorioCrud,
DocumentoAcessorioEmLoteView,
MateriaAnexadaEmLoteView,
EtiquetaPesquisaView, FichaPesquisaView,
FichaSelecionaView, ImpressosView,
LegislacaoCitadaCrud, MateriaAssuntoCrud,
@ -93,6 +94,8 @@ urlpatterns_materia = [
url(r'^materia/acessorio-em-lote', DocumentoAcessorioEmLoteView.as_view(),
name='acessorio_em_lote'),
url(r'^materia/(?P<pk>\d+)/anexada-em-lote', MateriaAnexadaEmLoteView.as_view(),
name='anexada_em_lote'),
url(r'^materia/primeira-tramitacao-em-lote',
PrimeiraTramitacaoEmLoteView.as_view(),
name='primeira_tramitacao_em_lote'),

145
sapl/materia/views.py

@ -51,6 +51,7 @@ from sapl.utils import (YES_NO_CHOICES, autor_label, autor_modal, SEPARADOR_HASH
show_results_filter_set, mail_service_configured)
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
AnexadaEmLoteFilterSet,
AdicionarVariasAutoriasFilterSet, DespachoInicialForm,
DocumentoAcessorioForm, EtiquetaPesquisaForm,
FichaPesquisaForm, FichaSelecionaForm, MateriaAssuntoForm,
@ -1114,8 +1115,7 @@ class RelatoriaCrud(MasterDetailCrud):
try:
self.logger.debug("user=" + username + ". Tentando obter objeto Comissao de pk={}.".format(
context['form'].initial['comissao']))
comissao = Comissao.objects.get(
pk=context['form'].initial['comissao'])
comissao = Comissao.objects.get(pk=context['form'].initial['comissao'])
except:
self.logger.error("user=" + username + ". Objeto Comissão de pk={} não encontrado.".format(
context['form'].initial['comissao']))
@ -1124,17 +1124,20 @@ class RelatoriaCrud(MasterDetailCrud):
else:
self.logger.info("user=" + username + ". Objeto Comissao de pk={} obtido com sucesso.".format(
context['form'].initial['comissao']))
composicao = comissao.composicao_set.order_by(
'-periodo__data_inicio').first()
participacao = Participacao.objects.filter(
composicao=composicao)
parlamentares = []
parlamentares.append(['', '---------'])
for p in participacao:
if p.titular:
parlamentares.append(
[p.parlamentar.id, p.parlamentar.nome_parlamentar])
materia = MateriaLegislativa.objects.get(pk=self.kwargs.get('pk'))
ano_materia = materia.ano
comissao = Comissao.objects.get(pk=context['form'].initial['comissao'])
composicoes = comissao.composicao_set.all()
composicao = comissao.composicao_set.filter(periodo__data_inicio__year=ano_materia)
participacoes = Participacao.objects.select_related().filter(composicao=composicao)
parlamentares = [('', '---------')] + [
(participacao.parlamentar.id, participacao.parlamentar.nome_parlamentar) for participacao in
participacoes if participacao.titular]
context['form'].fields['parlamentar'].choices = parlamentares
return context
@ -1178,13 +1181,19 @@ class RelatoriaCrud(MasterDetailCrud):
else:
self.logger.info("user=" + username + ". Objeto Comissao de pk={} obtido com sucesso.".format(
context['form'].initial['comissao']))
composicao = comissao.composicao_set.order_by(
'-periodo__data_inicio').first()
participacao = Participacao.objects.filter(
composicao=composicao)
parlamentares = [[p.parlamentar.id, p.parlamentar.nome_parlamentar] for
p in participacao if p.titular]
relatoria = Relatoria.objects.select_related('materia').get(pk=self.kwargs.get('pk'))
ano_materia = relatoria.materia.ano
comissao = Comissao.objects.get(pk=context['form'].initial['comissao'])
composicoes = comissao.composicao_set.all()
composicao = comissao.composicao_set.filter(periodo__data_inicio__year=ano_materia)
participacoes = Participacao.objects.select_related().filter(composicao=composicao)
parlamentares = [('', '---------')] + [
(participacao.parlamentar.id, participacao.parlamentar.nome_parlamentar) for participacao in
participacoes if participacao.titular]
context['form'].fields['parlamentar'].choices = parlamentares
@ -1921,19 +1930,50 @@ class AcompanhamentoMateriaView(CreateView):
confirmar o acompanhamento desta matéria.')
messages.add_message(request, messages.SUCCESS, msg)
# Se o elemento existir e o email não foi confirmado:
# gerar novo hash e reenviar mensagem de email
elif not acompanhar[0].confirmado:
acompanhar = acompanhar[0]
acompanhar.hash = hash_txt
acompanhar.save()
base_url = get_base_url(request)
destinatario = AcompanhamentoMateria.objects.get(
materia=materia,
email=email,
confirmado=False
)
casa = CasaLegislativa.objects.first()
do_envia_email_confirmacao(base_url,
casa,
"materia",
materia,
destinatario)
self.logger.debug('user=' + usuario.username + '. Foi enviado um e-mail de confirmação. Confira sua caixa \
de mensagens e clique no link que nós enviamos para \
confirmar o acompanhamento desta matéria.')
msg = _('Foi enviado um e-mail de confirmação. Confira sua caixa \
de mensagens e clique no link que nós enviamos para \
confirmar o acompanhamento desta matéria.')
messages.add_message(request, messages.SUCCESS, msg)
# Caso esse Acompanhamento já exista
# avisa ao usuário que essa matéria já está sendo acompanhada
else:
self.logger.debug("user=" + usuario.username +
". Este e-mail já está acompanhando essa matéria.")
msg = _('Este e-mail já está acompanhando essa matéria.')
messages.add_message(request, messages.INFO, msg)
messages.add_message(request, messages.ERROR, msg)
return self.render_to_response(
{'form': form,
'materia': materia,
'error': _('Essa matéria já está\
sendo acompanhada por este e-mail.')})
'materia': materia
})
return HttpResponseRedirect(self.get_success_url())
else:
return self.render_to_response(
@ -1996,6 +2036,65 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
messages.add_message(request, messages.SUCCESS, msg)
return self.get(request, self.kwargs)
class MateriaAnexadaEmLoteView(PermissionRequiredMixin, FilterView):
filterset_class = AnexadaEmLoteFilterSet
template_name = 'materia/em_lote/anexada.html'
permission_required = ('materia.add_documentoacessorio',)
def get_context_data(self, **kwargs):
context = super(MateriaAnexadaEmLoteView,
self).get_context_data(**kwargs)
context['root_pk'] = self.kwargs['pk']
context['subnav_template_name'] = 'materia/subnav.yaml'
context['title'] = _('Matérias Anexadas em Lote')
# Verifica se os campos foram preenchidos
if not self.filterset.form.is_valid():
return context
qr = self.request.GET.copy()
context['object_list'] = context['object_list'].order_by(
'ano', 'numero')
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
context['show_results'] = show_results_filter_set(qr)
return context
def post(self, request, *args, **kwargs):
marcadas = request.POST.getlist('materia_id')
if len(marcadas) == 0:
msg = _('Nenhuma máteria foi selecionada.')
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
data_anexacao = datetime.strptime(
request.POST['data_anexacao'], "%d/%m/%Y").date()
if request.POST['data_desanexacao'] == '':
data_desanexacao = None
else:
data_desanexacao = datetime.strptime(
request.POST['data_desanexacao'], "%d/%m/%Y").date()
principal = MateriaLegislativa.objects.get(pk = kwargs['pk'])
for materia in MateriaLegislativa.objects.filter(id__in = marcadas):
anexada = Anexada()
anexada.materia_principal = principal
anexada.materia_anexada = materia
anexada.data_anexacao = data_anexacao
anexada.data_desanexacao = data_desanexacao
anexada.save()
msg = _('Materia(s) anexada(s).')
messages.add_message(request, messages.SUCCESS, msg)
return self.get(request, self.kwargs)
class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
filterset_class = PrimeiraTramitacaoEmLoteFilterSet

24
sapl/parlamentares/forms.py

@ -20,6 +20,7 @@ from sapl.utils import FileFieldCheckMixin
from sapl.base.models import Autor, TipoAutor
from sapl.crispy_layout_mixin import form_actions, to_row
from sapl.rules import SAPL_GROUP_VOTANTE
import django_filters
from .models import (ComposicaoColigacao, Filiacao, Frente, Legislatura,
Mandato, Parlamentar, Votante)
@ -210,6 +211,29 @@ class ParlamentarForm(FileFieldCheckMixin, ModelForm):
attrs={'id': 'texto-rico'})}
class ParlamentarFilterSet(django_filters.FilterSet):
nome_parlamentar = django_filters.CharFilter(
label=_('Nome do Parlamentar'),
lookup_expr='icontains')
class Meta:
model = Parlamentar
fields = ['nome_parlamentar']
def __init__(self, *args, **kwargs):
super(ParlamentarFilterSet, self).__init__(*args, **kwargs)
row0 = to_row([('nome_parlamentar', 12)])
self.form.helper = SaplFormHelper()
self.form.helper.form_method = 'GET'
self.form.helper.layout = Layout(
Fieldset(_('Pesquisa de Parlamentar'),
row0,
form_actions(label='Pesquisar'))
)
class ParlamentarCreateForm(ParlamentarForm):
legislatura = forms.ModelChoiceField(

8
sapl/parlamentares/urls.py

@ -17,7 +17,9 @@ from sapl.parlamentares.views import (CargoMesaCrud, ColigacaoCrud,
frente_atualiza_lista_parlamentares,
insere_parlamentar_composicao,
parlamentares_frente_selected,
remove_parlamentar_composicao)
remove_parlamentar_composicao,
parlamentares_filiados,
PesquisarParlamentarView)
from .apps import AppConfig
@ -33,6 +35,9 @@ urlpatterns = [
VotanteView.get_urls()
)),
url(r'^parlamentar/pesquisar-parlamentar/',
PesquisarParlamentarView.as_view(), name='pesquisar_parlamentar'),
url(r'^parlamentar/(?P<pk>\d+)/materias$',
ParlamentarMateriasView.as_view(), name='parlamentar_materias'),
@ -60,6 +65,7 @@ urlpatterns = [
url(r'^sistema/parlamentar/tipo-militar/',
include(TipoMilitarCrud.get_urls())),
url(r'^sistema/parlamentar/partido/', include(PartidoCrud.get_urls())),
url(r'^sistema/parlamentar/partido/(?P<pk>\d+)/filiados$', parlamentares_filiados, name='parlamentares_filiados'),
url(r'^sistema/mesa-diretora/sessao-legislativa/',
include(SessaoLegislativaCrud.get_urls())),

79
sapl/parlamentares/views.py

@ -10,6 +10,7 @@ from django.db.models import F, Q
from django.db.models.aggregates import Count
from django.http import JsonResponse
from django.http.response import HttpResponseRedirect
from django.shortcuts import render
from django.templatetags.static import static
from django.utils import timezone
from django.utils.datastructures import MultiValueDictKeyError
@ -17,20 +18,22 @@ from django.utils.translation import ugettext_lazy as _
from django.views.decorators.clickjacking import xframe_options_exempt
from django.views.generic import FormView
from django.views.generic.edit import UpdateView
from django_filters.views import FilterView
from image_cropping.utils import get_backend
from sapl.base.forms import SessaoLegislativaForm, PartidoForm
from sapl.base.models import Autor
from sapl.comissoes.models import Participacao
from sapl.crud.base import (RP_CHANGE, RP_DETAIL, RP_LIST, Crud, CrudAux,
CrudBaseForListAndDetailExternalAppView,
MasterDetailCrud)
MasterDetailCrud, make_pagination)
from sapl.materia.models import Autoria, Proposicao, Relatoria
from sapl.parlamentares.apps import AppConfig
from sapl.utils import parlamentares_ativos
from sapl.utils import (parlamentares_ativos, show_results_filter_set)
from .forms import (FiliacaoForm, FrenteForm, LegislaturaForm, MandatoForm,
ParlamentarCreateForm, ParlamentarForm, VotanteForm)
ParlamentarCreateForm, ParlamentarForm, VotanteForm, ParlamentarFilterSet)
from .models import (CargoMesa, Coligacao, ComposicaoColigacao, ComposicaoMesa,
Dependente, Filiacao, Frente, Legislatura, Mandato,
NivelInstrucao, Parlamentar, Partido, SessaoLegislativa,
@ -164,6 +167,63 @@ class ProposicaoParlamentarCrud(CrudBaseForListAndDetailExternalAppView):
_('Texto Eletrônico'))
class PesquisarParlamentarView(FilterView):
model = Parlamentar
filterset_class = ParlamentarFilterSet
paginate_by = 10
def get_filterset_kwargs(self, filterset_class):
super(PesquisarParlamentarView,
self).get_filterset_kwargs(filterset_class)
kwargs = {'data': self.request.GET or None}
qs = self.get_queryset().order_by('nome_parlamentar').distinct()
kwargs.update({
'queryset': qs,
})
return kwargs
def get_context_data(self, **kwargs):
context = super(PesquisarParlamentarView,
self).get_context_data(**kwargs)
paginator = context['paginator']
page_obj = context['page_obj']
context['page_range'] = make_pagination(
page_obj.number, paginator.num_pages)
context['NO_ENTRIES_MSG'] = 'Nenhum parlamentar encontrado!'
context['title'] = _('Parlamentares')
return context
def get(self, request, *args, **kwargs):
super(PesquisarParlamentarView, self).get(request)
data = self.filterset.data
url = ''
if data:
url = "&" + str(self.request.environ['QUERY_STRING'])
if url.startswith("&page"):
ponto_comeco = url.find('nome_parlamentar=') - 1
url = url[ponto_comeco:]
context = self.get_context_data(filter=self.filterset,
object_list=self.object_list,
filter_url=url,
numero_res=len(self.object_list)
)
context['show_results'] = show_results_filter_set(
self.request.GET.copy())
return self.render_to_response(context)
class ParticipacaoParlamentarCrud(CrudBaseForListAndDetailExternalAppView):
model = Participacao
parent_field = 'parlamentar'
@ -688,6 +748,19 @@ class ParlamentarMateriasView(FormView):
})
def get_data_filicao(parlamentar):
return parlamentar.filiacao_set.order_by('-data').first().data.strftime('%d/%m/%Y')
def parlamentares_filiados(request, pk):
template_name = 'parlamentares/partido_filiados.html'
parlamentares = Parlamentar.objects.all()
partido = Partido.objects.get(pk=pk)
parlamentares_filiados = [(parlamentar, get_data_filicao(parlamentar)) for parlamentar in parlamentares if
parlamentar.filiacao_atual == partido.sigla]
return render(request, template_name, {'partido': partido, 'parlamentares': parlamentares_filiados})
class MesaDiretoraView(FormView):
template_name = 'parlamentares/composicaomesa_form.html'
success_url = reverse_lazy('sapl.parlamentares:mesa_diretora')

10
sapl/protocoloadm/forms.py

@ -52,16 +52,14 @@ class AcompanhamentoDocumentoForm(ModelForm):
def __init__(self, *args, **kwargs):
row1 = to_row([('email', 10)])
row1.append(
Column(form_actions(label='Cadastrar'), css_class='col-md-2')
)
row1 = to_row([('email', 12)])
self.helper = SaplFormHelper()
self.helper.layout = Layout(
Fieldset(
_('Acompanhamento de Documento por e-mail'), row1
_('Acompanhamento de Documento por e-mail'),
row1,
form_actions(label='Cadastrar')
)
)
super(AcompanhamentoDocumentoForm, self).__init__(*args, **kwargs)

39
sapl/protocoloadm/views.py

@ -243,7 +243,7 @@ class AcompanhamentoDocumentoView(CreateView):
"documento",
documento,
destinatario)
self.logger.info('user={} .Foi enviado um e-mail de confirmação. Confira sua caixa '
self.logger.info('user={}. Foi enviado um e-mail de confirmação. Confira sua caixa '
'de mensagens e clique no link que nós enviamos para '
'confirmar o acompanhamento deste documento.'.format(usuario.username))
msg = _('Foi enviado um e-mail de confirmação. Confira sua caixa \
@ -251,19 +251,50 @@ class AcompanhamentoDocumentoView(CreateView):
confirmar o acompanhamento deste documento.')
messages.add_message(request, messages.SUCCESS, msg)
# Se o elemento existir e o email não foi confirmado:
# gerar novo hash e reenviar mensagem de email
elif not acompanhar[0].confirmado:
acompanhar = acompanhar[0]
acompanhar.hash = hash_txt
acompanhar.save()
base_url = get_base_url(request)
destinatario = AcompanhamentoDocumento.objects.get(
documento=documento,
email=email,
confirmado=False
)
casa = CasaLegislativa.objects.first()
do_envia_email_confirmacao(base_url,
casa,
"documento",
documento,
destinatario)
self.logger.info('user={}. Foi enviado um e-mail de confirmação. Confira sua caixa \
de mensagens e clique no link que nós enviamos para \
confirmar o acompanhamento deste documento.'.format(usuario.username))
msg = _('Foi enviado um e-mail de confirmação. Confira sua caixa \
de mensagens e clique no link que nós enviamos para \
confirmar o acompanhamento deste documento.')
messages.add_message(request, messages.SUCCESS, msg)
# Caso esse Acompanhamento já exista
# avisa ao usuário que esse documento já está sendo acompanhado
else:
self.logger.info('user=' + request.user.username +
'. Este e-mail já está acompanhando esse documento (pk={}).'.format(pk))
msg = _('Este e-mail já está acompanhando esse documento.')
messages.add_message(request, messages.INFO, msg)
messages.add_message(request, messages.ERROR, msg)
return self.render_to_response(
{'form': form,
'documento': documento,
'error': _('Esse documento já está\
sendo acompanhada por este e-mail.')})
})
return HttpResponseRedirect(self.get_success_url())
else:
return self.render_to_response(

85
sapl/relatorios/templates/pdf_sessao_plenaria_gerar.py

@ -1,19 +1,18 @@
##parameters=rodape_dic, sessao='', imagem, inf_basicas_dic, lst_mesa, lst_presenca_sessao, lst_expedientes, lst_expediente_materia, lst_oradores_expediente, lst_presenca_ordem_dia, lst_votacao, lst_oradores
# #parameters=rodape_dic, sessao='', imagem, inf_basicas_dic, lst_mesa, lst_presenca_sessao, lst_expedientes, lst_expediente_materia, lst_oradores_expediente, lst_presenca_ordem_dia, lst_votacao, lst_oradores
"""Script para geração do PDF das sessoes plenarias
Autor: Gustavo Lepri
Atualizado por Luciano De Fázio - 22/03/2012
versão: 1.0
"""
import time
import os
import time
from django.template.defaultfilters import safe
from django.utils.html import strip_tags
from trml2pdf import parseString
from sapl.sessao.models import ResumoOrdenacao
from trml2pdf import parseString
def cabecalho(inf_basicas_dic, imagem):
"""
@ -124,7 +123,7 @@ def inf_basicas(inf_basicas_dic):
dat_inicio_sessao + ' <b>- </b> ' + hr_inicio_sessao + '</para>\n'
tmp += '\t\t<para style="P2" spaceAfter="5"><b>Encerramento: </b> ' + \
dat_fim_sessao + ' <b>- </b> ' + hr_fim_sessao + '</para>\n'
dat_fim_sessao + ' <b>- </b> ' + hr_fim_sessao + '</para>\n'
return tmp
@ -145,7 +144,7 @@ def mesa(lst_mesa):
return tmp
def presenca(lst_presenca_sessao,lst_ausencia_sessao):
def presenca(lst_presenca_sessao, lst_ausencia_sessao):
"""
"""
@ -202,14 +201,18 @@ def expediente_materia(lst_expediente_materia):
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
tmp += '<blockTable style="repeater" repeatRows="1">\n'
tmp += '<blockTable style="repeater" repeatRows="1" colWidths="3.5cm,11.5cm,3.5cm">>\n'
tmp += '<tr><td >Matéria</td><td>Ementa</td><td>Resultado da Votação</td></tr>\n'
for expediente_materia in lst_expediente_materia:
tmp += '<tr><td><para style="P3"><b>' + str(expediente_materia['num_ordem']) + '</b> - ' + expediente_materia['id_materia'] + '</para>\n' + '<para style="P3"><b>Turno: </b>' + expediente_materia[
'des_turno'] + '</para>\n' + '<para style="P3"><b>'+ expediente_materia['num_autores'] + ': </b>' + str(expediente_materia['nom_autor']) + '</para></td>\n'
'des_turno'] + '</para>\n' + '<para style="P3"><b>' + expediente_materia['num_autores'] + ': </b>' + str(expediente_materia['nom_autor']) + '</para></td>\n'
txt_ementa = expediente_materia['txt_ementa'].replace('&', '&amp;')
if len(txt_ementa) > 1000:
txt_ementa = txt_ementa[:1000] + "..."
# txt_ementa = dont_break_out(expediente_materia['txt_ementa'])
# if len(txt_ementa) > 800:
# txt_ementa = txt_ementa[:800] + "..."
tmp += '<td><para style="P4">' + txt_ementa + '</para>' + '<para style="P4">' + expediente_materia['ordem_observacao'] + '</para></td>\n'
tmp += '<td><para style="P3"><b>' + \
str(expediente_materia['nom_resultado']) + \
@ -224,6 +227,30 @@ def expediente_materia(lst_expediente_materia):
return tmp
def expediente_materia_vot_nom(lst_expediente_materia_vot_nom):
"""
"""
tmp = ''
tmp += '\t\t<para style="P1">Votações Nominais - Matérias do Expediente</para>\n\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
tmp += '<blockTable style="repeater" repeatRows="1">\n'
tmp += '<tr><td >Matéria</td><td>Votos</td></tr>\n'
for expediente_materia_vot_nom in lst_expediente_materia_vot_nom:
tmp += '<tr><td><para style="P3">' + str(expediente_materia_vot_nom['titulo']) + '</para></td>'
if expediente_materia_vot_nom['votos']:
tmp += '<td>'
for v in expediente_materia_vot_nom['votos']:
tmp += '<para style="P3"><b>' + str(v.parlamentar) + '</b> - ' + v.voto + '</para>'
tmp += '</td>'
else:
tmp += '<td><para style="P3"><b>Matéria não votada</b></para></td>'
tmp += '</tr>\n'
tmp += '\t\t</blockTable>\n'
return tmp
def oradores_expediente(lst_oradores_expediente):
"""
@ -271,7 +298,7 @@ def votacao(lst_votacao):
tmp += '<tr><td >Matéria</td><td>Ementa</td><td>Resultado da Votação</td></tr>\n'
for votacao in lst_votacao:
tmp += '<tr><td><para style="P3"><b>' + str(votacao['num_ordem']) + '</b> - ' + votacao['id_materia'] + '</para>\n' + '<para style="P3"><b>Turno:</b> ' + votacao[
'des_turno'] + '</para>\n' + '<para style="P3"><b>'+ votacao['num_autores'] +': </b>' + str(votacao['nom_autor']) + '</para></td>\n'
'des_turno'] + '</para>\n' + '<para style="P3"><b>' + votacao['num_autores'] + ': </b>' + str(votacao['nom_autor']) + '</para></td>\n'
txt_ementa = votacao['txt_ementa'].replace('&', '&amp;')
if len(txt_ementa) > 1000:
txt_ementa = txt_ementa[:1000] + "..."
@ -289,6 +316,30 @@ def votacao(lst_votacao):
return tmp
def votacao_vot_nom(lst_votacao_vot_nom):
"""
"""
tmp = ''
tmp += '\t\t<para style="P1">Votações Nominais - Matérias da Ordem do Dia</para>\n\n'
tmp += '\t\t<para style="P2">\n'
tmp += '\t\t\t<font color="white"> <br/></font>\n'
tmp += '\t\t</para>\n'
tmp += '<blockTable style="repeater" repeatRows="1">\n'
tmp += '<tr><td >Matéria</td><td>Votos</td></tr>\n'
for votacao_vot_nom in lst_votacao_vot_nom:
tmp += '<tr><td><para style="P3">' + str(votacao_vot_nom['titulo']) + '</para></td>'
if votacao_vot_nom['votos']:
tmp += '<td>'
for v in votacao_vot_nom['votos']:
tmp += '<para style="P3"><b>' + str(v.parlamentar) + '</b> - ' + v.voto + '</para>'
tmp += '</td>'
else:
tmp += '<td><para style="P3"><b>Matéria não votada</b></para></td>'
tmp += '</tr>\n'
tmp += '\t\t</blockTable>\n'
return tmp
def oradores(lst_oradores):
"""
@ -323,7 +374,7 @@ def ocorrencias(lst_ocorrencias):
return tmp
def principal(rodape_dic, imagem, inf_basicas_dic, lst_mesa, lst_presenca_sessao, lst_ausencia_sessao, lst_expedientes, lst_expediente_materia, lst_oradores_expediente, lst_presenca_ordem_dia, lst_votacao, lst_oradores, lst_ocorrencias):
def principal(rodape_dic, imagem, inf_basicas_dic, lst_mesa, lst_presenca_sessao, lst_ausencia_sessao, lst_expedientes, lst_expediente_materia, lst_expediente_materia_vot_nom, lst_oradores_expediente, lst_presenca_ordem_dia, lst_votacao, lst_votacao_vot_nom, lst_oradores, lst_ocorrencias):
"""
"""
arquivoPdf = str(int(time.time() * 100)) + ".pdf"
@ -349,10 +400,12 @@ def principal(rodape_dic, imagem, inf_basicas_dic, lst_mesa, lst_presenca_sessao
'cont_mult': '',
'exp': expedientes(lst_expedientes),
'id_basica': inf_basicas(inf_basicas_dic),
'lista_p': presenca(lst_presenca_sessao,lst_ausencia_sessao),
'lista_p': presenca(lst_presenca_sessao, lst_ausencia_sessao),
'lista_p_o_d': presenca_ordem_dia(lst_presenca_ordem_dia),
'mat_exp': expediente_materia(lst_expediente_materia),
'v_n_mat_exp': expediente_materia_vot_nom(lst_expediente_materia_vot_nom),
'mat_o_d': votacao(lst_votacao),
'v_n_mat_o_d': votacao_vot_nom(lst_votacao_vot_nom),
'mesa_d': mesa(lst_mesa),
'oradores_exped': oradores_expediente(lst_oradores_expediente),
'oradores_expli': oradores(lst_oradores),
@ -371,16 +424,20 @@ def principal(rodape_dic, imagem, inf_basicas_dic, lst_mesa, lst_presenca_sessao
tmp += dict_ord_template[ordenacao.nono]
tmp += dict_ord_template[ordenacao.decimo]
tmp += dict_ord_template[ordenacao.decimo_primeiro]
tmp += dict_ord_template[ordenacao.decimo_segundo]
tmp += dict_ord_template[ordenacao.decimo_terceiro]
else:
tmp += inf_basicas(inf_basicas_dic)
tmp += mesa(lst_mesa)
tmp += presenca(lst_presenca_sessao,lst_ausencia_sessao)
tmp += presenca(lst_presenca_sessao, lst_ausencia_sessao)
tmp += expedientes(lst_expedientes)
tmp += expediente_materia(lst_expediente_materia)
tmp += expediente_materia_vot_nom(lst_expediente_materia_vot_nom)
tmp += oradores_expediente(lst_oradores_expediente)
tmp += presenca_ordem_dia(lst_presenca_ordem_dia)
tmp += votacao(lst_votacao)
tmp += votacao_vot_nom(lst_votacao_vot_nom)
tmp += oradores(lst_oradores)
tmp += ocorrencias(lst_ocorrencias)

53
sapl/relatorios/views.py

@ -19,7 +19,8 @@ from sapl.sessao.models import (ExpedienteMateria, ExpedienteSessao,
IntegranteMesa, JustificativaAusencia,
Orador, OradorExpediente,
OrdemDia, PresencaOrdemDia, SessaoPlenaria,
SessaoPlenariaPresenca, OcorrenciaSessao)
SessaoPlenariaPresenca, OcorrenciaSessao,
RegistroVotacao, VotoParlamentar)
from sapl.settings import STATIC_ROOT
from sapl.utils import LISTA_DE_UFS, TrocaTag, filiacao_data
@ -633,6 +634,28 @@ def get_sessao_plenaria(sessao, casa):
dic_expediente_materia["votacao_observacao"] = ' '
lst_expediente_materia.append(dic_expediente_materia)
# Lista dos votos nominais das matérias do Expediente
lst_expediente_materia_vot_nom = []
materias_expediente_votacao_nominal = ExpedienteMateria.objects.filter(
sessao_plenaria=sessao,
tipo_votacao=2).order_by('-materia')
for mevn in materias_expediente_votacao_nominal:
votos_materia = []
titulo_materia = mevn.materia
registro = RegistroVotacao.objects.filter(expediente=mevn)
if registro:
for vp in VotoParlamentar.objects.filter(votacao=registro).order_by('parlamentar'):
votos_materia.append(vp)
dic_expediente_materia_vot_nom = {
'titulo': titulo_materia,
'votos': votos_materia
}
lst_expediente_materia_vot_nom.append(dic_expediente_materia_vot_nom)
# Lista dos oradores do Expediente
lst_oradores_expediente = []
for orador_expediente in OradorExpediente.objects.filter(
@ -722,6 +745,28 @@ def get_sessao_plenaria(sessao, casa):
dic_votacao["nom_resultado"] = "Matéria não votada"
lst_votacao.append(dic_votacao)
# Lista dos votos nominais das matérias da Ordem do Dia
lst_votacao_vot_nom = []
materias_ordem_dia_votacao_nominal = OrdemDia.objects.filter(
sessao_plenaria=sessao,
tipo_votacao=2).order_by('-materia')
for modvn in materias_ordem_dia_votacao_nominal:
votos_materia_od = []
t_materia = modvn.materia
registro_od = RegistroVotacao.objects.filter(ordem=modvn)
if registro_od:
for vp_od in VotoParlamentar.objects.filter(votacao=registro_od).order_by('parlamentar'):
votos_materia_od.append(vp_od)
dic_votacao_vot_nom = {
'titulo': t_materia,
'votos': votos_materia_od
}
lst_votacao_vot_nom.append(dic_votacao_vot_nom)
# Lista dos oradores nas Explicações Pessoais
lst_oradores = []
for orador in Orador.objects.filter(
@ -767,9 +812,11 @@ def get_sessao_plenaria(sessao, casa):
lst_ausencia_sessao,
lst_expedientes,
lst_expediente_materia,
lst_expediente_materia_vot_nom,
lst_oradores_expediente,
lst_presenca_ordem_dia,
lst_votacao,
lst_votacao_vot_nom,
lst_oradores,
lst_ocorrencias)
@ -822,9 +869,11 @@ def relatorio_sessao_plenaria(request, pk):
lst_ausencia_sessao,
lst_expedientes,
lst_expediente_materia,
lst_expediente_materia_vot_nom,
lst_oradores_expediente,
lst_presenca_ordem_dia,
lst_votacao,
lst_votacao_vot_nom,
lst_oradores,
lst_ocorrencias) = get_sessao_plenaria(sessao, casa)
@ -843,9 +892,11 @@ def relatorio_sessao_plenaria(request, pk):
lst_ausencia_sessao,
lst_expedientes,
lst_expediente_materia,
lst_expediente_materia_vot_nom,
lst_oradores_expediente,
lst_presenca_ordem_dia,
lst_votacao,
lst_votacao_vot_nom,
lst_oradores,
lst_ocorrencias)

15
sapl/sessao/forms.py

@ -43,7 +43,9 @@ ORDENACAO_RESUMO = [('cont_mult', 'Conteúdo Multimídia'),
('mesa_d', 'Mesa Diretora'),
('oradores_exped', 'Oradores do Expediente'),
('oradores_expli', 'Oradores das Explicações Pessoais'),
('ocorr_sessao', 'Ocorrências da Sessão')]
('ocorr_sessao', 'Ocorrências da Sessão'),
('v_n_mat_exp', 'Votações Nominais - Matérias do Expediente'),
('v_n_mat_o_d', 'Votações Nominais - Matérias da Ordem do Dia')]
class SessaoPlenariaForm(FileFieldCheckMixin, ModelForm):
@ -761,6 +763,10 @@ class ResumoOrdenacaoForm(forms.Form):
choices=ORDENACAO_RESUMO)
decimo_primeiro = forms.ChoiceField(label='11°',
choices=ORDENACAO_RESUMO)
decimo_segundo = forms.ChoiceField(label='12°',
choices=ORDENACAO_RESUMO)
decimo_terceiro = forms.ChoiceField(label='13°',
choices=ORDENACAO_RESUMO)
def __init__(self, *args, **kwargs):
super(ResumoOrdenacaoForm, self).__init__(*args, **kwargs)
@ -787,12 +793,17 @@ class ResumoOrdenacaoForm(forms.Form):
[('decimo', 12)])
row11 = to_row(
[('decimo_primeiro', 12)])
row12 = to_row(
[('decimo_segundo', 12)])
row13 = to_row(
[('decimo_terceiro', 12)])
self.helper = SaplFormHelper()
self.helper.layout = Layout(
Fieldset(_(''),
row1, row2, row3, row4, row5,
row6, row7, row8, row9, row10, row11,
row6, row7, row8, row9, row10,
row11, row12, row13,
form_actions(label='Atualizar'))
)

25
sapl/sessao/migrations/0033_auto_20190228_1803.py

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.20 on 2019-02-28 21:03
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('sessao', '0032_merge_20181122_1527'),
]
operations = [
migrations.AddField(
model_name='resumoordenacao',
name='decimo_segundo',
field=models.CharField(default='Votos Nominais Mat Expediente', max_length=30),
),
migrations.AddField(
model_name='resumoordenacao',
name='decimo_terceiro',
field=models.CharField(default='Votos Nominais Mat Ordem Dia', max_length=30),
),
]

2
sapl/sessao/models.py

@ -577,6 +577,8 @@ class ResumoOrdenacao(models.Model):
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")
class Meta:
verbose_name = _('Ordenação do Resumo de uma Sessão')

127
sapl/sessao/views.py

@ -1260,7 +1260,9 @@ class ResumoOrdenacaoView(PermissionRequiredMixin, FormView):
'oitavo': ordenacao.oitavo,
'nono': ordenacao.nono,
'decimo': ordenacao.decimo,
'decimo_primeiro': ordenacao.decimo_primeiro})
'decimo_primeiro': ordenacao.decimo_primeiro,
'decimo_segundo': ordenacao.decimo_segundo,
'decimo_terceiro': ordenacao.decimo_terceiro})
return initial
def form_valid(self, form):
@ -1277,6 +1279,8 @@ class ResumoOrdenacaoView(PermissionRequiredMixin, FormView):
ordenacao.nono = form.cleaned_data['nono']
ordenacao.decimo = form.cleaned_data['decimo']
ordenacao.decimo_primeiro = form.cleaned_data['decimo_primeiro']
ordenacao.decimo_segundo = form.cleaned_data['decimo_segundo']
ordenacao.decimo_terceiro = form.cleaned_data['decimo_terceiro']
ordenacao.save()
@ -1294,6 +1298,7 @@ def get_turno(turno):
class ResumoView(DetailView):
template_name = 'sessao/resumo.html'
model = SessaoPlenaria
logger = logging.getLogger(__name__)
def get(self, request, *args, **kwargs):
self.object = self.get_object()
@ -1418,7 +1423,30 @@ class ResumoView(DetailView):
materias_expediente.append(mat)
context.update({'materia_expediente': materias_expediente})
# Votos de Votação Nominal de Matérias Expediente
materias_expediente_votacao_nominal = ExpedienteMateria.objects.filter(
sessao_plenaria_id=self.object.id,
tipo_votacao=2).order_by('-materia')
votacoes = []
for mevn in materias_expediente_votacao_nominal:
votos_materia = []
titulo_materia = mevn.materia
registro = RegistroVotacao.objects.filter(expediente=mevn)
if registro:
for vp in VotoParlamentar.objects.filter(votacao=registro).order_by('parlamentar'):
votos_materia.append(vp)
dados_votacao = {
'titulo': titulo_materia,
'votos': votos_materia
}
votacoes.append(dados_votacao)
context.update({'votos_nominais_materia_expediente': votacoes})
# =====================================================================
# Oradores Expediente
oradores = []
@ -1518,6 +1546,29 @@ class ResumoView(DetailView):
context.update({'materias_ordem': materias_ordem})
# Votos de Votação Nominal de Matérias Ordem do Dia
materias_ordem_dia_votacao_nominal = OrdemDia.objects.filter(
sessao_plenaria_id=self.object.id,
tipo_votacao=2).order_by('-materia')
votacoes_od = []
for modvn in materias_ordem_dia_votacao_nominal:
votos_materia_od = []
t_materia = modvn.materia
registro_od = RegistroVotacao.objects.filter(ordem=modvn)
if registro_od:
for vp_od in VotoParlamentar.objects.filter(votacao=registro_od).order_by('parlamentar'):
votos_materia_od.append(vp_od)
dados_votacao_od = {
'titulo': t_materia,
'votos': votos_materia_od
}
votacoes_od.append(dados_votacao_od)
context.update({'votos_nominais_materia_ordem_dia': votacoes_od})
# =====================================================================
# Oradores nas Explicações Pessoais
oradores_explicacoes = []
@ -1556,7 +1607,9 @@ class ResumoView(DetailView):
'lista_p': 'lista_presenca.html',
'lista_p_o_d': 'lista_presenca_ordem_dia.html',
'mat_exp': 'materias_expediente.html',
'v_n_mat_exp': 'votos_nominais_materias_expediente.html',
'mat_o_d': 'materias_ordem_dia.html',
'v_n_mat_o_d': 'votos_nominais_materias_ordem_dia.html',
'mesa_d': 'mesa_diretora.html',
'oradores_exped': 'oradores_expediente.html',
'oradores_expli': 'oradores_explicacoes.html',
@ -1564,18 +1617,39 @@ class ResumoView(DetailView):
}
if ordenacao:
context.update(
{'primeiro_ordenacao': dict_ord_template[ordenacao.primeiro],
'segundo_ordenacao': dict_ord_template[ordenacao.segundo],
'terceiro_ordenacao': dict_ord_template[ordenacao.terceiro],
'quarto_ordenacao': dict_ord_template[ordenacao.quarto],
'quinto_ordenacao': dict_ord_template[ordenacao.quinto],
'sexto_ordenacao': dict_ord_template[ordenacao.sexto],
'setimo_ordenacao': dict_ord_template[ordenacao.setimo],
'oitavo_ordenacao': dict_ord_template[ordenacao.oitavo],
'nono_ordenacao': dict_ord_template[ordenacao.nono],
'decimo_ordenacao': dict_ord_template[ordenacao.decimo],
'decimo_primeiro_ordenacao': dict_ord_template[ordenacao.decimo_primeiro]})
try:
context.update(
{'primeiro_ordenacao': dict_ord_template[ordenacao.primeiro],
'segundo_ordenacao': dict_ord_template[ordenacao.segundo],
'terceiro_ordenacao': dict_ord_template[ordenacao.terceiro],
'quarto_ordenacao': dict_ord_template[ordenacao.quarto],
'quinto_ordenacao': dict_ord_template[ordenacao.quinto],
'sexto_ordenacao': dict_ord_template[ordenacao.sexto],
'setimo_ordenacao': dict_ord_template[ordenacao.setimo],
'oitavo_ordenacao': dict_ord_template[ordenacao.oitavo],
'nono_ordenacao': dict_ord_template[ordenacao.nono],
'decimo_ordenacao': dict_ord_template[ordenacao.decimo],
'decimo_primeiro_ordenacao': dict_ord_template[ordenacao.decimo_primeiro],
'decimo_segundo_ordenacao': dict_ord_template[ordenacao.decimo_segundo],
'decimo_terceiro_ordenacao': dict_ord_template[ordenacao.decimo_terceiro]})
except KeyError as e:
self.logger.error('user=' + request.user.username + '. ' + "KeyError: " + str(e) + ". Erro "
"ao tentar utilizar configuração de ordenação. Utilizando ordenação padrão.")
context.update(
{'primeiro_ordenacao': dict_ord_template['id_basica'],
'segundo_ordenacao': dict_ord_template['cont_mult'],
'terceiro_ordenacao': dict_ord_template['mesa_d'],
'quarto_ordenacao': dict_ord_template['lista_p'],
'quinto_ordenacao': dict_ord_template['exp'],
'sexto_ordenacao': dict_ord_template['mat_exp'],
'setimo_ordenacao': dict_ord_template['v_n_mat_exp'],
'oitavo_ordenacao': dict_ord_template['oradores_exped'],
'nono_ordenacao': dict_ord_template['lista_p_o_d'],
'decimo_ordenacao': dict_ord_template['mat_o_d'],
'decimo_primeiro_ordenacao': dict_ord_template['v_n_mat_o_d'],
'decimo_segundo_ordenacao': dict_ord_template['oradores_expli'],
'decimo_terceiro_ordenacao': dict_ord_template['ocorr_sessao']
})
else:
context.update(
{'primeiro_ordenacao': dict_ord_template['id_basica'],
@ -1584,11 +1658,14 @@ class ResumoView(DetailView):
'quarto_ordenacao': dict_ord_template['lista_p'],
'quinto_ordenacao': dict_ord_template['exp'],
'sexto_ordenacao': dict_ord_template['mat_exp'],
'setimo_ordenacao': dict_ord_template['oradores_exped'],
'oitavo_ordenacao': dict_ord_template['lista_p_o_d'],
'nono_ordenacao': dict_ord_template['mat_o_d'],
'decimo_ordenacao': dict_ord_template['oradores_expli'],
'decimo_primeiro_ordenacao': dict_ord_template['ocorr_sessao']})
'setimo_ordenacao': dict_ord_template['v_n_mat_exp'],
'oitavo_ordenacao': dict_ord_template['oradores_exped'],
'nono_ordenacao': dict_ord_template['lista_p_o_d'],
'decimo_ordenacao': dict_ord_template['mat_o_d'],
'decimo_primeiro_ordenacao': dict_ord_template['v_n_mat_o_d'],
'decimo_segundo_ordenacao': dict_ord_template['oradores_expli'],
'decimo_terceiro_ordenacao': dict_ord_template['ocorr_sessao']
})
return self.render_to_response(context)
@ -3284,17 +3361,16 @@ class VotacaoEmBlocoExpediente(PermissionRequiredForAppCrudMixin, ListView):
logger = logging.getLogger(__name__)
def get_queryset(self):
kwargs = self.kwargs
return ExpedienteMateria.objects.filter(sessao_plenaria_id=kwargs['pk'],
return ExpedienteMateria.objects.filter(sessao_plenaria_id=self.kwargs['pk'],
resultado='')
def get_context_data(self, **kwargs):
context = super(VotacaoEmBlocoExpediente,
self).get_context_data(**kwargs)
context['turno_choices'] = Tramitacao.TURNO_CHOICES
context['title'] = SessaoPlenaria.objects.get(id=self.kwargs['pk'])
context['pk'] = self.kwargs['pk']
context['root_pk'] = self.kwargs['pk']
context['title'] = SessaoPlenaria.objects.get(id=self.kwargs['pk'])
return context
@ -3335,7 +3411,8 @@ class VotacaoEmBlocoSimbolicaView(PermissionRequiredForAppCrudMixin, TemplateVie
context = {'pk': self.kwargs['pk'],
'root_pk': self.kwargs['pk'],
'title': SessaoPlenaria.objects.get(id=self.kwargs['pk']),
'origem': request.POST['origem']
'origem': request.POST['origem'],
'subnav_template_name': 'sessao/subnav.yaml'
}
if 'marcadas_1' in request.POST:
@ -3678,7 +3755,7 @@ class VotacaoEmBlocoNominalView(PermissionRequiredForAppCrudMixin, TemplateView)
voto_parlamentar = VotoParlamentar.objects.filter(
ordem=ordens_id[0])
else:
presencas = PresencaOrdemDia.objects.filter(
presencas = SessaoPlenariaPresenca.objects.filter(
sessao_plenaria_id=self.kwargs['pk'])
expedientes_id = self.request.POST.getlist('marcadas_2')
voto_parlamentar = VotoParlamentar.objects.filter(
@ -3693,7 +3770,7 @@ class VotacaoEmBlocoNominalView(PermissionRequiredForAppCrudMixin, TemplateView)
voto_parlamentar = VotoParlamentar.objects.filter(
ordem=ordens_id[0])
else:
presencas = PresencaOrdemDia.objects.filter(
presencas = SessaoPlenariaPresenca.objects.filter(
sessao_plenaria_id=self.kwargs['pk'])
expedientes_id = self.request.POST.getlist('expedientes')
voto_parlamentar = VotoParlamentar.objects.filter(

4
sapl/settings.py

@ -41,7 +41,7 @@ ALLOWED_HOSTS = ['*']
LOGIN_REDIRECT_URL = '/'
LOGIN_URL = '/login/?next='
SAPL_VERSION = '3.1.145'
SAPL_VERSION = '3.1.147'
if DEBUG:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
@ -274,7 +274,7 @@ FRONTEND_CUSTOM = config('FRONTEND_CUSTOM', default=False, cast=bool)
WEBPACK_LOADER = {
'DEFAULT': {
'CACHE': not DEBUG,
'BUNDLE_DIR_NAME': 'sapl/static/sapl/',
'BUNDLE_DIR_NAME': 'sapl/static/sapl/frontend',
'STATS_FILE': (BASE_DIR if not FRONTEND_CUSTOM else PROJECT_DIR.parent.child('sapl-frontend')).child('webpack-stats.json'),
'POLL_INTERVAL': 0.1,
'TIMEOUT': None,

BIN
sapl/static/sapl/css/chunk-vendors.81e1a0b9.css.gz

Binary file not shown.

1
sapl/static/sapl/css/compilacao.3372b760.css

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/css/compilacao.3372b760.css.gz

Binary file not shown.

1
sapl/static/sapl/css/sessao_online.ddd218af.css

@ -1 +0,0 @@
.body-sessao-online{overflow:hidden}.app-sessao-online{position:fixed;top:0;right:0;bottom:0;left:0;background-color:hsla(0,0%,97.6%,.95);z-index:1000;display:grid;grid-template-columns:50px 50px 50px 50px;grid-template-rows:auto}.container-messages[data-v-325582de]{position:fixed;bottom:0;right:1rem;z-index:10001}

BIN
sapl/static/sapl/css/sessao_online.ddd218af.css.gz

Binary file not shown.

0
sapl/static/sapl/audio/ring.mp3 → sapl/static/sapl/frontend/audio/ring.mp3

2
sapl/static/sapl/css/chunk-vendors.81e1a0b9.css → sapl/static/sapl/frontend/css/chunk-vendors.3c9fe6b4.css

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/css/chunk-vendors.3c9fe6b4.css.gz

Binary file not shown.

1
sapl/static/sapl/frontend/css/compilacao.1f5fb8cf.css

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/css/compilacao.1f5fb8cf.css.gz

Binary file not shown.

2
sapl/static/sapl/css/global.a9fa7d26.css → sapl/static/sapl/frontend/css/global.83a4a89d.css

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/css/global.a9fa7d26.css.gz → sapl/static/sapl/frontend/css/global.83a4a89d.css.gz

Binary file not shown.

0
sapl/static/sapl/css/painel.baa845ab.css → sapl/static/sapl/frontend/css/painel.baa845ab.css

0
sapl/static/sapl/css/painel.baa845ab.css.gz → sapl/static/sapl/frontend/css/painel.baa845ab.css.gz

0
sapl/static/sapl/fonts/fa-brands-400.4b115e11.woff2 → sapl/static/sapl/frontend/fonts/fa-brands-400.4b115e11.woff2

0
sapl/static/sapl/fonts/fa-brands-400.b90365bc.woff → sapl/static/sapl/frontend/fonts/fa-brands-400.b90365bc.woff

0
sapl/static/sapl/fonts/fa-brands-400.c39278f7.ttf → sapl/static/sapl/frontend/fonts/fa-brands-400.c39278f7.ttf

0
sapl/static/sapl/fonts/fa-brands-400.c39278f7.ttf.gz → sapl/static/sapl/frontend/fonts/fa-brands-400.c39278f7.ttf.gz

0
sapl/static/sapl/fonts/fa-brands-400.d9d17590.eot → sapl/static/sapl/frontend/fonts/fa-brands-400.d9d17590.eot

0
sapl/static/sapl/fonts/fa-brands-400.d9d17590.eot.gz → sapl/static/sapl/frontend/fonts/fa-brands-400.d9d17590.eot.gz

0
sapl/static/sapl/fonts/fa-regular-400.414ff5da.eot → sapl/static/sapl/frontend/fonts/fa-regular-400.414ff5da.eot

0
sapl/static/sapl/fonts/fa-regular-400.414ff5da.eot.gz → sapl/static/sapl/frontend/fonts/fa-regular-400.414ff5da.eot.gz

0
sapl/static/sapl/fonts/fa-regular-400.5dd3976c.woff → sapl/static/sapl/frontend/fonts/fa-regular-400.5dd3976c.woff

0
sapl/static/sapl/fonts/fa-regular-400.65779ebc.woff2 → sapl/static/sapl/frontend/fonts/fa-regular-400.65779ebc.woff2

0
sapl/static/sapl/fonts/fa-regular-400.f6c6f6c8.ttf → sapl/static/sapl/frontend/fonts/fa-regular-400.f6c6f6c8.ttf

0
sapl/static/sapl/fonts/fa-regular-400.f6c6f6c8.ttf.gz → sapl/static/sapl/frontend/fonts/fa-regular-400.f6c6f6c8.ttf.gz

0
sapl/static/sapl/fonts/fa-solid-900.46280631.woff2 → sapl/static/sapl/frontend/fonts/fa-solid-900.46280631.woff2

0
sapl/static/sapl/fonts/fa-solid-900.61969d43.woff → sapl/static/sapl/frontend/fonts/fa-solid-900.61969d43.woff

0
sapl/static/sapl/fonts/fa-solid-900.b5596f4d.eot → sapl/static/sapl/frontend/fonts/fa-solid-900.b5596f4d.eot

0
sapl/static/sapl/fonts/fa-solid-900.b5596f4d.eot.gz → sapl/static/sapl/frontend/fonts/fa-solid-900.b5596f4d.eot.gz

0
sapl/static/sapl/fonts/fa-solid-900.b70cea03.ttf → sapl/static/sapl/frontend/fonts/fa-solid-900.b70cea03.ttf

0
sapl/static/sapl/fonts/fa-solid-900.b70cea03.ttf.gz → sapl/static/sapl/frontend/fonts/fa-solid-900.b70cea03.ttf.gz

0
sapl/static/sapl/img/arrow.png → sapl/static/sapl/frontend/img/arrow.png

Before

Width:  |  Height:  |  Size: 262 B

After

Width:  |  Height:  |  Size: 262 B

0
sapl/static/sapl/img/authenticated.png → sapl/static/sapl/frontend/img/authenticated.png

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

0
sapl/static/sapl/img/avatar.png → sapl/static/sapl/frontend/img/avatar.png

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

0
sapl/static/sapl/img/beta.png → sapl/static/sapl/frontend/img/beta.png

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

0
sapl/static/sapl/img/brasao_transp.gif → sapl/static/sapl/frontend/img/brasao_transp.gif

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

0
sapl/static/sapl/img/down_arrow_select.jpg → sapl/static/sapl/frontend/img/down_arrow_select.jpg

Before

Width:  |  Height:  |  Size: 682 B

After

Width:  |  Height:  |  Size: 682 B

0
sapl/static/sapl/img/down_arrow_select.jpg.gz → sapl/static/sapl/frontend/img/down_arrow_select.jpg.gz

0
sapl/static/sapl/img/etiqueta.png → sapl/static/sapl/frontend/img/etiqueta.png

Before

Width:  |  Height:  |  Size: 694 B

After

Width:  |  Height:  |  Size: 694 B

0
sapl/static/sapl/img/fa-brands-400.80533988.svg → sapl/static/sapl/frontend/img/fa-brands-400.80533988.svg

Before

Width:  |  Height:  |  Size: 644 KiB

After

Width:  |  Height:  |  Size: 644 KiB

0
sapl/static/sapl/img/fa-brands-400.80533988.svg.gz → sapl/static/sapl/frontend/img/fa-brands-400.80533988.svg.gz

0
sapl/static/sapl/img/fa-regular-400.e7e957c8.svg → sapl/static/sapl/frontend/img/fa-regular-400.e7e957c8.svg

Before

Width:  |  Height:  |  Size: 141 KiB

After

Width:  |  Height:  |  Size: 141 KiB

0
sapl/static/sapl/img/fa-regular-400.e7e957c8.svg.gz → sapl/static/sapl/frontend/img/fa-regular-400.e7e957c8.svg.gz

0
sapl/static/sapl/img/fa-solid-900.82905d8d.svg → sapl/static/sapl/frontend/img/fa-solid-900.82905d8d.svg

Before

Width:  |  Height:  |  Size: 797 KiB

After

Width:  |  Height:  |  Size: 797 KiB

0
sapl/static/sapl/img/fa-solid-900.82905d8d.svg.gz → sapl/static/sapl/frontend/img/fa-solid-900.82905d8d.svg.gz

0
sapl/static/sapl/img/favicon.ico → sapl/static/sapl/frontend/img/favicon.ico

Before

Width:  |  Height:  |  Size: 975 B

After

Width:  |  Height:  |  Size: 975 B

0
sapl/static/sapl/img/file.png → sapl/static/sapl/frontend/img/file.png

Before

Width:  |  Height:  |  Size: 1021 B

After

Width:  |  Height:  |  Size: 1021 B

0
sapl/static/sapl/img/hand-note.png → sapl/static/sapl/frontend/img/hand-note.png

Before

Width:  |  Height:  |  Size: 502 B

After

Width:  |  Height:  |  Size: 502 B

0
sapl/static/sapl/img/icon_comissoes.png → sapl/static/sapl/frontend/img/icon_comissoes.png

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

0
sapl/static/sapl/img/icon_delete_white.png → sapl/static/sapl/frontend/img/icon_delete_white.png

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

0
sapl/static/sapl/img/icon_materia_legislativa.png → sapl/static/sapl/frontend/img/icon_materia_legislativa.png

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

0
sapl/static/sapl/img/icon_mesa_diretora.png → sapl/static/sapl/frontend/img/icon_mesa_diretora.png

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

0
sapl/static/sapl/img/icon_normas_juridicas.png → sapl/static/sapl/frontend/img/icon_normas_juridicas.png

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

0
sapl/static/sapl/img/icon_parlamentares.png → sapl/static/sapl/frontend/img/icon_parlamentares.png

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

0
sapl/static/sapl/img/icon_pautas.png → sapl/static/sapl/frontend/img/icon_pautas.png

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

0
sapl/static/sapl/img/icon_plenarias.png → sapl/static/sapl/frontend/img/icon_plenarias.png

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

0
sapl/static/sapl/img/icon_relatorios.png → sapl/static/sapl/frontend/img/icon_relatorios.png

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

0
sapl/static/sapl/img/icon_save_white.png → sapl/static/sapl/frontend/img/icon_save_white.png

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

0
sapl/static/sapl/img/lexml.gif → sapl/static/sapl/frontend/img/lexml.gif

Before

Width:  |  Height:  |  Size: 568 B

After

Width:  |  Height:  |  Size: 568 B

0
sapl/static/sapl/img/logo.png → sapl/static/sapl/frontend/img/logo.png

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

0
sapl/static/sapl/img/logo_cc.png → sapl/static/sapl/frontend/img/logo_cc.png

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

0
sapl/static/sapl/img/logo_interlegis.png → sapl/static/sapl/frontend/img/logo_interlegis.png

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

0
sapl/static/sapl/img/manual.png → sapl/static/sapl/frontend/img/manual.png

Before

Width:  |  Height:  |  Size: 343 B

After

Width:  |  Height:  |  Size: 343 B

0
sapl/static/sapl/img/pdflogo.png → sapl/static/sapl/frontend/img/pdflogo.png

Before

Width:  |  Height:  |  Size: 238 KiB

After

Width:  |  Height:  |  Size: 238 KiB

0
sapl/static/sapl/img/perfil.png → sapl/static/sapl/frontend/img/perfil.png

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

0
sapl/static/sapl/img/search-gray.png → sapl/static/sapl/frontend/img/search-gray.png

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

0
sapl/static/sapl/img/search.png → sapl/static/sapl/frontend/img/search.png

Before

Width:  |  Height:  |  Size: 367 B

After

Width:  |  Height:  |  Size: 367 B

0
sapl/static/sapl/img/ui-icons_2694e8_256x240.274157b3.png → sapl/static/sapl/frontend/img/ui-icons_2694e8_256x240.274157b3.png

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save