Browse Source

Merge branch '3.1.x' into tipo_votacao_multiplas_materias

pull/3781/head
cristian-longhi 2 weeks ago
committed by GitHub
parent
commit
3661516253
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 9
      sapl/audiencia/views.py
  2. 8
      sapl/base/views.py
  3. 11
      sapl/comissoes/views.py
  4. 28
      sapl/crud/base.py
  5. 40
      sapl/materia/views.py
  6. 3
      sapl/middleware.py
  7. 20
      sapl/norma/views.py
  8. 19
      sapl/parlamentares/views.py
  9. 27
      sapl/protocoloadm/views.py
  10. 67
      sapl/relatorios/views.py
  11. 15
      sapl/sessao/views.py
  12. 2
      sapl/settings.py
  13. 5
      sapl/static/.well-known/traffic-advice
  14. 15
      sapl/urls.py
  15. 9
      scripts/test_ratelimiter.sh

9
sapl/audiencia/views.py

@ -9,6 +9,12 @@ from sapl.crud.base import RP_DETAIL, RP_LIST, Crud, MasterDetailCrud
from .forms import AudienciaForm, AnexoAudienciaPublicaForm
from .models import AudienciaPublica, AnexoAudienciaPublica
from ratelimit.decorators import ratelimit
from django.utils.decorators import method_decorator
from ..settings import RATE_LIMITER_RATE
from ..utils import ratelimit_ip
def index(request):
return HttpResponse("Audiência Pública")
@ -105,6 +111,3 @@ class AnexoAudienciaPublicaCrud(MasterDetailCrud):
qs = super(MasterDetailCrud.ListView, self).get_queryset()
kwargs = {self.crud.parent_field: self.kwargs['pk']}
return qs.filter(**kwargs).order_by('-data', '-id')
class DetailView(AudienciaPublicaMixin, MasterDetailCrud.DetailView):
pass

8
sapl/base/views.py

