Browse Source

Impl registro do Google Recaptcha

pull/3337/head
Leandro Roberto 5 years ago
parent
commit
b5d376febf
  1. 16
      sapl/base/forms.py
  2. 23
      sapl/base/migrations/0043_auto_20210203_1442.py
  3. 20
      sapl/base/models.py
  4. 222
      sapl/base/views.py
  5. 14
      sapl/context_processors.py
  6. 12
      sapl/materia/views.py
  7. 13
      sapl/protocoloadm/views.py
  8. 2
      sapl/settings.py
  9. 3
      sapl/templates/base/layouts.yaml
  10. 5
      sapl/templates/base/login.html
  11. 2
      sapl/templates/materia/materialegislativa_detail.html
  12. 2
      sapl/templates/materia/materialegislativa_filter.html
  13. 2
      sapl/templates/protocoloadm/documentoadministrativo_filter.html
  14. 15
      sapl/utils.py

16
sapl/base/forms.py

@ -1565,6 +1565,18 @@ class ConfiguracoesAppForm(ModelForm):
label=_('Mostrar brasão da Casa no painel?'), label=_('Mostrar brasão da Casa no painel?'),
required=False) required=False)
google_recaptcha_site_key = forms.CharField(
label=AppConfig._meta.get_field(
'google_recaptcha_site_key').verbose_name,
max_length=256,
required=False)
google_recaptcha_secret_key = forms.CharField(
label=AppConfig._meta.get_field(
'google_recaptcha_secret_key').verbose_name,
max_length=256,
required=False)
class Meta: class Meta:
model = AppConfig model = AppConfig
fields = ['documentos_administrativos', fields = ['documentos_administrativos',
@ -1588,7 +1600,9 @@ class ConfiguracoesAppForm(ModelForm):
'estatisticas_acesso_normas', 'estatisticas_acesso_normas',
'escolher_numero_materia_proposicao', 'escolher_numero_materia_proposicao',
'tramitacao_materia', 'tramitacao_materia',
'tramitacao_documento'] 'tramitacao_documento',
'google_recaptcha_site_key',
'google_recaptcha_secret_key']
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(ConfiguracoesAppForm, self).__init__(*args, **kwargs) super(ConfiguracoesAppForm, self).__init__(*args, **kwargs)

23
sapl/base/migrations/0043_auto_20210203_1442.py

@ -0,0 +1,23 @@
# Generated by Django 2.2.13 on 2021-02-03 17:42
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('base', '0042_auto_20201013_1151'),
]
operations = [
migrations.AddField(
model_name='appconfig',
name='google_recaptcha_secret_key',
field=models.CharField(default='', max_length=256, verbose_name='Chave privada gerada pelo Google Recaptcha'),
),
migrations.AddField(
model_name='appconfig',
name='google_recaptcha_site_key',
field=models.CharField(default='', max_length=256, verbose_name='Chave pública gerada pelo Google Recaptcha'),
),
]

20
sapl/base/models.py

@ -179,17 +179,27 @@ class AppConfig(models.Model):
choices=YES_NO_CHOICES, default=False) choices=YES_NO_CHOICES, default=False)
escolher_numero_materia_proposicao = models.BooleanField( escolher_numero_materia_proposicao = models.BooleanField(
verbose_name=_('Indicar número da matéria a ser gerada na proposição?'), verbose_name=_(
'Indicar número da matéria a ser gerada na proposição?'),
choices=YES_NO_CHOICES, default=False) choices=YES_NO_CHOICES, default=False)
tramitacao_materia = models.BooleanField( tramitacao_materia = models.BooleanField(
verbose_name=_('Tramitar matérias anexadas junto com as matérias principais?'), verbose_name=_(
'Tramitar matérias anexadas junto com as matérias principais?'),
choices=YES_NO_CHOICES, default=True) choices=YES_NO_CHOICES, default=True)
tramitacao_documento = models.BooleanField( tramitacao_documento = models.BooleanField(
verbose_name=_('Tramitar documentos anexados junto com os documentos principais?'), verbose_name=_(
'Tramitar documentos anexados junto com os documentos principais?'),
choices=YES_NO_CHOICES, default=True) choices=YES_NO_CHOICES, default=True)
google_recaptcha_site_key = models.CharField(
verbose_name=_('Chave pública gerada pelo Google Recaptcha'),
max_length=256, default='')
google_recaptcha_secret_key = models.CharField(
verbose_name=_('Chave privada gerada pelo Google Recaptcha'),
max_length=256, default='')
class Meta: class Meta:
verbose_name = _('Configurações da Aplicação') verbose_name = _('Configurações da Aplicação')
verbose_name_plural = _('Configurações da Aplicação') verbose_name_plural = _('Configurações da Aplicação')
@ -219,7 +229,8 @@ class TipoAutor(models.Model):
descricao = models.CharField( descricao = models.CharField(
max_length=50, max_length=50,
verbose_name=_('Descrição'), verbose_name=_('Descrição'),
help_text=_('Obs: Não crie tipos de autores semelhante aos tipos fixos. ') help_text=_(
'Obs: Não crie tipos de autores semelhante aos tipos fixos. ')
) )
content_type = models.OneToOneField( content_type = models.OneToOneField(
@ -325,4 +336,3 @@ class AuditLog(models.Model):
self.model_name, self.model_name,
self.username, self.username,
) )

222
sapl/base/views.py

