mirror of https://github.com/interlegis/sapl.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
547 lines
20 KiB
547 lines
20 KiB
|
|
from django.conf import settings
|
|
from django.contrib.auth import get_user_model
|
|
from django.contrib.auth.mixins import PermissionRequiredMixin
|
|
from django.contrib.auth.models import Group
|
|
from django.contrib.auth.tokens import default_token_generator
|
|
from django.core.exceptions import ObjectDoesNotExist
|
|
from django.core.mail import send_mail
|
|
from django.core.urlresolvers import reverse
|
|
from django.db.models import Count
|
|
from django.http import HttpResponseRedirect
|
|
from django.utils.encoding import force_bytes
|
|
from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode
|
|
from django.utils.translation import ugettext_lazy as _
|
|
from django.views.generic.base import TemplateView
|
|
from django_filters.views import FilterView
|
|
from haystack.views import SearchView
|
|
|
|
from sapl.base.forms import AutorForm, AutorFormForAdmin, TipoAutorForm
|
|
from sapl.base.models import Autor, TipoAutor
|
|
from sapl.crud.base import CrudAux
|
|
from sapl.materia.models import (Autoria, MateriaLegislativa,
|
|
TipoMateriaLegislativa)
|
|
from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria,
|
|
SessaoPlenariaPresenca)
|
|
from sapl.utils import parlamentares_ativos, sapl_logger
|
|
|
|
from .forms import (CasaLegislativaForm, ConfiguracoesAppForm,
|
|
RelatorioAtasFilterSet,
|
|
RelatorioHistoricoTramitacaoFilterSet,
|
|
RelatorioMateriasPorAnoAutorTipoFilterSet,
|
|
RelatorioMateriasPorAutorFilterSet,
|
|
RelatorioMateriasTramitacaoilterSet,
|
|
RelatorioPresencaSessaoFilterSet)
|
|
from .models import AppConfig, CasaLegislativa
|
|
|
|
|
|
def get_casalegislativa():
|
|
return CasaLegislativa.objects.first()
|
|
|
|
|
|
class ConfirmarEmailView(TemplateView):
|
|
template_name = "email/confirma.html"
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
uid = urlsafe_base64_decode(self.kwargs['uidb64'])
|
|
user = get_user_model().objects.get(id=uid)
|
|
user.is_active = True
|
|
user.save()
|
|
context = self.get_context_data(**kwargs)
|
|
return self.render_to_response(context)
|
|
|
|
|
|
class TipoAutorCrud(CrudAux):
|
|
model = TipoAutor
|
|
help_path = 'tipo-autor'
|
|
|
|
class BaseMixin(CrudAux.BaseMixin):
|
|
list_field_names = ['descricao', 'content_type']
|
|
form_class = TipoAutorForm
|
|
|
|
|
|
class AutorCrud(CrudAux):
|
|
model = Autor
|
|
help_path = 'autor'
|
|
|
|
class BaseMixin(CrudAux.BaseMixin):
|
|
list_field_names = ['tipo', 'nome', 'user']
|
|
|
|
class DeleteView(CrudAux.DeleteView):
|
|
|
|
def delete(self, *args, **kwargs):
|
|
self.object = self.get_object()
|
|
|
|
if self.object.user:
|
|
# FIXME melhorar captura de grupo de Autor, levando em conta
|
|
# trad
|
|
grupo = Group.objects.filter(name='Autor')[0]
|
|
self.object.user.groups.remove(grupo)
|
|
|
|
return CrudAux.DeleteView.delete(self, *args, **kwargs)
|
|
|
|
class UpdateView(CrudAux.UpdateView):
|
|
layout_key = None
|
|
form_class = AutorForm
|
|
|
|
def form_valid(self, form):
|
|
# devido a implement do form o form_valid do Crud deve ser pulado
|
|
return super(CrudAux.UpdateView, self).form_valid(form)
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
if request.user.is_superuser:
|
|
self.form_class = AutorFormForAdmin
|
|
return CrudAux.UpdateView.post(self, request, *args, **kwargs)
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
if request.user.is_superuser:
|
|
self.form_class = AutorFormForAdmin
|
|
return CrudAux.UpdateView.get(self, request, *args, **kwargs)
|
|
|
|
def get_success_url(self):
|
|
pk_autor = self.object.id
|
|
url_reverse = reverse('sapl.base:autor_detail',
|
|
kwargs={'pk': pk_autor})
|
|
try:
|
|
kwargs = {}
|
|
user = self.object.user
|
|
|
|
if not user:
|
|
return url_reverse
|
|
|
|
kwargs['token'] = default_token_generator.make_token(user)
|
|
kwargs['uidb64'] = urlsafe_base64_encode(force_bytes(user.pk))
|
|
assunto = "SAPL - Confirmação de Conta"
|
|
full_url = self.request.get_raw_uri()
|
|
url_base = full_url[:full_url.find('sistema') - 1]
|
|
|
|
mensagem = (
|
|
"Este e-mail foi utilizado para fazer cadastro no " +
|
|
"SAPL com o perfil de Autor. Agora você pode " +
|
|
"criar/editar/enviar Proposições.\n" +
|
|
"Seu nome de usuário é: " +
|
|
self.request.POST['username'] + "\n"
|
|
"Caso você não tenha feito este cadastro, por favor " +
|
|
"ignore esta mensagem. Caso tenha, clique " +
|
|
"no link abaixo\n" + url_base +
|
|
reverse('sapl.base:confirmar_email', kwargs=kwargs))
|
|
remetente = [settings.EMAIL_SEND_USER]
|
|
destinatario = [user.email]
|
|
send_mail(assunto, mensagem, remetente, destinatario,
|
|
fail_silently=False)
|
|
except:
|
|
sapl_logger.error(
|
|
_('Erro no envio de email na edição de Autores.'))
|
|
return url_reverse
|
|
|
|
class CreateView(CrudAux.CreateView):
|
|
form_class = AutorForm
|
|
layout_key = None
|
|
|
|
def post(self, request, *args, **kwargs):
|
|
if request.user.is_superuser:
|
|
self.form_class = AutorFormForAdmin
|
|
return CrudAux.CreateView.post(self, request, *args, **kwargs)
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
if request.user.is_superuser:
|
|
self.form_class = AutorFormForAdmin
|
|
return CrudAux.CreateView.get(self, request, *args, **kwargs)
|
|
|
|
def get_success_url(self):
|
|
pk_autor = self.object.id
|
|
url_reverse = reverse('sapl.base:autor_detail',
|
|
kwargs={'pk': pk_autor})
|
|
try:
|
|
kwargs = {}
|
|
user = self.object.user
|
|
|
|
if not user:
|
|
return url_reverse
|
|
|
|
kwargs['token'] = default_token_generator.make_token(user)
|
|
kwargs['uidb64'] = urlsafe_base64_encode(force_bytes(user.pk))
|
|
assunto = "SAPL - Confirmação de Conta"
|
|
full_url = self.request.get_raw_uri()
|
|
url_base = full_url[:full_url.find('sistema') - 1]
|
|
|
|
mensagem = (
|
|
"Este e-mail foi utilizado para fazer cadastro no " +
|
|
"SAPL com o perfil de Autor. Agora você pode " +
|
|
"criar/editar/enviar Proposições.\n" +
|
|
"Seu nome de usuário é: " +
|
|
self.request.POST['username'] + "\n"
|
|
"Caso você não tenha feito este cadastro, por favor " +
|
|
"ignore esta mensagem. Caso tenha, clique " +
|
|
"no link abaixo\n" + url_base +
|
|
reverse('sapl.base:confirmar_email', kwargs=kwargs))
|
|
remetente = [settings.EMAIL_SEND_USER]
|
|
destinatario = [user.email]
|
|
send_mail(assunto, mensagem, remetente, destinatario,
|
|
fail_silently=False)
|
|
except:
|
|
sapl_logger.error(
|
|
_('Erro no envio de email na criação de Autores.'))
|
|
return url_reverse
|
|
|
|
|
|
class RelatorioAtasView(FilterView):
|
|
model = SessaoPlenaria
|
|
filterset_class = RelatorioAtasFilterSet
|
|
template_name = 'base/RelatorioAtas_filter.html'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(RelatorioAtasView,
|
|
self).get_context_data(**kwargs)
|
|
context['title'] = _('Atas das Sessões Plenárias')
|
|
|
|
# Verifica se os campos foram preenchidos
|
|
if not self.filterset.form.is_valid():
|
|
return context
|
|
|
|
context['object_list'] = context['object_list'].exclude(upload_ata='')
|
|
qr = self.request.GET.copy()
|
|
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
|
|
return context
|
|
|
|
|
|
class RelatorioPresencaSessaoView(FilterView):
|
|
model = SessaoPlenaria
|
|
filterset_class = RelatorioPresencaSessaoFilterSet
|
|
template_name = 'base/RelatorioPresencaSessao_filter.html'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(RelatorioPresencaSessaoView,
|
|
self).get_context_data(**kwargs)
|
|
context['title'] = _('Presença dos parlamentares nas sessões')
|
|
|
|
# Verifica se os campos foram preenchidos
|
|
if not self.filterset.form.is_valid():
|
|
return context
|
|
|
|
# =====================================================================
|
|
if 'salvar' in self.request.GET:
|
|
where = context['object_list'].query.where
|
|
_range = where.children[0].rhs
|
|
|
|
sufixo = 'sessao_plenaria__data_inicio__range'
|
|
param0 = {'%s' % sufixo: _range}
|
|
|
|
# Parlamentares com Mandato no intervalo de tempo (Ativos)
|
|
parlamentares_qs = parlamentares_ativos(
|
|
_range[0], _range[1]).order_by('nome_parlamentar')
|
|
parlamentares_id = parlamentares_qs.values_list(
|
|
'id', flat=True)
|
|
|
|
# Presenças de cada Parlamentar em Sessões
|
|
presenca_sessao = SessaoPlenariaPresenca.objects.filter(
|
|
parlamentar_id__in=parlamentares_id,
|
|
sessao_plenaria__data_inicio__range=_range).values_list(
|
|
'parlamentar_id').annotate(
|
|
sessao_count=Count('id'))
|
|
|
|
# Presenças de cada Ordem do Dia
|
|
presenca_ordem = PresencaOrdemDia.objects.filter(
|
|
parlamentar_id__in=parlamentares_id,
|
|
sessao_plenaria__data_inicio__range=_range).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_sessao = context['object_list'].count()
|
|
|
|
# Completa o dicionario as informacoes parlamentar/sessao/ordem
|
|
parlamentares_presencas = []
|
|
for i, p in enumerate(parlamentares_qs):
|
|
parlamentares_presencas.append({
|
|
'parlamentar': p,
|
|
'sessao_porc': 0,
|
|
'ordemdia_porc': 0
|
|
})
|
|
try:
|
|
sessao_count = presenca_sessao.get(parlamentar_id=p.id)[1]
|
|
except ObjectDoesNotExist:
|
|
sessao_count = 0
|
|
try:
|
|
ordemdia_count = presenca_ordem.get(parlamentar_id=p.id)[1]
|
|
except ObjectDoesNotExist:
|
|
ordemdia_count = 0
|
|
|
|
parlamentares_presencas[i].update({
|
|
'sessao_count': sessao_count,
|
|
'ordemdia_count': ordemdia_count
|
|
})
|
|
|
|
if total_sessao != 0:
|
|
parlamentares_presencas[i].update(
|
|
{'sessao_porc': round(
|
|
sessao_count * 100 / total_sessao, 2)})
|
|
if total_ordemdia != 0:
|
|
parlamentares_presencas[i].update(
|
|
{'ordemdia_porc': round(
|
|
ordemdia_count * 100 / total_ordemdia, 2)})
|
|
|
|
context['date_range'] = _range
|
|
context['total_ordemdia'] = total_ordemdia
|
|
context['total_sessao'] = context['object_list'].count()
|
|
context['parlamentares'] = parlamentares_presencas
|
|
context['periodo'] = (
|
|
self.request.GET['data_inicio_0'] +
|
|
' - ' + self.request.GET['data_inicio_1'])
|
|
# =====================================================================
|
|
qr = self.request.GET.copy()
|
|
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
|
|
return context
|
|
|
|
|
|
class RelatorioHistoricoTramitacaoView(FilterView):
|
|
model = MateriaLegislativa
|
|
filterset_class = RelatorioHistoricoTramitacaoFilterSet
|
|
template_name = 'base/RelatorioHistoricoTramitacao_filter.html'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(RelatorioHistoricoTramitacaoView,
|
|
self).get_context_data(**kwargs)
|
|
context['title'] = _('Histórico de Tramitações')
|
|
qr = self.request.GET.copy()
|
|
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
|
|
return context
|
|
|
|
|
|
class RelatorioMateriasTramitacaoView(FilterView):
|
|
model = MateriaLegislativa
|
|
filterset_class = RelatorioMateriasTramitacaoilterSet
|
|
template_name = 'base/RelatorioMateriasPorTramitacao_filter.html'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(RelatorioMateriasTramitacaoView,
|
|
self).get_context_data(**kwargs)
|
|
|
|
context['title'] = _('Matérias por Ano, Autor e Tipo')
|
|
|
|
qs = context['object_list']
|
|
qs = qs.filter(em_tramitacao=True)
|
|
context['object_list'] = qs
|
|
|
|
qtdes = {}
|
|
for tipo in TipoMateriaLegislativa.objects.all():
|
|
qs = context['object_list']
|
|
qtde = len(qs.filter(tipo_id=tipo.id))
|
|
if qtde > 0:
|
|
qtdes[tipo] = qtde
|
|
context['qtdes'] = qtdes
|
|
|
|
qr = self.request.GET.copy()
|
|
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
|
|
|
|
return context
|
|
|
|
|
|
class RelatorioMateriasPorAnoAutorTipoView(FilterView):
|
|
model = MateriaLegislativa
|
|
filterset_class = RelatorioMateriasPorAnoAutorTipoFilterSet
|
|
template_name = 'base/RelatorioMateriasPorAnoAutorTipo_filter.html'
|
|
|
|
def get_materias_autor_ano(self, ano):
|
|
|
|
autorias = Autoria.objects.filter(materia__ano=ano).values(
|
|
'autor',
|
|
'materia__tipo__sigla',
|
|
'materia__tipo__descricao').annotate(
|
|
total=Count('materia__tipo')).order_by(
|
|
'autor',
|
|
'materia__tipo')
|
|
|
|
autores_ids = set([i['autor'] for i in autorias])
|
|
|
|
autores = dict((a.id, a) for a in Autor.objects.filter(
|
|
id__in=autores_ids))
|
|
|
|
relatorio = []
|
|
visitados = set()
|
|
curr = None
|
|
|
|
for a in autorias:
|
|
# se mudou autor, salva atual, caso existente, e reinicia `curr`
|
|
if a['autor'] not in visitados:
|
|
if curr:
|
|
relatorio.append(curr)
|
|
|
|
curr = {}
|
|
curr['autor'] = autores[a['autor']]
|
|
curr['materia'] = []
|
|
curr['total'] = 0
|
|
|
|
visitados.add(a['autor'])
|
|
|
|
# atualiza valores
|
|
curr['materia'].append((a['materia__tipo__descricao'], a['total']))
|
|
curr['total'] += a['total']
|
|
# adiciona o ultimo
|
|
relatorio.append(curr)
|
|
|
|
return relatorio
|
|
|
|
|
|
def get_filterset_kwargs(self, filterset_class):
|
|
super(RelatorioMateriasPorAnoAutorTipoView,
|
|
self).get_filterset_kwargs(filterset_class)
|
|
|
|
kwargs = {'data': self.request.GET or None}
|
|
return kwargs
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(RelatorioMateriasPorAnoAutorTipoView,
|
|
self).get_context_data(**kwargs)
|
|
|
|
context['title'] = _('Matérias por Ano, Autor e Tipo')
|
|
|
|
qtdes = {}
|
|
for tipo in TipoMateriaLegislativa.objects.all():
|
|
qs = kwargs['object_list']
|
|
qtde = len(qs.filter(tipo_id=tipo.id))
|
|
if qtde > 0:
|
|
qtdes[tipo] = qtde
|
|
context['qtdes'] = qtdes
|
|
|
|
qr = self.request.GET.copy()
|
|
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
|
|
|
|
if 'ano' in self.request.GET and self.request.GET['ano']:
|
|
ano = int(self.request.GET['ano'])
|
|
context['relatorio'] = self.get_materias_autor_ano(ano)
|
|
else:
|
|
context['relatorio'] = []
|
|
|
|
return context
|
|
|
|
|
|
class RelatorioMateriasPorAutorView(FilterView):
|
|
model = MateriaLegislativa
|
|
filterset_class = RelatorioMateriasPorAutorFilterSet
|
|
template_name = 'base/RelatorioMateriasPorAutor_filter.html'
|
|
|
|
def get_filterset_kwargs(self, filterset_class):
|
|
super(RelatorioMateriasPorAutorView,
|
|
self).get_filterset_kwargs(filterset_class)
|
|
|
|
kwargs = {'data': self.request.GET or None}
|
|
return kwargs
|
|
|
|
def get_context_data(self, **kwargs):
|
|
context = super(RelatorioMateriasPorAutorView,
|
|
self).get_context_data(**kwargs)
|
|
|
|
context['title'] = _('Matérias por Autor')
|
|
|
|
qtdes = {}
|
|
for tipo in TipoMateriaLegislativa.objects.all():
|
|
qs = kwargs['object_list']
|
|
qtde = len(qs.filter(tipo_id=tipo.id))
|
|
if qtde > 0:
|
|
qtdes[tipo] = qtde
|
|
context['qtdes'] = qtdes
|
|
|
|
qr = self.request.GET.copy()
|
|
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
|
|
|
|
return context
|
|
|
|
|
|
class CasaLegislativaCrud(CrudAux):
|
|
model = CasaLegislativa
|
|
|
|
class BaseMixin(CrudAux.BaseMixin):
|
|
list_field_names = ['codigo', 'nome', 'sigla']
|
|
form_class = CasaLegislativaForm
|
|
|
|
class ListView(CrudAux.ListView):
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
casa = get_casalegislativa()
|
|
if casa:
|
|
return HttpResponseRedirect(
|
|
reverse('sapl.base:casalegislativa_detail',
|
|
kwargs={'pk': casa.pk}))
|
|
else:
|
|
return HttpResponseRedirect(
|
|
reverse('sapl.base:casalegislativa_create'))
|
|
|
|
class DetailView(CrudAux.DetailView):
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
return HttpResponseRedirect(
|
|
reverse('sapl.base:casalegislativa_update',
|
|
kwargs={'pk': self.kwargs['pk']}))
|
|
|
|
|
|
class HelpView(PermissionRequiredMixin, TemplateView):
|
|
# XXX treat non existing template as a 404!!!!
|
|
|
|
def get_template_names(self):
|
|
return ['ajuda/%s.html' % self.kwargs['topic']]
|
|
|
|
|
|
class AppConfigCrud(CrudAux):
|
|
model = AppConfig
|
|
|
|
class BaseMixin(CrudAux.BaseMixin):
|
|
form_class = ConfiguracoesAppForm
|
|
|
|
@property
|
|
def list_url(self):
|
|
return ''
|
|
|
|
@property
|
|
def create_url(self):
|
|
return ''
|
|
|
|
class CreateView(CrudAux.CreateView):
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
app_config = AppConfig.objects.last()
|
|
if app_config:
|
|
return HttpResponseRedirect(
|
|
reverse('sapl.base:appconfig_update',
|
|
kwargs={'pk': app_config.pk}))
|
|
else:
|
|
self.object = None
|
|
return super(CrudAux.CreateView, self).get(
|
|
request, *args, **kwargs)
|
|
|
|
class ListView(CrudAux.ListView):
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
return HttpResponseRedirect(reverse('sapl.base:appconfig_create'))
|
|
|
|
class DetailView(CrudAux.DetailView):
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
return HttpResponseRedirect(reverse('sapl.base:appconfig_create'))
|
|
|
|
class DeleteView(CrudAux.DeleteView):
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
return HttpResponseRedirect(reverse('sapl.base:appconfig_create'))
|
|
|
|
|
|
class SaplSearchView(SearchView):
|
|
results_per_page = 10
|
|
|
|
def get_context(self):
|
|
context = super(SaplSearchView, self).get_context()
|
|
|
|
if 'models' in self.request.GET:
|
|
models = self.request.GET.getlist('models')
|
|
else:
|
|
models = []
|
|
|
|
context['models'] = ''
|
|
|
|
for m in models:
|
|
context['models'] = context['models'] + '&models=' + m
|
|
|
|
return context
|
|
|