Browse Source

Merge branch '3.1.x' into painel

pull/3814/head
Heitor 2 days ago
committed by GitHub
parent
commit
7d56729800
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 17
      CHANGES.md
  2. 2
      docker/docker-compose.yaml
  3. 204
      drfautoapi/drfautoapi.py
  4. 6
      frontend/src/__apps/parlamentar/main.js
  5. 3
      frontend/src/__global/js/functions.js
  6. 90
      frontend/webpack-stats.json
  7. 18
      sapl/api/serializers.py
  8. 117
      sapl/api/views.py
  9. 19
      sapl/api/views_materia.py
  10. 19
      sapl/sessao/forms.py
  11. 4
      sapl/sessao/views.py
  12. 2
      sapl/settings.py
  13. BIN
      sapl/static/sapl/frontend/css/chunk-vendors.045ec640.css.gz
  14. BIN
      sapl/static/sapl/frontend/css/compilacao.0baf3580.css.gz
  15. BIN
      sapl/static/sapl/frontend/css/global.042f6737.css.gz
  16. BIN
      sapl/static/sapl/frontend/css/painel.e2b9504e.css.gz
  17. BIN
      sapl/static/sapl/frontend/fonts/fa-brands-400.5d18d427.ttf.gz
  18. BIN
      sapl/static/sapl/frontend/fonts/fa-regular-400.81482cd4.ttf.gz
  19. BIN
      sapl/static/sapl/frontend/fonts/fa-solid-900.69d3141a.ttf.gz
  20. BIN
      sapl/static/sapl/frontend/fonts/fa-v4compatibility.2c070fd2.ttf.gz
  21. BIN
      sapl/static/sapl/frontend/img/down_arrow_select.jpg.gz
  22. BIN
      sapl/static/sapl/frontend/js/chunk-vendors.e8ab4373.js.LICENSE.txt.gz
  23. BIN
      sapl/static/sapl/frontend/js/chunk-vendors.e8ab4373.js.gz
  24. 4
      sapl/static/sapl/frontend/js/chunk-vendors.f2d6067d.js
  25. 0
      sapl/static/sapl/frontend/js/chunk-vendors.f2d6067d.js.LICENSE.txt
  26. BIN
      sapl/static/sapl/frontend/js/chunk-vendors.f2d6067d.js.LICENSE.txt.gz
  27. BIN
      sapl/static/sapl/frontend/js/chunk-vendors.f2d6067d.js.gz
  28. BIN
      sapl/static/sapl/frontend/js/compilacao.148cb66b.js.gz
  29. 2
      sapl/static/sapl/frontend/js/global.bb3e904b.js
  30. BIN
      sapl/static/sapl/frontend/js/global.bb3e904b.js.gz
  31. 2
      sapl/static/sapl/frontend/js/global.d557d20c.js
  32. 0
      sapl/static/sapl/frontend/js/global.d557d20c.js.LICENSE.txt
  33. BIN
      sapl/static/sapl/frontend/js/global.d557d20c.js.gz
  34. BIN
      sapl/static/sapl/frontend/js/painel.f3190acc.js.gz
  35. 1
      sapl/static/sapl/frontend/js/parlamentar.a1a4b65b.js
  36. BIN
      sapl/static/sapl/frontend/js/parlamentar.a1a4b65b.js.gz
  37. 1
      sapl/static/sapl/frontend/js/parlamentar.f63027a7.js
  38. BIN
      sapl/static/sapl/frontend/js/parlamentar.f63027a7.js.gz
  39. BIN
      sapl/static/sapl/frontend/js/skins/content/dark/content.css.gz
  40. BIN
      sapl/static/sapl/frontend/js/skins/content/dark/content.js.gz
  41. BIN
      sapl/static/sapl/frontend/js/skins/content/dark/content.min.css.gz
  42. BIN
      sapl/static/sapl/frontend/js/skins/content/default/content.css.gz
  43. BIN
      sapl/static/sapl/frontend/js/skins/content/default/content.js.gz
  44. BIN
      sapl/static/sapl/frontend/js/skins/content/default/content.min.css.gz
  45. BIN
      sapl/static/sapl/frontend/js/skins/content/document/content.css.gz
  46. BIN
      sapl/static/sapl/frontend/js/skins/content/document/content.js.gz
  47. BIN
      sapl/static/sapl/frontend/js/skins/content/document/content.min.css.gz
  48. BIN
      sapl/static/sapl/frontend/js/skins/content/tinymce-5-dark/content.css.gz
  49. BIN
      sapl/static/sapl/frontend/js/skins/content/tinymce-5-dark/content.js.gz
  50. BIN
      sapl/static/sapl/frontend/js/skins/content/tinymce-5-dark/content.min.css.gz
  51. BIN
      sapl/static/sapl/frontend/js/skins/content/tinymce-5/content.css.gz
  52. BIN
      sapl/static/sapl/frontend/js/skins/content/tinymce-5/content.js.gz
  53. BIN
      sapl/static/sapl/frontend/js/skins/content/tinymce-5/content.min.css.gz
  54. BIN
      sapl/static/sapl/frontend/js/skins/content/writer/content.css.gz
  55. BIN
      sapl/static/sapl/frontend/js/skins/content/writer/content.js.gz
  56. BIN
      sapl/static/sapl/frontend/js/skins/content/writer/content.min.css.gz
  57. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.css.gz
  58. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.inline.css.gz
  59. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.inline.js.gz
  60. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.inline.min.css.gz
  61. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.js.gz
  62. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.min.css.gz
  63. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.css.gz
  64. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.js.gz
  65. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.min.css.gz
  66. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.shadowdom.css.gz
  67. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.shadowdom.js.gz
  68. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.shadowdom.min.css.gz
  69. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide/content.css.gz
  70. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide/content.inline.css.gz
  71. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide/content.inline.js.gz
  72. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide/content.inline.min.css.gz
  73. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide/content.js.gz
  74. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide/content.min.css.gz
  75. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide/skin.css.gz
  76. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide/skin.js.gz
  77. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide/skin.min.css.gz
  78. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide/skin.shadowdom.css.gz
  79. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide/skin.shadowdom.js.gz
  80. BIN
      sapl/static/sapl/frontend/js/skins/ui/oxide/skin.shadowdom.min.css.gz
  81. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.css.gz
  82. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.inline.css.gz
  83. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.inline.js.gz
  84. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.inline.min.css.gz
  85. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.js.gz
  86. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.min.css.gz
  87. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.css.gz
  88. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.js.gz
  89. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.min.css.gz
  90. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.shadowdom.css.gz
  91. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.shadowdom.js.gz
  92. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.shadowdom.min.css.gz
  93. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.css.gz
  94. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.inline.css.gz
  95. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.inline.js.gz
  96. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.inline.min.css.gz
  97. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.js.gz
  98. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.min.css.gz
  99. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5/skin.css.gz
  100. BIN
      sapl/static/sapl/frontend/js/skins/ui/tinymce-5/skin.js.gz