@ -1,62 +1,67 @@
from collections import OrderedDict
import collections import collections
import itertools
import datetime import datetime
import itertools
import logging import logging
import os import os
from collections import OrderedDict
from django.contrib import messages from django.contrib import messages
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.auth.models import Group, User from django.contrib.auth.models import Group, User
from django.contrib.auth.tokens import default_token_generator from django.contrib.auth.tokens import default_token_generator
from django.contrib.auth.views import (PasswordResetView,PasswordResetConfirmView, PasswordResetCompleteView, from django.contrib.auth.views import (PasswordResetView, PasswordResetConfirmView, PasswordResetCompleteView,
PasswordResetDoneView) PasswordResetDoneView)
from django.core.exceptions import ObjectDoesNotExist, PermissionDenied, ValidationError from django.core.exceptions import ObjectDoesNotExist, PermissionDenied, ValidationError
from django.core.mail import send_mail from django.core.mail import send_mail
from django.urls import reverse, reverse_lazy
from django.db import connection from django.db import connection
from django.db.models import Count, Q, ProtectedError, Max from django.db.models import Count, Q, ProtectedError, Max
from django.shortcuts import render
from django.http import Http404, HttpResponseRedirect, JsonResponse from django.http import Http404, HttpResponseRedirect, JsonResponse
from django.shortcuts import render, redirect
from django.template import TemplateDoesNotExist from django.template import TemplateDoesNotExist
from django.template.loader import get_template from django.template.loader import get_template
from django.urls import reverse, reverse_lazy
from django.utils import timezone from django.utils import timezone
from django.utils.encoding import force_bytes from django.utils.encoding import force_bytes
from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic import (CreateView, DetailView, DeleteView, FormView, ListView, UpdateView) from django.views.generic import (
CreateView, DetailView, DeleteView, FormView, ListView, UpdateView)
from django.views.generic.base import RedirectView, TemplateView from django.views.generic.base import RedirectView, TemplateView
from django_filters.views import FilterView from django_filters.views import FilterView
from haystack.views import SearchView
from haystack.query import SearchQuerySet from haystack.query import SearchQuerySet
from haystack.views import SearchView
from sapl.relatorios.views import (relatorio_materia_em_tramitacao, relatorio_materia_por_autor, from rest_framework.authtoken.models import Token
relatorio_materia_por_ano_autor, relatorio_presenca_sessao,
relatorio_historico_tramitacao, relatorio_fim_prazo_tramitacao, relatorio_atas,
relatorio_audiencia, relatorio_normas_mes, relatorio_normas_vigencia,
relatorio_historico_tramitacao_adm, relatorio_reuniao,
relatorio_estatisticas_acesso_normas, relatorio_normas_por_autor,
relatorio_documento_acessorio)
from sapl import settings from sapl import settings
from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica from sapl.audiencia.models import AudienciaPublica, TipoAudienciaPublica
from sapl.base.models import Autor, TipoAutor
from sapl.base.forms import (AutorForm, AutorFormForAdmin, TipoAutorForm, AutorFilterSet, RecuperarSenhaForm, from sapl.base.forms import (AutorForm, AutorFormForAdmin, TipoAutorForm, AutorFilterSet, RecuperarSenhaForm,
NovaSenhaForm) NovaSenhaForm)
from sapl.base.models import Autor, TipoAutor
from sapl.comissoes.models import Comissao, Reuniao from sapl.comissoes.models import Comissao, Reuniao
from sapl.crud.base import CrudAux, make_pagination from sapl.crud.base import CrudAux, make_pagination
from sapl.materia.models import (Anexada, Autoria, DocumentoAcessorio, MateriaEmTramitacao, MateriaLegislativa, from sapl.materia.models import (Anexada, Autoria, DocumentoAcessorio, MateriaEmTramitacao, MateriaLegislativa,
Proposicao, StatusTramitacao, TipoDocumento, TipoMateriaLegislativa, UnidadeTramitacao, Proposicao, StatusTramitacao, TipoDocumento, TipoMateriaLegislativa, UnidadeTramitacao,
Tramitacao) Tramitacao)
from sapl.norma.models import NormaJuridica, TipoNormaJuridica from sapl.norma.models import NormaJuridica, TipoNormaJuridica
from sapl.parlamentares.models import (Filiacao, Legislatura, Mandato, Parlamentar, SessaoLegislativa) from sapl.parlamentares.models import (
Filiacao, Legislatura, Mandato, Parlamentar, SessaoLegislativa)
from sapl.protocoloadm.models import (Anexado, DocumentoAdministrativo, Protocolo, StatusTramitacaoAdministrativo, from sapl.protocoloadm.models import (Anexado, DocumentoAdministrativo, Protocolo, StatusTramitacaoAdministrativo,
TipoDocumentoAdministrativo) TipoDocumentoAdministrativo)
from sapl.sessao.models import (Bancada, PresencaOrdemDia, SessaoPlenaria, SessaoPlenariaPresenca, TipoSessaoPlenaria) from sapl.relatorios.views import (relatorio_materia_em_tramitacao, relatorio_materia_por_autor,
relatorio_materia_por_ano_autor, relatorio_presenca_sessao,
relatorio_historico_tramitacao, relatorio_fim_prazo_tramitacao, relatorio_atas,
relatorio_audiencia, relatorio_normas_mes, relatorio_normas_vigencia,
relatorio_historico_tramitacao_adm, relatorio_reuniao,
relatorio_estatisticas_acesso_normas, relatorio_normas_por_autor,
relatorio_documento_acessorio)
from sapl.sessao.models import (
Bancada, PresencaOrdemDia, SessaoPlenaria, SessaoPlenariaPresenca, TipoSessaoPlenaria)
from sapl.settings import EMAIL_SEND_USER from sapl.settings import EMAIL_SEND_USER
from sapl.utils import (gerar_hash_arquivo, intervalos_tem_intersecao, mail_service_configured, parlamentares_ativos, from sapl.utils import (gerar_hash_arquivo, intervalos_tem_intersecao, mail_service_configured, parlamentares_ativos,
SEPARADOR_HASH_PROPOSICAO, show_results_filter_set, num_materias_por_tipo) SEPARADOR_HASH_PROPOSICAO, show_results_filter_set, num_materias_por_tipo,
google_recaptcha_configured)
from .forms import (AlterarSenhaForm, CasaLegislativaForm, ConfiguracoesAppForm, RelatorioAtasFilterSet, from .forms import (AlterarSenhaForm, CasaLegislativaForm, ConfiguracoesAppForm, RelatorioAtasFilterSet,
RelatorioAudienciaFilterSet, RelatorioDataFimPrazoTramitacaoFilterSet, RelatorioAudienciaFilterSet, RelatorioDataFimPrazoTramitacaoFilterSet,
RelatorioHistoricoTramitacaoFilterSet, RelatorioMateriasPorAnoAutorTipoFilterSet, RelatorioHistoricoTramitacaoFilterSet, RelatorioMateriasPorAnoAutorTipoFilterSet,
@ -67,8 +72,6 @@ from .forms import (AlterarSenhaForm, CasaLegislativaForm, ConfiguracoesAppForm,
RelatorioNormasPorAutorFilterSet) RelatorioNormasPorAutorFilterSet)
from .models import AppConfig, CasaLegislativa from .models import AppConfig, CasaLegislativa
from rest_framework.authtoken.models import Token
def get_casalegislativa(): def get_casalegislativa():
return CasaLegislativa.objects.first() return CasaLegislativa.objects.first()
@ -87,6 +90,8 @@ class ConfirmarEmailView(TemplateView):
class RecuperarSenhaEmailView(PasswordResetView): class RecuperarSenhaEmailView(PasswordResetView):
logger = logging.getLogger(__name__)
success_url = reverse_lazy('sapl.base:recuperar_senha_finalizado') success_url = reverse_lazy('sapl.base:recuperar_senha_finalizado')
email_template_name = 'base/recuperar_senha_email.html' email_template_name = 'base/recuperar_senha_email.html'
html_email_template_name = 'base/recuperar_senha_email.html' html_email_template_name = 'base/recuperar_senha_email.html'
@ -94,6 +99,24 @@ class RecuperarSenhaEmailView(PasswordResetView):
from_email = EMAIL_SEND_USER from_email = EMAIL_SEND_USER
form_class = RecuperarSenhaForm form_class = RecuperarSenhaForm
def get(self, request, *args, **kwargs):
if not google_recaptcha_configured():
self.logger.warning(_('Google Recaptcha não configurado!'))
messages.error(request, _('Google Recaptcha não configurado!'))
return redirect(request.META.get('HTTP_REFERER', '/'))
return PasswordResetView.get(self, request, *args, **kwargs)
def post(self, request, *args, **kwargs):
if not google_recaptcha_configured():
self.logger.warning(_('Google Recaptcha não configurado!'))
messages.error(request, _('Google Recaptcha não configurado!'))
return redirect(request.META.get('HTTP_REFERER', '/'))
return PasswordResetView.post(self, request, *args, **kwargs)
class RecuperarSenhaFinalizadoView(PasswordResetDoneView): class RecuperarSenhaFinalizadoView(PasswordResetDoneView):
template_name = 'base/recupera_senha_email_enviado.html' template_name = 'base/recupera_senha_email_enviado.html'
@ -330,7 +353,8 @@ class PesquisarAutorView(FilterView):
paginator = context['paginator'] paginator = context['paginator']
page_obj = context['page_obj'] page_obj = context['page_obj']
context['page_range'] = make_pagination(page_obj.number, paginator.num_pages) context['page_range'] = make_pagination(
page_obj.number, paginator.num_pages)
context['NO_ENTRIES_MSG'] = 'Nenhum Autor encontrado!' context['NO_ENTRIES_MSG'] = 'Nenhum Autor encontrado!'
@ -354,13 +378,14 @@ class PesquisarAutorView(FilterView):
filter_url=url, filter_url=url,
numero_res=len(self.object_list)) numero_res=len(self.object_list))
context['show_results'] = show_results_filter_set(self.request.GET.copy()) context['show_results'] = show_results_filter_set(
self.request.GET.copy())
return self.render_to_response(context) return self.render_to_response(context)
class RelatoriosListView(TemplateView): class RelatoriosListView(TemplateView):
template_name='base/relatorios_list.html' template_name = 'base/relatorios_list.html'
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(TemplateView, self).get_context_data(**kwargs) context = super(TemplateView, self).get_context_data(**kwargs)
@ -471,11 +496,13 @@ class RelatorioPresencaSessaoView(RelatorioMixin, FilterView):
cd = self.filterset.form.cleaned_data cd = self.filterset.form.cleaned_data
if not cd['data_inicio'] and not cd['sessao_legislativa'] \ if not cd['data_inicio'] and not cd['sessao_legislativa'] \
and not cd['legislatura']: and not cd['legislatura']:
msg = _("Formulário inválido! Preencha pelo menos algum dos campos Período, Legislatura ou Sessão Legislativa.") msg = _(
"Formulário inválido! Preencha pelo menos algum dos campos Período, Legislatura ou Sessão Legislativa.")
messages.error(self.request, msg) messages.error(self.request, msg)
return context return context
# Caso a data tenha sido preenchida, verifica se foi preenchida corretamente # Caso a data tenha sido preenchida, verifica se foi preenchida
# corretamente
if self.request.GET.get('data_inicio_0') and not self.request.GET.get('data_inicio_1'): if self.request.GET.get('data_inicio_0') and not self.request.GET.get('data_inicio_1'):
msg = _("Formulário inválido! Preencha a data do Período Final.") msg = _("Formulário inválido! Preencha a data do Período Final.")
messages.error(self.request, msg) messages.error(self.request, msg)
@ -497,14 +524,16 @@ class RelatorioPresencaSessaoView(RelatorioMixin, FilterView):
sessao_legislativa_pk = self.request.GET.get('sessao_legislativa') sessao_legislativa_pk = self.request.GET.get('sessao_legislativa')
if sessao_legislativa_pk: if sessao_legislativa_pk:
param0['sessao_plenaria__sessao_legislativa_id'] = sessao_legislativa_pk param0['sessao_plenaria__sessao_legislativa_id'] = sessao_legislativa_pk
sessao_legislativa = SessaoLegislativa.objects.get(id=sessao_legislativa_pk) sessao_legislativa = SessaoLegislativa.objects.get(
id=sessao_legislativa_pk)
context['sessao_legislativa'] = sessao_legislativa context['sessao_legislativa'] = sessao_legislativa
tipo_sessao_plenaria_pk = self.request.GET.get('tipo') tipo_sessao_plenaria_pk = self.request.GET.get('tipo')
context['tipo'] = '' context['tipo'] = ''
if tipo_sessao_plenaria_pk: if tipo_sessao_plenaria_pk:
param0['sessao_plenaria__tipo_id'] = tipo_sessao_plenaria_pk param0['sessao_plenaria__tipo_id'] = tipo_sessao_plenaria_pk
context['tipo'] = TipoSessaoPlenaria.objects.get(id=tipo_sessao_plenaria_pk) context['tipo'] = TipoSessaoPlenaria.objects.get(
id=tipo_sessao_plenaria_pk)
_range = [] _range = []
@ -517,29 +546,35 @@ class RelatorioPresencaSessaoView(RelatorioMixin, FilterView):
_range = [legislatura.data_inicio, legislatura.data_fim] _range = [legislatura.data_inicio, legislatura.data_fim]
elif sessao_legislativa_pk: elif sessao_legislativa_pk:
_range = [sessao_legislativa.data_inicio, sessao_legislativa.data_fim] _range = [sessao_legislativa.data_inicio,
sessao_legislativa.data_fim]
param0.update({'sessao_plenaria__data_inicio__range': _range}) param0.update({'sessao_plenaria__data_inicio__range': _range})
# Parlamentares com Mandato no intervalo de tempo (Ativos) # Parlamentares com Mandato no intervalo de tempo (Ativos)
parlamentares_qs = parlamentares_ativos(_range[0], _range[1]).order_by('nome_parlamentar') parlamentares_qs = parlamentares_ativos(
_range[0], _range[1]).order_by('nome_parlamentar')
parlamentares_id = parlamentares_qs.values_list('id', flat=True) parlamentares_id = parlamentares_qs.values_list('id', flat=True)
# Presenças de cada Parlamentar em Sessões # Presenças de cada Parlamentar em Sessões
presenca_sessao = SessaoPlenariaPresenca.objects.filter(**param0).values_list('parlamentar_id').annotate(sessao_count=Count('id')) presenca_sessao = SessaoPlenariaPresenca.objects.filter(
**param0).values_list('parlamentar_id').annotate(sessao_count=Count('id'))
# Presenças de cada Ordem do Dia # Presenças de cada Ordem do Dia
presenca_ordem = PresencaOrdemDia.objects.filter(**param0).values_list('parlamentar_id').annotate(sessao_count=Count('id')) presenca_ordem = PresencaOrdemDia.objects.filter(
**param0).values_list('parlamentar_id').annotate(sessao_count=Count('id'))
total_ordemdia = PresencaOrdemDia.objects.filter(**param0).distinct('sessao_plenaria__id').order_by('sessao_plenaria__id').count() total_ordemdia = PresencaOrdemDia.objects.filter(
**param0).distinct('sessao_plenaria__id').order_by('sessao_plenaria__id').count()
total_sessao = context['object_list'].count() total_sessao = context['object_list'].count()
username = self.request.user.username username = self.request.user.username
context['exibir_somente_titular'] = self.request.GET.get('exibir_somente_titular') == 'on' context['exibir_somente_titular'] = self.request.GET.get(
context['exibir_somente_ativo'] = self.request.GET.get('exibir_somente_ativo') == 'on' 'exibir_somente_titular') == 'on'
context['exibir_somente_ativo'] = self.request.GET.get(
'exibir_somente_ativo') == 'on'
# Completa o dicionario as informacoes parlamentar/sessao/ordem # Completa o dicionario as informacoes parlamentar/sessao/ordem
parlamentares_presencas = [] parlamentares_presencas = []
@ -594,17 +629,21 @@ class RelatorioPresencaSessaoView(RelatorioMixin, FilterView):
continue continue
try: try:
self.logger.debug(F'user={username}. Tentando obter presença do parlamentar (pk={p.id}).') self.logger.debug(
F'user={username}. Tentando obter presença do parlamentar (pk={p.id}).')
sessao_count = presenca_sessao.get(parlamentar_id=p.id)[1] sessao_count = presenca_sessao.get(parlamentar_id=p.id)[1]
except ObjectDoesNotExist as e: except ObjectDoesNotExist as e:
self.logger.error(F'user={username}. Erro ao obter presença do parlamentar (pk={p.id}). Definido como 0. {str(e)}') self.logger.error(
F'user={username}. Erro ao obter presença do parlamentar (pk={p.id}). Definido como 0. {str(e)}')
sessao_count = 0 sessao_count = 0
try: try:
# Presenças de cada Ordem do Dia # Presenças de cada Ordem do Dia
self.logger.info(F'user={username}. Tentando obter PresencaOrdemDia para o parlamentar pk={p.id}.') self.logger.info(
F'user={username}. Tentando obter PresencaOrdemDia para o parlamentar pk={p.id}.')
ordemdia_count = presenca_ordem.get(parlamentar_id=p.id)[1] ordemdia_count = presenca_ordem.get(parlamentar_id=p.id)[1]
except ObjectDoesNotExist: except ObjectDoesNotExist:
self.logger.error(F'user={username}. Erro ao obter PresencaOrdemDia para o parlamentar pk={p.id}. Definido como 0.') self.logger.error(
F'user={username}. Erro ao obter PresencaOrdemDia para o parlamentar pk={p.id}. Definido como 0.')
ordemdia_count = 0 ordemdia_count = 0
parlamentar.update({ parlamentar.update({
@ -613,9 +652,11 @@ class RelatorioPresencaSessaoView(RelatorioMixin, FilterView):
}) })
if total_sessao != 0: if total_sessao != 0:
parlamentar.update({'sessao_porc': round(sessao_count * 100 / total_sessao, 2)}) parlamentar.update({'sessao_porc': round(
sessao_count * 100 / total_sessao, 2)})
if total_ordemdia != 0: if total_ordemdia != 0:
parlamentar.update({'ordemdia_porc': round(ordemdia_count * 100 / total_ordemdia, 2)}) parlamentar.update({'ordemdia_porc': round(
ordemdia_count * 100 / total_ordemdia, 2)})
parlamentares_presencas.append(parlamentar) parlamentares_presencas.append(parlamentar)
@ -626,10 +667,12 @@ class RelatorioPresencaSessaoView(RelatorioMixin, FilterView):
context['periodo'] = f"{self.request.GET['data_inicio_0']} - {self.request.GET['data_inicio_1']}" context['periodo'] = f"{self.request.GET['data_inicio_0']} - {self.request.GET['data_inicio_1']}"
context['sessao_legislativa'] = '' context['sessao_legislativa'] = ''
context['legislatura'] = '' context['legislatura'] = ''
context['exibir_ordem'] = self.request.GET.get('exibir_ordem_dia') == 'on' context['exibir_ordem'] = self.request.GET.get(
'exibir_ordem_dia') == 'on'
if sessao_legislativa_pk: if sessao_legislativa_pk:
context['sessao_legislativa'] = SessaoLegislativa.objects.get(id=sessao_legislativa_pk) context['sessao_legislativa'] = SessaoLegislativa.objects.get(
id=sessao_legislativa_pk)
if legislatura_pk: if legislatura_pk:
context['legislatura'] = Legislatura.objects.get(id=legislatura_pk) context['legislatura'] = Legislatura.objects.get(id=legislatura_pk)
# ===================================================================== # =====================================================================
@ -650,7 +693,8 @@ class RelatorioHistoricoTramitacaoView(RelatorioMixin, FilterView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(RelatorioHistoricoTramitacaoView, context = super(RelatorioHistoricoTramitacaoView,
self).get_context_data(**kwargs) self).get_context_data(**kwargs)
context['title'] = _('Histórico de Tramitações de Matérias Legislativas') context['title'] = _(
'Histórico de Tramitações de Matérias Legislativas')
if not self.filterset.form.is_valid(): if not self.filterset.form.is_valid():
return context return context
qr = self.request.GET.copy() qr = self.request.GET.copy()
@ -852,7 +896,8 @@ class RelatorioMateriasTramitacaoView(RelatorioMixin, FilterView):
qs = qs.filter(**kwargs) qs = qs.filter(**kwargs)
data['queryset'] = qs data['queryset'] = qs
self.total_resultados_tipos = num_materias_por_tipo(qs, "materia__tipo") self.total_resultados_tipos = num_materias_por_tipo(
qs, "materia__tipo")
return data return data
@ -1072,8 +1117,8 @@ class RelatorioNormasPublicadasMesView(RelatorioMixin, FilterView):
context['ano'] = self.request.GET['ano'] context['ano'] = self.request.GET['ano']
normas_mes = collections.OrderedDict() normas_mes = collections.OrderedDict()
meses = {1: 'Janeiro', 2: 'Fevereiro', 3:'Março', 4: 'Abril', 5: 'Maio', 6:'Junho', meses = {1: 'Janeiro', 2: 'Fevereiro', 3: 'Março', 4: 'Abril', 5: 'Maio', 6: 'Junho',
7: 'Julho', 8: 'Agosto', 9:'Setembro', 10:'Outubro', 11:'Novembro', 12:'Dezembro'} 7: 'Julho', 8: 'Agosto', 9: 'Setembro', 10: 'Outubro', 11: 'Novembro', 12: 'Dezembro'}
for norma in context['object_list']: for norma in context['object_list']:
if not meses[norma.data.month] in normas_mes: if not meses[norma.data.month] in normas_mes:
normas_mes[meses[norma.data.month]] = [] normas_mes[meses[norma.data.month]] = []
@ -1110,16 +1155,17 @@ class RelatorioNormasVigenciaView(RelatorioMixin, FilterView):
if vigencia == 'True': if vigencia == 'True':
qs_dt_not_null = qs.filter(data_vigencia__isnull=True) qs_dt_not_null = qs.filter(data_vigencia__isnull=True)
qs = (qs_dt_not_null | qs.filter(data_vigencia__gte=datetime.datetime.now().date())).distinct() qs = (qs_dt_not_null | qs.filter(
data_vigencia__gte=datetime.datetime.now().date())).distinct()
else: else:
qs = qs.filter(data_vigencia__lt=datetime.datetime.now().date()) qs = qs.filter(
data_vigencia__lt=datetime.datetime.now().date())
kwargs.update({ kwargs.update({
'queryset': qs 'queryset': qs
}) })
return kwargs return kwargs
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(RelatorioNormasVigenciaView, context = super(RelatorioNormasVigenciaView,
self).get_context_data(**kwargs) self).get_context_data(**kwargs)
@ -1129,17 +1175,20 @@ class RelatorioNormasVigenciaView(RelatorioMixin, FilterView):
if not self.filterset.form.is_valid(): if not self.filterset.form.is_valid():
return context return context
normas_totais = NormaJuridica.objects.filter(ano=self.request.GET['ano']) normas_totais = NormaJuridica.objects.filter(
ano=self.request.GET['ano'])
context['quant_total'] = len(normas_totais) context['quant_total'] = len(normas_totais)
if self.request.GET['vigencia'] == 'True': if self.request.GET['vigencia'] == 'True':
context['vigencia'] = 'Vigente' context['vigencia'] = 'Vigente'
context['quant_vigente'] = len(context['object_list']) context['quant_vigente'] = len(context['object_list'])
context['quant_nao_vigente'] = context['quant_total'] - context['quant_vigente'] context['quant_nao_vigente'] = context['quant_total'] - \
context['quant_vigente']
else: else:
context['vigencia'] = 'Não vigente' context['vigencia'] = 'Não vigente'
context['quant_nao_vigente'] = len(context['object_list']) context['quant_nao_vigente'] = len(context['object_list'])
context['quant_vigente'] = context['quant_total'] - context['quant_nao_vigente'] context['quant_vigente'] = context['quant_total'] - \
context['quant_nao_vigente']
qr = self.request.GET.copy() qr = self.request.GET.copy()
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else '' context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
@ -1178,8 +1227,8 @@ class EstatisticasAcessoNormas(TemplateView):
rows = cursor.fetchall() rows = cursor.fetchall()
normas_mes = collections.OrderedDict() normas_mes = collections.OrderedDict()
meses = {1: 'Janeiro', 2: 'Fevereiro', 3:'Março', 4: 'Abril', 5: 'Maio', 6:'Junho', meses = {1: 'Janeiro', 2: 'Fevereiro', 3: 'Março', 4: 'Abril', 5: 'Maio', 6: 'Junho',
7: 'Julho', 8: 'Agosto', 9:'Setembro', 10:'Outubro', 11:'Novembro', 12:'Dezembro'} 7: 'Julho', 8: 'Agosto', 9: 'Setembro', 10: 'Outubro', 11: 'Novembro', 12: 'Dezembro'}
for row in rows: for row in rows:
if not meses[int(row[2])] in normas_mes: if not meses[int(row[2])] in normas_mes:
@ -1189,7 +1238,8 @@ class EstatisticasAcessoNormas(TemplateView):
# Ordena por acesso e limita em 5 # Ordena por acesso e limita em 5
for n in normas_mes: for n in normas_mes:
sorted_by_value = sorted(normas_mes[n], key=lambda kv: kv[1], reverse=True) sorted_by_value = sorted(
normas_mes[n], key=lambda kv: kv[1], reverse=True)
normas_mes[n] = sorted_by_value[0:5] normas_mes[n] = sorted_by_value[0:5]
context['normas_mes'] = normas_mes context['normas_mes'] = normas_mes
@ -1293,6 +1343,7 @@ class ListarInconsistenciasView(PermissionRequiredMixin, ListView):
) )
return tabela return tabela
def materias_anexadas_ciclicas(): def materias_anexadas_ciclicas():
ciclos = [] ciclos = []
@ -1306,7 +1357,8 @@ def materias_anexadas_ciclicas():
ma = anexadas.pop() ma = anexadas.pop()
if ma not in visitados: if ma not in visitados:
visitados.append(ma) visitados.append(ma)
anexadas.extend([a.materia_anexada for a in Anexada.objects.filter(materia_principal=ma)]) anexadas.extend(
[a.materia_anexada for a in Anexada.objects.filter(materia_principal=ma)])
else: else:
ciclo_list = visitados + [ma] ciclo_list = visitados + [ma]
ciclos.append(ciclo_list) ciclos.append(ciclo_list)
@ -1320,6 +1372,7 @@ def materias_anexadas_ciclicas():
return ciclos_unique return ciclos_unique
def is_ciclo_unique(ciclo, ciclos_set): def is_ciclo_unique(ciclo, ciclos_set):
if set(ciclo) not in ciclos_set: if set(ciclo) not in ciclos_set:
ciclos_set.append(set(ciclo)) ciclos_set.append(set(ciclo))
@ -1327,6 +1380,7 @@ def is_ciclo_unique(ciclo, ciclos_set):
else: else:
return False return False
def anexados_ciclicos(ofMateriaLegislativa): def anexados_ciclicos(ofMateriaLegislativa):
ciclicos = [] ciclicos = []
@ -1367,7 +1421,8 @@ def anexados_ciclicos(ofMateriaLegislativa):
) )
anexados_temp.extend(anexados_anexado) anexados_temp.extend(anexados_anexado)
else: else:
ciclicos.append((anexado.data_anexacao, anexado.materia_principal, anexado.materia_anexada)) ciclicos.append(
(anexado.data_anexacao, anexado.materia_principal, anexado.materia_anexada))
else: else:
if anexado.documento_anexado not in anexados_total: if anexado.documento_anexado not in anexados_total:
if not principal['documento_principal'] == anexado.documento_anexado.pk: if not principal['documento_principal'] == anexado.documento_anexado.pk:
@ -1377,7 +1432,8 @@ def anexados_ciclicos(ofMateriaLegislativa):
) )
anexados_temp.extend(anexados_anexado) anexados_temp.extend(anexados_anexado)
else: else:
ciclicos.append((anexado.data_anexacao, anexado.documento_principal, anexado.documento_anexado)) ciclicos.append(
(anexado.data_anexacao, anexado.documento_principal, anexado.documento_anexado))
return ciclicos return ciclicos
@ -1547,10 +1603,12 @@ def parlamentares_filiacoes_intersecao():
for c in combinacoes: for c in combinacoes:
data_filiacao1 = c[0].data data_filiacao1 = c[0].data
data_desfiliacao1 = c[0].data_desfiliacao if c[0].data_desfiliacao else timezone.now().date() data_desfiliacao1 = c[0].data_desfiliacao if c[0].data_desfiliacao else timezone.now(
).date()
data_filiacao2 = c[1].data data_filiacao2 = c[1].data
data_desfiliacao2 = c[1].data_desfiliacao if c[1].data_desfiliacao else timezone.now().date() data_desfiliacao2 = c[1].data_desfiliacao if c[1].data_desfiliacao else timezone.now(
).date()
if data_filiacao1 and data_filiacao2: if data_filiacao1 and data_filiacao2:
exists = intervalos_tem_intersecao( exists = intervalos_tem_intersecao(
@ -1593,10 +1651,12 @@ def parlamentares_mandatos_intersecao():
for c in combinacoes: for c in combinacoes:
data_inicio_mandato1 = c[0].data_inicio_mandato data_inicio_mandato1 = c[0].data_inicio_mandato
data_fim_mandato1 = c[0].data_fim_mandato if c[0].data_fim_mandato else timezone.now().date() data_fim_mandato1 = c[0].data_fim_mandato if c[0].data_fim_mandato else timezone.now(
).date()
data_inicio_mandato2 = c[1].data_inicio_mandato data_inicio_mandato2 = c[1].data_inicio_mandato
data_fim_mandato2 = c[1].data_fim_mandato if c[1].data_fim_mandato else timezone.now().date() data_fim_mandato2 = c[1].data_fim_mandato if c[1].data_fim_mandato else timezone.now(
).date()
if data_inicio_mandato1 and data_inicio_mandato2: if data_inicio_mandato1 and data_inicio_mandato2:
exists = intervalos_tem_intersecao( exists = intervalos_tem_intersecao(
@ -1669,13 +1729,16 @@ def get_estatistica(request):
normas = NormaJuridica.objects.all() normas = NormaJuridica.objects.all()
datas = [ datas = [
materias.order_by('-data_ultima_atualizacao').values_list('data_ultima_atualizacao', flat=True) materias.order_by(
'-data_ultima_atualizacao').values_list('data_ultima_atualizacao', flat=True)
.exclude(data_ultima_atualizacao__isnull=True).first(), .exclude(data_ultima_atualizacao__isnull=True).first(),
normas.order_by('-data_ultima_atualizacao').values_list('data_ultima_atualizacao', flat=True) normas.order_by(
'-data_ultima_atualizacao').values_list('data_ultima_atualizacao', flat=True)
.exclude(data_ultima_atualizacao__isnull=True).first() .exclude(data_ultima_atualizacao__isnull=True).first()
] ]
max_data = max(datas) if datas[0] and datas[1] else next(iter([i for i in datas if i is not None]), '') max_data = max(datas) if datas[0] and datas[1] else next(
iter([i for i in datas if i is not None]), '')
return JsonResponse({ return JsonResponse({
"data_ultima_atualizacao": max_data, "data_ultima_atualizacao": max_data,
@ -1964,7 +2027,8 @@ class DeleteUsuarioView(PermissionRequiredMixin, DeleteView):
try: try:
super(DeleteUsuarioView, self).delete(request, *args, **kwargs) super(DeleteUsuarioView, self).delete(request, *args, **kwargs)
except ProtectedError as exception: except ProtectedError as exception:
error_url = reverse_lazy('sapl.base:user_delete', kwargs={'pk': self.kwargs['pk']}) error_url = reverse_lazy('sapl.base:user_delete', kwargs={
'pk': self.kwargs['pk']})
error_message = "O usuário não pode ser removido, pois é referenciado por:<br><ul>" error_message = "O usuário não pode ser removido, pois é referenciado por:<br><ul>"
for e in exception.protected_objects: for e in exception.protected_objects:
@ -2099,13 +2163,15 @@ class AppConfigCrud(CrudAux):
recibo_prop_atual = AppConfig.objects.last().receber_recibo_proposicao recibo_prop_atual = AppConfig.objects.last().receber_recibo_proposicao
recibo_prop_novo = self.request.POST['receber_recibo_proposicao'] recibo_prop_novo = self.request.POST['receber_recibo_proposicao']
if recibo_prop_novo == 'False' and recibo_prop_atual: if recibo_prop_novo == 'False' and recibo_prop_atual:
props = Proposicao.objects.filter(hash_code='', data_recebimento__isnull=True).exclude(data_envio__isnull=True) props = Proposicao.objects.filter(
hash_code='', data_recebimento__isnull=True).exclude(data_envio__isnull=True)
for prop in props: for prop in props:
try: try:
self.gerar_hash(prop) self.gerar_hash(prop)
except ValidationError as e: except ValidationError as e:
form.add_error('receber_recibo_proposicao',e) form.add_error('receber_recibo_proposicao', e)
msg = _("Não foi possível mudar a configuração porque a Proposição {} não possui texto original vinculado!".format(prop)) msg = _(
"Não foi possível mudar a configuração porque a Proposição {} não possui texto original vinculado!".format(prop))
messages.error(self.request, msg) messages.error(self.request, msg)
return super().form_invalid(form) return super().form_invalid(form)
return super().form_valid(form) return super().form_valid(form)
@ -2117,7 +2183,8 @@ class AppConfigCrud(CrudAux):
inst.texto_original.path, str(inst.pk)) inst.texto_original.path, str(inst.pk))
inst.save() inst.save()
except IOError: except IOError:
raise ValidationError("Existem proposicoes com arquivos inexistentes.") raise ValidationError(
"Existem proposicoes com arquivos inexistentes.")
elif inst.texto_articulado.exists(): elif inst.texto_articulado.exists():
ta = inst.texto_articulado.first() ta = inst.texto_articulado.first()
inst.hash_code = 'P' + ta.hash() + SEPARADOR_HASH_PROPOSICAO + str(inst.pk) inst.hash_code = 'P' + ta.hash() + SEPARADOR_HASH_PROPOSICAO + str(inst.pk)
@ -2136,7 +2203,6 @@ class AppConfigCrud(CrudAux):
reverse('sapl.base:appconfig_update', reverse('sapl.base:appconfig_update',
kwargs={'pk': app_config.pk})) kwargs={'pk': app_config.pk}))
class UpdateView(CrudAux.UpdateView): class UpdateView(CrudAux.UpdateView):
template_name = 'base/AppConfig.html' template_name = 'base/AppConfig.html'
@ -2258,6 +2324,7 @@ class LogotipoView(RedirectView):
logo = casa and casa.logotipo and casa.logotipo.name logo = casa and casa.logotipo and casa.logotipo.name
return os.path.join(settings.MEDIA_URL, logo) if logo else STATIC_LOGO return os.path.join(settings.MEDIA_URL, logo) if logo else STATIC_LOGO
def filtro_campos(dicionario): def filtro_campos(dicionario):
chaves_desejadas = ['ementa', chaves_desejadas = ['ementa',
@ -2280,6 +2347,7 @@ def filtro_campos(dicionario):
return dicionario return dicionario
def pesquisa_textual(request): def pesquisa_textual(request):
if 'q' not in request.GET: if 'q' not in request.GET:
@ -2299,7 +2367,8 @@ def pesquisa_textual(request):
try: try:
sec_dict['pk'] = e.object.pk sec_dict['pk'] = e.object.pk
except: except:
# Index and db are out of sync. Object has been deleted from database # Index and db are out of sync. Object has been deleted from
# database
continue continue
dici = filtro_campos(e.object.__dict__) dici = filtro_campos(e.object.__dict__)
sec_dict['objeto'] = str(dici) sec_dict['objeto'] = str(dici)
@ -2309,7 +2378,6 @@ def pesquisa_textual(request):
json_dict['resultados'].append(sec_dict) json_dict['resultados'].append(sec_dict)
return JsonResponse(json_dict) return JsonResponse(json_dict)
@ -2322,7 +2390,8 @@ class RelatorioHistoricoTramitacaoAdmView(RelatorioMixin, FilterView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super(RelatorioHistoricoTramitacaoAdmView, context = super(RelatorioHistoricoTramitacaoAdmView,
self).get_context_data(**kwargs) self).get_context_data(**kwargs)
context['title'] = _('Histórico de Tramitações de Documento Administrativo') context['title'] = _(
'Histórico de Tramitações de Documento Administrativo')
if not self.filterset.form.is_valid(): if not self.filterset.form.is_valid():
return context return context
qr = self.request.GET.copy() qr = self.request.GET.copy()
@ -2361,6 +2430,7 @@ class RelatorioHistoricoTramitacaoAdmView(RelatorioMixin, FilterView):
return context return context
class RelatorioNormasPorAutorView(RelatorioMixin, FilterView): class RelatorioNormasPorAutorView(RelatorioMixin, FilterView):
model = NormaJuridica model = NormaJuridica
filterset_class = RelatorioNormasPorAutorFilterSet filterset_class = RelatorioNormasPorAutorFilterSet

14
sapl/context_processors.py

@ -1,13 +1,14 @@
import logging import logging
from django.conf import settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from sapl.base.views import get_casalegislativa from sapl.utils import google_recaptcha_configured as google_recaptcha_configured_utils
from sapl.utils import mail_service_configured as mail_service_configured_utils from sapl.utils import mail_service_configured as mail_service_configured_utils
def parliament_info(request): def parliament_info(request):
from sapl.base.views import get_casalegislativa
casa = get_casalegislativa() casa = get_casalegislativa()
if casa: if casa:
return casa.__dict__ return casa.__dict__
@ -22,3 +23,12 @@ def mail_service_configured(request):
logger.warning(_('Servidor de email não configurado.')) logger.warning(_('Servidor de email não configurado.'))
return {'mail_service_configured': False} return {'mail_service_configured': False}
return {'mail_service_configured': True} return {'mail_service_configured': True}
def google_recaptcha_configured(request):
if not google_recaptcha_configured_utils():
logger = logging.getLogger(__name__)
logger.warning(_('Google Recaptcha não configurado.'))
return {'google_recaptcha_configured': False}
return {'google_recaptcha_configured': True}

12
sapl/materia/views.py

@ -56,7 +56,8 @@ from sapl.settings import MAX_DOC_UPLOAD_SIZE, MEDIA_ROOT
from sapl.utils import (autor_label, autor_modal, gerar_hash_arquivo, get_base_url, 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, get_client_ip, get_mime_type_from_file_extension, lista_anexados,
mail_service_configured, montar_row_autor, SEPARADOR_HASH_PROPOSICAO, mail_service_configured, montar_row_autor, SEPARADOR_HASH_PROPOSICAO,
show_results_filter_set, YES_NO_CHOICES, get_tempfile_dir) show_results_filter_set, YES_NO_CHOICES, get_tempfile_dir,
google_recaptcha_configured)
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
AnexadaEmLoteFilterSet, AdicionarVariasAutoriasFilterSet, AnexadaEmLoteFilterSet, AdicionarVariasAutoriasFilterSet,
@ -2090,6 +2091,10 @@ class AcompanhamentoMateriaView(CreateView):
messages.error(request, _('Serviço de Acompanhamento de ' messages.error(request, _('Serviço de Acompanhamento de '
'Matérias não foi configurado')) 'Matérias não foi configurado'))
return redirect('/') return redirect('/')
if not google_recaptcha_configured():
self.logger.warning(_('Google Recaptcha não configurado!'))
messages.error(request, _('Google Recaptcha não configurado!'))
return redirect(request.META.get('HTTP_REFERER', '/'))
pk = self.kwargs['pk'] pk = self.kwargs['pk']
materia = MateriaLegislativa.objects.get(id=pk) materia = MateriaLegislativa.objects.get(id=pk)
@ -2106,6 +2111,11 @@ class AcompanhamentoMateriaView(CreateView):
'Matérias não foi configurado')) 'Matérias não foi configurado'))
return redirect('/') return redirect('/')
if not google_recaptcha_configured():
self.logger.warning(_('Google Recaptcha não configurado!'))
messages.error(request, _('Google Recaptcha não configurado!'))
return redirect(request.META.get('HTTP_REFERER', '/'))
form = AcompanhamentoMateriaForm(request.POST) form = AcompanhamentoMateriaForm(request.POST)
pk = self.kwargs['pk'] pk = self.kwargs['pk']
materia = MateriaLegislativa.objects.get(id=pk) materia = MateriaLegislativa.objects.get(id=pk)

13
sapl/protocoloadm/views.py

@ -40,7 +40,8 @@ from sapl.protocoloadm.models import Protocolo, DocumentoAdministrativo
from sapl.relatorios.views import relatorio_doc_administrativos from sapl.relatorios.views import relatorio_doc_administrativos
from sapl.utils import (create_barcode, get_base_url, get_client_ip, from sapl.utils import (create_barcode, get_base_url, get_client_ip,
get_mime_type_from_file_extension, lista_anexados, get_mime_type_from_file_extension, lista_anexados,
show_results_filter_set, mail_service_configured, from_date_to_datetime_utc) show_results_filter_set, mail_service_configured, from_date_to_datetime_utc,
google_recaptcha_configured)
from .forms import (AcompanhamentoDocumentoForm, AnexadoEmLoteFilterSet, AnexadoForm, from .forms import (AcompanhamentoDocumentoForm, AnexadoEmLoteFilterSet, AnexadoForm,
AnularProtocoloAdmForm, compara_tramitacoes_doc, AnularProtocoloAdmForm, compara_tramitacoes_doc,
@ -200,6 +201,11 @@ class AcompanhamentoDocumentoView(CreateView):
'Documentos não foi configurado')) 'Documentos não foi configurado'))
return redirect('/') return redirect('/')
if not google_recaptcha_configured():
self.logger.warning(_('Google Recaptcha não configurado!'))
messages.error(request, _('Google Recaptcha não configurado!'))
return redirect(request.META.get('HTTP_REFERER', '/'))
pk = self.kwargs['pk'] pk = self.kwargs['pk']
documento = DocumentoAdministrativo.objects.get(id=pk) documento = DocumentoAdministrativo.objects.get(id=pk)
@ -214,6 +220,11 @@ class AcompanhamentoDocumentoView(CreateView):
'Documentos não foi configurado')) 'Documentos não foi configurado'))
return redirect('/') return redirect('/')
if not google_recaptcha_configured():
self.logger.warning(_('Google Recaptcha não configurado!'))
messages.error(request, _('Google Recaptcha não configurado!'))
return redirect(request.META.get('HTTP_REFERER', '/'))
form = AcompanhamentoDocumentoForm(request.POST) form = AcompanhamentoDocumentoForm(request.POST)
pk = self.kwargs['pk'] pk = self.kwargs['pk']
documento = DocumentoAdministrativo.objects.get(id=pk) documento = DocumentoAdministrativo.objects.get(id=pk)