@ -48,7 +48,7 @@ from sapl.parlamentares.models import (
from sapl.protocoloadm.models import (Anexado, Protocolo)
from sapl.relatorios.views import (relatorio_estatisticas_acesso_normas)
from sapl.sessao.models import (Bancada, SessaoPlenaria)
from sapl.settings import EMAIL_SEND_USER
from sapl.settings import EMAIL_SEND_USER, RATE_LIMITER_RATE
from sapl.utils import (gerar_hash_arquivo, intervalos_tem_intersecao, mail_service_configured,
SEPARADOR_HASH_PROPOSICAO, show_results_filter_set, google_recaptcha_configured,
get_client_ip, sapn_is_enabled, is_weak_password, ratelimit_ip)
@ -68,7 +68,7 @@ class IndexView(TemplateView):
@method_decorator(ratelimit(key=ratelimit_ip,
rate='10/m',
rate=RATE_LIMITER_RATE,
method=ratelimit.UNSAFE,
block=True),
name='dispatch')
@ -1400,6 +1400,10 @@ class SaplSearchView(SearchView):
return context
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class PesquisarAuditLogView(PermissionRequiredMixin, FilterView):
model = AuditLog
filterset_class = AuditLogFilterSet

11
sapl/comissoes/views.py

@ -28,11 +28,16 @@ from sapl.crud.base import (Crud, CrudAux, MasterDetailCrud,
RP_LIST)
from sapl.materia.models import (MateriaEmTramitacao, MateriaLegislativa,
PautaReuniao, Tramitacao)
from sapl.utils import show_results_filter_set
from sapl.utils import show_results_filter_set, ratelimit_ip
from .models import (CargoComissao, Comissao, Composicao, DocumentoAcessorio,
Participacao, Periodo, Reuniao, TipoComissao)
from ratelimit.decorators import ratelimit
from django.utils.decorators import method_decorator
from ..settings import RATE_LIMITER_RATE
def pegar_url_composicao(pk):
participacao = Participacao.objects.get(id=pk)
@ -333,6 +338,10 @@ class RemovePautaView(PermissionRequiredMixin, CreateView):
return HttpResponseRedirect(success_url)
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class AdicionaPautaView(PermissionRequiredMixin, FilterView):
filterset_class = PautaReuniaoFilterSet
template_name = 'comissoes/pauta.html'

28
sapl/crud/base.py

@ -26,7 +26,11 @@ from sapl.crispy_layout_mixin import CrispyLayoutFormMixin, get_field_display
from sapl.crispy_layout_mixin import SaplFormHelper
from sapl.rules import (RP_ADD, RP_CHANGE, RP_DELETE, RP_DETAIL,
RP_LIST)
from sapl.utils import normalize
from sapl.settings import RATE_LIMITER_RATE
from sapl.utils import normalize, ratelimit_ip
from ratelimit.decorators import ratelimit
from django.utils.decorators import method_decorator
logger = logging.getLogger(settings.BASE_DIR.name)
@ -101,7 +105,6 @@ variáveis do crud:
class SearchMixin(models.Model):
search = models.TextField(blank=True, default='')
logger = logging.getLogger(__name__)
@ -267,7 +270,6 @@ class CrudBaseMixin(CrispyLayoutFormMixin):
obj.public = []
if hasattr(self, 'permission_required') and self.permission_required:
self.permission_required = tuple(
(
self.permission(pr) for pr in (
@ -388,6 +390,10 @@ class CrudBaseMixin(CrispyLayoutFormMixin):
return self.model._meta.verbose_name_plural
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class CrudListView(PermissionRequiredContainerCrudMixin, ListView):
permission_required = (RP_LIST,)
logger = logging.getLogger(__name__)
@ -724,9 +730,12 @@ class CrudCreateView(PermissionRequiredContainerCrudMixin,
return super().form_valid(form)
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class CrudDetailView(PermissionRequiredContainerCrudMixin,
DetailView, MultipleObjectMixin):
permission_required = (RP_DETAIL,)
no_entries_msg = _('Nenhum registro Associado.')
paginate_by = 10
@ -976,7 +985,6 @@ class Crud:
view.permission_required and \
hasattr(cls, 'public') and \
cls.public:
# print(view.permission_required, view)
# print(cls.public, cls)
@ -1036,7 +1044,6 @@ class Crud:
def build(cls, _model, _help_topic, _model_set=None, list_field_names=[]):
def create_class(_list_field_names):
class ModelCrud(cls):
model = _model
model_set = _model_set
@ -1080,7 +1087,6 @@ class CrudAux(Crud):
@classonlymethod
def build(cls, _model, _help_topic, _model_set=None, list_field_names=[]):
ModelCrud = Crud.build(
_model, _help_topic, _model_set, list_field_names)
@ -1182,6 +1188,10 @@ class MasterDetailCrud(Crud):
context['title'] = title
return context
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class ListView(Crud.ListView):
permission_required = RP_LIST,
logger = logging.getLogger(__name__)
@ -1414,6 +1424,10 @@ class MasterDetailCrud(Crud):
else:
return self.resolve_url(ACTION_LIST, args=(pk,))
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class DetailView(Crud.DetailView):
permission_required = RP_DETAIL,
template_name = 'crud/detail_detail.html'

40
sapl/materia/views.py

@ -51,7 +51,7 @@ from sapl.materia.forms import (AnexadaForm, AutoriaForm, AutoriaMultiCreateForm
from sapl.norma.models import LegislacaoCitada
from sapl.parlamentares.models import Legislatura
from sapl.protocoloadm.models import Protocolo
from sapl.settings import MAX_DOC_UPLOAD_SIZE, MEDIA_ROOT
from sapl.settings import MAX_DOC_UPLOAD_SIZE, MEDIA_ROOT, RATE_LIMITER_RATE
from sapl.utils import (autor_label, autor_modal, gerar_hash_arquivo, get_base_url,
get_client_ip, get_mime_type_from_file_extension, lista_anexados,
mail_service_configured, montar_row_autor, SEPARADOR_HASH_PROPOSICAO,
@ -134,6 +134,10 @@ def proposicao_texto(request, pk):
raise Http404
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class AdicionarVariasAutorias(PermissionRequiredForAppCrudMixin, FilterView):
app_label = sapl.materia.apps.AppConfig.label
filterset_class = AdicionarVariasAutoriasFilterSet
@ -394,6 +398,10 @@ class StatusTramitacaoCrud(CrudAux):
return reverse('sapl.materia:pesquisar_statustramitacao')
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class PesquisarStatusTramitacaoView(FilterView):
model = StatusTramitacao
filterset_class = StatusTramitacaoFilterSet
@ -1461,10 +1469,6 @@ class TramitacaoCrud(MasterDetailCrud):
return initial
@method_decorator(ratelimit(key=ratelimit_ip,
rate='10/m',
block=True),
name='dispatch')
class ListView(MasterDetailCrud.ListView):
def get_queryset(self):
@ -1537,10 +1541,6 @@ class TramitacaoCrud(MasterDetailCrud):
return HttpResponseRedirect(url)
@method_decorator(ratelimit(key=ratelimit_ip,
rate='10/m',
block=True),
name='dispatch')
class DetailView(MasterDetailCrud.DetailView):
template_name = "materia/tramitacao_detail.html"
@ -1918,10 +1918,6 @@ class MateriaLegislativaCrud(Crud):
def get_success_url(self):
return self.search_url
@method_decorator(ratelimit(key=ratelimit_ip,
rate='10/m',
block=True),
name='dispatch')
class DetailView(Crud.DetailView):
layout_key = 'MateriaLegislativaDetail'
@ -1934,10 +1930,6 @@ class MateriaLegislativaCrud(Crud):
pk=self.kwargs['pk'])
return context
@method_decorator(ratelimit(key=ratelimit_ip,
rate='10/m',
block=True),
name='dispatch')
class ListView(Crud.ListView, RedirectView):
def get_redirect_url(self, *args, **kwargs):
@ -2059,7 +2051,7 @@ class AcompanhamentoExcluirView(TemplateView):
@method_decorator(ratelimit(key=ratelimit_ip,
rate='10/m',
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class MateriaLegislativaPesquisaView(MultiFormatOutputMixin, FilterView):
@ -2323,6 +2315,10 @@ class AcompanhamentoMateriaView(CreateView):
kwargs={'pk': self.kwargs['pk']})
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
filterset_class = AcessorioEmLoteFilterSet
template_name = 'materia/em_lote/acessorio.html'
@ -2435,6 +2431,10 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
return self.get(request, self.kwargs)
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class MateriaAnexadaEmLoteView(PermissionRequiredMixin, FilterView):
filterset_class = AnexadaEmLoteFilterSet
template_name = 'materia/em_lote/anexada.html'
@ -2559,6 +2559,10 @@ class MateriaAnexadaEmLoteView(PermissionRequiredMixin, FilterView):
return HttpResponseRedirect(success_url)
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
filterset_class = PrimeiraTramitacaoEmLoteFilterSet
template_name = 'materia/em_lote/tramitacao.html'

3
sapl/middleware.py

@ -19,3 +19,6 @@ class CheckWeakPasswordMiddleware:
return redirect('sapl.base:alterar_senha')
return self.get_response(request)

20
sapl/norma/views.py

@ -38,7 +38,7 @@ from .forms import (AnexoNormaJuridicaForm, NormaFilterSet, NormaJuridicaForm,
AutoriaNormaForm, AssuntoNormaFilterSet)
from .models import (AnexoNormaJuridica, AssuntoNorma, NormaJuridica, NormaRelacionada,
TipoNormaJuridica, TipoVinculoNormaJuridica, AutoriaNorma, NormaEstatisticas)
from ..settings import RATE_LIMITER_RATE
# LegislacaoCitadaCrud = Crud.build(LegislacaoCitada, '')
TipoNormaCrud = CrudAux.build(
@ -60,6 +60,10 @@ class AssuntoNormaCrud(CrudAux):
return reverse('sapl.norma:pesquisar_assuntonorma')
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class PesquisarAssuntoNormaView(FilterView):
model = AssuntoNorma
filterset_class = AssuntoNormaFilterSet
@ -151,7 +155,7 @@ class NormaRelacionadaCrud(MasterDetailCrud):
@method_decorator(ratelimit(key=ratelimit_ip,
rate='10/m',
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class NormaPesquisaView(MultiFormatOutputMixin, FilterView):
@ -239,10 +243,6 @@ class AnexoNormaJuridicaCrud(MasterDetailCrud):
initial['ano'] = self.object.ano
return initial
@method_decorator(ratelimit(key=ratelimit_ip,
rate='10/m',
block=True),
name='dispatch')
class DetailView(MasterDetailCrud.DetailView):
form_class = AnexoNormaJuridicaForm
layout_key = 'AnexoNormaJuridica'
@ -291,10 +291,6 @@ class NormaCrud(Crud):
namespace = self.model._meta.app_config.name
return reverse('%s:%s' % (namespace, 'norma_pesquisa'))
@method_decorator(ratelimit(key=ratelimit_ip,
rate='10/m',
block=True),
name='dispatch')
class DetailView(Crud.DetailView):
def get(self, request, *args, **kwargs):
estatisticas_acesso_normas = AppConfig.objects.first().estatisticas_acesso_normas
@ -352,10 +348,6 @@ class NormaCrud(Crud):
layout_key = 'NormaJuridicaCreate'
@method_decorator(ratelimit(key=ratelimit_ip,
rate='10/m',
block=True),
name='dispatch')
class ListView(Crud.ListView):
def get(self, request, *args, **kwargs):

19
sapl/parlamentares/views.py

@ -33,7 +33,7 @@ from sapl.materia.models import Autoria, Proposicao, Relatoria
from sapl.norma.models import AutoriaNorma, NormaJuridica
from sapl.parlamentares.apps import AppConfig
from sapl.rules import SAPL_GROUP_VOTANTE
from sapl.utils import (parlamentares_ativos, show_results_filter_set)
from sapl.utils import (parlamentares_ativos, show_results_filter_set, ratelimit_ip)
from .forms import (ColigacaoFilterSet, FiliacaoForm, FrenteForm, LegislaturaForm, MandatoForm,
ParlamentarCreateForm, ParlamentarForm, VotanteForm,
@ -45,6 +45,11 @@ from .models import (CargoMesa, Coligacao, ComposicaoColigacao, ComposicaoMesa,
SituacaoMilitar, TipoAfastamento, TipoDependente, Votante,
Bloco, FrenteCargo, FrenteParlamentar, BlocoCargo, BlocoMembro, MesaDiretora)
from ratelimit.decorators import ratelimit
from django.utils.decorators import method_decorator
from ..settings import RATE_LIMITER_RATE
FrenteCargoCrud = CrudAux.build(FrenteCargo, 'frente_cargo')
BlocoCargoCrud = CrudAux.build(BlocoCargo, 'bloco_cargo')
CargoMesaCrud = CrudAux.build(CargoMesa, 'cargo_mesa')
@ -183,6 +188,10 @@ class ProposicaoParlamentarCrud(CrudBaseForListAndDetailExternalAppView):
_('Texto Eletrônico'))
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class PesquisarParlamentarView(FilterView):
model = Parlamentar
filterset_class = ParlamentarFilterSet
@ -245,6 +254,10 @@ class PesquisarParlamentarView(FilterView):
return self.render_to_response(context)
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class PesquisarColigacaoView(FilterView):
model = Coligacao
filterset_class = ColigacaoFilterSet
@ -301,6 +314,10 @@ class PesquisarColigacaoView(FilterView):
return self.render_to_response(context)
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class PesquisarPartidoView(FilterView):
model = Partido
filterset_class = PartidoFilterSet

27
sapl/protocoloadm/views.py

@ -47,7 +47,7 @@ from sapl.relatorios.views import relatorio_doc_administrativos
from sapl.utils import (create_barcode, get_base_url, get_client_ip,
get_mime_type_from_file_extension, lista_anexados,
show_results_filter_set, mail_service_configured, from_date_to_datetime_utc,
google_recaptcha_configured, get_tempfile_dir, MultiFormatOutputMixin)
google_recaptcha_configured, get_tempfile_dir, MultiFormatOutputMixin, ratelimit_ip)
from .forms import (AcompanhamentoDocumentoForm, AnexadoEmLoteFilterSet, AnexadoForm,
AnularProtocoloAdmForm, compara_tramitacoes_doc,
@ -62,7 +62,10 @@ from .forms import (AcompanhamentoDocumentoForm, AnexadoEmLoteFilterSet, Anexado
from .models import (Anexado, AcompanhamentoDocumento, DocumentoAcessorioAdministrativo,
DocumentoAdministrativo, StatusTramitacaoAdministrativo,
TipoDocumentoAdministrativo, TramitacaoAdministrativo)
from ..settings import MEDIA_ROOT
from ..settings import MEDIA_ROOT, RATE_LIMITER_RATE
from ratelimit.decorators import ratelimit
from django.utils.decorators import method_decorator
TipoDocumentoAdministrativoCrud = CrudAux.build(
TipoDocumentoAdministrativo, '')
@ -535,6 +538,10 @@ class StatusTramitacaoAdministrativoCrud(CrudAux):
ordering = 'sigla'
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class ProtocoloPesquisaView(PermissionRequiredMixin, FilterView):
model = Protocolo
filterset_class = ProtocoloFilterSet
@ -1032,6 +1039,10 @@ class ProtocoloMateriaTemplateView(PermissionRequiredMixin, TemplateView):
return context
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin,
MultiFormatOutputMixin,
PermissionRequiredMixin,
@ -1165,6 +1176,10 @@ class AnexadoCrud(MasterDetailCrud):
return 'AnexadoDetail'
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class DocumentoAnexadoEmLoteView(PermissionRequiredMixin, FilterView):
filterset_class = AnexadoEmLoteFilterSet
template_name = 'protocoloadm/em_lote/anexado.html'
@ -1642,6 +1657,10 @@ class FichaSelecionaAdmView(PermissionRequiredMixin, FormView):
'materia/impressos/ficha_adm_pdf.html')
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class PrimeiraTramitacaoEmLoteAdmView(PermissionRequiredMixin, FilterView):
filterset_class = PrimeiraTramitacaoEmLoteAdmFilterSet
template_name = 'protocoloadm/em_lote/tramitacaoadm.html'
@ -1878,6 +1897,10 @@ class VinculoDocAdminMateriaCrud(MasterDetailCrud):
return context
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class VinculoDocAdminMateriaEmLoteView(PermissionRequiredMixin, FilterView):
filterset_class = VinculoDocAdminMateriaEmLoteFilterSet
template_name = 'protocoloadm/em_lote/vinculodocadminmateria.html'

67
sapl/relatorios/views.py

@ -48,10 +48,10 @@ from sapl.sessao.views import (get_identificacao_basica, get_mesa_diretora,
get_oradores_explicacoes_pessoais, get_consideracoes_finais,
get_ocorrencias_da_sessao, get_assinaturas,
get_correspondencias)
from sapl.settings import MEDIA_URL
from sapl.settings import MEDIA_URL, RATE_LIMITER_RATE
from sapl.settings import STATIC_ROOT
from sapl.utils import LISTA_DE_UFS, TrocaTag, filiacao_data, create_barcode, show_results_filter_set, \
num_materias_por_tipo, parlamentares_ativos, MultiFormatOutputMixin
num_materias_por_tipo, parlamentares_ativos, MultiFormatOutputMixin, ratelimit_ip
from .templates import (pdf_capa_processo_gerar,
pdf_documento_administrativo_gerar, pdf_espelho_gerar,
pdf_etiqueta_protocolo_gerar, pdf_materia_gerar,
@ -59,6 +59,9 @@ from .templates import (pdf_capa_processo_gerar,
pdf_protocolo_gerar, pdf_sessao_plenaria_gerar)
from sapl.crud.base import make_pagination
from ratelimit.decorators import ratelimit
from django.utils.decorators import method_decorator
def get_kwargs_params(request, fields):
kwargs = {}
@ -1841,6 +1844,10 @@ class RelatorioMixin:
return self.render_to_response(context)
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class RelatorioDocumentosAcessoriosView(RelatorioMixin, FilterView):
model = DocumentoAcessorio
filterset_class = RelatorioDocumentosAcessoriosFilterSet
@ -1885,6 +1892,10 @@ class RelatorioDocumentosAcessoriosView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class RelatorioVotacoesNominaisView(RelatorioMixin, MultiFormatOutputMixin, FilterView):
model = VotoParlamentar
filterset_class = RelatorioVotacoesNominaisFilterSet
@ -1954,6 +1965,10 @@ class RelatorioVotacoesNominaisView(RelatorioMixin, MultiFormatOutputMixin, Filt
return context
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class RelatorioAtasView(RelatorioMixin, FilterView):
model = SessaoPlenaria
filterset_class = RelatorioAtasFilterSet
@ -1979,6 +1994,10 @@ class RelatorioAtasView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class RelatorioPresencaSessaoView(RelatorioMixin, FilterView):
logger = logging.getLogger(__name__)
model = SessaoPlenaria
@ -2213,6 +2232,10 @@ class RelatorioPresencaSessaoView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class RelatorioHistoricoTramitacaoView(RelatorioMixin, FilterView):
model = MateriaLegislativa
filterset_class = RelatorioHistoricoTramitacaoFilterSet
@ -2270,6 +2293,10 @@ class RelatorioHistoricoTramitacaoView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class RelatorioDataFimPrazoTramitacaoView(RelatorioMixin, FilterView):
model = MateriaEmTramitacao
filterset_class = RelatorioDataFimPrazoTramitacaoFilterSet
@ -2333,6 +2360,10 @@ class RelatorioDataFimPrazoTramitacaoView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class RelatorioReuniaoView(RelatorioMixin, FilterView):
model = Reuniao
filterset_class = RelatorioReuniaoFilterSet
@ -2367,6 +2398,10 @@ class RelatorioReuniaoView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class RelatorioAudienciaView(RelatorioMixin, FilterView):
model = AudienciaPublica
filterset_class = RelatorioAudienciaFilterSet
@ -2401,6 +2436,10 @@ class RelatorioAudienciaView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class RelatorioMateriasTramitacaoView(RelatorioMixin, FilterView):
model = MateriaEmTramitacao
filterset_class = RelatorioMateriasTramitacaoFilterSet
@ -2515,6 +2554,10 @@ class RelatorioMateriasTramitacaoView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class RelatorioMateriasPorAnoAutorTipoView(RelatorioMixin, FilterView):
model = MateriaLegislativa
filterset_class = RelatorioMateriasPorAnoAutorTipoFilterSet
@ -2594,6 +2637,10 @@ class RelatorioMateriasPorAnoAutorTipoView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class RelatorioMateriasPorAutorView(RelatorioMixin, FilterView):
model = MateriaLegislativa
filterset_class = RelatorioMateriasPorAutorFilterSet
@ -2665,6 +2712,10 @@ class RelatorioMateriaAnoAssuntoView(ListView):
return context
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class RelatorioNormasPublicadasMesView(RelatorioMixin, FilterView):
model = NormaJuridica
filterset_class = RelatorioNormasMesFilterSet
@ -2705,6 +2756,10 @@ class RelatorioNormasPublicadasMesView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class RelatorioNormasVigenciaView(RelatorioMixin, FilterView):
model = NormaJuridica
filterset_class = RelatorioNormasVigenciaFilterSet
@ -2769,6 +2824,10 @@ class RelatorioNormasVigenciaView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class RelatorioHistoricoTramitacaoAdmView(RelatorioMixin, FilterView):
model = DocumentoAdministrativo
filterset_class = RelatorioHistoricoTramitacaoAdmFilterSet
@ -2819,6 +2878,10 @@ class RelatorioHistoricoTramitacaoAdmView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class RelatorioNormasPorAutorView(RelatorioMixin, FilterView):
model = NormaJuridica
filterset_class = RelatorioNormasPorAutorFilterSet

15
sapl/sessao/views.py

@ -47,7 +47,7 @@ from sapl.sessao.apps import AppConfig
from sapl.sessao.forms import ExpedienteMateriaForm, OrdemDiaForm, OrdemExpedienteLeituraForm, \
CorrespondenciaForm, CorrespondenciaEmLoteFilterSet
from sapl.sessao.models import Correspondencia
from sapl.settings import TIME_ZONE
from sapl.settings import TIME_ZONE, RATE_LIMITER_RATE
from sapl.utils import show_results_filter_set, remover_acentos, get_client_ip, \
MultiFormatOutputMixin, PautaMultiFormatOutputMixin, ratelimit_ip
@ -3798,7 +3798,7 @@ class SessaoListView(ListView):
@method_decorator(ratelimit(key=ratelimit_ip,
rate='10/m',
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class PautaSessaoView(TemplateView):
@ -3817,7 +3817,7 @@ class PautaSessaoView(TemplateView):
@method_decorator(ratelimit(key=ratelimit_ip,
rate='10/m',
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class PautaSessaoDetailView(PautaMultiFormatOutputMixin, DetailView):
@ -4001,6 +4001,10 @@ class PautaSessaoDetailView(PautaMultiFormatOutputMixin, DetailView):
return self.render_to_response(context)
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class PesquisarSessaoPlenariaView(MultiFormatOutputMixin, FilterView):
model = SessaoPlenaria
filterset_class = SessaoPlenariaFilterSet
@ -4088,6 +4092,7 @@ class PesquisarSessaoPlenariaView(MultiFormatOutputMixin, FilterView):
return r
class PesquisarPautaSessaoView(PesquisarSessaoPlenariaView):
filterset_class = PautaSessaoFilterSet
template_name = 'sessao/pauta_sessao_filter.html'
@ -5388,6 +5393,10 @@ class CorrespondenciaCrud(MasterDetailCrud):
return obj
@method_decorator(ratelimit(key=ratelimit_ip,
rate=RATE_LIMITER_RATE,
block=True),
name='dispatch')
class CorrespondenciaEmLoteView(PermissionRequiredMixin, FilterView):
filterset_class = CorrespondenciaEmLoteFilterSet
template_name = 'sessao/em_lote/correspondencia.html'

2
sapl/settings.py

@ -315,6 +315,8 @@ MAX_DOC_UPLOAD_SIZE = 150 * 1024 * 1024 # 150MB
MAX_IMAGE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB
DATA_UPLOAD_MAX_MEMORY_SIZE = 10 * 1024 * 1024 # 10MB
RATE_LIMITER_RATE = config('RATE_LIMITER_RATE', default='10/m')
# Internationalization
# https://docs.djangoproject.com/en/1.8/topics/i18n/
LANGUAGE_CODE = 'pt-br'

5
sapl/static/.well-known/traffic-advice

@ -0,0 +1,5 @@
{
"interval": 300,
"requests-per-second": 5,
"burst": 10
}

15
sapl/urls.py

@ -100,3 +100,18 @@ if settings.DEBUG:
'document_root': settings.MEDIA_ROOT,
}),
]
# Make the rate limiter return 429 (Too Many Requests) instead of 403 (Forbidden Access)
def custom_permission_denied_view(request, exception=None):
from django.http import HttpResponse, HttpResponseForbidden
from ratelimit.exceptions import Ratelimited
if isinstance(exception, Ratelimited):
resp = HttpResponse('Too many requests', status=429)
resp['Retry-After'] = '60'
return resp
return HttpResponseForbidden('Forbidden')
handler403 = custom_permission_denied_view

9
scripts/test_ratelimiter.sh

@ -1,9 +1,14 @@
#!/bin/bash
#URL=http://localhost:8000/materia/4379
URL=http://localhost:8000/norma/pesquisar
#URL=http://localhost:8000/norma/pesquisar
#URL=http://localhost/norma/pesquisar
#URL=https://sapl31demo.interlegis.leg.br/docadm/45
#URL=https://sapl.joaopessoa.pb.leg.br/materia/186300
#URL=http://localhost:8000/materia/4379/materiaassunto
#URL=http://localhost:8000/sessao/4984
URL="http://localhost:8000/docadm/pesq-doc-adm?tipo=&o=&numero=&complemento=&ano=&protocolo__numero=&numero_externo=&data_0=&data_1=&interessado=&assunto=&tramitacao=&tramitacaoadministrativo__status=&tramitacaoadministrativo__unidade_tramitacao_destino=&pesquisar=Pesquisar"
for i in $(seq 1 6); do
for i in $(seq 1 12); do
curl -sS -o /dev/null -w "req=$i http=%{http_code} time=%{time_total}\n" "$URL"
done

Loading…
Cancel
Save