17
CHANGES.md

@ -1,4 +1,21 @@
3.1.165-RC0 / 2026-02-20
========================
* Implementa Header LastModified na Api (#3808)
* Impl expansão dinâmica de campos na API (#3809)
* Seleciona tipo de votação para múltiplas matérias ao incluir na Ordem do Dia ou Expediente (#3781)
* Adiciona requestId em requisições
* Hot-fix: conserta erro em JS de voto individual
* Coloca negrito em resultado de votação
* Inversão da ordem de ano e número em Adicionar Norma
* Aumento de nome de parlamentar
* Aumento do tamanho de Nome e Tema da Audiência Pública
* Conserta bug na pesquisa do Relatório de Votações Nominais (#3803)
* feat: impl filtro m2m com lookup '__in' para buscas com multiplos ids (#3807)
* Refatora rate limiter
* Release: 3.1.164-RC5
3.1.164-RC5 / 2025-09-22 3.1.164-RC5 / 2025-09-22
======================== ========================

2
docker/docker-compose.yaml

@ -33,7 +33,7 @@ services:
networks: networks:
- sapl-net - sapl-net
sapl: sapl:
image: interlegis/sapl:3.1.164-RC5 image: interlegis/sapl:3.1.165-RC0
# build: # build:
# context: ../ # context: ../
# dockerfile: ./docker/Dockerfile # dockerfile: ./docker/Dockerfile

204
drfautoapi/drfautoapi.py

@ -1,4 +1,5 @@
from collections import OrderedDict from collections import OrderedDict
from functools import cached_property
import django_filters import django_filters
import importlib import importlib
import inspect import inspect
@ -6,14 +7,16 @@ import logging
import re import re
from django.conf import settings from django.conf import settings
from django.contrib.contenttypes.models import ContentType
from django.contrib.postgres.fields.jsonb import JSONField from django.contrib.postgres.fields.jsonb import JSONField
from django.contrib.auth import get_user_model
from django.db.models.base import ModelBase from django.db.models.base import ModelBase
from django.db.models.fields import TextField, CharField from django.db.models.fields import TextField, CharField
from django.db.models.fields.files import FileField from django.db.models.fields.files import FileField
from django.db.models.fields.related import ManyToManyField from django.db.models.fields.related import ManyToManyField
from django.template.defaultfilters import capfirst from django.template.defaultfilters import capfirst
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.urls.conf import path from django.urls import reverse
from django_filters.constants import ALL_FIELDS, EMPTY_VALUES from django_filters.constants import ALL_FIELDS, EMPTY_VALUES
from django_filters.fields import ModelMultipleChoiceField from django_filters.fields import ModelMultipleChoiceField
from django_filters.filters import CharFilter from django_filters.filters import CharFilter
@ -21,6 +24,7 @@ from django_filters.filterset import FilterSet
from django_filters.rest_framework.backends import DjangoFilterBackend from django_filters.rest_framework.backends import DjangoFilterBackend
from django_filters.utils import resolve_field, get_all_model_fields from django_filters.utils import resolve_field, get_all_model_fields
from rest_framework import serializers as rest_serializers from rest_framework import serializers as rest_serializers
from rest_framework.relations import ManyRelatedField
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
@ -85,6 +89,7 @@ class M2MFilter(django_filters.ModelMultipleChoiceFilter):
class ApiFilterSetMixin(FilterSet): class ApiFilterSetMixin(FilterSet):
o = CharFilter(method='filter_o') o = CharFilter(method='filter_o')
id__in = CharFilter(method='filter_id__in')
class Meta: class Meta:
fields = '__all__' fields = '__all__'
@ -109,6 +114,13 @@ class ApiFilterSetMixin(FilterSet):
}, },
} }
def filter_id__in(self, queryset, name, value):
try:
ids = [int(v.strip()) for v in value.split(',')]
return queryset.filter(id__in=ids)
except:
return queryset
def filter_o(self, queryset, name, value): def filter_o(self, queryset, name, value):
try: try:
return queryset.order_by( return queryset.order_by(
@ -219,6 +231,17 @@ class ApiViewSetConstrutor():
class ApiViewSet(ModelViewSet): class ApiViewSet(ModelViewSet):
filter_backends = (DjangoFilterBackend,) filter_backends = (DjangoFilterBackend,)
class LastModifiedDecorator(object):
def __init__(self):
pass
def __call__(self, cls):
return cls
@classmethod
def last_modified_class(cls, klass):
cls.LastModifiedDecorator = klass
return cls
@classmethod @classmethod
def get_viewset_for_model(cls, model): def get_viewset_for_model(cls, model):
return cls._built_sets[model._meta.app_config][model] return cls._built_sets[model._meta.app_config][model]
@ -334,6 +357,7 @@ class ApiViewSetConstrutor():
if not hasattr(_meta_filterset, 'model'): if not hasattr(_meta_filterset, 'model'):
model = _model model = _model
@cls.LastModifiedDecorator()
class ModelApiViewSet(ApiViewSetConstrutor.ApiViewSet): class ModelApiViewSet(ApiViewSetConstrutor.ApiViewSet):
queryset = _model.objects.all() queryset = _model.objects.all()
filterset_class = ApiFilterSet filterset_class = ApiFilterSet
@ -434,3 +458,181 @@ class customize(object):
return _ApiViewSet return _ApiViewSet
class DrfAutoApiSerializerMixin(rest_serializers.ModelSerializer):
"""
Mixin de Serializer que implementa expansão dinâmica de campos
via parâmetros de query string:
- `expand`: expande os campos informados
- `include`: inclui apenas os campos informados
- `exclude`: exclui os campos informados
Exemplo:
- ?expand=campo1;campo2.sub_campo1,sub_campo2;campo3.sub_campo1.sub_sub_campo1,sub_sub_campo2
- ?include=campo1;campo2.sub_campo1,sub_campo2;campo3.sub_campo1.sub_sub_campo1,sub_sub_campo2
- ?exclude=campo1;campo2.sub_campo1,sub_campo2;campo3.sub_campo1.sub_sub_campo1,sub_sub_campo2
- ?expand=campo1&include=campo1.id,name&exclude=campo1.secret_field
Onde:
- campo1, campo2, campo3 são campos do model raiz
- sub_campo1, sub_campo2 são campos relacionados do campo2
- sub_sub_campo1, sub_sub_campo2 são campos relacionados do sub_campo1
Ou seja:
";" separa campos independentes do nível atual
"," separa campos relacionados do mesmo campo pai
"." indica o nível de profundidade dos campos relacionados
e ainda:
- `expand` pode ser usado para expansão direta, ou seja, campo1.sub_campo1 expande campo1
- `expand`, `include` e `exclude` podem ser usados juntos na mesma requisição
- `include` e `exclude` funcionam em subniveis se o campo pai estiver expandido
- `include` tem precedência sobre `exclude` e remove todo o resto
- `exclude` remove o campo do resultado final, mesmo que esteja em `include`
- Se nenhum dos parâmetros for informado, nenhum campo será expandido
- Filtros da API, paginação (`page` e `page_size`) e ordenação (`o`)
podem ser usados normalmente para filtrar os resultados
Atenção:
- A expansão não é aplicada para o model User do Django
- A expansão não é aplicada para campos customizados que utilizam SerializerMethodField
- Uma exceção é lançada e registrada no log caso ocorra algum erro na expansão de algum campo,
inclusive devido a recursão infinita
- A expansão automática de todos os campos relacionados (expand=all) está desabilitada
por necessidade de controle mais refinado.
- A expansão de campos relacionados ForeignKey e OneToOne é suportada.
- A expansão de campos relacionados ManyToMany é suportada.
- A expansão de campos relacionados reversos (related_name) não é suportada, mas pode ser implementada manualmente no serializer customizado, ou vir a ser implementada no futuro.
"""
__str__ = rest_serializers.SerializerMethodField()
class Meta:
fields = '__all__'
def get___str__(self, obj) -> str:
return str(obj)
@cached_property
def user_model(self):
return get_user_model()
def get_control_fields(self, control_field='expand'):
request = self.context.get('request', None)
if request:
param = request.query_params.get(control_field, '')
param = [e.strip() for e in param.split(';') if e.strip()]
param = [e.split('.') for e in param]
return param
return []
def get_fields(self):
fields = super().get_fields()
if not hasattr(self.root, 'drf_expand_fields'):
self.root.drf_expand_fields = self.get_control_fields('expand')
self.root.drf_include_fields = self.get_control_fields('include')
self.root.drf_exclude_fields = self.get_control_fields('exclude')
if not (self.root.drf_expand_fields or self.root.drf_include_fields or self.root.drf_exclude_fields):
return fields
model = self.Meta.model
expand_fields = self.root.drf_expand_fields
include_fields = self.root.drf_include_fields
exclude_fields = self.root.drf_exclude_fields
expand_all = False #['all'] in expand_fields
#if expand_all:
# request = self.context.get('request', None)
# user = getattr(request, 'user', None)
# expand_all = user and user.is_superuser
def parents(nd):
if not nd:
return []
return parents(nd.parent) + [nd.field_name]
sources = parents(self)
sources = list(filter(lambda x: x, sources))
if expand_fields:
exps = []
for exp in expand_fields:
if len(exp) > len(sources) and exp[0:len(sources)] == sources:
exps.extend(exp[len(sources)].split(','))
expand_fields = exps
if include_fields:
incls = []
for inf in include_fields:
if len(inf) - 1 == len(sources) and inf[:-1] == sources:
incls.extend(inf[-1].split(','))
if incls:
fields = OrderedDict(
[(k, v) for k, v in fields.items() if k in incls]
)
if exclude_fields:
excls = []
for inf in exclude_fields:
if len(inf) - 1 == len(sources) and inf[:-1] == sources:
excls.extend(inf[-1].split(','))
if excls:
fields = OrderedDict(
[(k, v) for k, v in fields.items() if k not in excls]
)
fields_with_relations_map_model = {f.name: f.related_model for f in model._meta.get_fields()
if f.is_relation and f.name in fields}
set_fields_with_relations = set(fields_with_relations_map_model.keys())
set_expand_fields = set(expand_fields)
set_fields_serialized = set(
map(
lambda kv: kv[0],
filter(
lambda kv: not isinstance(kv[1], rest_serializers.SerializerMethodField),
fields.items()
)
)
)
expand_fields = set_fields_with_relations.intersection(set_fields_serialized)
if not expand_all:
expand_fields = expand_fields.intersection(set_expand_fields)
# remove o User model da expansão
if self.user_model in fields_with_relations_map_model.values():
expand_fields = [f for f in expand_fields
if fields_with_relations_map_model[f] != self.user_model]
if not expand_fields:
return fields
for field_name in expand_fields:
field = fields[field_name]
model = fields_with_relations_map_model[field_name]
if model:
try:
serializer_class = ApiViewSetConstrutor.get_viewset_for_model(model).serializer_class
if hasattr(field, 'many') and field.many or isinstance(field, ManyRelatedField):
serializer_class = serializer_class(
many=True,
read_only=True,
context=self.context
)
else:
serializer_class = serializer_class(
read_only=True,
context=self.context
)
fields[field_name] = serializer_class
except Exception as e:
logger.error(f'Erro ao expandir campo {field_name} do model {model}: {e}')
return fields

6
frontend/src/__apps/parlamentar/main.js

@ -3,6 +3,12 @@ import Vue from 'vue'
import { FormSelectPlugin } from 'bootstrap-vue' import { FormSelectPlugin } from 'bootstrap-vue'
import axios from 'axios' import axios from 'axios'
// TODO: refatorar para aproveitar cache e LastModified no frontend oficial
// Configuração global para todas as requisições GET do axios
axios.defaults.headers.get['Cache-Control'] = 'no-cache, no-store, must-revalidate'
axios.defaults.headers.get['Pragma'] = 'no-cache' // Suporte para navegadores mais antigos
axios.defaults.headers.get['Expires'] = '0' // Expira imediatamente
axios.defaults.xsrfCookieName = 'csrftoken' axios.defaults.xsrfCookieName = 'csrftoken'
axios.defaults.xsrfHeaderName = 'X-CSRFToken' axios.defaults.xsrfHeaderName = 'X-CSRFToken'

3
frontend/src/__global/js/functions.js

@ -66,7 +66,8 @@ window.autorModal = function () {
$('#pesquisar').click(function () { $('#pesquisar').click(function () {
const json_data = { const json_data = {
q: $('#q').val() q: $('#q').val(),
utc_time: Date.now(),
// get_all: true // get_all: true
} }
$.get('/api/base/autor', json_data, function (data) { $.get('/api/base/autor', json_data, function (data) {

90
frontend/webpack-stats.json

@ -271,25 +271,25 @@
"path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/user.png", "path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/user.png",
"publicPath": "/static/sapl/frontend/img/user.png" "publicPath": "/static/sapl/frontend/img/user.png"
}, },
"js/chunk-vendors.e8ab4373.js": { "js/chunk-vendors.f2d6067d.js": {
"name": "js/chunk-vendors.e8ab4373.js", "name": "js/chunk-vendors.f2d6067d.js",
"path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/chunk-vendors.e8ab4373.js", "path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/chunk-vendors.f2d6067d.js",
"publicPath": "/static/sapl/frontend/js/chunk-vendors.e8ab4373.js" "publicPath": "/static/sapl/frontend/js/chunk-vendors.f2d6067d.js"
}, },
"js/chunk-vendors.e8ab4373.js.gz": { "js/chunk-vendors.f2d6067d.js.gz": {
"name": "js/chunk-vendors.e8ab4373.js.gz", "name": "js/chunk-vendors.f2d6067d.js.gz",
"path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/chunk-vendors.e8ab4373.js.gz", "path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/chunk-vendors.f2d6067d.js.gz",
"publicPath": "/static/sapl/frontend/js/chunk-vendors.e8ab4373.js.gz" "publicPath": "/static/sapl/frontend/js/chunk-vendors.f2d6067d.js.gz"
}, },
"js/chunk-vendors.e8ab4373.js.LICENSE.txt": { "js/chunk-vendors.f2d6067d.js.LICENSE.txt": {
"name": "js/chunk-vendors.e8ab4373.js.LICENSE.txt", "name": "js/chunk-vendors.f2d6067d.js.LICENSE.txt",
"path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/chunk-vendors.e8ab4373.js.LICENSE.txt", "path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/chunk-vendors.f2d6067d.js.LICENSE.txt",
"publicPath": "/static/sapl/frontend/js/chunk-vendors.e8ab4373.js.LICENSE.txt" "publicPath": "/static/sapl/frontend/js/chunk-vendors.f2d6067d.js.LICENSE.txt"
}, },
"js/chunk-vendors.e8ab4373.js.LICENSE.txt.gz": { "js/chunk-vendors.f2d6067d.js.LICENSE.txt.gz": {
"name": "js/chunk-vendors.e8ab4373.js.LICENSE.txt.gz", "name": "js/chunk-vendors.f2d6067d.js.LICENSE.txt.gz",
"path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/chunk-vendors.e8ab4373.js.LICENSE.txt.gz", "path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/chunk-vendors.f2d6067d.js.LICENSE.txt.gz",
"publicPath": "/static/sapl/frontend/js/chunk-vendors.e8ab4373.js.LICENSE.txt.gz" "publicPath": "/static/sapl/frontend/js/chunk-vendors.f2d6067d.js.LICENSE.txt.gz"
}, },
"js/compilacao.148cb66b.js": { "js/compilacao.148cb66b.js": {
"name": "js/compilacao.148cb66b.js", "name": "js/compilacao.148cb66b.js",
@ -301,20 +301,20 @@
"path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/compilacao.148cb66b.js.gz", "path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/compilacao.148cb66b.js.gz",
"publicPath": "/static/sapl/frontend/js/compilacao.148cb66b.js.gz" "publicPath": "/static/sapl/frontend/js/compilacao.148cb66b.js.gz"
}, },
"js/global.bb3e904b.js": { "js/global.d557d20c.js": {
"name": "js/global.bb3e904b.js", "name": "js/global.d557d20c.js",
"path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/global.bb3e904b.js", "path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/global.d557d20c.js",
"publicPath": "/static/sapl/frontend/js/global.bb3e904b.js" "publicPath": "/static/sapl/frontend/js/global.d557d20c.js"
}, },
"js/global.bb3e904b.js.gz": { "js/global.d557d20c.js.gz": {
"name": "js/global.bb3e904b.js.gz", "name": "js/global.d557d20c.js.gz",
"path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/global.bb3e904b.js.gz", "path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/global.d557d20c.js.gz",
"publicPath": "/static/sapl/frontend/js/global.bb3e904b.js.gz" "publicPath": "/static/sapl/frontend/js/global.d557d20c.js.gz"
}, },
"js/global.bb3e904b.js.LICENSE.txt": { "js/global.d557d20c.js.LICENSE.txt": {
"name": "js/global.bb3e904b.js.LICENSE.txt", "name": "js/global.d557d20c.js.LICENSE.txt",
"path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/global.bb3e904b.js.LICENSE.txt", "path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/global.d557d20c.js.LICENSE.txt",
"publicPath": "/static/sapl/frontend/js/global.bb3e904b.js.LICENSE.txt" "publicPath": "/static/sapl/frontend/js/global.d557d20c.js.LICENSE.txt"
}, },
"js/painel.f3190acc.js": { "js/painel.f3190acc.js": {
"name": "js/painel.f3190acc.js", "name": "js/painel.f3190acc.js",
@ -326,15 +326,15 @@
"path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/painel.f3190acc.js.gz", "path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/painel.f3190acc.js.gz",
"publicPath": "/static/sapl/frontend/js/painel.f3190acc.js.gz" "publicPath": "/static/sapl/frontend/js/painel.f3190acc.js.gz"
}, },
"js/parlamentar.a1a4b65b.js": { "js/parlamentar.f63027a7.js": {
"name": "js/parlamentar.a1a4b65b.js", "name": "js/parlamentar.f63027a7.js",
"path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/parlamentar.a1a4b65b.js", "path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/parlamentar.f63027a7.js",
"publicPath": "/static/sapl/frontend/js/parlamentar.a1a4b65b.js" "publicPath": "/static/sapl/frontend/js/parlamentar.f63027a7.js"
}, },
"js/parlamentar.a1a4b65b.js.gz": { "js/parlamentar.f63027a7.js.gz": {
"name": "js/parlamentar.a1a4b65b.js.gz", "name": "js/parlamentar.f63027a7.js.gz",
"path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/parlamentar.a1a4b65b.js.gz", "path": "/home/leandrojatai/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/parlamentar.f63027a7.js.gz",
"publicPath": "/static/sapl/frontend/js/parlamentar.a1a4b65b.js.gz" "publicPath": "/static/sapl/frontend/js/parlamentar.f63027a7.js.gz"
}, },
"js/skins/content/dark/content.css": { "js/skins/content/dark/content.css": {
"name": "js/skins/content/dark/content.css", "name": "js/skins/content/dark/content.css",
@ -1000,27 +1000,27 @@
"chunks": { "chunks": {
"compilacao": [ "compilacao": [
"css/chunk-vendors.045ec640.css", "css/chunk-vendors.045ec640.css",
"js/chunk-vendors.e8ab4373.js", "js/chunk-vendors.f2d6067d.js",
"css/compilacao.0baf3580.css", "css/compilacao.0baf3580.css",
"js/compilacao.148cb66b.js" "js/compilacao.148cb66b.js"
], ],
"global": [ "global": [
"css/chunk-vendors.045ec640.css", "css/chunk-vendors.045ec640.css",
"js/chunk-vendors.e8ab4373.js", "js/chunk-vendors.f2d6067d.js",
"css/global.042f6737.css", "css/global.042f6737.css",
"js/global.bb3e904b.js" "js/global.d557d20c.js"
], ],
"painel": [ "painel": [
"css/chunk-vendors.045ec640.css", "css/chunk-vendors.045ec640.css",
"js/chunk-vendors.e8ab4373.js", "js/chunk-vendors.f2d6067d.js",
"css/painel.e2b9504e.css", "css/painel.e2b9504e.css",
"js/painel.f3190acc.js" "js/painel.f3190acc.js"
], ],
"parlamentar": [ "parlamentar": [
"css/chunk-vendors.045ec640.css", "css/chunk-vendors.045ec640.css",
"js/chunk-vendors.e8ab4373.js", "js/chunk-vendors.f2d6067d.js",
"css/parlamentar.cd5dc5a8.css", "css/parlamentar.cd5dc5a8.css",
"js/parlamentar.a1a4b65b.js" "js/parlamentar.f63027a7.js"
] ]
}, },
"publicPath": "/static/sapl/frontend/" "publicPath": "/static/sapl/frontend/"

18
sapl/api/serializers.py

@ -4,6 +4,8 @@ from django.conf import settings
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
from django.db.models import Q from django.db.models import Q
from django.urls import reverse
from drfautoapi.drfautoapi import DrfAutoApiSerializerMixin
from image_cropping.utils import get_backend from image_cropping.utils import get_backend
from rest_framework import serializers from rest_framework import serializers
from rest_framework.fields import SerializerMethodField from rest_framework.fields import SerializerMethodField
@ -13,16 +15,13 @@ from sapl.parlamentares.models import Parlamentar, Mandato, Legislatura
from sapl.sessao.models import OrdemDia, SessaoPlenaria from sapl.sessao.models import OrdemDia, SessaoPlenaria
class SaplSerializerMixin(serializers.ModelSerializer): class SaplSerializerMixin(DrfAutoApiSerializerMixin):
__str__ = SerializerMethodField() link_detail_backend = serializers.SerializerMethodField()
metadata = SerializerMethodField() metadata = SerializerMethodField()
class Meta: class Meta(DrfAutoApiSerializerMixin.Meta):
fields = '__all__' fields = '__all__'
def get___str__(self, obj) -> str:
return str(obj)
def get_metadata(self, obj) -> dict: def get_metadata(self, obj) -> dict:
try: try:
metadata = Metadata.objects.get( metadata = Metadata.objects.get(
@ -35,6 +34,13 @@ class SaplSerializerMixin(serializers.ModelSerializer):
finally: finally:
return metadata return metadata
def get_link_detail_backend(self, obj) -> str:
try:
return reverse(f'{self.Meta.model._meta.app_config.name}:{self.Meta.model._meta.model_name}_detail',
kwargs={'pk': obj.pk})
except:
return ''
class ChoiceSerializer(serializers.Serializer): class ChoiceSerializer(serializers.Serializer):
value = serializers.SerializerMethodField() value = serializers.SerializerMethodField()

117
sapl/api/views.py

@ -9,6 +9,9 @@ from rest_framework.response import Response
from rest_framework.views import APIView from rest_framework.views import APIView
from drfautoapi.drfautoapi import ApiViewSetConstrutor from drfautoapi.drfautoapi import ApiViewSetConstrutor
from django.views.decorators.http import condition as django_condition
from sapl.base.models import AuditLog
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -21,8 +24,122 @@ def recria_token(request, pk):
return Response({"message": "Token recriado com sucesso!", "token": token.key}) return Response({"message": "Token recriado com sucesso!", "token": token.key})
class LastModifiedDecorator:
""" - Decorator para adicionar suporte a Last-Modified em ViewSets
- Baseado em django.views.decorators.http.condition
- Por padrão utiliza o AuditLog para determinar a data do last_modified
- Pode ser sobrescrito na customização do ViewSet caso necessário
- Existe um exemplo de sobrescrita em sapl/api/views_materia.py
- Devolve Last-Modified baseado no timestamp do último AuditLog
- Se for uma listagem, considera o último AuditLog de todos os objetos
retornados na listagem levando em consideração resultado de FilterSet.
- Retorna 304 Not Modified se o recurso não foi modificado
"""
def __call__(self, cls):
original_dispatch = cls.dispatch
self.model = cls.queryset.model
def wrapped_dispatch(view, request, *args, **kwargs):
drf_request = request
wsgi_request = view.initialize_request(request, *args, **kwargs)
last_modified_func = self.last_modified_func if not hasattr(view, 'last_modified_func') else view.last_modified_func
def patched_viewset_method(*_args, **_kwargs):
return original_dispatch(view, drf_request, *args, **kwargs)
django_decorator = django_condition(last_modified_func=last_modified_func)
decorated_viewset_method = django_decorator(patched_viewset_method)
return decorated_viewset_method(wsgi_request, *args, view=view, **kwargs)
cls.dispatch = wrapped_dispatch
return cls
def last_modified_func(self, request, *args, **kwargs):
default_fields_for_timestamp = (
'data_ultima_atualizacao',
'ultima_edicao'
)
# tenta encontrar um dos campos acima para usar como last_modified
fields = tuple(
filter(
lambda f: f in default_fields_for_timestamp,
map(
lambda f: f.name, self.model._meta.get_fields()
)
)
)
field_name = fields[0] if fields else None
# Retornando None. que indica para o decorator retornar 200 OK sem Last-Modified
# Na prática, desativando o AuditLog como last_modified
# Porém, mantendo a estrutura para possível uso futuro
if not field_name:
# sem campo definido para last_modified, usa AuditLog
return None # self.last_modified_func__auditlog(request, *args, **kwargs)
pk = kwargs.get('pk', None)
if pk:
return self.model.objects.filter(pk=pk).values_list(field_name, flat=True)[:1].first()
view = kwargs.get('view', None)
if view:
queryset = view.get_queryset()
for backend in list(view.filter_backends):
queryset = backend().filter_queryset(request, queryset, view)
else:
queryset = self.model.objects.all()
timestamp = queryset.order_by(f'-{field_name}').values_list(field_name, flat=True)[:1].first()
return timestamp
def last_modified_func__auditlog(self, request, *args, **kwargs):
""" - Método padrão para obter o last_modified baseado no AuditLog
- Pode ser sobrescrito na customização do ViewSet caso necessário
- Existe um exemplo de sobrescrita em sapl/api/views_materia.py
"""
try:
if 'pk' in kwargs:
obj_id = kwargs['pk']
last_log = AuditLog.objects.filter(
model_name=self.model._meta.model_name,
object_id=obj_id
).order_by('-timestamp').values_list('timestamp', flat=True)[:1].first()
else:
view = kwargs.get('view', None)
if view:
for backend in list(view.filter_backends):
queryset = backend().filter_queryset(request, view.queryset, view)
if queryset.exists():
last_log = AuditLog.objects.filter(
model_name=self.model._meta.model_name,
object_id__in=queryset.values_list('pk', flat=True)
).order_by('-timestamp').values_list('timestamp', flat=True)[:1].first()
else:
last_log = None
else:
last_log = AuditLog.objects.filter(
model_name=self.model._meta.model_name,
object_id__in=self.model.objects.values_list('pk', flat=True)
).order_by('-timestamp').values_list('timestamp', flat=True)[:1].first()
if last_log:
return last_log
except Exception as e:
logger.error(f"Erro ao obter last_modified: {e}")
return None
SaplApiViewSetConstrutor = ApiViewSetConstrutor SaplApiViewSetConstrutor = ApiViewSetConstrutor
SaplApiViewSetConstrutor.last_modified_class(LastModifiedDecorator)
SaplApiViewSetConstrutor.import_modules([ SaplApiViewSetConstrutor.import_modules([
'sapl.api.views_audiencia', 'sapl.api.views_audiencia',
'sapl.api.views_base', 'sapl.api.views_base',

19
sapl/api/views_materia.py

@ -110,6 +110,25 @@ class _MateriaLegislativaViewSet:
self.queryset = self.get_object().anexadas.all() self.queryset = self.get_object().anexadas.all()
return self.list(request, *args, **kwargs) return self.list(request, *args, **kwargs)
"""
O próprio decorator LastModifiedDecorator implementa o método last_modified_func que atende o caso
específico de MateriaLegislativa, baseado no campo data_ultima_atualizacao.
Portanto, não necessidade de reimplementar este método aqui. Mas segue o código comentado
para referência futura caso necessário e como exemplo de implementação customizada que sobrescreve
o comportamento padrão do decorator.
def last_modified_func(self, request, *args, **kwargs):
pk = kwargs.get('pk', None)
if pk:
return MateriaLegislativa.objects.filter(pk=pk).values_list('data_ultima_atualizacao', flat=True)[:1].first()
queryset = self.get_queryset()
for backend in list(self.filter_backends):
queryset = backend().filter_queryset(request, self.queryset, self)
timestamp = queryset.order_by('-data_ultima_atualizacao').values_list('data_ultima_atualizacao', flat=True)[:1].first()
return timestamp
"""
@customize(TipoMateriaLegislativa) @customize(TipoMateriaLegislativa)
class _TipoMateriaLegislativaViewSet: class _TipoMateriaLegislativaViewSet:

19
sapl/sessao/forms.py

@ -22,7 +22,8 @@ from sapl.materia.models import (MateriaLegislativa, StatusTramitacao,
from sapl.parlamentares.models import Mandato, Parlamentar from sapl.parlamentares.models import Mandato, Parlamentar
from sapl.protocoloadm.models import TipoDocumentoAdministrativo,\ from sapl.protocoloadm.models import TipoDocumentoAdministrativo,\
DocumentoAdministrativo DocumentoAdministrativo
from sapl.sessao.models import Correspondencia from sapl.sessao.models import Correspondencia, AbstractOrdemDia
from sapl.utils import (autor_label, autor_modal, from sapl.utils import (autor_label, autor_modal,
choice_anos_com_sessaoplenaria, choice_anos_com_sessaoplenaria,
FileFieldCheckMixin, FileFieldCheckMixin,
@ -563,6 +564,22 @@ class SessaoPlenariaFilterSet(django_filters.FilterSet):
) )
class AdicionarVariasMateriasForm(forms.Form):
check_all = forms.BooleanField(
label='Marcar/Desmarcar Todos',
required=False,
widget=forms.CheckboxInput(
attrs={'onchange':'checkAll(this)'}),
)
tipo_votacao = forms.ChoiceField(required=False,
choices= AbstractOrdemDia.TIPO_VOTACAO_CHOICES,
initial=False,
widget=forms.RadioSelect(
attrs={'onchange':'marcaTipoVotacao()'}),
)
class AdicionarVariasMateriasFilterSet(MateriaLegislativaFilterSet): class AdicionarVariasMateriasFilterSet(MateriaLegislativaFilterSet):
o = MateriaPesquisaOrderingFilter() o = MateriaPesquisaOrderingFilter()

4
sapl/sessao/views.py

@ -51,7 +51,7 @@ from sapl.settings import TIME_ZONE, RATE_LIMITER_RATE
from sapl.utils import show_results_filter_set, remover_acentos, get_client_ip, \ from sapl.utils import show_results_filter_set, remover_acentos, get_client_ip, \
MultiFormatOutputMixin, PautaMultiFormatOutputMixin, ratelimit_ip MultiFormatOutputMixin, PautaMultiFormatOutputMixin, ratelimit_ip
from .forms import (AdicionarVariasMateriasFilterSet, BancadaForm, from .forms import (AdicionarVariasMateriasFilterSet, AdicionarVariasMateriasForm, BancadaForm,
ExpedienteForm, JustificativaAusenciaForm, OcorrenciaSessaoForm, ListMateriaForm, ExpedienteForm, JustificativaAusenciaForm, OcorrenciaSessaoForm, ListMateriaForm,
MesaForm, OradorExpedienteForm, OradorForm, PautaSessaoFilterSet, MesaForm, OradorExpedienteForm, OradorForm, PautaSessaoFilterSet,
PresencaForm, ResumoOrdenacaoForm, SessaoPlenariaFilterSet, PresencaForm, ResumoOrdenacaoForm, SessaoPlenariaFilterSet,
@ -4190,6 +4190,8 @@ class AdicionarVariasMateriasExpediente(PermissionRequiredForAppCrudMixin,
qr = self.request.GET.copy() qr = self.request.GET.copy()
form = AdicionarVariasMateriasForm
context['form'] = form
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else '' context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
context['pk_sessao'] = self.kwargs['pk'] context['pk_sessao'] = self.kwargs['pk']

2
sapl/settings.py

@ -43,7 +43,7 @@ ALLOWED_HOSTS = ['*']
LOGIN_REDIRECT_URL = '/' LOGIN_REDIRECT_URL = '/'
LOGIN_URL = '/login/?next=' LOGIN_URL = '/login/?next='
SAPL_VERSION = '3.1.164-RC5' SAPL_VERSION = '3.1.165-RC0'
if DEBUG: if DEBUG:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

BIN
sapl/static/sapl/frontend/css/chunk-vendors.045ec640.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/css/compilacao.0baf3580.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/css/global.042f6737.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/css/painel.e2b9504e.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-brands-400.5d18d427.ttf.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-regular-400.81482cd4.ttf.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-solid-900.69d3141a.ttf.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/fonts/fa-v4compatibility.2c070fd2.ttf.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/img/down_arrow_select.jpg.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/chunk-vendors.e8ab4373.js.LICENSE.txt.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/chunk-vendors.e8ab4373.js.gz

Binary file not shown.

4
sapl/static/sapl/frontend/js/chunk-vendors.e8ab4373.js → sapl/static/sapl/frontend/js/chunk-vendors.f2d6067d.js

File diff suppressed because one or more lines are too long

0
sapl/static/sapl/frontend/js/chunk-vendors.e8ab4373.js.LICENSE.txt → sapl/static/sapl/frontend/js/chunk-vendors.f2d6067d.js.LICENSE.txt

BIN
sapl/static/sapl/frontend/js/chunk-vendors.f2d6067d.js.LICENSE.txt.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/chunk-vendors.f2d6067d.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/compilacao.148cb66b.js.gz

Binary file not shown.

2
sapl/static/sapl/frontend/js/global.bb3e904b.js

File diff suppressed because one or more lines are too long

BIN
sapl/static/sapl/frontend/js/global.bb3e904b.js.gz

Binary file not shown.

2
sapl/static/sapl/frontend/js/global.d557d20c.js

File diff suppressed because one or more lines are too long

0
sapl/static/sapl/frontend/js/global.bb3e904b.js.LICENSE.txt → sapl/static/sapl/frontend/js/global.d557d20c.js.LICENSE.txt

BIN
sapl/static/sapl/frontend/js/global.d557d20c.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/painel.f3190acc.js.gz

Binary file not shown.

1
sapl/static/sapl/frontend/js/parlamentar.a1a4b65b.js

@ -1 +0,0 @@
(()=>{"use strict";var u,p,e,t={8020:(e,a,t)=>{t(3792),t(3362),t(9085),t(9391),t(6918),t(2008),t(2712),t(3288),t(6099),t(8781);var r=t(2893),i=t(8246),s=t(7906),n=t(2543);s.A.defaults.xsrfCookieName="csrftoken",s.A.defaults.xsrfHeaderName="X-CSRFToken",r.Ay.use(i.m0),new r.Ay({delimiters:["[[","]]"],el:"#app2",data:function(){return{nome_pesquisa:"",is_pesquisa:!1,legislatura_selecionada:"",legislaturas:[],parlamentares:[],visible_parlamentares:[],size_parlamentares:0,filter_ativo:!0,filter_titular:""}},watch:{nome_pesquisa:function(e){this.debouncepesquisaParlamentar()}},created:function(){this.debouncepesquisaParlamentar=n.debounce(this.pesquisaParlamentar,500)},methods:{getParlamentares:function(e){var a=this;!this.legislatura_selecionada&&"0"!==this.legislatura_selecionada.toString()||s.A.get("/api/parlamentares/legislatura/"+this.legislatura_selecionada+"/parlamentares/?get_all=true").then(function(e){a.parlamentares=e.data,a.visible_parlamentares=a.parlamentares,a.size_parlamentares=a.visible_parlamentares.length,a.checkTitularAtivo()}).catch(function(e){console.error("Ocorreu um erro ao obter os dados de parlamentares:"+e)})},pesquisaParlamentar:function(e){var a=this;s.A.get("/api/parlamentares/parlamentar/search_parlamentares/",{params:{nome_parlamentar:this.nome_pesquisa}}).then(function(e){a.parlamentares=e.data,a.visible_parlamentares=a.parlamentares,a.size_parlamentares=a.visible_parlamentares.length}).catch(function(e){console.error("Erro ao procurar parlamentar:"+e)})},checkTitularAtivo:function(e){this.visible_parlamentares=this.parlamentares,this.filter_ativo&&(this.visible_parlamentares=this.visible_parlamentares.filter(function(e){return e.ativo})),this.filter_titular&&(this.visible_parlamentares=this.visible_parlamentares.filter(function(e){return"Sim"===e.titular})),this.size_parlamentares=this.visible_parlamentares.length},pesquisaChange:function(e){this.is_pesquisa=!this.is_pesquisa,this.filter_ativo=!0,this.is_pesquisa?this.parlamentares=[]:this.getParlamentares()}},mounted:function(){var a=this;s.A.get("/api/parlamentares/legislatura/?get_all=true").then(function(e){a.legislaturas=e.data;var i=(new Date).getFullYear();a.legislatura_selecionada=a.legislaturas.reduce(function(e,a){var t=new Date(a.data_inicio+" 00:00").getFullYear(),r=new Date(a.data_fim+" 00:00").getFullYear();return e=t<=i&&i<=r?a.id:e},"")}).then(function(e){a.getParlamentares()}).catch(function(e){console.error("Ocorreu um erro ao obter os dados de legislação: "+e)})}})}},r={};function c(e){var a=r[e];return void 0!==a||(a=r[e]={id:e,loaded:!1,exports:{}},t[e].call(a.exports,a,a.exports,c),a.loaded=!0),a.exports}c.m=t,u=[],c.O=(e,a,t,r)=>{if(!a){for(var i=1/0,s=0;s<u.length;s++){for(var n,[a,t,r]=u[s],l=!0,o=0;o<a.length;o++)(!1&r||r<=i)&&Object.keys(c.O).every(e=>c.O[e](a[o]))?a.splice(o--,1):(l=!1,r<i&&(i=r));l&&(u.splice(s--,1),void 0!==(n=t()))&&(e=n)}return e}r=r||0;for(var s=u.length;0<s&&u[s-1][2]>r;s--)u[s]=u[s-1];u[s]=[a,t,r]},c.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return c.d(a,{a:a}),a},c.d=(e,a)=>{for(var t in a)c.o(a,t)&&!c.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},c.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),c.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),c.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},c.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),c.j=788,p={788:0},c.O.j=e=>0===p[e],a=(e,a)=>{var t,r,i,[s,n,l]=a,o=0;if(s.some(e=>0!==p[e])){for(t in n)c.o(n,t)&&(c.m[t]=n[t]);l&&(i=l(c))}for(e&&e(a);o<s.length;o++)r=s[o],c.o(p,r)&&p[r]&&p[r][0](),p[r]=0;return c.O(i)},(e=self.webpackChunksapl_frontend=self.webpackChunksapl_frontend||[]).forEach(a.bind(null,0)),e.push=a.bind(null,e.push.bind(e));var a=c.O(void 0,[504],()=>c(8020));c.O(a)})();

BIN
sapl/static/sapl/frontend/js/parlamentar.a1a4b65b.js.gz

Binary file not shown.

1
sapl/static/sapl/frontend/js/parlamentar.f63027a7.js

@ -0,0 +1 @@
(()=>{"use strict";var u,c,e,t={8020:(e,a,t)=>{t(3792),t(3362),t(9085),t(9391),t(6918),t(2008),t(2712),t(3288),t(6099),t(8781);var r=t(2893),s=t(8246),i=t(7906),n=t(2543);i.A.defaults.headers.get["Cache-Control"]="no-cache, no-store, must-revalidate",i.A.defaults.headers.get.Pragma="no-cache",i.A.defaults.headers.get.Expires="0",i.A.defaults.xsrfCookieName="csrftoken",i.A.defaults.xsrfHeaderName="X-CSRFToken",r.Ay.use(s.m0),new r.Ay({delimiters:["[[","]]"],el:"#app2",data:function(){return{nome_pesquisa:"",is_pesquisa:!1,legislatura_selecionada:"",legislaturas:[],parlamentares:[],visible_parlamentares:[],size_parlamentares:0,filter_ativo:!0,filter_titular:""}},watch:{nome_pesquisa:function(e){this.debouncepesquisaParlamentar()}},created:function(){this.debouncepesquisaParlamentar=n.debounce(this.pesquisaParlamentar,500)},methods:{getParlamentares:function(e){var a=this;!this.legislatura_selecionada&&"0"!==this.legislatura_selecionada.toString()||i.A.get("/api/parlamentares/legislatura/"+this.legislatura_selecionada+"/parlamentares/?get_all=true").then(function(e){a.parlamentares=e.data,a.visible_parlamentares=a.parlamentares,a.size_parlamentares=a.visible_parlamentares.length,a.checkTitularAtivo()}).catch(function(e){console.error("Ocorreu um erro ao obter os dados de parlamentares:"+e)})},pesquisaParlamentar:function(e){var a=this;i.A.get("/api/parlamentares/parlamentar/search_parlamentares/",{params:{nome_parlamentar:this.nome_pesquisa}}).then(function(e){a.parlamentares=e.data,a.visible_parlamentares=a.parlamentares,a.size_parlamentares=a.visible_parlamentares.length}).catch(function(e){console.error("Erro ao procurar parlamentar:"+e)})},checkTitularAtivo:function(e){this.visible_parlamentares=this.parlamentares,this.filter_ativo&&(this.visible_parlamentares=this.visible_parlamentares.filter(function(e){return e.ativo})),this.filter_titular&&(this.visible_parlamentares=this.visible_parlamentares.filter(function(e){return"Sim"===e.titular})),this.size_parlamentares=this.visible_parlamentares.length},pesquisaChange:function(e){this.is_pesquisa=!this.is_pesquisa,this.filter_ativo=!0,this.is_pesquisa?this.parlamentares=[]:this.getParlamentares()}},mounted:function(){var a=this;i.A.get("/api/parlamentares/legislatura/?get_all=true").then(function(e){a.legislaturas=e.data;var s=(new Date).getFullYear();a.legislatura_selecionada=a.legislaturas.reduce(function(e,a){var t=new Date(a.data_inicio+" 00:00").getFullYear(),r=new Date(a.data_fim+" 00:00").getFullYear();return e=t<=s&&s<=r?a.id:e},"")}).then(function(e){a.getParlamentares()}).catch(function(e){console.error("Ocorreu um erro ao obter os dados de legislação: "+e)})}})}},r={};function p(e){var a=r[e];return void 0!==a||(a=r[e]={id:e,loaded:!1,exports:{}},t[e].call(a.exports,a,a.exports,p),a.loaded=!0),a.exports}p.m=t,u=[],p.O=(e,a,t,r)=>{if(!a){for(var s=1/0,i=0;i<u.length;i++){for(var n,[a,t,r]=u[i],l=!0,o=0;o<a.length;o++)(!1&r||r<=s)&&Object.keys(p.O).every(e=>p.O[e](a[o]))?a.splice(o--,1):(l=!1,r<s&&(s=r));l&&(u.splice(i--,1),void 0!==(n=t()))&&(e=n)}return e}r=r||0;for(var i=u.length;0<i&&u[i-1][2]>r;i--)u[i]=u[i-1];u[i]=[a,t,r]},p.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return p.d(a,{a:a}),a},p.d=(e,a)=>{for(var t in a)p.o(a,t)&&!p.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:a[t]})},p.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),p.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),p.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},p.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),p.j=788,c={788:0},p.O.j=e=>0===c[e],a=(e,a)=>{var t,r,s,[i,n,l]=a,o=0;if(i.some(e=>0!==c[e])){for(t in n)p.o(n,t)&&(p.m[t]=n[t]);l&&(s=l(p))}for(e&&e(a);o<i.length;o++)r=i[o],p.o(c,r)&&c[r]&&c[r][0](),c[r]=0;return p.O(s)},(e=self.webpackChunksapl_frontend=self.webpackChunksapl_frontend||[]).forEach(a.bind(null,0)),e.push=a.bind(null,e.push.bind(e));var a=p.O(void 0,[504],()=>p(8020));p.O(a)})();

BIN
sapl/static/sapl/frontend/js/parlamentar.f63027a7.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/content/dark/content.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/content/dark/content.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/content/dark/content.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/content/default/content.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/content/default/content.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/content/default/content.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/content/document/content.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/content/document/content.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/content/document/content.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/content/tinymce-5-dark/content.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/content/tinymce-5-dark/content.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/content/tinymce-5-dark/content.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/content/tinymce-5/content.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/content/tinymce-5/content.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/content/tinymce-5/content.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/content/writer/content.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/content/writer/content.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/content/writer/content.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.inline.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.inline.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.inline.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.shadowdom.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.shadowdom.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.shadowdom.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide/content.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide/content.inline.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide/content.inline.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide/content.inline.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide/content.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide/content.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide/skin.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide/skin.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide/skin.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide/skin.shadowdom.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide/skin.shadowdom.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/oxide/skin.shadowdom.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.inline.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.inline.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.inline.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.shadowdom.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.shadowdom.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.shadowdom.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.inline.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.inline.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.inline.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.js.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.min.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5/skin.css.gz

Binary file not shown.

BIN
sapl/static/sapl/frontend/js/skins/ui/tinymce-5/skin.js.gz

Binary file not shown.

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

Loading…
Cancel
Save