2
sapl/settings.py

@ -195,6 +195,8 @@ TEMPLATES = [
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
'sapl.context_processors.parliament_info', 'sapl.context_processors.parliament_info',
'sapl.context_processors.mail_service_configured', 'sapl.context_processors.mail_service_configured',
'sapl.context_processors.google_recaptcha_configured',
], ],
'debug': DEBUG 'debug': DEBUG
}, },

3
sapl/templates/base/layouts.yaml

@ -55,6 +55,9 @@ AppConfig:
- cronometro_ordem cronometro_consideracoes - cronometro_ordem cronometro_consideracoes
- mostrar_brasao_painel - mostrar_brasao_painel
{% trans 'Segurança' %}:
- google_recaptcha_site_key google_recaptcha_secret_key
TipoAutor: TipoAutor:
{% trans 'Tipo Autor' %}: {% trans 'Tipo Autor' %}:
- descricao - descricao

5
sapl/templates/base/login.html

@ -41,7 +41,12 @@
</tr> </tr>
</table> </table>
</p> </p>
{% if google_recaptcha_configured %}
<h5><a href="{% url 'sapl.base:recuperar_senha_email' %}"><center>Esqueceu sua senha?</center></a></h6> <h5><a href="{% url 'sapl.base:recuperar_senha_email' %}"><center>Esqueceu sua senha?</center></a></h6>
{% else %}
<br>
{% endif %}
<p class="bs-component"> <p class="bs-component">
<center> <center>
<input class="btn btn-lg btn-success btn-block" type="submit" value="login" /> <input class="btn btn-lg btn-success btn-block" type="submit" value="login" />

