@ -0,0 +1,50 @@ |
|||||
|
|
||||
|
3.1.163-RC16 / 2023-09-13 |
||||
|
========================= |
||||
|
|
||||
|
* Conserta bug em relatórios com emenda longa. (#3674) |
||||
|
* fix: restring acesso ao prometheus metrics para apenas ips locais/invalidos (#3668) |
||||
|
* feat: adiciona filtro de autor no relatorio de tramitacao com data fim de prazo (#3671) |
||||
|
* fix: verifica se existe dispositivo atualizador ao tentar montar nota alteracao (#3669) |
||||
|
* Revert "Remove redirect de URLs (#3652)" |
||||
|
|
||||
|
3.1.163-RC15 / 2023-08-11 |
||||
|
========================= |
||||
|
|
||||
|
* HOT-FIX: conserta geração de CHANGES.md |
||||
|
* fix: Cria novos campos para o model proposicao para salvar o usuario responsavel por cada acao (#3660) |
||||
|
* Simplificação da tela de pesquisa de Matéria Legislativa (#3662) |
||||
|
* bump pyyaml |
||||
|
* Adiciona controle de visibilidade no módulo de relatorios |
||||
|
* Adiciona coluna de justificativa de ausência (#3657) |
||||
|
* Adiciona coluna de justificativa de ausência |
||||
|
* Conserta lógica para embutir SAPL em iframe (#3653) |
||||
|
* Move relatorios para app de relatorios (#3656) |
||||
|
* Remove redirect de URLs (#3652) |
||||
|
* Hot-fix: endpoint do prometheus endpoint URL |
||||
|
* feat: Adiciona funcionalidade de baixar lista de documentos acessorios de um documento administrativo (#3650) |
||||
|
|
||||
|
3.1.163-RC14 / 2023-06-28 |
||||
|
========================= |
||||
|
|
||||
|
* HOT-FIX: conserta changelog |
||||
|
* feat: Torna o campo Data Nascimento de Parlamentares sensivel (#3648) |
||||
|
* hot-fix: desconecta signal pre_save no migrate |
||||
|
|
||||
|
3.1.163-RC13 / 2023-06-18 |
||||
|
========================= |
||||
|
|
||||
|
* Add options to abort release generation |
||||
|
* Adiciona documentação automática de mudanças |
||||
|
* Adiciona link para texto original em Sessão Plenária (#3644) |
||||
|
* Altera nome completo para nome parlamentar em ata (#3645) |
||||
|
* refactor: altera título do link e descrição de relatório |
||||
|
* feat: Script to find and extract codified images pasted into text fields using the tinyMCE editor (#3643) |
||||
|
* feat: adiciona a coluna assunto na list de correspondencias do expediente do dia (#3640) |
||||
|
* fix: força periodo de busca no relatorio audit log (#3639) |
||||
|
* add migrate de ano novo |
||||
|
* impl: add campo para script do google analytics |
||||
|
* refactor: corrige relatório alinhando a proposta da nomenclatura |
||||
|
* hot-fix: corrige inicialização de variável |
||||
|
* fix: ativa filtro que estava comentado para debug |
||||
|
* impl: captura de assinaturas eletrônicas em matérias |
@ -0,0 +1,12 @@ |
|||||
|
#!/usr/bin/env bash |
||||
|
|
||||
|
SOLR_USER=solr |
||||
|
SOLR_PASSWORD=SolrRocks |
||||
|
SOLR_HOST=localhost |
||||
|
SOLR_PORT=8983 |
||||
|
|
||||
|
CONFIGSET_NAME=sapl_configset |
||||
|
CONFIGSET_FILE=sapl_configset.zip |
||||
|
|
||||
|
export SOLR_URL="http://$SOLR_USER:$SOLR_PASSWORD@$SOLR_HOST:$SOLR_PORT/solr/admin/configs?action=UPLOAD&name=$CONFIGSET_NAME&wt=json" |
||||
|
curl -X POST -L -F "file=@$CONFIGSET_FILE;type=application/zip" $SOLR_URL |
@ -0,0 +1,111 @@ |
|||||
|
version: "3.7" |
||||
|
services: |
||||
|
sapldb: |
||||
|
image: postgres:10.5-alpine |
||||
|
restart: always |
||||
|
container_name: postgres |
||||
|
labels: |
||||
|
NAME: "postgres" |
||||
|
environment: |
||||
|
POSTGRES_PASSWORD: sapl |
||||
|
POSTGRES_USER: sapl |
||||
|
POSTGRES_DB: sapl |
||||
|
PGDATA : /var/lib/postgresql/data/ |
||||
|
volumes: |
||||
|
- sapldb_data:/var/lib/postgresql/data/ |
||||
|
ports: |
||||
|
- "5433:5432" |
||||
|
networks: |
||||
|
- sapl-net |
||||
|
solr1: |
||||
|
image: solr:8.11 |
||||
|
restart: unless-stopped |
||||
|
command: bash -c "docker-entrypoint.sh solr zk cp file:/var/security.json zk:security.json && exec solr-foreground" |
||||
|
container_name: solr |
||||
|
labels: |
||||
|
NAME: "solr" |
||||
|
ports: |
||||
|
- "8983:8983" |
||||
|
environment: |
||||
|
- ZK_HOST=zoo1:2181 |
||||
|
- SOLR_HEAP=1g |
||||
|
- SOLR_OPTS=-Djute.maxbuffer=50000000 |
||||
|
networks: |
||||
|
- sapl-net |
||||
|
depends_on: |
||||
|
- zoo1 |
||||
|
volumes: |
||||
|
- type: bind |
||||
|
source: ./solr_cloud/security.json |
||||
|
target: /var/security.json |
||||
|
- solr_data:/opt/solr/server/solr |
||||
|
- solr_configsets:/opt/solr/server/solr/configsets |
||||
|
|
||||
|
sapl: |
||||
|
image: interlegis/sapl:3.1.163-RC2 |
||||
|
# build: |
||||
|
# context: ../ |
||||
|
# dockerfile: ./docker/Dockerfile |
||||
|
container_name: sapl |
||||
|
labels: |
||||
|
NAME: "sapl" |
||||
|
restart: always |
||||
|
environment: |
||||
|
ADMIN_PASSWORD: interlegis |
||||
|
ADMIN_EMAIL: email@dominio.net |
||||
|
DEBUG: 'False' |
||||
|
EMAIL_PORT: 587 |
||||
|
EMAIL_USE_TLS: 'False' |
||||
|
EMAIL_HOST: smtp.dominio.net |
||||
|
EMAIL_HOST_USER: usuariosmtp |
||||
|
EMAIL_SEND_USER: usuariosmtp |
||||
|
EMAIL_HOST_PASSWORD: senhasmtp |
||||
|
USE_SOLR: 'True' |
||||
|
SOLR_COLLECTION: sapl |
||||
|
SOLR_URL: http://solr:SolrRocks@solr1:8983 |
||||
|
TZ: America/Sao_Paulo |
||||
|
volumes: |
||||
|
- sapl_data:/var/interlegis/sapl/data |
||||
|
- sapl_media:/var/interlegis/sapl/media |
||||
|
depends_on: |
||||
|
- sapldb |
||||
|
- solr1 |
||||
|
ports: |
||||
|
- "80:80" |
||||
|
networks: |
||||
|
- sapl-net |
||||
|
zoo1: |
||||
|
image: zookeeper:3.8 |
||||
|
container_name: zoo1 |
||||
|
hostname: zoo1 |
||||
|
restart: unless-stopped |
||||
|
ports: |
||||
|
- 2181:2181 |
||||
|
- 7001:7000 |
||||
|
environment: |
||||
|
ZOO_MY_ID: 1 |
||||
|
ZOOKEEPER_TICK_TIME: 2000 |
||||
|
ZOOKEEPER_CLIENT_PORT: 2181 |
||||
|
JVMFLAGS: "-Xmx1024m -Djute.maxbuffer=50000000" |
||||
|
ZOO_SERVERS: server.1=zoo1:2888:3888;2181 |
||||
|
ZOO_LOG4J_PROP: "INFO,ROLLINGFILE" |
||||
|
ZOO_4LW_COMMANDS_WHITELIST: mntr, conf, ruok |
||||
|
ZOO_CFG_EXTRA: "metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider metricsProvider.httpPort=7000 metricsProvider.exportJvmInfo=true" |
||||
|
volumes: |
||||
|
- zoo_data:/data |
||||
|
- zoo_log:/datalog |
||||
|
networks: |
||||
|
- sapl-net |
||||
|
networks: |
||||
|
sapl-net: |
||||
|
name: sapl-net |
||||
|
driver: bridge |
||||
|
volumes: |
||||
|
sapldb_data: |
||||
|
sapl_data: |
||||
|
sapl_media: |
||||
|
solr_data: |
||||
|
solr_home: |
||||
|
solr_configsets: |
||||
|
zoo_data: |
||||
|
zoo_log: |
@ -0,0 +1,13 @@ |
|||||
|
{ |
||||
|
"authentication":{ |
||||
|
"blockUnknown": true, |
||||
|
"class":"solr.BasicAuthPlugin", |
||||
|
"credentials":{"solr":"IV0EHq1OnNrj6gvRCwvFwTrZ1+z1oBbnQdiVC3otuq0= Ndd7LKvVBAaZIF0QAVi1ekCfAJXr1GGfLtRUXhgrF8c="}, |
||||
|
"forwardCredentials": false, |
||||
|
"realm": "Solr Login" |
||||
|
}, |
||||
|
"authorization":{ |
||||
|
"class":"solr.RuleBasedAuthorizationPlugin", |
||||
|
"permissions":[{"name":"security-edit", "role":"admin"}], |
||||
|
"user-role":{"solr":"admin"} |
||||
|
}} |
@ -0,0 +1 @@ |
|||||
|
# Transformar em projeto externo instalável para uso geral |
@ -0,0 +1,409 @@ |
|||||
|
from collections import OrderedDict |
||||
|
import importlib |
||||
|
import inspect |
||||
|
import logging |
||||
|
import re |
||||
|
|
||||
|
from django.apps.config import AppConfig |
||||
|
from django.apps.registry import apps |
||||
|
from django.conf import settings |
||||
|
from django.contrib.postgres.fields.jsonb import JSONField |
||||
|
from django.db.models.base import ModelBase |
||||
|
from django.db.models.fields import TextField, CharField |
||||
|
from django.db.models.fields.files import FileField |
||||
|
from django.template.defaultfilters import capfirst |
||||
|
from django.utils.translation import ugettext_lazy as _ |
||||
|
import django_filters |
||||
|
from django_filters.constants import ALL_FIELDS, EMPTY_VALUES |
||||
|
from django_filters.filters import CharFilter |
||||
|
from django_filters.filterset import FilterSet |
||||
|
from django_filters.rest_framework.backends import DjangoFilterBackend |
||||
|
from django_filters.utils import resolve_field, get_all_model_fields |
||||
|
from rest_framework import serializers as rest_serializers |
||||
|
from rest_framework.response import Response |
||||
|
from rest_framework.routers import DefaultRouter |
||||
|
from rest_framework.viewsets import ModelViewSet |
||||
|
|
||||
|
|
||||
|
logger = logging.getLogger(__name__) |
||||
|
|
||||
|
|
||||
|
class SplitStringCharFilter(django_filters.CharFilter): |
||||
|
_re = re.compile(r'("[^"]+"| +|[^"]+)') |
||||
|
|
||||
|
def filter(self, qs, value): |
||||
|
if value in EMPTY_VALUES: |
||||
|
return qs |
||||
|
if self.distinct: |
||||
|
qs = qs.distinct() |
||||
|
lookup = '%s__%s' % (self.field_name, self.lookup_expr) |
||||
|
|
||||
|
values = [value] |
||||
|
if self.lookup_expr == 'icontains': |
||||
|
if not '"' in value: |
||||
|
values = value.split(' ') |
||||
|
else: |
||||
|
values = list( |
||||
|
filter( |
||||
|
lambda x: x and x != ' ' and x[0] != '"', |
||||
|
self._re.findall(value) |
||||
|
) |
||||
|
) + list( |
||||
|
map( |
||||
|
lambda x: x[1:-1], |
||||
|
filter( |
||||
|
lambda x: x and x[0] == '"', |
||||
|
self._re.findall(value) |
||||
|
) |
||||
|
) |
||||
|
) |
||||
|
|
||||
|
if not isinstance(values, list): |
||||
|
values = [values] |
||||
|
for v in values: |
||||
|
qs = self.get_method(qs)(**{lookup: v}) |
||||
|
return qs |
||||
|
|
||||
|
|
||||
|
class ApiFilterSetMixin(FilterSet): |
||||
|
|
||||
|
o = CharFilter(method='filter_o') |
||||
|
|
||||
|
class Meta: |
||||
|
fields = '__all__' |
||||
|
filter_overrides = { |
||||
|
FileField: { |
||||
|
'filter_class': django_filters.CharFilter, |
||||
|
'extra': lambda f: { |
||||
|
'lookup_expr': 'exact', |
||||
|
}, |
||||
|
}, |
||||
|
CharField: { |
||||
|
'filter_class': SplitStringCharFilter, |
||||
|
}, |
||||
|
TextField: { |
||||
|
'filter_class': SplitStringCharFilter, |
||||
|
}, |
||||
|
JSONField: { |
||||
|
'filter_class': django_filters.CharFilter, |
||||
|
'extra': lambda f: { |
||||
|
'lookup_expr': 'exact', |
||||
|
}, |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
def filter_o(self, queryset, name, value): |
||||
|
try: |
||||
|
return queryset.order_by( |
||||
|
*map(str.strip, value.split(','))) |
||||
|
except: |
||||
|
return queryset |
||||
|
|
||||
|
@classmethod |
||||
|
def get_fields(cls): |
||||
|
model = cls._meta.model |
||||
|
fields_model = get_all_model_fields(model) |
||||
|
fields_filter = cls._meta.fields |
||||
|
exclude = cls._meta.exclude |
||||
|
|
||||
|
if exclude is not None and fields_filter is None: |
||||
|
fields_filter = ALL_FIELDS |
||||
|
|
||||
|
fields = fields_filter if isinstance(fields_filter, dict) else {} |
||||
|
|
||||
|
for f_str in fields_model: |
||||
|
if f_str not in fields: |
||||
|
|
||||
|
f = model._meta.get_field(f_str) |
||||
|
|
||||
|
if f.many_to_many: |
||||
|
fields[f_str] = ['exact'] |
||||
|
continue |
||||
|
|
||||
|
fields[f_str] = ['exact'] |
||||
|
|
||||
|
def get_keys_lookups(cl, sub_f): |
||||
|
r = [] |
||||
|
for lk, lv in cl.items(): |
||||
|
|
||||
|
if lk in ('contained_by', 'trigram_similar', 'unaccent', 'search'): |
||||
|
continue |
||||
|
|
||||
|
sflk = f'{sub_f}{"__" if sub_f else ""}{lk}' |
||||
|
r.append(sflk) |
||||
|
|
||||
|
if hasattr(lv, 'get_lookups'): |
||||
|
r += get_keys_lookups(lv.get_lookups(), sflk) |
||||
|
|
||||
|
if hasattr(lv, 'output_field') and hasattr(lv, 'output_field.get_lookups'): |
||||
|
r.append(f'{sflk}{"__" if sflk else ""}range') |
||||
|
|
||||
|
r += get_keys_lookups(lv.output_field.class_lookups, sflk) |
||||
|
|
||||
|
return r |
||||
|
|
||||
|
fields[f_str] = list( |
||||
|
set(fields[f_str] + get_keys_lookups(f.get_lookups(), ''))) |
||||
|
|
||||
|
# Remove excluded fields |
||||
|
exclude = exclude or [] |
||||
|
|
||||
|
fields = [(f, lookups) |
||||
|
for f, lookups in fields.items() if f not in exclude] |
||||
|
|
||||
|
return OrderedDict(fields) |
||||
|
|
||||
|
@classmethod |
||||
|
def filter_for_field(cls, f, name, lookup_expr='exact'): |
||||
|
# Redefine método estático para ignorar filtro para |
||||
|
# fields que não possuam lookup_expr informado |
||||
|
|
||||
|
f, lookup_type = resolve_field(f, lookup_expr) |
||||
|
|
||||
|
default = { |
||||
|
'field_name': name, |
||||
|
'label': capfirst(f.verbose_name), |
||||
|
'lookup_expr': lookup_expr |
||||
|
} |
||||
|
|
||||
|
filter_class, params = cls.filter_for_lookup( |
||||
|
f, lookup_type) |
||||
|
default.update(params) |
||||
|
if filter_class is not None: |
||||
|
return filter_class(**default) |
||||
|
return None |
||||
|
|
||||
|
|
||||
|
class BusinessRulesNotImplementedMixin: |
||||
|
http_method_names = ['get', 'head', 'options', 'trace'] |
||||
|
|
||||
|
def create(self, request, *args, **kwargs): |
||||
|
raise Exception(_("POST Create não implementado")) |
||||
|
|
||||
|
def update(self, request, *args, **kwargs): |
||||
|
raise Exception(_("PUT and PATCH não implementado")) |
||||
|
|
||||
|
def delete(self, request, *args, **kwargs): |
||||
|
raise Exception(_("DELETE Delete não implementado")) |
||||
|
|
||||
|
|
||||
|
class ApiViewSetConstrutor(): |
||||
|
|
||||
|
_built_sets = {} |
||||
|
|
||||
|
class ApiViewSet(ModelViewSet): |
||||
|
filter_backends = (DjangoFilterBackend,) |
||||
|
|
||||
|
@classmethod |
||||
|
def get_viewset_for_model(cls, model): |
||||
|
return cls._built_sets[model._meta.app_config][model] |
||||
|
|
||||
|
@classmethod |
||||
|
def update(cls, other): |
||||
|
cls._built_sets.update(other._built_sets) |
||||
|
|
||||
|
@classmethod |
||||
|
def import_modules(cls, modules): |
||||
|
for m in modules: |
||||
|
importlib.import_module(m) |
||||
|
|
||||
|
@classmethod |
||||
|
def router(cls, router_class=DefaultRouter): |
||||
|
router = router_class() |
||||
|
for app, built_sets in cls._built_sets.items(): |
||||
|
for model, viewset in built_sets.items(): |
||||
|
router.register( |
||||
|
f'{app.label}/{model._meta.model_name}', viewset) |
||||
|
return router |
||||
|
|
||||
|
@classmethod |
||||
|
def build_class(cls, apps_or_models): |
||||
|
|
||||
|
DRFAUTOAPI = settings.DRFAUTOAPI |
||||
|
|
||||
|
serializers_classes = {} |
||||
|
filters_classes = {} |
||||
|
|
||||
|
global_serializer_mixin = rest_serializers.ModelSerializer |
||||
|
global_filter_class = ApiFilterSetMixin |
||||
|
|
||||
|
try: |
||||
|
if DRFAUTOAPI: |
||||
|
if 'DEFAULT_SERIALIZER_MODULE' in DRFAUTOAPI: |
||||
|
serializers = importlib.import_module( |
||||
|
DRFAUTOAPI['DEFAULT_SERIALIZER_MODULE'] |
||||
|
) |
||||
|
serializers_classes = inspect.getmembers(serializers) |
||||
|
serializers_classes = {i[0]: i[1] for i in filter( |
||||
|
lambda x: x[0].endswith('Serializer'), |
||||
|
serializers_classes |
||||
|
)} |
||||
|
|
||||
|
if 'DEFAULT_FILTER_MODULE' in DRFAUTOAPI: |
||||
|
filters = importlib.import_module( |
||||
|
DRFAUTOAPI['DEFAULT_FILTER_MODULE'] |
||||
|
) |
||||
|
filters_classes = inspect.getmembers(filters) |
||||
|
filters_classes = {i[0]: i[1] for i in filter( |
||||
|
lambda x: x[0].endswith('FilterSet'), |
||||
|
filters_classes |
||||
|
)} |
||||
|
|
||||
|
if 'GLOBAL_SERIALIZER_MIXIN' in DRFAUTOAPI: |
||||
|
cs = DRFAUTOAPI['GLOBAL_SERIALIZER_MIXIN'].split('.') |
||||
|
module = importlib.import_module( |
||||
|
'.'.join(cs[0:-1])) |
||||
|
global_serializer_mixin = getattr(module, cs[-1]) |
||||
|
|
||||
|
if 'GLOBAL_FILTERSET_MIXIN' in DRFAUTOAPI: |
||||
|
cs = DRFAUTOAPI['GLOBAL_FILTERSET_MIXIN'].split('.') |
||||
|
m = importlib.import_module('.'.join(cs[0:-1])) |
||||
|
global_filter_class = getattr(m, cs[-1]) |
||||
|
|
||||
|
except Exception as e: |
||||
|
logger.error(e) |
||||
|
|
||||
|
built_sets = {} |
||||
|
|
||||
|
def build(_model): |
||||
|
object_name = _model._meta.object_name |
||||
|
|
||||
|
serializer_name = f'{object_name}Serializer' |
||||
|
_serializer_class = serializers_classes.get( |
||||
|
serializer_name, global_serializer_mixin) |
||||
|
|
||||
|
filter_name = f'{object_name}FilterSet' |
||||
|
_filterset_class = filters_classes.get( |
||||
|
filter_name, global_filter_class) |
||||
|
|
||||
|
def create_class(): |
||||
|
|
||||
|
_meta_serializer = object if not hasattr( |
||||
|
_serializer_class, 'Meta') else _serializer_class.Meta |
||||
|
|
||||
|
class ApiSerializer(_serializer_class): |
||||
|
|
||||
|
class Meta(_meta_serializer): |
||||
|
if not hasattr(_meta_serializer, 'ref_name'): |
||||
|
ref_name = f'{object_name}Serializer' |
||||
|
|
||||
|
if not hasattr(_meta_serializer, 'model'): |
||||
|
model = _model |
||||
|
|
||||
|
if hasattr(_meta_serializer, 'exclude'): |
||||
|
exclude = _meta_serializer.exclude |
||||
|
else: |
||||
|
if not hasattr(_meta_serializer, 'fields'): |
||||
|
fields = '__all__' |
||||
|
elif _meta_serializer.fields != '__all__': |
||||
|
fields = list(_meta_serializer.fields) |
||||
|
else: |
||||
|
fields = _meta_serializer.fields |
||||
|
|
||||
|
_meta_filterset = object if not hasattr( |
||||
|
_filterset_class, 'Meta') else _filterset_class.Meta |
||||
|
|
||||
|
class ApiFilterSet(_filterset_class): |
||||
|
|
||||
|
class Meta(_meta_filterset, ): |
||||
|
if not hasattr(_meta_filterset, 'model'): |
||||
|
model = _model |
||||
|
|
||||
|
class ModelApiViewSet(ApiViewSetConstrutor.ApiViewSet): |
||||
|
queryset = _model.objects.all() |
||||
|
filterset_class = ApiFilterSet |
||||
|
serializer_class = ApiSerializer |
||||
|
|
||||
|
return ModelApiViewSet |
||||
|
|
||||
|
viewset = create_class() |
||||
|
viewset.__name__ = '%sModelViewSet' % _model.__name__ |
||||
|
return viewset |
||||
|
|
||||
|
for am in apps_or_models: |
||||
|
|
||||
|
if isinstance(am, ModelBase): |
||||
|
app = am._meta.app_config |
||||
|
else: |
||||
|
app = am |
||||
|
|
||||
|
if app not in cls._built_sets: |
||||
|
cls._built_sets[app] = {} |
||||
|
|
||||
|
if am != app: |
||||
|
cls._built_sets[app][am] = build(am) |
||||
|
continue |
||||
|
|
||||
|
for model in app.get_models(): |
||||
|
cls._built_sets[app][model] = build(model) |
||||
|
|
||||
|
return cls |
||||
|
|
||||
|
|
||||
|
# Toda Classe construida acima, pode ser redefinida e aplicado quaisquer |
||||
|
# das possibilidades para uma classe normal criada a partir de |
||||
|
# rest_framework.viewsets.ModelViewSet conforme exemplo para a classe autor |
||||
|
|
||||
|
# decorator que processa um endpoint detail trivial com base no model passado, |
||||
|
# Um endpoint detail geralmente é um conteúdo baseado numa FK com outros possíveis filtros |
||||
|
# e os passados pelo proprio cliente, além de o serializer e o filterset |
||||
|
# ser desse model passado |
||||
|
|
||||
|
|
||||
|
class wrapper_queryset_response_for_drf_action(object): |
||||
|
|
||||
|
def __init__(self, model): |
||||
|
self.model = model |
||||
|
|
||||
|
def __call__(self, cls): |
||||
|
|
||||
|
def wrapper(instance_view, *args, **kwargs): |
||||
|
# recupera a viewset do model anotado |
||||
|
iv = instance_view |
||||
|
viewset_from_model = ApiViewSetConstrutor._built_sets[ |
||||
|
self.model._meta.app_config][self.model] |
||||
|
|
||||
|
# apossa da instancia da viewset mae do action |
||||
|
# em uma viewset que processa dados do model passado no decorator |
||||
|
iv.queryset = viewset_from_model.queryset |
||||
|
iv.serializer_class = viewset_from_model.serializer_class |
||||
|
iv.filterset_class = viewset_from_model.filterset_class |
||||
|
|
||||
|
iv.queryset = instance_view.filter_queryset( |
||||
|
iv.get_queryset()) |
||||
|
|
||||
|
# chama efetivamente o metodo anotado que deve devolver um queryset |
||||
|
# com os filtros específicos definido pelo programador customizador |
||||
|
qs = cls(instance_view, *args, **kwargs) |
||||
|
|
||||
|
page = iv.paginate_queryset(qs) |
||||
|
data = iv.get_serializer( |
||||
|
page if page is not None else qs, many=True).data |
||||
|
|
||||
|
return iv.get_paginated_response( |
||||
|
data) if page is not None else Response(data) |
||||
|
|
||||
|
return wrapper |
||||
|
|
||||
|
|
||||
|
# decorator para recuperar e transformar o default |
||||
|
class customize(object): |
||||
|
|
||||
|
def __init__(self, model): |
||||
|
self.model = model |
||||
|
|
||||
|
def __call__(self, cls): |
||||
|
|
||||
|
class _ApiViewSet( |
||||
|
cls, |
||||
|
ApiViewSetConstrutor._built_sets[ |
||||
|
self.model._meta.app_config][self.model] |
||||
|
): |
||||
|
pass |
||||
|
|
||||
|
if hasattr(_ApiViewSet, 'build'): |
||||
|
_ApiViewSet = _ApiViewSet.build() |
||||
|
|
||||
|
ApiViewSetConstrutor._built_sets[ |
||||
|
self.model._meta.app_config][self.model] = _ApiViewSet |
||||
|
return _ApiViewSet |
Before Width: | Height: | Size: 262 B |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 59 KiB |
Before Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 682 B |
Before Width: | Height: | Size: 694 B |
Before Width: | Height: | Size: 975 B |
Before Width: | Height: | Size: 1021 B |
Before Width: | Height: | Size: 502 B |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 568 B |
Before Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 343 B |
Before Width: | Height: | Size: 238 KiB |
Before Width: | Height: | Size: 6.2 KiB |
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 367 B |
Before Width: | Height: | Size: 290 B |
@ -1 +1,807 @@ |
|||||
{"status":"done","publicPath":"/static/sapl/frontend/","chunks":{"chunk-vendors":[{"name":"css/chunk-vendors.da853c1c.css","publicPath":"/static/sapl/frontend/css/chunk-vendors.da853c1c.css","path":"sapl/static/sapl/frontend/css/chunk-vendors.da853c1c.css"},{"name":"js/chunk-vendors.926da1dd.js","publicPath":"/static/sapl/frontend/js/chunk-vendors.926da1dd.js","path":"sapl/static/sapl/frontend/js/chunk-vendors.926da1dd.js"},{"name":"css/chunk-vendors.da853c1c.css.map","publicPath":"/static/sapl/frontend/css/chunk-vendors.da853c1c.css.map","path":"sapl/static/sapl/frontend/css/chunk-vendors.da853c1c.css.map"},{"name":"js/chunk-vendors.926da1dd.js.map","publicPath":"/static/sapl/frontend/js/chunk-vendors.926da1dd.js.map","path":"sapl/static/sapl/frontend/js/chunk-vendors.926da1dd.js.map"}],"compilacao":[{"name":"css/compilacao.90ba9ac3.css","publicPath":"/static/sapl/frontend/css/compilacao.90ba9ac3.css","path":"sapl/static/sapl/frontend/css/compilacao.90ba9ac3.css"},{"name":"js/compilacao.ae866d2d.js","publicPath":"/static/sapl/frontend/js/compilacao.ae866d2d.js","path":"sapl/static/sapl/frontend/js/compilacao.ae866d2d.js"},{"name":"css/compilacao.90ba9ac3.css.map","publicPath":"/static/sapl/frontend/css/compilacao.90ba9ac3.css.map","path":"sapl/static/sapl/frontend/css/compilacao.90ba9ac3.css.map"},{"name":"js/compilacao.ae866d2d.js.map","publicPath":"/static/sapl/frontend/js/compilacao.ae866d2d.js.map","path":"sapl/static/sapl/frontend/js/compilacao.ae866d2d.js.map"}],"global":[{"name":"css/global.cfffff0f.css","publicPath":"/static/sapl/frontend/css/global.cfffff0f.css","path":"sapl/static/sapl/frontend/css/global.cfffff0f.css"},{"name":"js/global.8d7024d2.js","publicPath":"/static/sapl/frontend/js/global.8d7024d2.js","path":"sapl/static/sapl/frontend/js/global.8d7024d2.js"},{"name":"css/global.cfffff0f.css.map","publicPath":"/static/sapl/frontend/css/global.cfffff0f.css.map","path":"sapl/static/sapl/frontend/css/global.cfffff0f.css.map"},{"name":"js/global.8d7024d2.js.map","publicPath":"/static/sapl/frontend/js/global.8d7024d2.js.map","path":"sapl/static/sapl/frontend/js/global.8d7024d2.js.map"}],"painel":[{"name":"css/painel.5d957a9b.css","publicPath":"/static/sapl/frontend/css/painel.5d957a9b.css","path":"sapl/static/sapl/frontend/css/painel.5d957a9b.css"},{"name":"js/painel.22053ae6.js","publicPath":"/static/sapl/frontend/js/painel.22053ae6.js","path":"sapl/static/sapl/frontend/js/painel.22053ae6.js"},{"name":"css/painel.5d957a9b.css.map","publicPath":"/static/sapl/frontend/css/painel.5d957a9b.css.map","path":"sapl/static/sapl/frontend/css/painel.5d957a9b.css.map"},{"name":"js/painel.22053ae6.js.map","publicPath":"/static/sapl/frontend/js/painel.22053ae6.js.map","path":"sapl/static/sapl/frontend/js/painel.22053ae6.js.map"}],"parlamentar":[{"name":"css/parlamentar.0e433876.css","publicPath":"/static/sapl/frontend/css/parlamentar.0e433876.css","path":"sapl/static/sapl/frontend/css/parlamentar.0e433876.css"},{"name":"js/parlamentar.e6a288dc.js","publicPath":"/static/sapl/frontend/js/parlamentar.e6a288dc.js","path":"sapl/static/sapl/frontend/js/parlamentar.e6a288dc.js"},{"name":"css/parlamentar.0e433876.css.map","publicPath":"/static/sapl/frontend/css/parlamentar.0e433876.css.map","path":"sapl/static/sapl/frontend/css/parlamentar.0e433876.css.map"},{"name":"js/parlamentar.e6a288dc.js.map","publicPath":"/static/sapl/frontend/js/parlamentar.e6a288dc.js.map","path":"sapl/static/sapl/frontend/js/parlamentar.e6a288dc.js.map"}]}} |
{ |
||||
|
"status": "done", |
||||
|
"assets": { |
||||
|
"fonts/fa-brands-400.86c7e1fa.woff2": { |
||||
|
"name": "fonts/fa-brands-400.86c7e1fa.woff2", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/fonts/fa-brands-400.86c7e1fa.woff2", |
||||
|
"publicPath": "/static/sapl/frontend/fonts/fa-brands-400.86c7e1fa.woff2" |
||||
|
}, |
||||
|
"fonts/fa-brands-400.f5defc2e.ttf": { |
||||
|
"name": "fonts/fa-brands-400.f5defc2e.ttf", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/fonts/fa-brands-400.f5defc2e.ttf", |
||||
|
"publicPath": "/static/sapl/frontend/fonts/fa-brands-400.f5defc2e.ttf" |
||||
|
}, |
||||
|
"fonts/fa-regular-400.e0550912.woff2": { |
||||
|
"name": "fonts/fa-regular-400.e0550912.woff2", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/fonts/fa-regular-400.e0550912.woff2", |
||||
|
"publicPath": "/static/sapl/frontend/fonts/fa-regular-400.e0550912.woff2" |
||||
|
}, |
||||
|
"fonts/fa-regular-400.3edb9004.ttf": { |
||||
|
"name": "fonts/fa-regular-400.3edb9004.ttf", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/fonts/fa-regular-400.3edb9004.ttf", |
||||
|
"publicPath": "/static/sapl/frontend/fonts/fa-regular-400.3edb9004.ttf" |
||||
|
}, |
||||
|
"fonts/fa-solid-900.64d5644d.woff2": { |
||||
|
"name": "fonts/fa-solid-900.64d5644d.woff2", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/fonts/fa-solid-900.64d5644d.woff2", |
||||
|
"publicPath": "/static/sapl/frontend/fonts/fa-solid-900.64d5644d.woff2" |
||||
|
}, |
||||
|
"fonts/fa-solid-900.f418d876.ttf": { |
||||
|
"name": "fonts/fa-solid-900.f418d876.ttf", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/fonts/fa-solid-900.f418d876.ttf", |
||||
|
"publicPath": "/static/sapl/frontend/fonts/fa-solid-900.f418d876.ttf" |
||||
|
}, |
||||
|
"fonts/fa-v4compatibility.7e7e1dad.ttf": { |
||||
|
"name": "fonts/fa-v4compatibility.7e7e1dad.ttf", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/fonts/fa-v4compatibility.7e7e1dad.ttf", |
||||
|
"publicPath": "/static/sapl/frontend/fonts/fa-v4compatibility.7e7e1dad.ttf" |
||||
|
}, |
||||
|
"css/global.45591136.css": { |
||||
|
"name": "css/global.45591136.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/css/global.45591136.css", |
||||
|
"publicPath": "/static/sapl/frontend/css/global.45591136.css" |
||||
|
}, |
||||
|
"js/global.f01dd32a.js": { |
||||
|
"name": "js/global.f01dd32a.js", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/global.f01dd32a.js", |
||||
|
"publicPath": "/static/sapl/frontend/js/global.f01dd32a.js" |
||||
|
}, |
||||
|
"css/parlamentar.cd5dc5a8.css": { |
||||
|
"name": "css/parlamentar.cd5dc5a8.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/css/parlamentar.cd5dc5a8.css", |
||||
|
"publicPath": "/static/sapl/frontend/css/parlamentar.cd5dc5a8.css" |
||||
|
}, |
||||
|
"js/parlamentar.25e7f0fa.js": { |
||||
|
"name": "js/parlamentar.25e7f0fa.js", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/parlamentar.25e7f0fa.js", |
||||
|
"publicPath": "/static/sapl/frontend/js/parlamentar.25e7f0fa.js" |
||||
|
}, |
||||
|
"css/painel.e2b9504e.css": { |
||||
|
"name": "css/painel.e2b9504e.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/css/painel.e2b9504e.css", |
||||
|
"publicPath": "/static/sapl/frontend/css/painel.e2b9504e.css" |
||||
|
}, |
||||
|
"js/painel.7aa779e9.js": { |
||||
|
"name": "js/painel.7aa779e9.js", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/painel.7aa779e9.js", |
||||
|
"publicPath": "/static/sapl/frontend/js/painel.7aa779e9.js" |
||||
|
}, |
||||
|
"css/compilacao.f4baf459.css": { |
||||
|
"name": "css/compilacao.f4baf459.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/css/compilacao.f4baf459.css", |
||||
|
"publicPath": "/static/sapl/frontend/css/compilacao.f4baf459.css" |
||||
|
}, |
||||
|
"js/compilacao.d68d2b28.js": { |
||||
|
"name": "js/compilacao.d68d2b28.js", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/compilacao.d68d2b28.js", |
||||
|
"publicPath": "/static/sapl/frontend/js/compilacao.d68d2b28.js" |
||||
|
}, |
||||
|
"css/chunk-vendors.9904f9d0.css": { |
||||
|
"name": "css/chunk-vendors.9904f9d0.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/css/chunk-vendors.9904f9d0.css", |
||||
|
"publicPath": "/static/sapl/frontend/css/chunk-vendors.9904f9d0.css" |
||||
|
}, |
||||
|
"js/chunk-vendors.874df7f4.js": { |
||||
|
"name": "js/chunk-vendors.874df7f4.js", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/chunk-vendors.874df7f4.js", |
||||
|
"publicPath": "/static/sapl/frontend/js/chunk-vendors.874df7f4.js" |
||||
|
}, |
||||
|
"audio/ring.mp3": { |
||||
|
"name": "audio/ring.mp3", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/audio/ring.mp3", |
||||
|
"publicPath": "/static/sapl/frontend/audio/ring.mp3" |
||||
|
}, |
||||
|
"img/arrow.png": { |
||||
|
"name": "img/arrow.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/arrow.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/arrow.png" |
||||
|
}, |
||||
|
"img/authenticated.png": { |
||||
|
"name": "img/authenticated.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/authenticated.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/authenticated.png" |
||||
|
}, |
||||
|
"img/avatar.png": { |
||||
|
"name": "img/avatar.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/avatar.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/avatar.png" |
||||
|
}, |
||||
|
"img/beta.png": { |
||||
|
"name": "img/beta.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/beta.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/beta.png" |
||||
|
}, |
||||
|
"img/bg.png": { |
||||
|
"name": "img/bg.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/bg.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/bg.png" |
||||
|
}, |
||||
|
"img/brasao_transp.gif": { |
||||
|
"name": "img/brasao_transp.gif", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/brasao_transp.gif", |
||||
|
"publicPath": "/static/sapl/frontend/img/brasao_transp.gif" |
||||
|
}, |
||||
|
"img/down_arrow_select.jpg": { |
||||
|
"name": "img/down_arrow_select.jpg", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/down_arrow_select.jpg", |
||||
|
"publicPath": "/static/sapl/frontend/img/down_arrow_select.jpg" |
||||
|
}, |
||||
|
"img/etiqueta.png": { |
||||
|
"name": "img/etiqueta.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/etiqueta.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/etiqueta.png" |
||||
|
}, |
||||
|
"img/favicon.ico": { |
||||
|
"name": "img/favicon.ico", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/favicon.ico", |
||||
|
"publicPath": "/static/sapl/frontend/img/favicon.ico" |
||||
|
}, |
||||
|
"img/file.png": { |
||||
|
"name": "img/file.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/file.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/file.png" |
||||
|
}, |
||||
|
"img/hand-note.png": { |
||||
|
"name": "img/hand-note.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/hand-note.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/hand-note.png" |
||||
|
}, |
||||
|
"img/icon_comissoes.png": { |
||||
|
"name": "img/icon_comissoes.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/icon_comissoes.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/icon_comissoes.png" |
||||
|
}, |
||||
|
"img/icon_delete_white.png": { |
||||
|
"name": "img/icon_delete_white.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/icon_delete_white.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/icon_delete_white.png" |
||||
|
}, |
||||
|
"img/icon_materia_legislativa.png": { |
||||
|
"name": "img/icon_materia_legislativa.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/icon_materia_legislativa.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/icon_materia_legislativa.png" |
||||
|
}, |
||||
|
"img/icon_mesa_diretora.png": { |
||||
|
"name": "img/icon_mesa_diretora.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/icon_mesa_diretora.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/icon_mesa_diretora.png" |
||||
|
}, |
||||
|
"img/icon_normas_juridicas.png": { |
||||
|
"name": "img/icon_normas_juridicas.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/icon_normas_juridicas.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/icon_normas_juridicas.png" |
||||
|
}, |
||||
|
"img/icon_normas_juridicas_destaque.png": { |
||||
|
"name": "img/icon_normas_juridicas_destaque.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/icon_normas_juridicas_destaque.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/icon_normas_juridicas_destaque.png" |
||||
|
}, |
||||
|
"img/icon_parlamentares.png": { |
||||
|
"name": "img/icon_parlamentares.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/icon_parlamentares.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/icon_parlamentares.png" |
||||
|
}, |
||||
|
"img/icon_pautas.png": { |
||||
|
"name": "img/icon_pautas.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/icon_pautas.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/icon_pautas.png" |
||||
|
}, |
||||
|
"img/icon_plenarias.png": { |
||||
|
"name": "img/icon_plenarias.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/icon_plenarias.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/icon_plenarias.png" |
||||
|
}, |
||||
|
"img/icon_relatorios.png": { |
||||
|
"name": "img/icon_relatorios.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/icon_relatorios.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/icon_relatorios.png" |
||||
|
}, |
||||
|
"img/icon_save_white.png": { |
||||
|
"name": "img/icon_save_white.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/icon_save_white.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/icon_save_white.png" |
||||
|
}, |
||||
|
"img/lexml.gif": { |
||||
|
"name": "img/lexml.gif", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/lexml.gif", |
||||
|
"publicPath": "/static/sapl/frontend/img/lexml.gif" |
||||
|
}, |
||||
|
"img/logo.png": { |
||||
|
"name": "img/logo.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/logo.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/logo.png" |
||||
|
}, |
||||
|
"img/logo_cc.png": { |
||||
|
"name": "img/logo_cc.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/logo_cc.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/logo_cc.png" |
||||
|
}, |
||||
|
"img/logo_interlegis.png": { |
||||
|
"name": "img/logo_interlegis.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/logo_interlegis.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/logo_interlegis.png" |
||||
|
}, |
||||
|
"img/manual.png": { |
||||
|
"name": "img/manual.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/manual.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/manual.png" |
||||
|
}, |
||||
|
"img/pdflogo.png": { |
||||
|
"name": "img/pdflogo.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/pdflogo.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/pdflogo.png" |
||||
|
}, |
||||
|
"img/perfil.png": { |
||||
|
"name": "img/perfil.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/perfil.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/perfil.png" |
||||
|
}, |
||||
|
"img/search-gray.png": { |
||||
|
"name": "img/search-gray.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/search-gray.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/search-gray.png" |
||||
|
}, |
||||
|
"img/search.png": { |
||||
|
"name": "img/search.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/search.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/search.png" |
||||
|
}, |
||||
|
"img/user.png": { |
||||
|
"name": "img/user.png", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/user.png", |
||||
|
"publicPath": "/static/sapl/frontend/img/user.png" |
||||
|
}, |
||||
|
"js/skins/content/dark/content.css": { |
||||
|
"name": "js/skins/content/dark/content.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/dark/content.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/dark/content.css" |
||||
|
}, |
||||
|
"js/skins/content/dark/content.min.css": { |
||||
|
"name": "js/skins/content/dark/content.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/dark/content.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/dark/content.min.css" |
||||
|
}, |
||||
|
"js/skins/content/default/content.css": { |
||||
|
"name": "js/skins/content/default/content.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/default/content.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/default/content.css" |
||||
|
}, |
||||
|
"js/skins/content/default/content.min.css": { |
||||
|
"name": "js/skins/content/default/content.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/default/content.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/default/content.min.css" |
||||
|
}, |
||||
|
"js/skins/content/document/content.css": { |
||||
|
"name": "js/skins/content/document/content.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/document/content.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/document/content.css" |
||||
|
}, |
||||
|
"js/skins/content/document/content.min.css": { |
||||
|
"name": "js/skins/content/document/content.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/document/content.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/document/content.min.css" |
||||
|
}, |
||||
|
"js/skins/content/tinymce-5/content.css": { |
||||
|
"name": "js/skins/content/tinymce-5/content.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/tinymce-5/content.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/tinymce-5/content.css" |
||||
|
}, |
||||
|
"js/skins/content/tinymce-5/content.min.css": { |
||||
|
"name": "js/skins/content/tinymce-5/content.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/tinymce-5/content.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/tinymce-5/content.min.css" |
||||
|
}, |
||||
|
"js/skins/content/tinymce-5-dark/content.css": { |
||||
|
"name": "js/skins/content/tinymce-5-dark/content.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/tinymce-5-dark/content.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/tinymce-5-dark/content.css" |
||||
|
}, |
||||
|
"js/skins/content/tinymce-5-dark/content.min.css": { |
||||
|
"name": "js/skins/content/tinymce-5-dark/content.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/tinymce-5-dark/content.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/tinymce-5-dark/content.min.css" |
||||
|
}, |
||||
|
"js/skins/content/writer/content.css": { |
||||
|
"name": "js/skins/content/writer/content.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/writer/content.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/writer/content.css" |
||||
|
}, |
||||
|
"js/skins/content/writer/content.min.css": { |
||||
|
"name": "js/skins/content/writer/content.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/writer/content.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/writer/content.min.css" |
||||
|
}, |
||||
|
"js/skins/ui/oxide/content.css": { |
||||
|
"name": "js/skins/ui/oxide/content.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide/content.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide/content.css" |
||||
|
}, |
||||
|
"js/skins/ui/oxide/content.inline.css": { |
||||
|
"name": "js/skins/ui/oxide/content.inline.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide/content.inline.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide/content.inline.css" |
||||
|
}, |
||||
|
"js/skins/ui/oxide/content.inline.min.css": { |
||||
|
"name": "js/skins/ui/oxide/content.inline.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide/content.inline.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide/content.inline.min.css" |
||||
|
}, |
||||
|
"js/skins/ui/oxide/content.min.css": { |
||||
|
"name": "js/skins/ui/oxide/content.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide/content.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide/content.min.css" |
||||
|
}, |
||||
|
"js/skins/ui/oxide/skin.css": { |
||||
|
"name": "js/skins/ui/oxide/skin.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide/skin.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide/skin.css" |
||||
|
}, |
||||
|
"js/skins/ui/oxide/skin.min.css": { |
||||
|
"name": "js/skins/ui/oxide/skin.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide/skin.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide/skin.min.css" |
||||
|
}, |
||||
|
"js/skins/ui/oxide/skin.shadowdom.css": { |
||||
|
"name": "js/skins/ui/oxide/skin.shadowdom.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide/skin.shadowdom.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide/skin.shadowdom.css" |
||||
|
}, |
||||
|
"js/skins/ui/oxide/skin.shadowdom.min.css": { |
||||
|
"name": "js/skins/ui/oxide/skin.shadowdom.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide/skin.shadowdom.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide/skin.shadowdom.min.css" |
||||
|
}, |
||||
|
"js/skins/ui/oxide-dark/content.css": { |
||||
|
"name": "js/skins/ui/oxide-dark/content.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide-dark/content.css" |
||||
|
}, |
||||
|
"js/skins/ui/oxide-dark/content.inline.css": { |
||||
|
"name": "js/skins/ui/oxide-dark/content.inline.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.inline.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide-dark/content.inline.css" |
||||
|
}, |
||||
|
"js/skins/ui/oxide-dark/content.inline.min.css": { |
||||
|
"name": "js/skins/ui/oxide-dark/content.inline.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.inline.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide-dark/content.inline.min.css" |
||||
|
}, |
||||
|
"js/skins/ui/oxide-dark/content.min.css": { |
||||
|
"name": "js/skins/ui/oxide-dark/content.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide-dark/content.min.css" |
||||
|
}, |
||||
|
"js/skins/ui/oxide-dark/skin.css": { |
||||
|
"name": "js/skins/ui/oxide-dark/skin.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide-dark/skin.css" |
||||
|
}, |
||||
|
"js/skins/ui/oxide-dark/skin.min.css": { |
||||
|
"name": "js/skins/ui/oxide-dark/skin.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide-dark/skin.min.css" |
||||
|
}, |
||||
|
"js/skins/ui/oxide-dark/skin.shadowdom.css": { |
||||
|
"name": "js/skins/ui/oxide-dark/skin.shadowdom.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.shadowdom.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide-dark/skin.shadowdom.css" |
||||
|
}, |
||||
|
"js/skins/ui/oxide-dark/skin.shadowdom.min.css": { |
||||
|
"name": "js/skins/ui/oxide-dark/skin.shadowdom.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.shadowdom.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide-dark/skin.shadowdom.min.css" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5/content.css": { |
||||
|
"name": "js/skins/ui/tinymce-5/content.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5/content.css" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5/content.inline.css": { |
||||
|
"name": "js/skins/ui/tinymce-5/content.inline.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.inline.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5/content.inline.css" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5/content.inline.min.css": { |
||||
|
"name": "js/skins/ui/tinymce-5/content.inline.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.inline.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5/content.inline.min.css" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5/content.min.css": { |
||||
|
"name": "js/skins/ui/tinymce-5/content.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5/content.min.css" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5/skin.css": { |
||||
|
"name": "js/skins/ui/tinymce-5/skin.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5/skin.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5/skin.css" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5/skin.min.css": { |
||||
|
"name": "js/skins/ui/tinymce-5/skin.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5/skin.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5/skin.min.css" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5/skin.shadowdom.css": { |
||||
|
"name": "js/skins/ui/tinymce-5/skin.shadowdom.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5/skin.shadowdom.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5/skin.shadowdom.css" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5/skin.shadowdom.min.css": { |
||||
|
"name": "js/skins/ui/tinymce-5/skin.shadowdom.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5/skin.shadowdom.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5/skin.shadowdom.min.css" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5-dark/content.css": { |
||||
|
"name": "js/skins/ui/tinymce-5-dark/content.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.css" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5-dark/content.inline.css": { |
||||
|
"name": "js/skins/ui/tinymce-5-dark/content.inline.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.inline.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.inline.css" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5-dark/content.inline.min.css": { |
||||
|
"name": "js/skins/ui/tinymce-5-dark/content.inline.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.inline.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.inline.min.css" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5-dark/content.min.css": { |
||||
|
"name": "js/skins/ui/tinymce-5-dark/content.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.min.css" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5-dark/skin.css": { |
||||
|
"name": "js/skins/ui/tinymce-5-dark/skin.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.css" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5-dark/skin.min.css": { |
||||
|
"name": "js/skins/ui/tinymce-5-dark/skin.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.min.css" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5-dark/skin.shadowdom.css": { |
||||
|
"name": "js/skins/ui/tinymce-5-dark/skin.shadowdom.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.shadowdom.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.shadowdom.css" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5-dark/skin.shadowdom.min.css": { |
||||
|
"name": "js/skins/ui/tinymce-5-dark/skin.shadowdom.min.css", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.shadowdom.min.css", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.shadowdom.min.css" |
||||
|
}, |
||||
|
"js/chunk-vendors.874df7f4.js.LICENSE.txt": { |
||||
|
"name": "js/chunk-vendors.874df7f4.js.LICENSE.txt", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/chunk-vendors.874df7f4.js.LICENSE.txt", |
||||
|
"publicPath": "/static/sapl/frontend/js/chunk-vendors.874df7f4.js.LICENSE.txt" |
||||
|
}, |
||||
|
"js/global.f01dd32a.js.LICENSE.txt": { |
||||
|
"name": "js/global.f01dd32a.js.LICENSE.txt", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/global.f01dd32a.js.LICENSE.txt", |
||||
|
"publicPath": "/static/sapl/frontend/js/global.f01dd32a.js.LICENSE.txt" |
||||
|
}, |
||||
|
"fonts/fa-v4compatibility.7e7e1dad.ttf.gz": { |
||||
|
"name": "fonts/fa-v4compatibility.7e7e1dad.ttf.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/fonts/fa-v4compatibility.7e7e1dad.ttf.gz", |
||||
|
"publicPath": "/static/sapl/frontend/fonts/fa-v4compatibility.7e7e1dad.ttf.gz" |
||||
|
}, |
||||
|
"js/parlamentar.25e7f0fa.js.gz": { |
||||
|
"name": "js/parlamentar.25e7f0fa.js.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/parlamentar.25e7f0fa.js.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/parlamentar.25e7f0fa.js.gz" |
||||
|
}, |
||||
|
"css/painel.e2b9504e.css.gz": { |
||||
|
"name": "css/painel.e2b9504e.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/css/painel.e2b9504e.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/css/painel.e2b9504e.css.gz" |
||||
|
}, |
||||
|
"js/painel.7aa779e9.js.gz": { |
||||
|
"name": "js/painel.7aa779e9.js.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/painel.7aa779e9.js.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/painel.7aa779e9.js.gz" |
||||
|
}, |
||||
|
"js/compilacao.d68d2b28.js.gz": { |
||||
|
"name": "js/compilacao.d68d2b28.js.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/compilacao.d68d2b28.js.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/compilacao.d68d2b28.js.gz" |
||||
|
}, |
||||
|
"js/global.f01dd32a.js.gz": { |
||||
|
"name": "js/global.f01dd32a.js.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/global.f01dd32a.js.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/global.f01dd32a.js.gz" |
||||
|
}, |
||||
|
"css/compilacao.f4baf459.css.gz": { |
||||
|
"name": "css/compilacao.f4baf459.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/css/compilacao.f4baf459.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/css/compilacao.f4baf459.css.gz" |
||||
|
}, |
||||
|
"img/down_arrow_select.jpg.gz": { |
||||
|
"name": "img/down_arrow_select.jpg.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/img/down_arrow_select.jpg.gz", |
||||
|
"publicPath": "/static/sapl/frontend/img/down_arrow_select.jpg.gz" |
||||
|
}, |
||||
|
"js/skins/content/dark/content.css.gz": { |
||||
|
"name": "js/skins/content/dark/content.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/dark/content.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/dark/content.css.gz" |
||||
|
}, |
||||
|
"js/skins/content/dark/content.min.css.gz": { |
||||
|
"name": "js/skins/content/dark/content.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/dark/content.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/dark/content.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/content/default/content.min.css.gz": { |
||||
|
"name": "js/skins/content/default/content.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/default/content.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/default/content.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/content/default/content.css.gz": { |
||||
|
"name": "js/skins/content/default/content.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/default/content.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/default/content.css.gz" |
||||
|
}, |
||||
|
"js/skins/content/document/content.css.gz": { |
||||
|
"name": "js/skins/content/document/content.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/document/content.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/document/content.css.gz" |
||||
|
}, |
||||
|
"js/skins/content/document/content.min.css.gz": { |
||||
|
"name": "js/skins/content/document/content.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/document/content.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/document/content.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/content/tinymce-5/content.css.gz": { |
||||
|
"name": "js/skins/content/tinymce-5/content.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/tinymce-5/content.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/tinymce-5/content.css.gz" |
||||
|
}, |
||||
|
"js/skins/content/tinymce-5/content.min.css.gz": { |
||||
|
"name": "js/skins/content/tinymce-5/content.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/tinymce-5/content.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/tinymce-5/content.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/content/tinymce-5-dark/content.css.gz": { |
||||
|
"name": "js/skins/content/tinymce-5-dark/content.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/tinymce-5-dark/content.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/tinymce-5-dark/content.css.gz" |
||||
|
}, |
||||
|
"js/skins/content/writer/content.css.gz": { |
||||
|
"name": "js/skins/content/writer/content.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/writer/content.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/writer/content.css.gz" |
||||
|
}, |
||||
|
"js/skins/content/tinymce-5-dark/content.min.css.gz": { |
||||
|
"name": "js/skins/content/tinymce-5-dark/content.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/tinymce-5-dark/content.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/tinymce-5-dark/content.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/content/writer/content.min.css.gz": { |
||||
|
"name": "js/skins/content/writer/content.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/content/writer/content.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/content/writer/content.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/oxide/content.inline.css.gz": { |
||||
|
"name": "js/skins/ui/oxide/content.inline.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide/content.inline.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide/content.inline.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/oxide/content.css.gz": { |
||||
|
"name": "js/skins/ui/oxide/content.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide/content.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide/content.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/oxide/content.min.css.gz": { |
||||
|
"name": "js/skins/ui/oxide/content.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide/content.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide/content.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/oxide/content.inline.min.css.gz": { |
||||
|
"name": "js/skins/ui/oxide/content.inline.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide/content.inline.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide/content.inline.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/oxide/skin.shadowdom.css.gz": { |
||||
|
"name": "js/skins/ui/oxide/skin.shadowdom.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide/skin.shadowdom.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide/skin.shadowdom.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/oxide/skin.shadowdom.min.css.gz": { |
||||
|
"name": "js/skins/ui/oxide/skin.shadowdom.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide/skin.shadowdom.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide/skin.shadowdom.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/oxide-dark/content.css.gz": { |
||||
|
"name": "js/skins/ui/oxide-dark/content.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide-dark/content.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/oxide-dark/content.inline.css.gz": { |
||||
|
"name": "js/skins/ui/oxide-dark/content.inline.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.inline.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide-dark/content.inline.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/oxide-dark/content.inline.min.css.gz": { |
||||
|
"name": "js/skins/ui/oxide-dark/content.inline.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.inline.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide-dark/content.inline.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/oxide-dark/content.min.css.gz": { |
||||
|
"name": "js/skins/ui/oxide-dark/content.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide-dark/content.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide-dark/content.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/oxide/skin.min.css.gz": { |
||||
|
"name": "js/skins/ui/oxide/skin.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide/skin.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide/skin.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/oxide-dark/skin.shadowdom.css.gz": { |
||||
|
"name": "js/skins/ui/oxide-dark/skin.shadowdom.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.shadowdom.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide-dark/skin.shadowdom.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/oxide/skin.css.gz": { |
||||
|
"name": "js/skins/ui/oxide/skin.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide/skin.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide/skin.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/oxide-dark/skin.shadowdom.min.css.gz": { |
||||
|
"name": "js/skins/ui/oxide-dark/skin.shadowdom.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.shadowdom.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide-dark/skin.shadowdom.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5/content.inline.min.css.gz": { |
||||
|
"name": "js/skins/ui/tinymce-5/content.inline.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.inline.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5/content.inline.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5/content.inline.css.gz": { |
||||
|
"name": "js/skins/ui/tinymce-5/content.inline.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.inline.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5/content.inline.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5/content.css.gz": { |
||||
|
"name": "js/skins/ui/tinymce-5/content.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5/content.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5/content.min.css.gz": { |
||||
|
"name": "js/skins/ui/tinymce-5/content.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5/content.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5/content.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5/skin.shadowdom.css.gz": { |
||||
|
"name": "js/skins/ui/tinymce-5/skin.shadowdom.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5/skin.shadowdom.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5/skin.shadowdom.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/oxide-dark/skin.min.css.gz": { |
||||
|
"name": "js/skins/ui/oxide-dark/skin.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide-dark/skin.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5/skin.shadowdom.min.css.gz": { |
||||
|
"name": "js/skins/ui/tinymce-5/skin.shadowdom.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5/skin.shadowdom.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5/skin.shadowdom.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5-dark/content.inline.css.gz": { |
||||
|
"name": "js/skins/ui/tinymce-5-dark/content.inline.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.inline.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.inline.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/oxide-dark/skin.css.gz": { |
||||
|
"name": "js/skins/ui/oxide-dark/skin.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/oxide-dark/skin.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/oxide-dark/skin.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5-dark/content.css.gz": { |
||||
|
"name": "js/skins/ui/tinymce-5-dark/content.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5-dark/content.inline.min.css.gz": { |
||||
|
"name": "js/skins/ui/tinymce-5-dark/content.inline.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.inline.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.inline.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5-dark/content.min.css.gz": { |
||||
|
"name": "js/skins/ui/tinymce-5-dark/content.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5-dark/content.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5-dark/skin.shadowdom.css.gz": { |
||||
|
"name": "js/skins/ui/tinymce-5-dark/skin.shadowdom.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.shadowdom.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.shadowdom.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5-dark/skin.shadowdom.min.css.gz": { |
||||
|
"name": "js/skins/ui/tinymce-5-dark/skin.shadowdom.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.shadowdom.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.shadowdom.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5/skin.css.gz": { |
||||
|
"name": "js/skins/ui/tinymce-5/skin.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5/skin.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5/skin.css.gz" |
||||
|
}, |
||||
|
"js/chunk-vendors.874df7f4.js.LICENSE.txt.gz": { |
||||
|
"name": "js/chunk-vendors.874df7f4.js.LICENSE.txt.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/chunk-vendors.874df7f4.js.LICENSE.txt.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/chunk-vendors.874df7f4.js.LICENSE.txt.gz" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5/skin.min.css.gz": { |
||||
|
"name": "js/skins/ui/tinymce-5/skin.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5/skin.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5/skin.min.css.gz" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5-dark/skin.css.gz": { |
||||
|
"name": "js/skins/ui/tinymce-5-dark/skin.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.css.gz" |
||||
|
}, |
||||
|
"fonts/fa-regular-400.3edb9004.ttf.gz": { |
||||
|
"name": "fonts/fa-regular-400.3edb9004.ttf.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/fonts/fa-regular-400.3edb9004.ttf.gz", |
||||
|
"publicPath": "/static/sapl/frontend/fonts/fa-regular-400.3edb9004.ttf.gz" |
||||
|
}, |
||||
|
"js/skins/ui/tinymce-5-dark/skin.min.css.gz": { |
||||
|
"name": "js/skins/ui/tinymce-5-dark/skin.min.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.min.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/skins/ui/tinymce-5-dark/skin.min.css.gz" |
||||
|
}, |
||||
|
"css/global.45591136.css.gz": { |
||||
|
"name": "css/global.45591136.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/css/global.45591136.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/css/global.45591136.css.gz" |
||||
|
}, |
||||
|
"css/chunk-vendors.9904f9d0.css.gz": { |
||||
|
"name": "css/chunk-vendors.9904f9d0.css.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/css/chunk-vendors.9904f9d0.css.gz", |
||||
|
"publicPath": "/static/sapl/frontend/css/chunk-vendors.9904f9d0.css.gz" |
||||
|
}, |
||||
|
"fonts/fa-brands-400.f5defc2e.ttf.gz": { |
||||
|
"name": "fonts/fa-brands-400.f5defc2e.ttf.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/fonts/fa-brands-400.f5defc2e.ttf.gz", |
||||
|
"publicPath": "/static/sapl/frontend/fonts/fa-brands-400.f5defc2e.ttf.gz" |
||||
|
}, |
||||
|
"fonts/fa-solid-900.f418d876.ttf.gz": { |
||||
|
"name": "fonts/fa-solid-900.f418d876.ttf.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/fonts/fa-solid-900.f418d876.ttf.gz", |
||||
|
"publicPath": "/static/sapl/frontend/fonts/fa-solid-900.f418d876.ttf.gz" |
||||
|
}, |
||||
|
"js/chunk-vendors.874df7f4.js.gz": { |
||||
|
"name": "js/chunk-vendors.874df7f4.js.gz", |
||||
|
"path": "/home/leandro/desenvolvimento/envs/sapl/sapl/static/sapl/frontend/js/chunk-vendors.874df7f4.js.gz", |
||||
|
"publicPath": "/static/sapl/frontend/js/chunk-vendors.874df7f4.js.gz" |
||||
|
} |
||||
|
}, |
||||
|
"chunks": { |
||||
|
"global": [ |
||||
|
"css/chunk-vendors.9904f9d0.css", |
||||
|
"js/chunk-vendors.874df7f4.js", |
||||
|
"css/global.45591136.css", |
||||
|
"js/global.f01dd32a.js" |
||||
|
], |
||||
|
"parlamentar": [ |
||||
|
"css/chunk-vendors.9904f9d0.css", |
||||
|
"js/chunk-vendors.874df7f4.js", |
||||
|
"css/parlamentar.cd5dc5a8.css", |
||||
|
"js/parlamentar.25e7f0fa.js" |
||||
|
], |
||||
|
"painel": [ |
||||
|
"css/chunk-vendors.9904f9d0.css", |
||||
|
"js/chunk-vendors.874df7f4.js", |
||||
|
"css/painel.e2b9504e.css", |
||||
|
"js/painel.7aa779e9.js" |
||||
|
], |
||||
|
"compilacao": [ |
||||
|
"css/chunk-vendors.9904f9d0.css", |
||||
|
"js/chunk-vendors.874df7f4.js", |
||||
|
"css/compilacao.f4baf459.css", |
||||
|
"js/compilacao.d68d2b28.js" |
||||
|
] |
||||
|
}, |
||||
|
"publicPath": "/static/sapl/frontend/" |
||||
|
} |
@ -1,292 +0,0 @@ |
|||||
import logging |
|
||||
|
|
||||
from django import apps |
|
||||
from django.conf import settings |
|
||||
from django.contrib.contenttypes.models import ContentType |
|
||||
from django.core.exceptions import ObjectDoesNotExist |
|
||||
from django.db.models import Q |
|
||||
from django.db.models.signals import post_save |
|
||||
from django.dispatch import receiver |
|
||||
from django.utils import timezone |
|
||||
from django.utils.decorators import classonlymethod |
|
||||
from django.utils.translation import ugettext_lazy as _ |
|
||||
from django_filters.rest_framework.backends import DjangoFilterBackend |
|
||||
from rest_framework import serializers as rest_serializers |
|
||||
from rest_framework.authtoken.models import Token |
|
||||
from rest_framework.decorators import action, api_view, permission_classes |
|
||||
from rest_framework.fields import SerializerMethodField |
|
||||
from rest_framework.permissions import IsAuthenticated, IsAdminUser |
|
||||
from rest_framework.response import Response |
|
||||
from rest_framework.views import APIView |
|
||||
from rest_framework.viewsets import ModelViewSet |
|
||||
|
|
||||
from sapl.api.core.filters import SaplFilterSetMixin |
|
||||
from sapl.api.permissions import SaplModelPermissions |
|
||||
|
|
||||
# ATENÇÃO: MUDANÇAS NO CORE DEVEM SER REALIZADAS COM |
|
||||
# EXTREMA CAUTELA |
|
||||
|
|
||||
|
|
||||
class BusinessRulesNotImplementedMixin: |
|
||||
|
|
||||
def create(self, request, *args, **kwargs): |
|
||||
raise Exception(_("POST Create não implementado")) |
|
||||
|
|
||||
def update(self, request, *args, **kwargs): |
|
||||
raise Exception(_("PUT and PATCH não implementado")) |
|
||||
|
|
||||
def delete(self, request, *args, **kwargs): |
|
||||
raise Exception(_("DELETE Delete não implementado")) |
|
||||
|
|
||||
|
|
||||
class SaplApiViewSetConstrutor(): |
|
||||
|
|
||||
class SaplApiViewSet(ModelViewSet): |
|
||||
filter_backends = (DjangoFilterBackend,) |
|
||||
|
|
||||
_built_sets = {} |
|
||||
|
|
||||
@classonlymethod |
|
||||
def get_class_for_model(cls, model): |
|
||||
return cls._built_sets[model._meta.app_config][model] |
|
||||
|
|
||||
@classonlymethod |
|
||||
def build_class(cls): |
|
||||
import inspect |
|
||||
from sapl.api.core import serializers |
|
||||
|
|
||||
# Carrega todas as classes de sapl.api.serializers que possuam |
|
||||
# "Serializer" como Sufixo. |
|
||||
serializers_classes = inspect.getmembers(serializers) |
|
||||
|
|
||||
serializers_classes = {i[0]: i[1] for i in filter( |
|
||||
lambda x: x[0].endswith('Serializer'), |
|
||||
serializers_classes |
|
||||
)} |
|
||||
|
|
||||
# Carrega todas as classes de sapl.api.forms que possuam |
|
||||
# "FilterSet" como Sufixo. |
|
||||
from sapl.api.core import forms |
|
||||
filters_classes = inspect.getmembers(forms) |
|
||||
filters_classes = {i[0]: i[1] for i in filter( |
|
||||
lambda x: x[0].endswith('FilterSet'), |
|
||||
filters_classes |
|
||||
)} |
|
||||
|
|
||||
built_sets = {} |
|
||||
|
|
||||
def build(_model): |
|
||||
object_name = _model._meta.object_name |
|
||||
|
|
||||
# Caso Exista, pega a classe sapl.api.serializers.{model}Serializer |
|
||||
# ou utiliza a base do drf para gerar uma automática para o model |
|
||||
serializer_name = f'{object_name}Serializer' |
|
||||
_serializer_class = serializers_classes.get( |
|
||||
serializer_name, rest_serializers.ModelSerializer) |
|
||||
|
|
||||
# Caso Exista, pega a classe sapl.api.core.forms.{model}FilterSet |
|
||||
# ou utiliza a base definida em |
|
||||
# sapl.api.core.filters.SaplFilterSetMixin |
|
||||
filter_name = f'{object_name}FilterSet' |
|
||||
_filterset_class = filters_classes.get( |
|
||||
filter_name, SaplFilterSetMixin) |
|
||||
|
|
||||
def create_class(): |
|
||||
|
|
||||
_meta_serializer = object if not hasattr( |
|
||||
_serializer_class, 'Meta') else _serializer_class.Meta |
|
||||
|
|
||||
# Define uma classe padrão para serializer caso não tenha sido |
|
||||
# criada a classe sapl.api.core.serializers.{model}Serializer |
|
||||
class SaplSerializer(_serializer_class): |
|
||||
__str__ = SerializerMethodField() |
|
||||
|
|
||||
class Meta(_meta_serializer): |
|
||||
if not hasattr(_meta_serializer, 'ref_name'): |
|
||||
ref_name = f'{object_name}Serializer' |
|
||||
|
|
||||
if not hasattr(_meta_serializer, 'model'): |
|
||||
model = _model |
|
||||
|
|
||||
if hasattr(_meta_serializer, 'exclude'): |
|
||||
exclude = _meta_serializer.exclude |
|
||||
else: |
|
||||
if not hasattr(_meta_serializer, 'fields'): |
|
||||
fields = '__all__' |
|
||||
elif _meta_serializer.fields != '__all__': |
|
||||
fields = list( |
|
||||
_meta_serializer.fields) + ['__str__', ] |
|
||||
else: |
|
||||
fields = _meta_serializer.fields |
|
||||
|
|
||||
def get___str__(self, obj) -> str: |
|
||||
return str(obj) |
|
||||
|
|
||||
_meta_filterset = object if not hasattr( |
|
||||
_filterset_class, 'Meta') else _filterset_class.Meta |
|
||||
|
|
||||
# Define uma classe padrão para filtro caso não tenha sido |
|
||||
# criada a classe sapl.api.forms.{model}FilterSet |
|
||||
class SaplFilterSet(_filterset_class): |
|
||||
|
|
||||
class Meta(_meta_filterset): |
|
||||
if not hasattr(_meta_filterset, 'model'): |
|
||||
model = _model |
|
||||
|
|
||||
# Define uma classe padrão ModelViewSet de DRF |
|
||||
class ModelSaplViewSet(SaplApiViewSetConstrutor.SaplApiViewSet): |
|
||||
queryset = _model.objects.all() |
|
||||
|
|
||||
# Utiliza o filtro customizado pela classe |
|
||||
# sapl.api.core.forms.{model}FilterSet |
|
||||
# ou utiliza o trivial SaplFilterSet definido acima |
|
||||
filterset_class = SaplFilterSet |
|
||||
|
|
||||
# Utiliza o serializer customizado pela classe |
|
||||
# sapl.api.core.serializers.{model}Serializer |
|
||||
# ou utiliza o trivial SaplSerializer definido acima |
|
||||
serializer_class = SaplSerializer |
|
||||
|
|
||||
return ModelSaplViewSet |
|
||||
|
|
||||
viewset = create_class() |
|
||||
viewset.__name__ = '%sModelSaplViewSet' % _model.__name__ |
|
||||
return viewset |
|
||||
|
|
||||
apps_sapl = [apps.apps.get_app_config( |
|
||||
n[5:]) for n in settings.SAPL_APPS] |
|
||||
for app in apps_sapl: |
|
||||
cls._built_sets[app] = {} |
|
||||
for model in app.get_models(): |
|
||||
cls._built_sets[app][model] = build(model) |
|
||||
|
|
||||
return cls |
|
||||
|
|
||||
""" |
|
||||
1. Constroi uma rest_framework.viewsets.ModelViewSet para |
|
||||
todos os models de todas as apps do sapl |
|
||||
2. Define DjangoFilterBackend como ferramenta de filtro dos campos |
|
||||
3. Define Serializer como a seguir: |
|
||||
3.1 - Define um Serializer genérico para cada módel |
|
||||
3.2 - Recupera Serializer customizado em sapl.api.core.serializers |
|
||||
3.3 - Para todo model é opcional a existência de |
|
||||
sapl.api.core.serializers.{model}Serializer. |
|
||||
Caso não seja definido um Serializer customizado, utiliza-se o trivial |
|
||||
4. Define um FilterSet como a seguir: |
|
||||
4.1 - Define um FilterSet genérico para cada módel |
|
||||
4.2 - Recupera FilterSet customizado em sapl.api.core.forms |
|
||||
4.3 - Para todo model é opcional a existência de |
|
||||
sapl.api.core.forms.{model}FilterSet. |
|
||||
Caso não seja definido um FilterSet customizado, utiliza-se o trivial |
|
||||
4.4 - todos os campos que aceitam lookup 'exact' |
|
||||
podem ser filtrados por default |
|
||||
|
|
||||
5. SaplApiViewSetConstrutor não cria padrões e/ou exige conhecimento alem dos |
|
||||
exigidos pela DRF. |
|
||||
|
|
||||
6. As rotas são criadas seguindo nome da app e nome do model |
|
||||
http://localhost:9000/api/{applabel}/{model_name}/ |
|
||||
e seguem as variações definidas em: |
|
||||
https://www.django-rest-framework.org/api-guide/routers/#defaultrouter |
|
||||
|
|
||||
7. Todas as viewsets construídas por SaplApiViewSetConstrutor e suas rotas |
|
||||
(paginate list, detail, edit, create, delete) |
|
||||
bem como testes em ambiente de desenvolvimento podem ser conferidas em: |
|
||||
http://localhost:9000/api/ |
|
||||
desde que settings.DEBUG=True |
|
||||
|
|
||||
**SaplApiViewSetConstrutor._built_sets** é um dict de dicts de models conforme: |
|
||||
{ |
|
||||
... |
|
||||
|
|
||||
'audiencia': { |
|
||||
'tipoaudienciapublica': TipoAudienciaPublicaViewSet, |
|
||||
'audienciapublica': AudienciaPublicaViewSet, |
|
||||
'anexoaudienciapublica': AnexoAudienciaPublicaViewSet |
|
||||
|
|
||||
... |
|
||||
|
|
||||
}, |
|
||||
|
|
||||
... |
|
||||
|
|
||||
'base': { |
|
||||
'casalegislativa': CasaLegislativaViewSet, |
|
||||
'appconfig': AppConfigViewSet, |
|
||||
|
|
||||
... |
|
||||
|
|
||||
} |
|
||||
|
|
||||
... |
|
||||
|
|
||||
} |
|
||||
""" |
|
||||
|
|
||||
# Toda Classe construida acima, pode ser redefinida e aplicado quaisquer |
|
||||
# das possibilidades para uma classe normal criada a partir de |
|
||||
# rest_framework.viewsets.ModelViewSet conforme exemplo para a classe autor |
|
||||
|
|
||||
# decorator que processa um endpoint detail trivial com base no model passado, |
|
||||
# Um endpoint detail geralmente é um conteúdo baseado numa FK com outros possíveis filtros |
|
||||
# e os passados pelo proprio cliente, além de o serializer e o filterset |
|
||||
# ser desse model passado |
|
||||
|
|
||||
|
|
||||
class wrapper_queryset_response_for_drf_action(object): |
|
||||
|
|
||||
def __init__(self, model): |
|
||||
self.model = model |
|
||||
|
|
||||
def __call__(self, cls): |
|
||||
|
|
||||
def wrapper(instance_view, *args, **kwargs): |
|
||||
# recupera a viewset do model anotado |
|
||||
iv = instance_view |
|
||||
viewset_from_model = SaplApiViewSetConstrutor._built_sets[ |
|
||||
self.model._meta.app_config][self.model] |
|
||||
|
|
||||
# apossa da instancia da viewset mae do action |
|
||||
# em uma viewset que processa dados do model passado no decorator |
|
||||
iv.queryset = viewset_from_model.queryset |
|
||||
iv.serializer_class = viewset_from_model.serializer_class |
|
||||
iv.filterset_class = viewset_from_model.filterset_class |
|
||||
|
|
||||
iv.queryset = instance_view.filter_queryset( |
|
||||
iv.get_queryset()) |
|
||||
|
|
||||
# chama efetivamente o metodo anotado que deve devolver um queryset |
|
||||
# com os filtros específicos definido pelo programador customizador |
|
||||
qs = cls(instance_view, *args, **kwargs) |
|
||||
|
|
||||
page = iv.paginate_queryset(qs) |
|
||||
data = iv.get_serializer( |
|
||||
page if page is not None else qs, many=True).data |
|
||||
|
|
||||
return iv.get_paginated_response( |
|
||||
data) if page is not None else Response(data) |
|
||||
|
|
||||
return wrapper |
|
||||
|
|
||||
|
|
||||
# decorator para recuperar e transformar o default |
|
||||
class customize(object): |
|
||||
|
|
||||
def __init__(self, model): |
|
||||
self.model = model |
|
||||
|
|
||||
def __call__(self, cls): |
|
||||
|
|
||||
class _SaplApiViewSet( |
|
||||
cls, |
|
||||
SaplApiViewSetConstrutor._built_sets[ |
|
||||
self.model._meta.app_config][self.model] |
|
||||
): |
|
||||
pass |
|
||||
|
|
||||
if hasattr(_SaplApiViewSet, 'build'): |
|
||||
_SaplApiViewSet = _SaplApiViewSet.build() |
|
||||
|
|
||||
SaplApiViewSetConstrutor._built_sets[ |
|
||||
self.model._meta.app_config][self.model] = _SaplApiViewSet |
|
||||
return _SaplApiViewSet |
|
@ -1,110 +0,0 @@ |
|||||
|
|
||||
from collections import OrderedDict |
|
||||
|
|
||||
from django.db.models.fields.files import FileField |
|
||||
from django.template.defaultfilters import capfirst |
|
||||
from django_filters.constants import ALL_FIELDS |
|
||||
from django_filters.filters import CharFilter |
|
||||
from django_filters.filterset import FilterSet |
|
||||
from django_filters.utils import resolve_field, get_all_model_fields |
|
||||
import django_filters |
|
||||
|
|
||||
# ATENÇÃO: MUDANÇAS NO CORE DEVEM SER REALIZADAS COM |
|
||||
# EXTREMA CAUTELA E CONSCIENTE DOS IMPACTOS NA API |
|
||||
|
|
||||
|
|
||||
class SaplFilterSetMixin(FilterSet): |
|
||||
|
|
||||
o = CharFilter(method='filter_o') |
|
||||
|
|
||||
class Meta: |
|
||||
fields = '__all__' |
|
||||
filter_overrides = { |
|
||||
FileField: { |
|
||||
'filter_class': django_filters.CharFilter, |
|
||||
'extra': lambda f: { |
|
||||
'lookup_expr': 'exact', |
|
||||
}, |
|
||||
}, |
|
||||
} |
|
||||
|
|
||||
def filter_o(self, queryset, name, value): |
|
||||
try: |
|
||||
return queryset.order_by( |
|
||||
*map(str.strip, value.split(','))) |
|
||||
except: |
|
||||
return queryset |
|
||||
|
|
||||
@classmethod |
|
||||
def get_fields(cls): |
|
||||
model = cls._meta.model |
|
||||
fields_model = get_all_model_fields(model) |
|
||||
fields_filter = cls._meta.fields |
|
||||
exclude = cls._meta.exclude |
|
||||
|
|
||||
if exclude is not None and fields_filter is None: |
|
||||
fields_filter = ALL_FIELDS |
|
||||
|
|
||||
fields = fields_filter if isinstance(fields_filter, dict) else {} |
|
||||
|
|
||||
for f_str in fields_model: |
|
||||
if f_str not in fields: |
|
||||
|
|
||||
f = model._meta.get_field(f_str) |
|
||||
|
|
||||
if f.many_to_many: |
|
||||
fields[f_str] = ['exact'] |
|
||||
continue |
|
||||
|
|
||||
fields[f_str] = ['exact'] |
|
||||
|
|
||||
def get_keys_lookups(cl, sub_f): |
|
||||
r = [] |
|
||||
for lk, lv in cl.items(): |
|
||||
|
|
||||
if lk == 'contained_by': |
|
||||
continue |
|
||||
|
|
||||
sflk = f'{sub_f}{"__" if sub_f else ""}{lk}' |
|
||||
r.append(sflk) |
|
||||
|
|
||||
if hasattr(lv, 'class_lookups'): |
|
||||
r += get_keys_lookups(lv.class_lookups, sflk) |
|
||||
|
|
||||
if hasattr(lv, 'output_field'): |
|
||||
r.append(f'{sflk}{"__" if sflk else ""}range') |
|
||||
|
|
||||
r += get_keys_lookups(lv.output_field.class_lookups, sflk) |
|
||||
|
|
||||
return r |
|
||||
|
|
||||
fields[f_str] = list( |
|
||||
set(fields[f_str] + get_keys_lookups(f.class_lookups, ''))) |
|
||||
|
|
||||
# Remove excluded fields |
|
||||
exclude = exclude or [] |
|
||||
|
|
||||
fields = [(f, lookups) |
|
||||
for f, lookups in fields.items() if f not in exclude] |
|
||||
|
|
||||
return OrderedDict(fields) |
|
||||
|
|
||||
@classmethod |
|
||||
def filter_for_field(cls, f, name, lookup_expr='exact'): |
|
||||
# Redefine método estático para ignorar filtro para |
|
||||
# fields que não possuam lookup_expr informado |
|
||||
|
|
||||
f, lookup_type = resolve_field(f, lookup_expr) |
|
||||
|
|
||||
default = { |
|
||||
'field_name': name, |
|
||||
'label': capfirst(f.verbose_name), |
|
||||
'lookup_expr': lookup_expr |
|
||||
} |
|
||||
|
|
||||
filter_class, params = cls.filter_for_lookup( |
|
||||
f, lookup_type) |
|
||||
default.update(params) |
|
||||
if filter_class is not None: |
|
||||
return filter_class(**default) |
|
||||
return None |
|
@ -1,25 +0,0 @@ |
|||||
|
|
||||
from sapl.api.core.filters import SaplFilterSetMixin |
|
||||
from sapl.sessao.models import SessaoPlenaria |
|
||||
|
|
||||
# ATENÇÃO: MUDANÇAS NO CORE DEVEM SER REALIZADAS COM |
|
||||
# EXTREMA CAUTELA E CONSCIENTE DOS IMPACTOS NA API |
|
||||
|
|
||||
# FILTER SET dentro do core devem ser criados se o intuíto é um filter-set |
|
||||
# para o list da api. |
|
||||
# filter_set para actions, devem ser criados fora do core. |
|
||||
|
|
||||
# A CLASSE SessaoPlenariaFilterSet não é necessária |
|
||||
# o construtor da api construiría uma igual |
|
||||
# mas está aqui para demonstrar que caso queira customizar um filter_set |
|
||||
# que a api consiga recuperá-lo, para os endpoints básicos |
|
||||
# deve seguir os critérios de nomenclatura e herança |
|
||||
|
|
||||
# class [Model]FilterSet(SaplFilterSetMixin): |
|
||||
# class Meta(SaplFilterSetMixin.Meta): |
|
||||
|
|
||||
|
|
||||
class SessaoPlenariaFilterSet(SaplFilterSetMixin): |
|
||||
|
|
||||
class Meta(SaplFilterSetMixin.Meta): |
|
||||
model = SessaoPlenaria |
|
@ -1,50 +0,0 @@ |
|||||
import logging |
|
||||
|
|
||||
from django.conf import settings |
|
||||
from rest_framework import serializers |
|
||||
from rest_framework.relations import StringRelatedField |
|
||||
|
|
||||
from sapl.base.models import CasaLegislativa |
|
||||
|
|
||||
|
|
||||
class IntRelatedField(StringRelatedField): |
|
||||
|
|
||||
def to_representation(self, value): |
|
||||
return int(value) |
|
||||
|
|
||||
|
|
||||
class ChoiceSerializer(serializers.Serializer): |
|
||||
value = serializers.SerializerMethodField() |
|
||||
text = serializers.SerializerMethodField() |
|
||||
|
|
||||
def get_text(self, obj): |
|
||||
return obj[1] |
|
||||
|
|
||||
def get_value(self, obj): |
|
||||
return obj[0] |
|
||||
|
|
||||
|
|
||||
class ModelChoiceSerializer(ChoiceSerializer): |
|
||||
|
|
||||
def get_text(self, obj): |
|
||||
return str(obj) |
|
||||
|
|
||||
def get_value(self, obj): |
|
||||
return obj.id |
|
||||
|
|
||||
|
|
||||
class ModelChoiceObjectRelatedField(serializers.RelatedField): |
|
||||
|
|
||||
def to_representation(self, value): |
|
||||
return ModelChoiceSerializer(value).data |
|
||||
|
|
||||
|
|
||||
class CasaLegislativaSerializer(serializers.ModelSerializer): |
|
||||
version = serializers.SerializerMethodField() |
|
||||
|
|
||||
def get_version(self, obj): |
|
||||
return settings.SAPL_VERSION |
|
||||
|
|
||||
class Meta: |
|
||||
model = CasaLegislativa |
|
||||
fields = '__all__' |
|
@ -1,676 +1,27 @@ |
|||||
|
|
||||
import logging |
|
||||
|
|
||||
from django.contrib.contenttypes.models import ContentType |
|
||||
from django.db.models import Q |
|
||||
from django.db.models import Q |
|
||||
from django.forms.fields import CharField, MultiValueField |
|
||||
from django.forms.widgets import MultiWidget, TextInput |
|
||||
from django.http import Http404 |
|
||||
from django.utils import timezone |
|
||||
from django.utils.translation import ugettext_lazy as _ |
|
||||
from django_filters.filters import CharFilter, ModelChoiceFilter, DateFilter |
|
||||
from django_filters.rest_framework.backends import DjangoFilterBackend |
from django_filters.rest_framework.backends import DjangoFilterBackend |
||||
from django_filters.rest_framework.filterset import FilterSet |
|
||||
from rest_framework import serializers |
|
||||
from rest_framework.generics import ListAPIView |
|
||||
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin |
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin |
||||
from rest_framework.permissions import (IsAuthenticated, |
from rest_framework.permissions import AllowAny |
||||
IsAuthenticatedOrReadOnly, AllowAny) |
|
||||
from rest_framework.viewsets import GenericViewSet |
from rest_framework.viewsets import GenericViewSet |
||||
|
|
||||
from sapl.api.core.serializers import ModelChoiceSerializer, ChoiceSerializer |
from sapl.api.serializers import SessaoPlenariaECidadaniaSerializer |
||||
from sapl.api.serializers import AutorSerializer |
from sapl.sessao.models import SessaoPlenaria |
||||
from sapl.base.models import TipoAutor, Autor, CasaLegislativa |
|
||||
from sapl.materia.models import MateriaLegislativa |
|
||||
from sapl.parlamentares.models import Legislatura |
|
||||
from sapl.sessao.models import SessaoPlenaria, OrdemDia |
|
||||
from sapl.utils import SaplGenericRelation |
|
||||
from sapl.utils import generic_relations_for_model |
|
||||
|
|
||||
|
|
||||
class SaplGenericRelationSearchFilterSet(FilterSet): |
|
||||
q = CharFilter(method='filter_q') |
|
||||
|
|
||||
def filter_q(self, queryset, name, value): |
|
||||
|
|
||||
query = value.split(' ') |
|
||||
if query: |
|
||||
q = Q() |
|
||||
for qtext in query: |
|
||||
if not qtext: |
|
||||
continue |
|
||||
q_fs = Q(nome__icontains=qtext) |
|
||||
|
|
||||
order_by = [] |
|
||||
|
|
||||
for gr in generic_relations_for_model(self._meta.model): |
|
||||
sgr = gr[1] |
|
||||
for item in sgr: |
|
||||
if item.related_model != self._meta.model: |
|
||||
|
|
||||
continue |
|
||||
flag_order_by = True |
|
||||
for field in item.fields_search: |
|
||||
if flag_order_by: |
|
||||
flag_order_by = False |
|
||||
order_by.append('%s__%s' % ( |
|
||||
item.related_query_name(), |
|
||||
field[0]) |
|
||||
) |
|
||||
# if len(field) == 3 and field[2](qtext) is not |
|
||||
# None: |
|
||||
q_fs = q_fs | Q(**{'%s__%s%s' % ( |
|
||||
item.related_query_name(), |
|
||||
field[0], |
|
||||
field[1]): qtext if len(field) == 2 |
|
||||
else field[2](qtext)}) |
|
||||
|
|
||||
q = q & q_fs |
|
||||
|
|
||||
if q: |
|
||||
queryset = queryset.filter(q).order_by(*order_by) |
|
||||
|
|
||||
return queryset |
|
||||
|
|
||||
|
|
||||
class SearchForFieldWidget(MultiWidget): |
|
||||
|
|
||||
def decompress(self, value): |
|
||||
if value is None: |
|
||||
return [None, None] |
|
||||
return value |
|
||||
|
|
||||
def __init__(self, attrs=None): |
|
||||
widgets = (TextInput, TextInput) |
|
||||
MultiWidget.__init__(self, widgets, attrs) |
|
||||
|
|
||||
|
|
||||
class SearchForFieldField(MultiValueField): |
|
||||
widget = SearchForFieldWidget |
|
||||
|
|
||||
def __init__(self, *args, **kwargs): |
|
||||
fields = ( |
|
||||
CharField(), |
|
||||
CharField()) |
|
||||
super(SearchForFieldField, self).__init__(fields, *args, **kwargs) |
|
||||
|
|
||||
def compress(self, parameters): |
|
||||
if parameters: |
|
||||
return parameters |
|
||||
return None |
|
||||
|
|
||||
|
|
||||
class SearchForFieldFilter(CharFilter): |
|
||||
field_class = SearchForFieldField |
|
||||
|
|
||||
|
|
||||
class AutorChoiceFilterSet(SaplGenericRelationSearchFilterSet): |
|
||||
q = CharFilter(method='filter_q') |
|
||||
tipo = ModelChoiceFilter(queryset=TipoAutor.objects.all()) |
|
||||
|
|
||||
class Meta: |
|
||||
model = Autor |
|
||||
fields = ['q', |
|
||||
'tipo', |
|
||||
'nome', ] |
|
||||
|
|
||||
def filter_q(self, queryset, name, value): |
|
||||
return super().filter_q( |
|
||||
queryset, name, value).distinct('nome').order_by('nome') |
|
||||
|
|
||||
|
|
||||
class AutorSearchForFieldFilterSet(AutorChoiceFilterSet): |
|
||||
q = SearchForFieldFilter(method='filter_q') |
|
||||
|
|
||||
class Meta(AutorChoiceFilterSet.Meta): |
|
||||
pass |
|
||||
|
|
||||
def filter_q(self, queryset, name, value): |
|
||||
|
|
||||
value[0] = value[0].split(',') |
|
||||
value[1] = value[1].split(',') |
|
||||
|
|
||||
params = {} |
|
||||
for key, v in list(zip(value[0], value[1])): |
|
||||
if v in ['True', 'False']: |
|
||||
v = '1' if v == 'True' else '0' |
|
||||
params[key] = v |
|
||||
return queryset.filter(**params).distinct('nome').order_by('nome') |
|
||||
|
|
||||
|
|
||||
class AutoresPossiveisFilterSet(FilterSet): |
|
||||
logger = logging.getLogger(__name__) |
|
||||
data_relativa = DateFilter(method='filter_data_relativa') |
|
||||
tipo = CharFilter(method='filter_tipo') |
|
||||
|
|
||||
class Meta: |
|
||||
model = Autor |
|
||||
fields = ['data_relativa', 'tipo', ] |
|
||||
|
|
||||
def filter_data_relativa(self, queryset, name, value): |
|
||||
return queryset |
|
||||
|
|
||||
def filter_tipo(self, queryset, name, value): |
|
||||
|
|
||||
try: |
|
||||
self.logger.debug( |
|
||||
"Tentando obter TipoAutor correspondente à pk {}.".format(value)) |
|
||||
tipo = TipoAutor.objects.get(pk=value) |
|
||||
except: |
|
||||
self.logger.error("TipoAutor(pk={}) inexistente.".format(value)) |
|
||||
raise serializers.ValidationError(_('Tipo de Autor inexistente.')) |
|
||||
|
|
||||
qs = queryset.filter(tipo=tipo) |
|
||||
|
|
||||
return qs |
|
||||
|
|
||||
@property |
|
||||
def qs(self): |
|
||||
qs = super().qs |
|
||||
|
|
||||
data_relativa = self.form.cleaned_data['data_relativa'] \ |
|
||||
if 'data_relativa' in self.form.cleaned_data else None |
|
||||
|
|
||||
tipo = self.form.cleaned_data['tipo'] \ |
|
||||
if 'tipo' in self.form.cleaned_data else None |
|
||||
|
|
||||
if not tipo: |
|
||||
return qs |
|
||||
|
|
||||
tipo = TipoAutor.objects.get(pk=tipo) |
|
||||
if not tipo.content_type: |
|
||||
return qs |
|
||||
|
|
||||
filter_for_model = 'filter_%s' % tipo.content_type.model |
|
||||
|
|
||||
if not hasattr(self, filter_for_model): |
|
||||
return qs |
|
||||
|
|
||||
if not data_relativa: |
|
||||
data_relativa = timezone.now() |
|
||||
|
|
||||
return getattr(self, filter_for_model)(qs, data_relativa).distinct() |
|
||||
|
|
||||
def filter_parlamentar(self, queryset, data_relativa): |
|
||||
# não leva em conta afastamentos |
|
||||
legislatura_relativa = Legislatura.objects.filter( |
|
||||
data_inicio__lte=data_relativa, |
|
||||
data_fim__gte=data_relativa).first() |
|
||||
|
|
||||
q = Q( |
|
||||
parlamentar_set__mandato__data_inicio_mandato__lte=data_relativa, |
|
||||
parlamentar_set__mandato__data_fim_mandato__isnull=True) | Q( |
|
||||
parlamentar_set__mandato__data_inicio_mandato__lte=data_relativa, |
|
||||
parlamentar_set__mandato__data_fim_mandato__gte=data_relativa) |
|
||||
|
|
||||
if legislatura_relativa.atual(): |
|
||||
q = q & Q(parlamentar_set__ativo=True) |
|
||||
|
|
||||
legislatura_anterior = self.request.GET.get('legislatura_anterior', 'False') |
|
||||
if legislatura_anterior.lower() == 'true': |
|
||||
legislaturas = Legislatura.objects.filter( |
|
||||
data_fim__lte=data_relativa).order_by('-data_fim')[:2] |
|
||||
if len(legislaturas) == 2: |
|
||||
_, leg_anterior = legislaturas |
|
||||
q = q | Q(parlamentar_set__mandato__data_inicio_mandato__gte=leg_anterior.data_inicio) |
|
||||
|
|
||||
qs = queryset.filter(q) |
|
||||
return qs |
|
||||
|
|
||||
def filter_comissao(self, queryset, data_relativa): |
|
||||
return queryset.filter( |
|
||||
Q(comissao_set__data_extincao__isnull=True, |
|
||||
comissao_set__data_fim_comissao__isnull=True) | |
|
||||
Q(comissao_set__data_extincao__gte=data_relativa, |
|
||||
comissao_set__data_fim_comissao__isnull=True) | |
|
||||
Q(comissao_set__data_extincao__gte=data_relativa, |
|
||||
comissao_set__data_fim_comissao__isnull=True) | |
|
||||
Q(comissao_set__data_extincao__isnull=True, |
|
||||
comissao_set__data_fim_comissao__gte=data_relativa) | |
|
||||
Q(comissao_set__data_extincao__gte=data_relativa, |
|
||||
comissao_set__data_fim_comissao__gte=data_relativa), |
|
||||
comissao_set__data_criacao__lte=data_relativa) |
|
||||
|
|
||||
def filter_frente(self, queryset, data_relativa): |
|
||||
return queryset.filter( |
|
||||
Q(frente_set__data_extincao__isnull=True) | |
|
||||
Q(frente_set__data_extincao__gte=data_relativa), |
|
||||
frente_set__data_criacao__lte=data_relativa) |
|
||||
|
|
||||
def filter_bancada(self, queryset, data_relativa): |
|
||||
return queryset.filter( |
|
||||
Q(bancada_set__data_extincao__isnull=True) | |
|
||||
Q(bancada_set__data_extincao__gte=data_relativa), |
|
||||
bancada_set__data_criacao__lte=data_relativa) |
|
||||
|
|
||||
def filter_bloco(self, queryset, data_relativa): |
|
||||
return queryset.filter( |
|
||||
Q(bloco_set__data_extincao__isnull=True) | |
|
||||
Q(bloco_set__data_extincao__gte=data_relativa), |
|
||||
bloco_set__data_criacao__lte=data_relativa) |
|
||||
|
|
||||
def filter_orgao(self, queryset, data_relativa): |
|
||||
# na implementação, não havia regras a implementar para orgao |
|
||||
return queryset |
|
||||
|
|
||||
|
|
||||
class AutorChoiceSerializer(ModelChoiceSerializer): |
|
||||
|
|
||||
def get_text(self, obj): |
|
||||
return obj.nome |
|
||||
|
|
||||
class Meta: |
|
||||
model = Autor |
|
||||
fields = ['id', 'nome'] |
|
||||
|
|
||||
|
|
||||
class MateriaLegislativaOldSerializer(serializers.ModelSerializer): |
|
||||
|
|
||||
class Meta: |
|
||||
model = MateriaLegislativa |
|
||||
fields = '__all__' |
|
||||
|
|
||||
|
|
||||
class SessaoPlenariaOldSerializer(serializers.ModelSerializer): |
|
||||
|
|
||||
codReuniao = serializers.SerializerMethodField('get_pk_sessao') |
|
||||
codReuniaoPrincipal = serializers.SerializerMethodField('get_pk_sessao') |
|
||||
txtTituloReuniao = serializers.SerializerMethodField('get_name') |
|
||||
txtSiglaOrgao = serializers.SerializerMethodField('get_sigla_orgao') |
|
||||
txtApelido = serializers.SerializerMethodField('get_name') |
|
||||
txtNomeOrgao = serializers.SerializerMethodField('get_nome_orgao') |
|
||||
codEstadoReuniao = serializers.SerializerMethodField( |
|
||||
'get_estadoSessaoPlenaria') |
|
||||
txtTipoReuniao = serializers.SerializerMethodField('get_tipo_sessao') |
|
||||
txtObjeto = serializers.SerializerMethodField('get_assunto_sessao') |
|
||||
txtLocal = serializers.SerializerMethodField('get_endereco_orgao') |
|
||||
bolReuniaoConjunta = serializers.SerializerMethodField( |
|
||||
'get_reuniao_conjunta') |
|
||||
bolHabilitarEventoInterativo = serializers.SerializerMethodField( |
|
||||
'get_iterativo') |
|
||||
idYoutube = serializers.SerializerMethodField('get_url') |
|
||||
codEstadoTransmissaoYoutube = serializers.SerializerMethodField( |
|
||||
'get_estadoTransmissaoYoutube') |
|
||||
datReuniaoString = serializers.SerializerMethodField('get_date') |
|
||||
|
|
||||
# Constantes SessaoPlenaria (de 1-9) (apenas 3 serão usados) |
|
||||
SESSAO_FINALIZADA = 4 |
|
||||
SESSAO_EM_ANDAMENTO = 3 |
|
||||
SESSAO_CONVOCADA = 2 |
|
||||
|
|
||||
# Constantes EstadoTranmissaoYoutube (de 0 a 2) |
|
||||
TRANSMISSAO_ENCERRADA = 2 |
|
||||
TRANSMISSAO_EM_ANDAMENTO = 1 |
|
||||
SEM_TRANSMISSAO = 0 |
|
||||
|
|
||||
class Meta: |
|
||||
model = SessaoPlenaria |
|
||||
fields = ( |
|
||||
'codReuniao', |
|
||||
'codReuniaoPrincipal', |
|
||||
'txtTituloReuniao', |
|
||||
'txtSiglaOrgao', |
|
||||
'txtApelido', |
|
||||
'txtNomeOrgao', |
|
||||
'codEstadoReuniao', |
|
||||
'txtTipoReuniao', |
|
||||
'txtObjeto', |
|
||||
'txtLocal', |
|
||||
'bolReuniaoConjunta', |
|
||||
'bolHabilitarEventoInterativo', |
|
||||
'idYoutube', |
|
||||
'codEstadoTransmissaoYoutube', |
|
||||
'datReuniaoString' |
|
||||
) |
|
||||
|
|
||||
def __init__(self, *args, **kwargs): |
|
||||
super(SessaoPlenariaOldSerializer, self).__init__(args, kwargs) |
|
||||
|
|
||||
def get_pk_sessao(self, obj): |
|
||||
return obj.pk |
|
||||
|
|
||||
def get_name(self, obj): |
|
||||
return obj.__str__() |
|
||||
|
|
||||
def get_estadoSessaoPlenaria(self, obj): |
|
||||
if obj.finalizada: |
|
||||
return self.SESSAO_FINALIZADA |
|
||||
elif obj.iniciada: |
|
||||
return self.SESSAO_EM_ANDAMENTO |
|
||||
else: |
|
||||
return self.SESSAO_CONVOCADA |
|
||||
|
|
||||
def get_tipo_sessao(self, obj): |
|
||||
return obj.tipo.__str__() |
|
||||
|
|
||||
def get_url(self, obj): |
|
||||
return obj.url_video if obj.url_video else None |
|
||||
|
|
||||
def get_iterativo(self, obj): |
|
||||
return obj.interativa if obj.interativa else False |
|
||||
|
|
||||
def get_date(self, obj): |
|
||||
return "{} {}{}".format( |
|
||||
obj.data_inicio.strftime("%d/%m/%Y"), |
|
||||
obj.hora_inicio, |
|
||||
":00" |
|
||||
) |
|
||||
|
|
||||
def get_estadoTransmissaoYoutube(self, obj): |
|
||||
if obj.url_video: |
|
||||
if obj.finalizada: |
|
||||
return self.TRANSMISSAO_ENCERRADA |
|
||||
else: |
|
||||
return self.TRANSMISSAO_EM_ANDAMENTO |
|
||||
else: |
|
||||
return self.SEM_TRANSMISSAO |
|
||||
|
|
||||
def get_assunto_sessao(self, obj): |
|
||||
pauta_sessao = '' |
|
||||
ordem_dia = OrdemDia.objects.filter(sessao_plenaria=obj.pk) |
|
||||
pauta_sessao = ', '.join([i.materia.__str__() for i in ordem_dia]) |
|
||||
|
|
||||
return str(pauta_sessao) |
|
||||
|
|
||||
def get_endereco_orgao(self, obj): |
|
||||
return self.casa().endereco |
|
||||
|
|
||||
def get_reuniao_conjunta(self, obj): |
|
||||
return False |
|
||||
|
|
||||
def get_sigla_orgao(self, obj): |
|
||||
return self.casa().sigla |
|
||||
|
|
||||
def get_nome_orgao(self, obj): |
|
||||
return self.casa().nome |
|
||||
|
|
||||
def casa(self): |
|
||||
casa = CasaLegislativa.objects.first() |
|
||||
return casa |
|
||||
|
|
||||
|
|
||||
class ModelChoiceView(ListAPIView): |
|
||||
""" |
|
||||
Deprecated |
|
||||
|
|
||||
TODO Migrar para customização na api automática |
|
||||
|
|
||||
""" |
|
||||
|
|
||||
# FIXME aplicar permissão correta de usuário |
|
||||
permission_classes = (IsAuthenticated,) |
|
||||
serializer_class = ModelChoiceSerializer |
|
||||
|
|
||||
def get(self, request, *args, **kwargs): |
|
||||
self.model = ContentType.objects.get_for_id( |
|
||||
self.kwargs['content_type']).model_class() |
|
||||
|
|
||||
pagination = request.GET.get('pagination', '') |
|
||||
|
|
||||
if pagination == 'False': |
|
||||
self.pagination_class = None |
|
||||
|
|
||||
return ListAPIView.get(self, request, *args, **kwargs) |
|
||||
|
|
||||
def get_queryset(self): |
|
||||
return self.model.objects.all() |
|
||||
|
|
||||
|
|
||||
class AutorListView(ListAPIView): |
|
||||
""" |
|
||||
Deprecated |
|
||||
|
|
||||
TODO Migrar para customização na api automática |
|
||||
|
|
||||
Listagem de Autores com filtro para autores já cadastrados |
|
||||
e/ou possíveis autores. |
|
||||
|
|
||||
- tr - tipo do resultado |
|
||||
Prepera Lista de Autores para 2 cenários distintos |
|
||||
|
|
||||
- default = 1 |
|
||||
|
|
||||
= 1 -> para (value, text) usados geralmente |
|
||||
em combobox, radiobox, checkbox, etc com pesquisa básica |
|
||||
de Autores feita pelo django-filter |
|
||||
-> processo usado nas pesquisas, o mais usado. |
|
||||
|
|
||||
|
|
||||
= 3 -> Devolve instancias da classe Autor filtradas pelo |
|
||||
django-filter |
|
||||
|
|
||||
- tipo - chave primária do Tipo de Autor a ser filtrado |
|
||||
|
|
||||
- q - busca textual no nome do Autor ou em fields_search |
|
||||
declarados no field SaplGenericRelation das GenericFks |
|
||||
A busca textual acontece via django-filter com a |
|
||||
variável `tr` igual 1 ou 3. Em caso contrário, |
|
||||
o django-filter é desativado e a busca é feita |
|
||||
no model do ContentType associado ao tipo. |
|
||||
|
|
||||
- q_0 / q_1 - q_0 é opcional e quando usado, faz o código ignorar "q"... |
|
||||
|
|
||||
q_0 -> campos lookup a serem filtrados em qualquer Model |
|
||||
que implemente SaplGenericRelation |
|
||||
q_1 -> o valor que será pesquisado no lookup de q_0 |
|
||||
|
|
||||
q_0 e q_1 podem ser separados por ","... isso dará a |
|
||||
possibilidade de filtrar mais de um campo. |
|
||||
|
|
||||
|
|
||||
http://localhost:8000 |
|
||||
/api/autor?tr=1&q_0=parlamentar_set__ativo&q_1=False |
|
||||
/api/autor?tr=1&q_0=parlamentar_set__ativo&q_1=True |
|
||||
/api/autor?tr=3&q_0=parlamentar_set__ativo&q_1=False |
|
||||
/api/autor?tr=3&q_0=parlamentar_set__ativo&q_1=True |
|
||||
|
|
||||
http://localhost:8000 |
|
||||
/api/autor?tr=1 |
|
||||
&q_0=parlamentar_set__nome_parlamentar__icontains, |
|
||||
parlamentar_set__ativo |
|
||||
&q_1=Carvalho,False |
|
||||
/api/autor?tr=1 |
|
||||
&q_0=parlamentar_set__nome_parlamentar__icontains, |
|
||||
parlamentar_set__ativo |
|
||||
&q_1=Carvalho,True |
|
||||
/api/autor?tr=3 |
|
||||
&q_0=parlamentar_set__nome_parlamentar__icontains, |
|
||||
parlamentar_set__ativo |
|
||||
&q_1=Carvalho,False |
|
||||
/api/autor?tr=3 |
|
||||
&q_0=parlamentar_set__nome_parlamentar__icontains, |
|
||||
parlamentar_set__ativo |
|
||||
&q_1=Carvalho,True |
|
||||
|
|
||||
|
|
||||
não importa o campo que vc passe de qualquer dos Models |
|
||||
ligados... é possível ver que models são esses, |
|
||||
na ocasião do commit deste texto, executando: |
|
||||
In [6]: from sapl.utils import models_with_gr_for_model |
|
||||
|
|
||||
In [7]: models_with_gr_for_model(Autor) |
|
||||
Out[7]: |
|
||||
[sapl.parlamentares.models.Parlamentar, |
|
||||
sapl.parlamentares.models.Frente, |
|
||||
sapl.comissoes.models.Comissao, |
|
||||
sapl.materia.models.Orgao, |
|
||||
sapl.sessao.models.Bancada, |
|
||||
sapl.sessao.models.Bloco] |
|
||||
|
|
||||
qualquer atributo destes models podem ser passados |
|
||||
para busca |
|
||||
""" |
|
||||
logger = logging.getLogger(__name__) |
|
||||
|
|
||||
TR_AUTOR_CHOICE_SERIALIZER = 1 |
|
||||
TR_AUTOR_SERIALIZER = 3 |
|
||||
|
|
||||
permission_classes = (IsAuthenticatedOrReadOnly,) |
|
||||
queryset = Autor.objects.all() |
|
||||
model = Autor |
|
||||
|
|
||||
filter_class = AutorChoiceFilterSet |
|
||||
filter_backends = (DjangoFilterBackend,) |
|
||||
serializer_class = AutorChoiceSerializer |
|
||||
|
|
||||
@property |
|
||||
def tr(self): |
|
||||
username = self.request.user.username |
|
||||
try: |
|
||||
tr = int(self.request.GET.get |
|
||||
('tr', AutorListView.TR_AUTOR_CHOICE_SERIALIZER)) |
|
||||
|
|
||||
if tr not in (AutorListView.TR_AUTOR_CHOICE_SERIALIZER, |
|
||||
AutorListView.TR_AUTOR_SERIALIZER): |
|
||||
return AutorListView.TR_AUTOR_CHOICE_SERIALIZER |
|
||||
except Exception as e: |
|
||||
self.logger.error('user=' + username + '. ' + str(e)) |
|
||||
return AutorListView.TR_AUTOR_CHOICE_SERIALIZER |
|
||||
return tr |
|
||||
|
|
||||
def get(self, request, *args, **kwargs): |
|
||||
if self.tr == AutorListView.TR_AUTOR_SERIALIZER: |
|
||||
self.serializer_class = AutorSerializer |
|
||||
self.permission_classes = (IsAuthenticated,) |
|
||||
|
|
||||
if self.filter_class and 'q_0' in request.GET: |
|
||||
self.filter_class = AutorSearchForFieldFilterSet |
|
||||
|
|
||||
return ListAPIView.get(self, request, *args, **kwargs) |
|
||||
|
|
||||
|
|
||||
class AutoresProvaveisListView(ListAPIView): |
|
||||
""" |
|
||||
Deprecated |
|
||||
|
|
||||
TODO Migrar para customização na api automática |
|
||||
""" |
|
||||
|
|
||||
logger = logging.getLogger(__name__) |
|
||||
|
|
||||
permission_classes = (IsAuthenticatedOrReadOnly,) |
|
||||
queryset = Autor.objects.all() |
|
||||
model = Autor |
|
||||
|
|
||||
filter_class = None |
|
||||
filter_backends = [] |
|
||||
serializer_class = ChoiceSerializer |
|
||||
|
|
||||
def get_queryset(self): |
|
||||
|
|
||||
params = {'content_type__isnull': False} |
|
||||
username = self.request.user.username |
|
||||
tipo = '' |
|
||||
try: |
|
||||
tipo = int(self.request.GET.get('tipo', '')) |
|
||||
if tipo: |
|
||||
params['id'] = tipo |
|
||||
except Exception as e: |
|
||||
self.logger.error('user= ' + username + '. ' + str(e)) |
|
||||
pass |
|
||||
|
|
||||
tipos = TipoAutor.objects.filter(**params) |
|
||||
|
|
||||
if not tipos.exists() and tipo: |
|
||||
raise Http404() |
|
||||
|
|
||||
r = [] |
|
||||
for tipo in tipos: |
|
||||
q = self.request.GET.get('q', '').strip() |
|
||||
|
|
||||
model_class = tipo.content_type.model_class() |
|
||||
|
|
||||
fields = list(filter( |
|
||||
lambda field: isinstance(field, SaplGenericRelation) and |
|
||||
field.related_model == Autor, |
|
||||
model_class._meta.get_fields(include_hidden=True))) |
|
||||
|
|
||||
""" |
|
||||
fields - é um array de SaplGenericRelation que deve possuir o |
|
||||
atributo fields_search. Verifique na documentação da classe |
|
||||
a estrutura de fields_search. |
|
||||
""" |
|
||||
|
|
||||
assert len(fields) >= 1, (_( |
|
||||
'Não foi encontrado em %(model)s um atributo do tipo ' |
|
||||
'SaplGenericRelation que use o model %(model_autor)s') % { |
|
||||
'model': model_class._meta.verbose_name, |
|
||||
'model_autor': Autor._meta.verbose_name}) |
|
||||
|
|
||||
qs = model_class.objects.all() |
|
||||
|
|
||||
q_filter = Q() |
|
||||
if q: |
|
||||
for item in fields: |
|
||||
if item.related_model != Autor: |
|
||||
continue |
|
||||
q_fs = Q() |
|
||||
for field in item.fields_search: |
|
||||
q_fs = q_fs | Q(**{'%s%s' % ( |
|
||||
field[0], |
|
||||
field[1]): q}) |
|
||||
q_filter = q_filter & q_fs |
|
||||
|
|
||||
qs = qs.filter(q_filter).distinct( |
|
||||
fields[0].fields_search[0][0]).order_by( |
|
||||
fields[0].fields_search[0][0]) |
|
||||
else: |
|
||||
qs = qs.order_by(fields[0].fields_search[0][0]) |
|
||||
|
|
||||
qs = qs.values_list( |
|
||||
'id', fields[0].fields_search[0][0]) |
|
||||
r += list(qs) |
|
||||
|
|
||||
if tipos.count() > 1: |
|
||||
r.sort(key=lambda x: x[1].upper()) |
|
||||
return r |
|
||||
|
|
||||
|
|
||||
class AutoresPossiveisListView(ListAPIView): |
|
||||
""" |
|
||||
Deprecated |
|
||||
|
|
||||
TODO Migrar para customização na api automática |
|
||||
""" |
|
||||
|
|
||||
permission_classes = (IsAuthenticatedOrReadOnly,) |
|
||||
queryset = Autor.objects.all() |
|
||||
model = Autor |
|
||||
|
|
||||
pagination_class = None |
|
||||
|
|
||||
filter_class = AutoresPossiveisFilterSet |
|
||||
serializer_class = AutorChoiceSerializer |
|
||||
|
|
||||
|
|
||||
class MateriaLegislativaViewSet(ListModelMixin, |
|
||||
RetrieveModelMixin, |
|
||||
GenericViewSet): |
|
||||
""" |
|
||||
Deprecated |
|
||||
|
|
||||
TODO Migrar para customização na api automática |
|
||||
""" |
|
||||
|
|
||||
permission_classes = (IsAuthenticated,) |
|
||||
serializer_class = MateriaLegislativaOldSerializer |
|
||||
queryset = MateriaLegislativa.objects.all() |
|
||||
filter_backends = (DjangoFilterBackend,) |
|
||||
filter_fields = ('numero', 'ano', 'tipo',) |
|
||||
|
|
||||
|
|
||||
class SessaoPlenariaViewSet(ListModelMixin, |
class SessaoPlenariaViewSet(ListModelMixin, |
||||
RetrieveModelMixin, |
RetrieveModelMixin, |
||||
GenericViewSet): |
GenericViewSet): |
||||
""" |
""" |
||||
Deprecated |
Deprecated - Será eliminado na versão 3.2 |
||||
|
|
||||
TODO Migrar para customização na api automática |
* TODO: |
||||
|
* eliminar endpoint, transferido para SaplApiViewSetConstrutor |
||||
|
* /api/sessao-planaria -> /api/sessao/sessaoplenaria/ecidadania |
||||
|
* /api/sessao-planaria/{pk} -> /api/sessao/sessaoplenaria/{pk}/ecidadania |
||||
|
* verificar se ainda permanece necessidade desses endpoint's |
||||
""" |
""" |
||||
|
|
||||
permission_classes = (AllowAny,) |
permission_classes = (AllowAny,) |
||||
serializer_class = SessaoPlenariaOldSerializer |
serializer_class = SessaoPlenariaECidadaniaSerializer |
||||
queryset = SessaoPlenaria.objects.all() |
queryset = SessaoPlenaria.objects.all() |
||||
filter_backends = (DjangoFilterBackend,) |
filter_backends = (DjangoFilterBackend,) |
||||
filter_fields = ('data_inicio', 'data_fim', 'interativa') |
filter_fields = ('data_inicio', 'data_fim', 'interativa') |
||||
|
@ -0,0 +1,182 @@ |
|||||
|
import logging |
||||
|
|
||||
|
from django.db.models import Q |
||||
|
from django.utils import timezone |
||||
|
from django.utils.translation import ugettext_lazy as _ |
||||
|
from django_filters.filters import CharFilter, DateFilter, ModelChoiceFilter |
||||
|
from django_filters.filterset import FilterSet |
||||
|
from rest_framework import serializers |
||||
|
|
||||
|
from drfautoapi.drfautoapi import ApiFilterSetMixin |
||||
|
from sapl.base.models import TipoAutor, Autor |
||||
|
from sapl.parlamentares.models import Legislatura |
||||
|
from sapl.utils import generic_relations_for_model |
||||
|
|
||||
|
logger = logging.getLogger(__name__) |
||||
|
|
||||
|
|
||||
|
class SaplFilterSetMixin(ApiFilterSetMixin): |
||||
|
pass |
||||
|
|
||||
|
|
||||
|
class AutorFilterSet(SaplFilterSetMixin): |
||||
|
q = CharFilter(method='filter_q') |
||||
|
tipo = ModelChoiceFilter(queryset=TipoAutor.objects.all()) |
||||
|
|
||||
|
def filter_q(self, queryset, name, value): |
||||
|
|
||||
|
query = value.split(' ') |
||||
|
if query: |
||||
|
q = Q() |
||||
|
for qtext in query: |
||||
|
if not qtext: |
||||
|
continue |
||||
|
q_fs = Q(nome__icontains=qtext) | Q( |
||||
|
tipo__descricao__icontains=qtext) |
||||
|
|
||||
|
order_by = [] |
||||
|
|
||||
|
for gr in generic_relations_for_model(self._meta.model): |
||||
|
sgr = gr[1] |
||||
|
for item in sgr: |
||||
|
if item.related_model != self._meta.model: |
||||
|
continue |
||||
|
flag_order_by = True |
||||
|
for field in item.fields_search: |
||||
|
if flag_order_by: |
||||
|
flag_order_by = False |
||||
|
order_by.append('%s__%s' % ( |
||||
|
item.related_query_name(), |
||||
|
field[0]) |
||||
|
) |
||||
|
# if len(field) == 3 and field[2](qtext) is not |
||||
|
# None: |
||||
|
q_fs = q_fs | Q(**{'%s__%s%s' % ( |
||||
|
item.related_query_name(), |
||||
|
field[0], |
||||
|
field[1]): qtext if len(field) == 2 |
||||
|
else field[2](qtext)}) |
||||
|
|
||||
|
q = q & q_fs |
||||
|
|
||||
|
if q: |
||||
|
queryset = queryset.filter(q).order_by(*order_by) |
||||
|
|
||||
|
return queryset.distinct() |
||||
|
|
||||
|
|
||||
|
class AutoresPossiveisFilterSet(SaplFilterSetMixin): |
||||
|
data_relativa = DateFilter(method='filter_data_relativa') |
||||
|
tipo = CharFilter(method='filter_tipo') |
||||
|
|
||||
|
class Meta: |
||||
|
model = Autor |
||||
|
fields = ['data_relativa', 'tipo', ] |
||||
|
|
||||
|
def filter_data_relativa(self, queryset, name, value): |
||||
|
return queryset |
||||
|
|
||||
|
def filter_tipo(self, queryset, name, value): |
||||
|
|
||||
|
try: |
||||
|
logger.debug( |
||||
|
"Tentando obter TipoAutor correspondente à pk {}.".format(value)) |
||||
|
tipo = TipoAutor.objects.get(pk=value) |
||||
|
except: |
||||
|
logger.error("TipoAutor(pk={}) inexistente.".format(value)) |
||||
|
raise serializers.ValidationError(_('Tipo de Autor inexistente.')) |
||||
|
|
||||
|
qs = queryset.filter(tipo=tipo) |
||||
|
|
||||
|
return qs |
||||
|
|
||||
|
@property |
||||
|
def qs(self): |
||||
|
qs = super().qs |
||||
|
|
||||
|
data_relativa = self.form.cleaned_data['data_relativa'] \ |
||||
|
if 'data_relativa' in self.form.cleaned_data else None |
||||
|
|
||||
|
tipo = self.form.cleaned_data['tipo'] \ |
||||
|
if 'tipo' in self.form.cleaned_data else None |
||||
|
|
||||
|
if not tipo: |
||||
|
return qs |
||||
|
|
||||
|
tipo = TipoAutor.objects.get(pk=tipo) |
||||
|
if not tipo.content_type: |
||||
|
return qs |
||||
|
|
||||
|
filter_for_model = 'filter_%s' % tipo.content_type.model |
||||
|
|
||||
|
if not hasattr(self, filter_for_model): |
||||
|
return qs |
||||
|
|
||||
|
if not data_relativa: |
||||
|
data_relativa = timezone.now() |
||||
|
|
||||
|
return getattr(self, filter_for_model)(qs, data_relativa).distinct() |
||||
|
|
||||
|
def filter_parlamentar(self, queryset, data_relativa): |
||||
|
# não leva em conta afastamentos |
||||
|
legislatura_relativa = Legislatura.objects.filter( |
||||
|
data_inicio__lte=data_relativa, |
||||
|
data_fim__gte=data_relativa).first() |
||||
|
|
||||
|
q = Q( |
||||
|
parlamentar_set__mandato__data_inicio_mandato__lte=data_relativa, |
||||
|
parlamentar_set__mandato__data_fim_mandato__isnull=True) | Q( |
||||
|
parlamentar_set__mandato__data_inicio_mandato__lte=data_relativa, |
||||
|
parlamentar_set__mandato__data_fim_mandato__gte=data_relativa) |
||||
|
|
||||
|
if legislatura_relativa.atual(): |
||||
|
q = q & Q(parlamentar_set__ativo=True) |
||||
|
|
||||
|
legislatura_anterior = self.request.GET.get( |
||||
|
'legislatura_anterior', 'False') |
||||
|
if legislatura_anterior.lower() == 'true': |
||||
|
legislaturas = Legislatura.objects.filter( |
||||
|
data_fim__lte=data_relativa).order_by('-data_fim')[:2] |
||||
|
if len(legislaturas) == 2: |
||||
|
_, leg_anterior = legislaturas |
||||
|
q = q | Q( |
||||
|
parlamentar_set__mandato__data_inicio_mandato__gte=leg_anterior.data_inicio) |
||||
|
|
||||
|
qs = queryset.filter(q) |
||||
|
return qs |
||||
|
|
||||
|
def filter_comissao(self, queryset, data_relativa): |
||||
|
return queryset.filter( |
||||
|
Q(comissao_set__data_extincao__isnull=True, |
||||
|
comissao_set__data_fim_comissao__isnull=True) | |
||||
|
Q(comissao_set__data_extincao__gte=data_relativa, |
||||
|
comissao_set__data_fim_comissao__isnull=True) | |
||||
|
Q(comissao_set__data_extincao__gte=data_relativa, |
||||
|
comissao_set__data_fim_comissao__isnull=True) | |
||||
|
Q(comissao_set__data_extincao__isnull=True, |
||||
|
comissao_set__data_fim_comissao__gte=data_relativa) | |
||||
|
Q(comissao_set__data_extincao__gte=data_relativa, |
||||
|
comissao_set__data_fim_comissao__gte=data_relativa), |
||||
|
comissao_set__data_criacao__lte=data_relativa) |
||||
|
|
||||
|
def filter_frente(self, queryset, data_relativa): |
||||
|
return queryset.filter( |
||||
|
Q(frente_set__data_extincao__isnull=True) | |
||||
|
Q(frente_set__data_extincao__gte=data_relativa), |
||||
|
frente_set__data_criacao__lte=data_relativa) |
||||
|
|
||||
|
def filter_bancada(self, queryset, data_relativa): |
||||
|
return queryset.filter( |
||||
|
Q(bancada_set__data_extincao__isnull=True) | |
||||
|
Q(bancada_set__data_extincao__gte=data_relativa), |
||||
|
bancada_set__data_criacao__lte=data_relativa) |
||||
|
|
||||
|
def filter_bloco(self, queryset, data_relativa): |
||||
|
return queryset.filter( |
||||
|
Q(bloco_set__data_extincao__isnull=True) | |
||||
|
Q(bloco_set__data_extincao__gte=data_relativa), |
||||
|
bloco_set__data_criacao__lte=data_relativa) |
||||
|
|
||||
|
def filter_orgao(self, queryset, data_relativa): |
||||
|
# na implementação, não havia regras a implementar para orgao |
||||
|
return queryset |
@ -0,0 +1,10 @@ |
|||||
|
from django.conf import settings |
||||
|
from django.db.models.signals import post_save |
||||
|
from django.dispatch.dispatcher import receiver |
||||
|
from rest_framework.authtoken.models import Token |
||||
|
|
||||
|
|
||||
|
@receiver(post_save, sender=settings.AUTH_USER_MODEL) |
||||
|
def create_auth_token(sender, instance=None, created=False, **kwargs): |
||||
|
if created: |
||||
|
Token.objects.create(user=instance) |
@ -0,0 +1,11 @@ |
|||||
|
|
||||
|
from django.apps.registry import apps |
||||
|
|
||||
|
from drfautoapi.drfautoapi import ApiViewSetConstrutor, \ |
||||
|
customize, wrapper_queryset_response_for_drf_action |
||||
|
|
||||
|
AudienciaApiViewSetConstrutor = ApiViewSetConstrutor.build_class( |
||||
|
[ |
||||
|
apps.get_app_config('audiencia') |
||||
|
] |
||||
|
) |
@ -0,0 +1,180 @@ |
|||||
|
import logging |
||||
|
|
||||
|
from django.apps.registry import apps |
||||
|
from django.contrib.contenttypes.models import ContentType |
||||
|
from django.db.models import Q |
||||
|
from django.http.response import Http404 |
||||
|
from rest_framework.decorators import action |
||||
|
from rest_framework.response import Response |
||||
|
|
||||
|
from drfautoapi.drfautoapi import ApiViewSetConstrutor, customize |
||||
|
from sapl.api.forms import AutoresPossiveisFilterSet |
||||
|
from sapl.api.serializers import ChoiceSerializer |
||||
|
from sapl.base.models import Autor, TipoAutor |
||||
|
from sapl.utils import models_with_gr_for_model, SaplGenericRelation |
||||
|
|
||||
|
|
||||
|
logger = logging.getLogger(__name__) |
||||
|
|
||||
|
ApiViewSetConstrutor.build_class( |
||||
|
[ |
||||
|
apps.get_app_config('contenttypes'), |
||||
|
apps.get_app_config('base') |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
|
||||
|
@customize(ContentType) |
||||
|
class _ContentTypeSet: |
||||
|
http_method_names = ['get', 'head', 'options', 'trace'] |
||||
|
|
||||
|
|
||||
|
@customize(Autor) |
||||
|
class _AutorViewSet: |
||||
|
""" |
||||
|
Nesta customização do que foi criado em |
||||
|
ApiViewSetConstrutor além do ofertado por |
||||
|
rest_framework.viewsets.ModelViewSet, dentre outras customizações |
||||
|
possíveis, foi adicionado as rotas referentes aos relacionamentos genéricos |
||||
|
|
||||
|
* padrão de ModelViewSet |
||||
|
* /api/base/autor/ POST - create |
||||
|
* /api/base/autor/ GET - list |
||||
|
* /api/base/autor/{pk}/ GET - detail |
||||
|
* /api/base/autor/{pk}/ PUT - update |
||||
|
* /api/base/autor/{pk}/ PATCH - partial_update |
||||
|
* /api/base/autor/{pk}/ DELETE - destroy |
||||
|
|
||||
|
* rotas desta classe local criadas pelo método build local: |
||||
|
* /api/base/autor/parlamentar |
||||
|
devolve apenas autores que são parlamentares |
||||
|
* /api/base/autor/comissao |
||||
|
devolve apenas autores que são comissões |
||||
|
* /api/base/autor/bloco |
||||
|
devolve apenas autores que são blocos parlamentares |
||||
|
* /api/base/autor/bancada |
||||
|
devolve apenas autores que são bancadas parlamentares |
||||
|
* /api/base/autor/frente |
||||
|
devolve apenas autores que são Frene parlamentares |
||||
|
* /api/base/autor/orgao |
||||
|
devolve apenas autores que são Órgãos |
||||
|
""" |
||||
|
|
||||
|
def list_for_content_type(self, content_type): |
||||
|
qs = self.get_queryset() |
||||
|
qs = qs.filter(content_type=content_type) |
||||
|
|
||||
|
page = self.paginate_queryset(qs) |
||||
|
if page is not None: |
||||
|
serializer = self.serializer_class(page, many=True) |
||||
|
return self.get_paginated_response(serializer.data) |
||||
|
|
||||
|
serializer = self.get_serializer(page, many=True) |
||||
|
return Response(serializer.data) |
||||
|
|
||||
|
@classmethod |
||||
|
def build(cls): |
||||
|
|
||||
|
models_with_gr_for_autor = models_with_gr_for_model(Autor) |
||||
|
|
||||
|
for _model in models_with_gr_for_autor: |
||||
|
|
||||
|
@action(detail=False, name=_model._meta.model_name) |
||||
|
def actionclass(self, request, *args, **kwargs): |
||||
|
model = getattr(self, self.action)._AutorViewSet__model |
||||
|
|
||||
|
content_type = ContentType.objects.get_for_model(model) |
||||
|
return self.list_for_content_type(content_type) |
||||
|
|
||||
|
func = actionclass |
||||
|
func.mapping['get'] = func.kwargs['name'] |
||||
|
func.url_name = func.kwargs['name'] |
||||
|
func.url_path = func.kwargs['name'] |
||||
|
func.__name__ = func.kwargs['name'] |
||||
|
func.__model = _model |
||||
|
|
||||
|
setattr(cls, _model._meta.model_name, func) |
||||
|
return cls |
||||
|
|
||||
|
@action(detail=False) |
||||
|
def possiveis(self, request, *args, **kwargs): |
||||
|
self.filterset_class = AutoresPossiveisFilterSet |
||||
|
return self.list(request, *args, **kwargs) |
||||
|
|
||||
|
@action(detail=False) |
||||
|
def provaveis(self, request, *args, **kwargs): |
||||
|
|
||||
|
self.get_queryset = self.provaveis__get_queryset |
||||
|
|
||||
|
self.filter_backends = [] |
||||
|
self.filterset_class = None |
||||
|
self.serializer_class = ChoiceSerializer |
||||
|
return self.list(request, *args, **kwargs) |
||||
|
|
||||
|
def provaveis__get_queryset(self): |
||||
|
params = {'content_type__isnull': False} |
||||
|
username = self.request.user.username |
||||
|
tipo = '' |
||||
|
try: |
||||
|
tipo = int(self.request.GET.get('tipo', '')) |
||||
|
if tipo: |
||||
|
params['id'] = tipo |
||||
|
except Exception as e: |
||||
|
logger.error('user= ' + username + '. ' + str(e)) |
||||
|
pass |
||||
|
|
||||
|
tipos = TipoAutor.objects.filter(**params) |
||||
|
|
||||
|
if not tipos.exists() and tipo: |
||||
|
raise Http404() |
||||
|
|
||||
|
r = [] |
||||
|
for tipo in tipos: |
||||
|
q = self.request.GET.get('q', '').strip() |
||||
|
|
||||
|
model_class = tipo.content_type.model_class() |
||||
|
|
||||
|
fields = list(filter( |
||||
|
lambda field: isinstance(field, SaplGenericRelation) and |
||||
|
field.related_model == Autor, |
||||
|
model_class._meta.get_fields(include_hidden=True))) |
||||
|
|
||||
|
""" |
||||
|
fields - é um array de SaplGenericRelation que deve possuir o |
||||
|
atributo fields_search. Verifique na documentação da classe |
||||
|
a estrutura de fields_search. |
||||
|
""" |
||||
|
|
||||
|
assert len(fields) >= 1, (_( |
||||
|
'Não foi encontrado em %(model)s um atributo do tipo ' |
||||
|
'SaplGenericRelation que use o model %(model_autor)s') % { |
||||
|
'model': model_class._meta.verbose_name, |
||||
|
'model_autor': Autor._meta.verbose_name}) |
||||
|
|
||||
|
qs = model_class.objects.all() |
||||
|
|
||||
|
q_filter = Q() |
||||
|
if q: |
||||
|
for item in fields: |
||||
|
if item.related_model != Autor: |
||||
|
continue |
||||
|
q_fs = Q() |
||||
|
for field in item.fields_search: |
||||
|
q_fs = q_fs | Q(**{'%s%s' % ( |
||||
|
field[0], |
||||
|
field[1]): q}) |
||||
|
q_filter = q_filter & q_fs |
||||
|
|
||||
|
qs = qs.filter(q_filter).distinct( |
||||
|
fields[0].fields_search[0][0]).order_by( |
||||
|
fields[0].fields_search[0][0]) |
||||
|
else: |
||||
|
qs = qs.order_by(fields[0].fields_search[0][0]) |
||||
|
|
||||
|
qs = qs.values_list( |
||||
|
'id', fields[0].fields_search[0][0]) |
||||
|
r += list(qs) |
||||
|
|
||||
|
if tipos.count() > 1: |
||||
|
r.sort(key=lambda x: x[1].upper()) |
||||
|
return r |
@ -0,0 +1,12 @@ |
|||||
|
|
||||
|
from django.apps.registry import apps |
||||
|
|
||||
|
from drfautoapi.drfautoapi import ApiViewSetConstrutor, \ |
||||
|
customize, wrapper_queryset_response_for_drf_action |
||||
|
|
||||
|
|
||||
|
ApiViewSetConstrutor.build_class( |
||||
|
[ |
||||
|
apps.get_app_config('comissoes') |
||||
|
] |
||||
|
) |
@ -0,0 +1,12 @@ |
|||||
|
|
||||
|
from django.apps.registry import apps |
||||
|
|
||||
|
from drfautoapi.drfautoapi import ApiViewSetConstrutor, \ |
||||
|
customize, wrapper_queryset_response_for_drf_action |
||||
|
|
||||
|
|
||||
|
ApiViewSetConstrutor.build_class( |
||||
|
[ |
||||
|
apps.get_app_config('compilacao') |
||||
|
] |
||||
|
) |
@ -0,0 +1,129 @@ |
|||||
|
|
||||
|
from django.apps.registry import apps |
||||
|
from django.db.models import Q |
||||
|
from rest_framework.decorators import action |
||||
|
from rest_framework.response import Response |
||||
|
|
||||
|
from drfautoapi.drfautoapi import ApiViewSetConstrutor, \ |
||||
|
customize, wrapper_queryset_response_for_drf_action |
||||
|
from sapl.api.permissions import SaplModelPermissions |
||||
|
from sapl.materia.models import TipoMateriaLegislativa, Tramitacao,\ |
||||
|
MateriaLegislativa, Proposicao |
||||
|
|
||||
|
|
||||
|
ApiViewSetConstrutor.build_class( |
||||
|
[ |
||||
|
apps.get_app_config('materia') |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
|
||||
|
@customize(Proposicao) |
||||
|
class _ProposicaoViewSet: |
||||
|
""" |
||||
|
list: |
||||
|
Retorna lista de Proposições |
||||
|
|
||||
|
* Permissões: |
||||
|
|
||||
|
* Usuário Dono: |
||||
|
* Pode listar todas suas Proposições |
||||
|
|
||||
|
* Usuário Conectado ou Anônimo: |
||||
|
* Pode listar todas as Proposições incorporadas |
||||
|
|
||||
|
retrieve: |
||||
|
Retorna uma proposição passada pelo 'id' |
||||
|
|
||||
|
* Permissões: |
||||
|
|
||||
|
* Usuário Dono: |
||||
|
* Pode recuperar qualquer de suas Proposições |
||||
|
|
||||
|
* Usuário Conectado ou Anônimo: |
||||
|
* Pode recuperar qualquer das proposições incorporadas |
||||
|
|
||||
|
""" |
||||
|
|
||||
|
class ProposicaoPermission(SaplModelPermissions): |
||||
|
|
||||
|
def has_permission(self, request, view): |
||||
|
if request.method == 'GET': |
||||
|
return True |
||||
|
# se a solicitação é list ou detail, libera o teste de permissão |
||||
|
# e deixa o get_queryset filtrar de acordo com a regra de |
||||
|
# visibilidade das proposições, ou seja: |
||||
|
# 1. proposição incorporada é proposição pública |
||||
|
# 2. não incorporada só o autor pode ver |
||||
|
else: |
||||
|
perm = super().has_permission(request, view) |
||||
|
return perm |
||||
|
# não é list ou detail, então passa pelas regras de permissão e, |
||||
|
# depois disso ainda passa pelo filtro de get_queryset |
||||
|
|
||||
|
permission_classes = (ProposicaoPermission,) |
||||
|
|
||||
|
def get_queryset(self): |
||||
|
qs = super().get_queryset() |
||||
|
|
||||
|
q = Q(data_recebimento__isnull=False, object_id__isnull=False) |
||||
|
if not self.request.user.is_anonymous: |
||||
|
|
||||
|
autor_do_usuario_logado = self.request.user.autor_set.first() |
||||
|
|
||||
|
# se usuário logado é operador de algum autor |
||||
|
if autor_do_usuario_logado: |
||||
|
q = Q(autor=autor_do_usuario_logado) |
||||
|
|
||||
|
# se é operador de protocolo, ve qualquer coisa enviada |
||||
|
if self.request.user.has_perm('protocoloadm.list_protocolo'): |
||||
|
q = Q(data_envio__isnull=False) | Q( |
||||
|
data_devolucao__isnull=False) |
||||
|
|
||||
|
qs = qs.filter(q) |
||||
|
return qs |
||||
|
|
||||
|
|
||||
|
@customize(MateriaLegislativa) |
||||
|
class _MateriaLegislativaViewSet: |
||||
|
|
||||
|
class Meta: |
||||
|
ordering = ['-ano', 'tipo', 'numero'] |
||||
|
|
||||
|
@action(detail=True, methods=['GET']) |
||||
|
def ultima_tramitacao(self, request, *args, **kwargs): |
||||
|
|
||||
|
materia = self.get_object() |
||||
|
if not materia.tramitacao_set.exists(): |
||||
|
return Response({}) |
||||
|
|
||||
|
ultima_tramitacao = materia.tramitacao_set.order_by( |
||||
|
'-data_tramitacao', '-id').first() |
||||
|
|
||||
|
serializer_class = ApiViewSetConstrutor.get_viewset_for_model( |
||||
|
Tramitacao).serializer_class(ultima_tramitacao) |
||||
|
|
||||
|
return Response(serializer_class.data) |
||||
|
|
||||
|
@action(detail=True, methods=['GET']) |
||||
|
def anexadas(self, request, *args, **kwargs): |
||||
|
self.queryset = self.get_object().anexadas.all() |
||||
|
return self.list(request, *args, **kwargs) |
||||
|
|
||||
|
|
||||
|
@customize(TipoMateriaLegislativa) |
||||
|
class _TipoMateriaLegislativaViewSet: |
||||
|
|
||||
|
@action(detail=True, methods=['POST']) |
||||
|
def change_position(self, request, *args, **kwargs): |
||||
|
result = { |
||||
|
'status': 200, |
||||
|
'message': 'OK' |
||||
|
} |
||||
|
d = request.data |
||||
|
if 'pos_ini' in d and 'pos_fim' in d: |
||||
|
if d['pos_ini'] != d['pos_fim']: |
||||
|
pk = kwargs['pk'] |
||||
|
TipoMateriaLegislativa.objects.reposicione(pk, d['pos_fim']) |
||||
|
|
||||
|
return Response(result) |
@ -0,0 +1,14 @@ |
|||||
|
|
||||
|
from django.apps.registry import apps |
||||
|
from rest_framework.decorators import action |
||||
|
|
||||
|
from drfautoapi.drfautoapi import ApiViewSetConstrutor, \ |
||||
|
customize, wrapper_queryset_response_for_drf_action |
||||
|
from sapl.norma.models import NormaJuridica |
||||
|
|
||||
|
|
||||
|
ApiViewSetConstrutor.build_class( |
||||
|
[ |
||||
|
apps.get_app_config('norma') |
||||
|
] |
||||
|
) |
@ -0,0 +1,11 @@ |
|||||
|
|
||||
|
from django.apps.registry import apps |
||||
|
|
||||
|
from drfautoapi.drfautoapi import ApiViewSetConstrutor, \ |
||||
|
customize, wrapper_queryset_response_for_drf_action |
||||
|
|
||||
|
ApiViewSetConstrutor.build_class( |
||||
|
[ |
||||
|
apps.get_app_config('painel') |
||||
|
] |
||||
|
) |
@ -0,0 +1,119 @@ |
|||||
|
|
||||
|
from django.apps.registry import apps |
||||
|
from django.contrib.contenttypes.models import ContentType |
||||
|
from django.core.exceptions import ObjectDoesNotExist |
||||
|
from rest_framework.decorators import action |
||||
|
from rest_framework.response import Response |
||||
|
|
||||
|
from drfautoapi.drfautoapi import customize, ApiViewSetConstrutor, \ |
||||
|
wrapper_queryset_response_for_drf_action |
||||
|
|
||||
|
from sapl.api.permissions import SaplModelPermissions |
||||
|
from sapl.api.serializers import ParlamentarSerializerVerbose, \ |
||||
|
ParlamentarSerializerPublic |
||||
|
from sapl.materia.models import Proposicao |
||||
|
from sapl.parlamentares.models import Mandato, Legislatura |
||||
|
from sapl.parlamentares.models import Parlamentar |
||||
|
|
||||
|
ApiViewSetConstrutor.build_class( |
||||
|
[ |
||||
|
apps.get_app_config('parlamentares') |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
|
||||
|
@customize(Parlamentar) |
||||
|
class _ParlamentarViewSet: |
||||
|
|
||||
|
class ParlamentarPermission(SaplModelPermissions): |
||||
|
|
||||
|
def has_permission(self, request, view): |
||||
|
if request.method == 'GET': |
||||
|
return True |
||||
|
else: |
||||
|
perm = super().has_permission(request, view) |
||||
|
return perm |
||||
|
|
||||
|
permission_classes = (ParlamentarPermission,) |
||||
|
|
||||
|
def get_serializer(self, *args, **kwargs): |
||||
|
if not self.request.user.has_perm('parlamentares.add_parlamentar'): |
||||
|
self.serializer_class = ParlamentarSerializerPublic |
||||
|
return super().get_serializer(*args, **kwargs) |
||||
|
|
||||
|
@action(detail=True) |
||||
|
def proposicoes(self, request, *args, **kwargs): |
||||
|
""" |
||||
|
Lista de proposições públicas de parlamentar específico |
||||
|
|
||||
|
:param int id: - Identificador do parlamentar que se quer recuperar as proposições |
||||
|
:return: uma lista de proposições |
||||
|
""" |
||||
|
# /api/parlamentares/parlamentar/{id}/proposicoes/ |
||||
|
# recupera proposições enviadas e incorporadas do parlamentar |
||||
|
# deve coincidir com |
||||
|
# /parlamentar/{pk}/proposicao |
||||
|
|
||||
|
return self.get_proposicoes(**kwargs) |
||||
|
|
||||
|
@wrapper_queryset_response_for_drf_action(model=Proposicao) |
||||
|
def get_proposicoes(self, **kwargs): |
||||
|
|
||||
|
return self.get_queryset().filter( |
||||
|
data_envio__isnull=False, |
||||
|
data_recebimento__isnull=False, |
||||
|
cancelado=False, |
||||
|
autor__object_id=kwargs['pk'], |
||||
|
autor__content_type=ContentType.objects.get_for_model(Parlamentar) |
||||
|
) |
||||
|
|
||||
|
@action(detail=False, methods=['GET']) |
||||
|
def search_parlamentares(self, request, *args, **kwargs): |
||||
|
nome = request.query_params.get('nome_parlamentar', '') |
||||
|
parlamentares = Parlamentar.objects.filter( |
||||
|
nome_parlamentar__icontains=nome) |
||||
|
serializer_class = ParlamentarSerializerVerbose( |
||||
|
parlamentares, many=True, context={'request': request}) |
||||
|
return Response(serializer_class.data) |
||||
|
|
||||
|
|
||||
|
@customize(Legislatura) |
||||
|
class _LegislaturaViewSet: |
||||
|
|
||||
|
@action(detail=True) |
||||
|
def parlamentares(self, request, *args, **kwargs): |
||||
|
|
||||
|
def get_serializer_context(): |
||||
|
return { |
||||
|
'request': self.request, 'legislatura': kwargs['pk'] |
||||
|
} |
||||
|
|
||||
|
def get_serializer_class(): |
||||
|
return ParlamentarSerializerVerbose |
||||
|
|
||||
|
self.get_serializer_context = get_serializer_context |
||||
|
self.get_serializer_class = get_serializer_class |
||||
|
|
||||
|
return self.get_parlamentares() |
||||
|
|
||||
|
@wrapper_queryset_response_for_drf_action(model=Parlamentar) |
||||
|
def get_parlamentares(self): |
||||
|
|
||||
|
try: |
||||
|
legislatura = Legislatura.objects.get(pk=self.kwargs['pk']) |
||||
|
except ObjectDoesNotExist: |
||||
|
return Response("") |
||||
|
|
||||
|
filter_params = { |
||||
|
'legislatura': legislatura, |
||||
|
'data_inicio_mandato__gte': legislatura.data_inicio, |
||||
|
'data_fim_mandato__lte': legislatura.data_fim, |
||||
|
} |
||||
|
|
||||
|
mandatos = Mandato.objects.filter( |
||||
|
**filter_params).order_by('-data_inicio_mandato') |
||||
|
|
||||
|
parlamentares = self.get_queryset().filter( |
||||
|
mandato__in=mandatos).distinct() |
||||
|
|
||||
|
return parlamentares |
@ -0,0 +1,102 @@ |
|||||
|
|
||||
|
from django.apps.registry import apps |
||||
|
|
||||
|
from drfautoapi.drfautoapi import ApiViewSetConstrutor, \ |
||||
|
customize, wrapper_queryset_response_for_drf_action |
||||
|
from sapl.api.permissions import SaplModelPermissions |
||||
|
from sapl.base.models import AppConfig, DOC_ADM_OSTENSIVO |
||||
|
from sapl.protocoloadm.models import DocumentoAdministrativo, \ |
||||
|
DocumentoAcessorioAdministrativo, TramitacaoAdministrativo, Anexado |
||||
|
|
||||
|
|
||||
|
ApiViewSetConstrutor.build_class( |
||||
|
[ |
||||
|
apps.get_app_config('protocoloadm') |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
|
||||
|
@customize(DocumentoAdministrativo) |
||||
|
class _DocumentoAdministrativoViewSet: |
||||
|
|
||||
|
class DocumentoAdministrativoPermission(SaplModelPermissions): |
||||
|
|
||||
|
def has_permission(self, request, view): |
||||
|
if request.method == 'GET': |
||||
|
comportamento = AppConfig.attr('documentos_administrativos') |
||||
|
if comportamento == DOC_ADM_OSTENSIVO: |
||||
|
return True |
||||
|
""" |
||||
|
Diante da lógica implementada na manutenção de documentos |
||||
|
administrativos: |
||||
|
- Se o comportamento é doc adm ostensivo, deve passar pelo |
||||
|
teste de permissões sem avaliá-las |
||||
|
- se o comportamento é doc adm restritivo, deve passar pelo |
||||
|
teste de permissões avaliando-as |
||||
|
""" |
||||
|
return super().has_permission(request, view) |
||||
|
|
||||
|
permission_classes = (DocumentoAdministrativoPermission,) |
||||
|
|
||||
|
def get_queryset(self): |
||||
|
""" |
||||
|
mesmo tendo passado pelo teste de permissões, deve ser filtrado, |
||||
|
pelo campo restrito. Sendo este igual a True, disponibilizar apenas |
||||
|
a um usuário conectado. Apenas isso, sem critérios outros de permissão, |
||||
|
conforme implementado em DocumentoAdministrativoCrud |
||||
|
""" |
||||
|
qs = super().get_queryset() |
||||
|
|
||||
|
if self.request.user.is_anonymous: |
||||
|
qs = qs.exclude(restrito=True) |
||||
|
return qs |
||||
|
|
||||
|
|
||||
|
@customize(DocumentoAcessorioAdministrativo) |
||||
|
class _DocumentoAcessorioAdministrativoViewSet: |
||||
|
|
||||
|
permission_classes = ( |
||||
|
_DocumentoAdministrativoViewSet.DocumentoAdministrativoPermission,) |
||||
|
|
||||
|
def get_queryset(self): |
||||
|
qs = super().get_queryset() |
||||
|
|
||||
|
if self.request.user.is_anonymous: |
||||
|
qs = qs.exclude(documento__restrito=True) |
||||
|
return qs |
||||
|
|
||||
|
|
||||
|
@customize(TramitacaoAdministrativo) |
||||
|
class _TramitacaoAdministrativoViewSet: |
||||
|
# TODO: Implementar regras de manutenção das post, put, patch |
||||
|
# tramitacação de adm possui regras previstas de limitação de origem |
||||
|
# destino |
||||
|
|
||||
|
http_method_names = ['get', 'head', 'options', 'trace'] |
||||
|
|
||||
|
permission_classes = ( |
||||
|
_DocumentoAdministrativoViewSet.DocumentoAdministrativoPermission,) |
||||
|
|
||||
|
def get_queryset(self): |
||||
|
qs = super().get_queryset() |
||||
|
|
||||
|
if self.request.user.is_anonymous: |
||||
|
qs = qs.exclude(documento__restrito=True) |
||||
|
return qs |
||||
|
|
||||
|
|
||||
|
@customize(Anexado) |
||||
|
class _AnexadoViewSet: |
||||
|
# TODO: Implementar regras de manutenção post, put, patch |
||||
|
# anexado deve possuir controle que impeça anexação cíclica |
||||
|
http_method_names = ['get', 'head', 'options', 'trace'] |
||||
|
|
||||
|
permission_classes = ( |
||||
|
_DocumentoAdministrativoViewSet.DocumentoAdministrativoPermission,) |
||||
|
|
||||
|
def get_queryset(self): |
||||
|
qs = super().get_queryset() |
||||
|
|
||||
|
if self.request.user.is_anonymous: |
||||
|
qs = qs.exclude(documento__restrito=True) |
||||
|
return qs |
@ -0,0 +1,47 @@ |
|||||
|
|
||||
|
from django.apps.registry import apps |
||||
|
from rest_framework.decorators import action |
||||
|
from rest_framework.response import Response |
||||
|
|
||||
|
from drfautoapi.drfautoapi import ApiViewSetConstrutor, \ |
||||
|
customize, wrapper_queryset_response_for_drf_action |
||||
|
from sapl.api.serializers import ChoiceSerializer,\ |
||||
|
SessaoPlenariaECidadaniaSerializer |
||||
|
from sapl.sessao.models import SessaoPlenaria, ExpedienteSessao |
||||
|
from sapl.utils import choice_anos_com_sessaoplenaria |
||||
|
|
||||
|
|
||||
|
ApiViewSetConstrutor.build_class( |
||||
|
[ |
||||
|
apps.get_app_config('sessao') |
||||
|
] |
||||
|
) |
||||
|
|
||||
|
|
||||
|
@customize(SessaoPlenaria) |
||||
|
class _SessaoPlenariaViewSet: |
||||
|
|
||||
|
@action(detail=False) |
||||
|
def years(self, request, *args, **kwargs): |
||||
|
years = choice_anos_com_sessaoplenaria() |
||||
|
|
||||
|
serializer = ChoiceSerializer(years, many=True) |
||||
|
return Response(serializer.data) |
||||
|
|
||||
|
@action(detail=True) |
||||
|
def expedientes(self, request, *args, **kwargs): |
||||
|
return self.get_expedientes() |
||||
|
|
||||
|
@wrapper_queryset_response_for_drf_action(model=ExpedienteSessao) |
||||
|
def get_expedientes(self): |
||||
|
return self.get_queryset().filter(sessao_plenaria_id=self.kwargs['pk']) |
||||
|
|
||||
|
@action(detail=True) |
||||
|
def ecidadania(self, request, *args, **kwargs): |
||||
|
self.serializer_class = SessaoPlenariaECidadaniaSerializer |
||||
|
return self.retrieve(request, *args, **kwargs) |
||||
|
|
||||
|
@action(detail=False, url_path='ecidadania') |
||||
|
def ecidadania_list(self, request, *args, **kwargs): |
||||
|
self.serializer_class = SessaoPlenariaECidadaniaSerializer |
||||
|
return self.list(request, *args, **kwargs) |
@ -1,413 +0,0 @@ |
|||||
import logging |
|
||||
|
|
||||
from django.contrib.contenttypes.models import ContentType |
|
||||
from django.core.exceptions import ObjectDoesNotExist |
|
||||
from django.db.models import Q |
|
||||
from django.utils.decorators import classonlymethod |
|
||||
from django.utils.translation import ugettext_lazy as _ |
|
||||
from rest_framework.decorators import action |
|
||||
from rest_framework.response import Response |
|
||||
|
|
||||
from sapl.api.core import customize, SaplApiViewSetConstrutor, \ |
|
||||
wrapper_queryset_response_for_drf_action, \ |
|
||||
BusinessRulesNotImplementedMixin |
|
||||
from sapl.api.core.serializers import ChoiceSerializer |
|
||||
from sapl.api.permissions import SaplModelPermissions |
|
||||
from sapl.api.serializers import ParlamentarSerializerVerbose, \ |
|
||||
ParlamentarSerializerPublic |
|
||||
from sapl.base.models import Autor, AppConfig, DOC_ADM_OSTENSIVO |
|
||||
from sapl.materia.models import Proposicao, TipoMateriaLegislativa, \ |
|
||||
MateriaLegislativa, Tramitacao |
|
||||
from sapl.norma.models import NormaJuridica |
|
||||
from sapl.parlamentares.models import Mandato, Legislatura |
|
||||
from sapl.parlamentares.models import Parlamentar |
|
||||
from sapl.protocoloadm.models import DocumentoAdministrativo, \ |
|
||||
DocumentoAcessorioAdministrativo, TramitacaoAdministrativo, Anexado |
|
||||
from sapl.sessao.models import SessaoPlenaria, ExpedienteSessao |
|
||||
from sapl.utils import models_with_gr_for_model, choice_anos_com_sessaoplenaria |
|
||||
|
|
||||
SaplApiViewSetConstrutor = SaplApiViewSetConstrutor.build_class() |
|
||||
|
|
||||
|
|
||||
@customize(Autor) |
|
||||
class _AutorViewSet: |
|
||||
# Customização para AutorViewSet com implementação de actions específicas |
|
||||
""" |
|
||||
Nesta customização do que foi criado em |
|
||||
SaplApiViewSetConstrutor além do ofertado por |
|
||||
rest_framework.viewsets.ModelViewSet, dentre outras customizações |
|
||||
possíveis, foi adicionado as rotas referentes aos relacionamentos genéricos |
|
||||
|
|
||||
* padrão de ModelViewSet |
|
||||
/api/base/autor/ POST - create |
|
||||
/api/base/autor/ GET - list |
|
||||
/api/base/autor/{pk}/ GET - detail |
|
||||
/api/base/autor/{pk}/ PUT - update |
|
||||
/api/base/autor/{pk}/ PATCH - partial_update |
|
||||
/api/base/autor/{pk}/ DELETE - destroy |
|
||||
|
|
||||
* rotas desta classe local criadas pelo método build: |
|
||||
/api/base/autor/parlamentar |
|
||||
devolve apenas autores que são parlamentares |
|
||||
/api/base/autor/comissao |
|
||||
devolve apenas autores que são comissões |
|
||||
/api/base/autor/bloco |
|
||||
devolve apenas autores que são blocos parlamentares |
|
||||
/api/base/autor/bancada |
|
||||
devolve apenas autores que são bancadas parlamentares |
|
||||
/api/base/autor/frente |
|
||||
devolve apenas autores que são Frene parlamentares |
|
||||
/api/base/autor/orgao |
|
||||
devolve apenas autores que são Órgãos |
|
||||
""" |
|
||||
|
|
||||
def list_for_content_type(self, content_type): |
|
||||
qs = self.get_queryset() |
|
||||
qs = qs.filter(content_type=content_type) |
|
||||
|
|
||||
page = self.paginate_queryset(qs) |
|
||||
if page is not None: |
|
||||
serializer = self.serializer_class(page, many=True) |
|
||||
return self.get_paginated_response(serializer.data) |
|
||||
|
|
||||
serializer = self.get_serializer(page, many=True) |
|
||||
return Response(serializer.data) |
|
||||
|
|
||||
@classonlymethod |
|
||||
def build(cls): |
|
||||
|
|
||||
models_with_gr_for_autor = models_with_gr_for_model(Autor) |
|
||||
|
|
||||
for _model in models_with_gr_for_autor: |
|
||||
|
|
||||
@action(detail=False, name=_model._meta.model_name) |
|
||||
def actionclass(self, request, *args, **kwargs): |
|
||||
model = getattr(self, self.action)._AutorViewSet__model |
|
||||
|
|
||||
content_type = ContentType.objects.get_for_model(model) |
|
||||
return self.list_for_content_type(content_type) |
|
||||
|
|
||||
func = actionclass |
|
||||
func.mapping['get'] = func.kwargs['name'] |
|
||||
func.url_name = func.kwargs['name'] |
|
||||
func.url_path = func.kwargs['name'] |
|
||||
func.__name__ = func.kwargs['name'] |
|
||||
func.__model = _model |
|
||||
|
|
||||
setattr(cls, _model._meta.model_name, func) |
|
||||
return cls |
|
||||
|
|
||||
|
|
||||
@customize(Parlamentar) |
|
||||
class _ParlamentarViewSet: |
|
||||
|
|
||||
class ParlamentarPermission(SaplModelPermissions): |
|
||||
|
|
||||
def has_permission(self, request, view): |
|
||||
if request.method == 'GET': |
|
||||
return True |
|
||||
else: |
|
||||
perm = super().has_permission(request, view) |
|
||||
return perm |
|
||||
|
|
||||
permission_classes = (ParlamentarPermission,) |
|
||||
|
|
||||
def get_serializer(self, *args, **kwargs): |
|
||||
if not self.request.user.has_perm('parlamentares.add_parlamentar'): |
|
||||
self.serializer_class = ParlamentarSerializerPublic |
|
||||
return super().get_serializer(*args, **kwargs) |
|
||||
|
|
||||
@action(detail=True) |
|
||||
def proposicoes(self, request, *args, **kwargs): |
|
||||
""" |
|
||||
Lista de proposições públicas de parlamentar específico |
|
||||
|
|
||||
:param int id: - Identificador do parlamentar que se quer recuperar as proposições |
|
||||
:return: uma lista de proposições |
|
||||
""" |
|
||||
# /api/parlamentares/parlamentar/{id}/proposicoes/ |
|
||||
# recupera proposições enviadas e incorporadas do parlamentar |
|
||||
# deve coincidir com |
|
||||
# /parlamentar/{pk}/proposicao |
|
||||
|
|
||||
return self.get_proposicoes(**kwargs) |
|
||||
|
|
||||
@wrapper_queryset_response_for_drf_action(model=Proposicao) |
|
||||
def get_proposicoes(self, **kwargs): |
|
||||
|
|
||||
return self.get_queryset().filter( |
|
||||
data_envio__isnull=False, |
|
||||
data_recebimento__isnull=False, |
|
||||
cancelado=False, |
|
||||
autor__object_id=kwargs['pk'], |
|
||||
autor__content_type=ContentType.objects.get_for_model(Parlamentar) |
|
||||
) |
|
||||
|
|
||||
@action(detail=False, methods=['GET']) |
|
||||
def search_parlamentares(self, request, *args, **kwargs): |
|
||||
nome = request.query_params.get('nome_parlamentar', '') |
|
||||
parlamentares = Parlamentar.objects.filter( |
|
||||
nome_parlamentar__icontains=nome) |
|
||||
serializer_class = ParlamentarSerializerVerbose( |
|
||||
parlamentares, many=True, context={'request': request}) |
|
||||
return Response(serializer_class.data) |
|
||||
|
|
||||
|
|
||||
@customize(Legislatura) |
|
||||
class _LegislaturaViewSet: |
|
||||
|
|
||||
@action(detail=True) |
|
||||
def parlamentares(self, request, *args, **kwargs): |
|
||||
|
|
||||
def get_serializer_context(): |
|
||||
return { |
|
||||
'request': self.request, 'legislatura': kwargs['pk'] |
|
||||
} |
|
||||
|
|
||||
def get_serializer_class(): |
|
||||
return ParlamentarSerializerVerbose |
|
||||
|
|
||||
self.get_serializer_context = get_serializer_context |
|
||||
self.get_serializer_class = get_serializer_class |
|
||||
|
|
||||
return self.get_parlamentares() |
|
||||
|
|
||||
@wrapper_queryset_response_for_drf_action(model=Parlamentar) |
|
||||
def get_parlamentares(self): |
|
||||
|
|
||||
try: |
|
||||
legislatura = Legislatura.objects.get(pk=self.kwargs['pk']) |
|
||||
except ObjectDoesNotExist: |
|
||||
return Response("") |
|
||||
|
|
||||
filter_params = { |
|
||||
'legislatura': legislatura, |
|
||||
'data_inicio_mandato__gte': legislatura.data_inicio, |
|
||||
'data_fim_mandato__lte': legislatura.data_fim, |
|
||||
} |
|
||||
|
|
||||
mandatos = Mandato.objects.filter( |
|
||||
**filter_params).order_by('-data_inicio_mandato') |
|
||||
|
|
||||
parlamentares = self.get_queryset().filter( |
|
||||
mandato__in=mandatos).distinct() |
|
||||
|
|
||||
return parlamentares |
|
||||
|
|
||||
|
|
||||
@customize(Proposicao) |
|
||||
class _ProposicaoViewSet: |
|
||||
""" |
|
||||
list: |
|
||||
Retorna lista de Proposições |
|
||||
|
|
||||
* Permissões: |
|
||||
|
|
||||
* Usuário Dono: |
|
||||
* Pode listar todas suas Proposições |
|
||||
|
|
||||
* Usuário Conectado ou Anônimo: |
|
||||
* Pode listar todas as Proposições incorporadas |
|
||||
|
|
||||
retrieve: |
|
||||
Retorna uma proposição passada pelo 'id' |
|
||||
|
|
||||
* Permissões: |
|
||||
|
|
||||
* Usuário Dono: |
|
||||
* Pode recuperar qualquer de suas Proposições |
|
||||
|
|
||||
* Usuário Conectado ou Anônimo: |
|
||||
* Pode recuperar qualquer das proposições incorporadas |
|
||||
|
|
||||
""" |
|
||||
|
|
||||
class ProposicaoPermission(SaplModelPermissions): |
|
||||
|
|
||||
def has_permission(self, request, view): |
|
||||
if request.method == 'GET': |
|
||||
return True |
|
||||
# se a solicitação é list ou detail, libera o teste de permissão |
|
||||
# e deixa o get_queryset filtrar de acordo com a regra de |
|
||||
# visibilidade das proposições, ou seja: |
|
||||
# 1. proposição incorporada é proposição pública |
|
||||
# 2. não incorporada só o autor pode ver |
|
||||
else: |
|
||||
perm = super().has_permission(request, view) |
|
||||
return perm |
|
||||
# não é list ou detail, então passa pelas regras de permissão e, |
|
||||
# depois disso ainda passa pelo filtro de get_queryset |
|
||||
|
|
||||
permission_classes = (ProposicaoPermission,) |
|
||||
|
|
||||
def get_queryset(self): |
|
||||
qs = super().get_queryset() |
|
||||
|
|
||||
q = Q(data_recebimento__isnull=False, object_id__isnull=False) |
|
||||
if not self.request.user.is_anonymous: |
|
||||
|
|
||||
autor_do_usuario_logado = self.request.user.autor_set.first() |
|
||||
|
|
||||
# se usuário logado é operador de algum autor |
|
||||
if autor_do_usuario_logado: |
|
||||
q = Q(autor=autor_do_usuario_logado) |
|
||||
|
|
||||
# se é operador de protocolo, ve qualquer coisa enviada |
|
||||
if self.request.user.has_perm('protocoloadm.list_protocolo'): |
|
||||
q = Q(data_envio__isnull=False) | Q( |
|
||||
data_devolucao__isnull=False) |
|
||||
|
|
||||
qs = qs.filter(q) |
|
||||
return qs |
|
||||
|
|
||||
|
|
||||
@customize(MateriaLegislativa) |
|
||||
class _MateriaLegislativaViewSet: |
|
||||
|
|
||||
class Meta: |
|
||||
ordering = ['-ano', 'tipo', 'numero'] |
|
||||
|
|
||||
@action(detail=True, methods=['GET']) |
|
||||
def ultima_tramitacao(self, request, *args, **kwargs): |
|
||||
|
|
||||
materia = self.get_object() |
|
||||
if not materia.tramitacao_set.exists(): |
|
||||
return Response({}) |
|
||||
|
|
||||
ultima_tramitacao = materia.tramitacao_set.order_by( |
|
||||
'-data_tramitacao', '-id').first() |
|
||||
|
|
||||
serializer_class = SaplApiViewSetConstrutor.get_class_for_model( |
|
||||
Tramitacao).serializer_class(ultima_tramitacao) |
|
||||
|
|
||||
return Response(serializer_class.data) |
|
||||
|
|
||||
@action(detail=True, methods=['GET']) |
|
||||
def anexadas(self, request, *args, **kwargs): |
|
||||
self.queryset = self.get_object().anexadas.all() |
|
||||
return self.list(request, *args, **kwargs) |
|
||||
|
|
||||
|
|
||||
@customize(TipoMateriaLegislativa) |
|
||||
class _TipoMateriaLegislativaViewSet: |
|
||||
|
|
||||
@action(detail=True, methods=['POST']) |
|
||||
def change_position(self, request, *args, **kwargs): |
|
||||
result = { |
|
||||
'status': 200, |
|
||||
'message': 'OK' |
|
||||
} |
|
||||
d = request.data |
|
||||
if 'pos_ini' in d and 'pos_fim' in d: |
|
||||
if d['pos_ini'] != d['pos_fim']: |
|
||||
pk = kwargs['pk'] |
|
||||
TipoMateriaLegislativa.objects.reposicione(pk, d['pos_fim']) |
|
||||
|
|
||||
return Response(result) |
|
||||
|
|
||||
|
|
||||
@customize(DocumentoAdministrativo) |
|
||||
class _DocumentoAdministrativoViewSet: |
|
||||
|
|
||||
class DocumentoAdministrativoPermission(SaplModelPermissions): |
|
||||
|
|
||||
def has_permission(self, request, view): |
|
||||
if request.method == 'GET': |
|
||||
comportamento = AppConfig.attr('documentos_administrativos') |
|
||||
if comportamento == DOC_ADM_OSTENSIVO: |
|
||||
return True |
|
||||
""" |
|
||||
Diante da lógica implementada na manutenção de documentos |
|
||||
administrativos: |
|
||||
- Se o comportamento é doc adm ostensivo, deve passar pelo |
|
||||
teste de permissões sem avaliá-las |
|
||||
- se o comportamento é doc adm restritivo, deve passar pelo |
|
||||
teste de permissões avaliando-as |
|
||||
""" |
|
||||
return super().has_permission(request, view) |
|
||||
|
|
||||
permission_classes = (DocumentoAdministrativoPermission,) |
|
||||
|
|
||||
def get_queryset(self): |
|
||||
""" |
|
||||
mesmo tendo passado pelo teste de permissões, deve ser filtrado, |
|
||||
pelo campo restrito. Sendo este igual a True, disponibilizar apenas |
|
||||
a um usuário conectado. Apenas isso, sem critérios outros de permissão, |
|
||||
conforme implementado em DocumentoAdministrativoCrud |
|
||||
""" |
|
||||
qs = super().get_queryset() |
|
||||
|
|
||||
if self.request.user.is_anonymous: |
|
||||
qs = qs.exclude(restrito=True) |
|
||||
return qs |
|
||||
|
|
||||
|
|
||||
@customize(DocumentoAcessorioAdministrativo) |
|
||||
class _DocumentoAcessorioAdministrativoViewSet: |
|
||||
|
|
||||
permission_classes = ( |
|
||||
_DocumentoAdministrativoViewSet.DocumentoAdministrativoPermission,) |
|
||||
|
|
||||
def get_queryset(self): |
|
||||
qs = super().get_queryset() |
|
||||
|
|
||||
if self.request.user.is_anonymous: |
|
||||
qs = qs.exclude(documento__restrito=True) |
|
||||
return qs |
|
||||
|
|
||||
|
|
||||
@customize(TramitacaoAdministrativo) |
|
||||
class _TramitacaoAdministrativoViewSet(BusinessRulesNotImplementedMixin): |
|
||||
# TODO: Implementar regras de manutenção das tramitações de docs adms |
|
||||
|
|
||||
permission_classes = ( |
|
||||
_DocumentoAdministrativoViewSet.DocumentoAdministrativoPermission,) |
|
||||
|
|
||||
def get_queryset(self): |
|
||||
qs = super().get_queryset() |
|
||||
|
|
||||
if self.request.user.is_anonymous: |
|
||||
qs = qs.exclude(documento__restrito=True) |
|
||||
return qs |
|
||||
|
|
||||
|
|
||||
@customize(Anexado) |
|
||||
class _AnexadoViewSet(BusinessRulesNotImplementedMixin): |
|
||||
|
|
||||
permission_classes = ( |
|
||||
_DocumentoAdministrativoViewSet.DocumentoAdministrativoPermission,) |
|
||||
|
|
||||
def get_queryset(self): |
|
||||
qs = super().get_queryset() |
|
||||
|
|
||||
if self.request.user.is_anonymous: |
|
||||
qs = qs.exclude(documento__restrito=True) |
|
||||
return qs |
|
||||
|
|
||||
|
|
||||
@customize(SessaoPlenaria) |
|
||||
class _SessaoPlenariaViewSet: |
|
||||
|
|
||||
@action(detail=False) |
|
||||
def years(self, request, *args, **kwargs): |
|
||||
years = choice_anos_com_sessaoplenaria() |
|
||||
|
|
||||
serializer = ChoiceSerializer(years, many=True) |
|
||||
return Response(serializer.data) |
|
||||
|
|
||||
@action(detail=True) |
|
||||
def expedientes(self, request, *args, **kwargs): |
|
||||
return self.get_expedientes() |
|
||||
|
|
||||
@wrapper_queryset_response_for_drf_action(model=ExpedienteSessao) |
|
||||
def get_expedientes(self): |
|
||||
return self.get_queryset().filter(sessao_plenaria_id=self.kwargs['pk']) |
|
||||
|
|
||||
|
|
||||
@customize(NormaJuridica) |
|
||||
class _NormaJuridicaViewset: |
|
||||
|
|
||||
@action(detail=False, methods=['GET']) |
|
||||
def destaques(self, request, *args, **kwargs): |
|
||||
self.queryset = self.get_queryset().filter(norma_de_destaque=True) |
|
||||
return self.list(request, *args, **kwargs) |
|
@ -0,0 +1,27 @@ |
|||||
|
# Generated by Django 2.2.28 on 2023-01-31 03:01 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
def preencher_ano(apps, schema_editor): |
||||
|
AudienciaPublica = apps.get_model('audiencia', 'AudienciaPublica') |
||||
|
for audiencia in AudienciaPublica.objects.all(): |
||||
|
audiencia.ano = audiencia.data.year |
||||
|
audiencia.save() |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('audiencia', '0016_auto_20201013_1126'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name='audienciapublica', |
||||
|
name='ano', |
||||
|
field=models.PositiveSmallIntegerField(choices=[(2024, 2024), (2023, 2023), (2022, 2022), (2021, 2021), (2020, 2020), (2019, 2019), (2018, 2018), (2017, 2017), (2016, 2016), (2015, 2015), (2014, 2014), (2013, 2013), (2012, 2012), (2011, 2011), (2010, 2010), (2009, 2009), (2008, 2008), (2007, 2007), (2006, 2006), (2005, 2005), (2004, 2004), (2003, 2003), (2002, 2002), (2001, 2001), (2000, 2000), (1999, 1999), (1998, 1998), (1997, 1997), (1996, 1996), (1995, 1995), (1994, 1994), (1993, 1993), (1992, 1992), (1991, 1991), (1990, 1990), (1989, 1989), (1988, 1988), (1987, 1987), (1986, 1986), (1985, 1985), (1984, 1984), (1983, 1983), (1982, 1982), (1981, 1981), (1980, 1980), (1979, 1979), (1978, 1978), (1977, 1977), (1976, 1976), (1975, 1975), (1974, 1974), (1973, 1973), (1972, 1972), (1971, 1971), (1970, 1970), (1969, 1969), (1968, 1968), (1967, 1967), (1966, 1966), (1965, 1965), (1964, 1964), (1963, 1963), (1962, 1962), (1961, 1961), (1960, 1960), (1959, 1959), (1958, 1958), (1957, 1957), (1956, 1956), (1955, 1955), (1954, 1954), (1953, 1953), (1952, 1952), (1951, 1951), (1950, 1950), (1949, 1949), (1948, 1948), (1947, 1947), (1946, 1946), (1945, 1945), (1944, 1944), (1943, 1943), (1942, 1942), (1941, 1941), (1940, 1940), (1939, 1939), (1938, 1938), (1937, 1937), (1936, 1936), (1935, 1935), (1934, 1934), (1933, 1933), (1932, 1932), (1931, 1931), (1930, 1930), (1929, 1929), (1928, 1928), (1927, 1927), (1926, 1926), (1925, 1925), (1924, 1924), (1923, 1923), (1922, 1922), (1921, 1921), (1920, 1920), (1919, 1919), (1918, 1918), (1917, 1917), (1916, 1916), (1915, 1915), (1914, 1914), (1913, 1913), (1912, 1912), (1911, 1911), (1910, 1910), (1909, 1909), (1908, 1908), (1907, 1907), (1906, 1906), (1905, 1905), (1904, 1904), (1903, 1903), (1902, 1902), (1901, 1901), (1900, 1900), (1899, 1899), (1898, 1898), (1897, 1897), (1896, 1896), (1895, 1895), (1894, 1894), (1893, 1893), (1892, 1892), (1891, 1891), (1890, 1890)], default=2000, verbose_name='Ano'), |
||||
|
preserve_default=False, |
||||
|
), |
||||
|
migrations.RunPython(preencher_ano), |
||||
|
] |
@ -0,0 +1,17 @@ |
|||||
|
# Generated by Django 2.2.28 on 2023-05-29 19:41 |
||||
|
|
||||
|
from django.db import migrations |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('audiencia', '0017_audienciapublica_ano'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterModelOptions( |
||||
|
name='audienciapublica', |
||||
|
options={'ordering': ['ano', 'numero', 'nome', 'tipo'], 'verbose_name': 'Audiência Pública', 'verbose_name_plural': 'Audiências Públicas'}, |
||||
|
), |
||||
|
] |
@ -1,7 +0,0 @@ |
|||||
TipoAutor: |
|
||||
descricao: des_tipo_autor |
|
||||
|
|
||||
Autor: |
|
||||
nome: nom_autor |
|
||||
cargo: des_cargo |
|
||||
tipo: tip_autor |
|
@ -0,0 +1,38 @@ |
|||||
|
import json |
||||
|
import logging |
||||
|
|
||||
|
from django.core.management.base import BaseCommand |
||||
|
from sapl.base.models import AuditLog |
||||
|
|
||||
|
logger = logging.getLogger(__name__) |
||||
|
|
||||
|
|
||||
|
class Command(BaseCommand): |
||||
|
def handle(self, **options): |
||||
|
print("Backfilling AuditLog JSON Field...") |
||||
|
logs = AuditLog.objects.filter(data__isnull=True) |
||||
|
error_counter = 0 |
||||
|
if logs: |
||||
|
update_list = [] |
||||
|
for log in logs: |
||||
|
try: |
||||
|
obj = log.object[1:-1] \ |
||||
|
if log.object.startswith('[') else log.object |
||||
|
data = json.loads(obj) |
||||
|
log.data = data |
||||
|
except Exception as e: |
||||
|
error_counter += 1 |
||||
|
logging.error(e) |
||||
|
log.data = None |
||||
|
else: |
||||
|
update_list.append(log) |
||||
|
if len(update_list) == 1000: |
||||
|
AuditLog.objects.bulk_update(update_list, ['data']) |
||||
|
update_list = [] |
||||
|
if update_list: |
||||
|
AuditLog.objects.bulk_update(update_list, ['data']) |
||||
|
print(f"Logs backfilled: {len(logs) - error_counter}") |
||||
|
print(f"Logs with errors: {error_counter}") |
||||
|
print("Finished backfilling") |
||||
|
|
||||
|
|
@ -0,0 +1,19 @@ |
|||||
|
# Generated by Django 2.2.28 on 2022-06-27 11:56 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('base', '0047_auto_20210315_1522'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name='appconfig', |
||||
|
name='tramitacao_origem_fixa', |
||||
|
field=models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=True, |
||||
|
verbose_name='Fixar Origem das tramitações como sendo a tramitação de destino da última tramitação?'), |
||||
|
), |
||||
|
] |
@ -0,0 +1,18 @@ |
|||||
|
# Generated by Django 2.2.20 on 2022-07-28 23:29 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('base', '0048_appconfig_tramitacao_origem_fixa'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterField( |
||||
|
model_name='appconfig', |
||||
|
name='tramitacao_origem_fixa', |
||||
|
field=models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=True, help_text='Ao utilizar a opção NÂO, você compreende que os controles de origem e destino das tramitações são anulados, podendo seu operador registrar quaisquer origem e destino para as tramitações. Se você colocar Não, fizer tramitações aleatórias e voltar para SIM, o destino da tramitação mais recente será utilizado para a origem de uma nova inserção!', verbose_name='Fixar origem de novas tramitações como sendo a tramitação de destino da última tramitação?'), |
||||
|
), |
||||
|
] |
@ -0,0 +1,31 @@ |
|||||
|
# Generated by Django 2.2.20 on 2022-07-29 01:02 |
||||
|
|
||||
|
import django.contrib.postgres.fields.jsonb |
||||
|
import django.core.serializers.json |
||||
|
from django.db import migrations, models |
||||
|
import django.db.models.deletion |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('contenttypes', '0002_remove_content_type_name'), |
||||
|
('base', '0049_auto_20220728_2029'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.CreateModel( |
||||
|
name='Metadata', |
||||
|
fields=[ |
||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), |
||||
|
('object_id', models.PositiveIntegerField(blank=True, default=None, null=True)), |
||||
|
('metadata', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=None, encoder=django.core.serializers.json.DjangoJSONEncoder, null=True, verbose_name='Metadados')), |
||||
|
('content_type', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.PROTECT, to='contenttypes.ContentType')), |
||||
|
], |
||||
|
options={ |
||||
|
'verbose_name': 'Metadado', |
||||
|
'verbose_name_plural': 'Metadados', |
||||
|
'unique_together': {('content_type', 'object_id')}, |
||||
|
}, |
||||
|
), |
||||
|
] |
@ -0,0 +1,23 @@ |
|||||
|
# Generated by Django 2.2.28 on 2022-08-15 00:38 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('base', '0050_metadata'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name='appconfig', |
||||
|
name='identificacao_de_documentos', |
||||
|
field=models.CharField(default='{sigla} Nº {numero}/{ano}{-}{complemento} - {nome}', help_text='\n Como mostrar a identificação dos documentos administrativos?\n Você pode usar um conjunto de combinações que pretender.\n Ao fazer sua edição, será mostrado logo abaixo o último documento cadastrado, como exemplo de resultado de sua edição.\n Em caso de erro, nenhum documento será mostrado e aparecerá apenas o formato padrão mínimo, que é este: "{sigla} Nº {numero}/{ano}{-}{complemento} - {nome}".\n Muito importante, use as chaves "{}", sem elas, você estará inserindo um texto qualquer e não o valor de um campo.\n Você pode combinar as seguintes campos: {sigla} {nome} {numero} {ano} {complemento} {assunto}\n Ainda pode ser usado {/}, {-}, {.} se você quiser que uma barra, traço, ou ponto\n seja adicionado apenas se o próximo campo que será usado tenha algum conteúdo\n (não use dois destes destes condicionais em sequência, somente o último será considerado).\n ', max_length=254, verbose_name='Formato da identificação dos documentos'), |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='appconfig', |
||||
|
name='protocolo_manual', |
||||
|
field=models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=False, verbose_name='Permitir informe manual de data e hora de protocolo?'), |
||||
|
), |
||||
|
] |
@ -0,0 +1,15 @@ |
|||||
|
# Generated by Django 2.2.28 on 2022-09-14 14:25 |
||||
|
|
||||
|
from django.db import migrations |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('base', '0051_auto_20220814_2138'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.RunSQL("DROP TABLE IF EXISTS reversion_version"), |
||||
|
migrations.RunSQL("DROP TABLE IF EXISTS reversion_revision"), |
||||
|
] |
@ -0,0 +1,18 @@ |
|||||
|
# Generated by Django 2.2.28 on 2022-09-19 20:05 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('base', '0052_auto_20220914_1125'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterField( |
||||
|
model_name='appconfig', |
||||
|
name='sapl_as_sapn', |
||||
|
field=models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=False, verbose_name='Utilizar SAPL apenas como SAPL-Normas?'), |
||||
|
), |
||||
|
] |
@ -0,0 +1,14 @@ |
|||||
|
# Generated by Django 2.2.28 on 2022-09-21 15:17 |
||||
|
|
||||
|
from django.db import migrations |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('base', '0053_auto_20220919_1705'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.RunSQL("DROP TABLE IF EXISTS speedinfo_viewprofiler"), |
||||
|
] |
@ -0,0 +1,18 @@ |
|||||
|
# Generated by Django 2.2.28 on 2022-10-05 18:33 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('base', '0054_auto_20220921_1217'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AddField( |
||||
|
model_name='appconfig', |
||||
|
name='mostrar_voto', |
||||
|
field=models.BooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=False, verbose_name='Exibir voto do Parlamentar antes de encerrar a votação?'), |
||||
|
), |
||||
|
] |
@ -0,0 +1,23 @@ |
|||||
|
# Generated by Django 2.2.28 on 2022-11-18 16:30 |
||||
|
|
||||
|
import django.contrib.postgres.fields.jsonb |
||||
|
from django.db import migrations |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('base', '0055_appconfig_mostrar_voto'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterModelOptions( |
||||
|
name='auditlog', |
||||
|
options={'ordering': ('-id', '-timestamp'), 'verbose_name': 'AuditLog', 'verbose_name_plural': 'AuditLogs'}, |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name='auditlog', |
||||
|
name='data', |
||||
|
field=django.contrib.postgres.fields.jsonb.JSONField(null=True, verbose_name='data'), |
||||
|
), |
||||
|
] |