2
sapl/templates/materia/materialegislativa_detail.html

@ -3,7 +3,7 @@
{% block sub_actions %} {% block sub_actions %}
{{ block.super }} {{ block.super }}
{% if object.em_tramitacao and mail_service_configured %} {% if object.em_tramitacao and mail_service_configured and google_recaptcha_configured %}
<div class="actions btn-group btn-group-sm" role="group"> <div class="actions btn-group btn-group-sm" role="group">
<a href="{% url 'sapl.materia:acompanhar_materia' object.id %}" class="btn btn-outline-primary">Acompanhar Matéria</a> <a href="{% url 'sapl.materia:acompanhar_materia' object.id %}" class="btn btn-outline-primary">Acompanhar Matéria</a>
</div> </div>

2
sapl/templates/materia/materialegislativa_filter.html

@ -156,7 +156,7 @@
{% endfor %} {% endfor %}
{% endif %} {% endif %}
<p></p> <p></p>
{% if m.em_tramitacao and mail_service_configured %} {% if m.em_tramitacao and mail_service_configured and google_recaptcha_configured %}
<a href="{% url 'sapl.materia:acompanhar_materia' m.id %}">Acompanhar Matéria</a> <a href="{% url 'sapl.materia:acompanhar_materia' m.id %}">Acompanhar Matéria</a>
{% endif %} {% endif %}
{% endif %} {% endif %}

2
sapl/templates/protocoloadm/documentoadministrativo_filter.html

@ -63,7 +63,7 @@
{% if d.texto_integral %} {% if d.texto_integral %}
<strong><a href="{{ d.texto_integral.url }}">Texto Integral</a></strong></br> <strong><a href="{{ d.texto_integral.url }}">Texto Integral</a></strong></br>
{% endif %} {% endif %}
{% if d.tramitacao and mail_service_configured %} {% if d.tramitacao and mail_service_configured and google_recaptcha_configured %}
<a href="{% url 'sapl.protocoloadm:acompanhar_documento' d.id %}">Acompanhar Documento</a> <a href="{% url 'sapl.protocoloadm:acompanhar_documento' d.id %}">Acompanhar Documento</a>
{% endif %} {% endif %}
</td> </td>

15
sapl/utils.py

@ -1010,6 +1010,13 @@ def mail_service_configured(request=None):
return settings.EMAIL_RUNNING return settings.EMAIL_RUNNING
def google_recaptcha_configured():
logger = logging.getLogger(__name__)
from sapl.base.models import AppConfig
return not AppConfig.attr('google_recaptcha_site_key') == ''
def lista_anexados(principal, isMateriaLegislativa=True): def lista_anexados(principal, isMateriaLegislativa=True):
anexados_total = [] anexados_total = []
if isMateriaLegislativa: # MateriaLegislativa if isMateriaLegislativa: # MateriaLegislativa
@ -1078,6 +1085,8 @@ class GoogleRecapthaMixin:
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
from sapl.base.models import AppConfig
title_label = kwargs.pop('title_label') title_label = kwargs.pop('title_label')
action_label = kwargs.pop('action_label') action_label = kwargs.pop('action_label')
@ -1085,7 +1094,7 @@ class GoogleRecapthaMixin:
[ [
(Div( (Div(
css_class="g-recaptcha float-right", # if not settings.DEBUG else '', css_class="g-recaptcha float-right", # if not settings.DEBUG else '',
data_sitekey=settings.GOOGLE_RECAPTCHA_SITE_KEY data_sitekey=AppConfig.attr('google_recaptcha_site_key')
), 5), ), 5),
('email', 7), ('email', 7),
@ -1114,6 +1123,8 @@ class GoogleRecapthaMixin:
raise ValidationError( raise ValidationError(
_('Verificação do reCAPTCHA não efetuada.')) _('Verificação do reCAPTCHA não efetuada.'))
from sapl.base.models import AppConfig
import urllib3 import urllib3
import json import json
@ -1121,7 +1132,7 @@ class GoogleRecapthaMixin:
url = ('https://www.google.com/recaptcha/api/siteverify?' url = ('https://www.google.com/recaptcha/api/siteverify?'
'secret=%s' 'secret=%s'
'&response=%s' % (settings.GOOGLE_RECAPTCHA_SECRET_KEY, '&response=%s' % (AppConfig.attr('google_recaptcha_secret_key'),
recaptcha)) recaptcha))
http = urllib3.PoolManager() http = urllib3.PoolManager()

Loading…
Cancel
Save