diff --git a/README.rst b/README.rst index c245a89aa..6a7a74b91 100644 --- a/README.rst +++ b/README.rst @@ -31,7 +31,7 @@ Instalar as seguintes dependências do sistema:: sudo apt-get install git nginx python3-dev libpq-dev graphviz-dev graphviz \ pkg-config postgresql postgresql-contrib pgadmin3 python-psycopg2 \ software-properties-common build-essential libxml2-dev libjpeg-dev \ - libssl-dev libffi-dev libxslt1-dev python3-setuptools curl + libmysqlclient-dev libssl-dev libffi-dev libxslt1-dev python3-setuptools curl sudo easy_install3 pip lxml diff --git a/sapl/base/forms.py b/sapl/base/forms.py index 451b4b353..fde5c9393 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -273,12 +273,13 @@ class AutorForm(ModelForm): msg = _('Os emails não conferem.') self.valida_igualdade(cd['email'], cd['confirma_email'], msg) - if qs_user.filter(email=cd['email']).exists(): - raise ValidationError(_('Este email já foi cadastrado.')) + if not settings.DEBUG: + if qs_user.filter(email=cd['email']).exists(): + raise ValidationError(_('Este email já foi cadastrado.')) - if qs_autor.filter(user__email=cd['email']).exists(): - raise ValidationError( - _('Já existe um Autor com este email.')) + if qs_autor.filter(user__email=cd['email']).exists(): + raise ValidationError( + _('Já existe um Autor com este email.')) elif cd['action_user'] == 'A': if not User.objects.filter(username=cd['username']).exists(): @@ -390,8 +391,7 @@ class AutorForm(ModelForm): user_old.groups.remove(grupo) elif user_old: user_old.groups.remove(grupo) - else: - + elif user_old: user_old.groups.remove(grupo) return autor diff --git a/sapl/base/urls.py b/sapl/base/urls.py index e06580cfa..4fbda888b 100644 --- a/sapl/base/urls.py +++ b/sapl/base/urls.py @@ -3,7 +3,7 @@ from django.contrib.auth import views from django.contrib.auth.decorators import permission_required from django.views.generic.base import TemplateView -from sapl.base.views import AutorCrud, TipoAutorCrud +from sapl.base.views import AutorCrud, TipoAutorCrud, ConfirmarEmailView from .apps import AppConfig from .forms import LoginForm @@ -52,6 +52,11 @@ urlpatterns = [ RelatorioAtasView.as_view(), name='atas'), + url(r'^email/validate/(?P[0-9A-Za-z_\-]+)/' + '(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})$', + ConfirmarEmailView.as_view(), name='confirmar_email'), + + # todos os sublink s de sistema devem vir acima deste url(r'^sistema/', permission_required('base.view_tabelas_auxiliares') (TemplateView.as_view(template_name='sistema.html'))), diff --git a/sapl/base/views.py b/sapl/base/views.py index 9d41fe106..524375e2b 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -1,5 +1,6 @@ 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 @@ -8,7 +9,7 @@ from django.core.urlresolvers import reverse from django.db.models import Count, Q from django.http import HttpResponseRedirect from django.utils.encoding import force_bytes -from django.utils.http import urlsafe_base64_encode +from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode from django.utils.translation import ugettext_lazy as _ from django.views.generic.base import TemplateView from django_filters.views import FilterView @@ -21,6 +22,7 @@ from sapl.crud.base import CrudAux from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa from sapl.parlamentares.models import Parlamentar from sapl.sessao.models import OrdemDia, SessaoPlenaria +from sapl.utils import sapl_logger from .forms import (CasaLegislativaForm, ConfiguracoesAppForm, RelatorioAtasFilterSet, @@ -36,6 +38,18 @@ 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' @@ -57,9 +71,11 @@ class AutorCrud(CrudAux): def delete(self, *args, **kwargs): self.object = self.get_object() - # FIXME melhorar captura de grupo de Autor, levando em conta trad - grupo = Group.objects.filter(name='Autor')[0] - self.object.user.groups.remove(grupo) + 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) @@ -67,50 +83,65 @@ class AutorCrud(CrudAux): 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): - - # FIXME try except - testar envio de emails - pk_autor = self.object.id - kwargs = {} - user = self.object.user - - """if user.is_active: - return reverse('sapl.base:autor_detail', - kwargs={'pk': pk_autor})""" - - 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.materia:confirmar_email', kwargs=kwargs)) - remetente = [settings.EMAIL_SEND_USER] - destinatario = [user.email] - send_mail(assunto, mensagem, remetente, destinatario, - fail_silently=False) - return reverse('sapl.base:autor_detail', - kwargs={'pk': pk_autor}) + 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 @@ -118,32 +149,39 @@ class AutorCrud(CrudAux): def get_success_url(self): pk_autor = self.object.id - # FIXME try except - testar envio de emails - kwargs = {} - user = self.object.user - 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.materia:confirmar_email', kwargs=kwargs)) - remetente = settings.EMAIL_SEND_USER - destinatario = [user.email] - send_mail(assunto, mensagem, remetente, destinatario, - fail_silently=False) - - return reverse('sapl.base:autor_detail', - kwargs={'pk': pk_autor}) + 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): diff --git a/sapl/materia/urls.py b/sapl/materia/urls.py index a6f85016a..5400978c6 100644 --- a/sapl/materia/urls.py +++ b/sapl/materia/urls.py @@ -3,7 +3,7 @@ from django.conf.urls import include, url from sapl.materia.views import (AcompanhamentoConfirmarView, AcompanhamentoExcluirView, AcompanhamentoMateriaView, AnexadaCrud, - AutoriaCrud, ConfirmarEmailView, + AutoriaCrud, ConfirmarProposicao, DespachoInicialCrud, DocumentoAcessorioCrud, DocumentoAcessorioEmLoteView, @@ -39,9 +39,6 @@ urlpatterns_materia = [ url(r'^materia/(?P[0-9]+)/ta$', MateriaTaView.as_view(), name='materia_ta'), - url(r'^materia/confirmar/(?P[0-9A-Za-z_\-]+)/' - '(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})$', - ConfirmarEmailView.as_view(), name='confirmar_email'), url(r'^materia/pesquisar-materia$', MateriaLegislativaPesquisaView.as_view(), name='pesquisar_materia'), diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 54309b0f7..d7354123e 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -106,28 +106,23 @@ class ProposicaoTaView(IntegracaoTaView): @permission_required_for_app(app_label=apps.AppConfig.label) def recuperar_materia(request): tipo = TipoMateriaLegislativa.objects.get(pk=request.GET['tipo']) - materia = MateriaLegislativa.objects.filter(tipo=tipo).last() + ano = request.GET.get('ano', '') + + param = {'tipo': tipo} + param['data_apresentacao__year'] = ano if ano else datetime.now().year + + materia = MateriaLegislativa.objects.filter(**param).order_by( + 'tipo', 'ano', 'numero').values_list('numero', 'ano').last() if materia: - response = JsonResponse({'numero': materia.numero + 1, - 'ano': datetime.now().year}) + response = JsonResponse({'numero': materia[0] + 1, + 'ano': materia[1]}) else: - response = JsonResponse({'numero': 1, 'ano': datetime.now().year}) + response = JsonResponse( + {'numero': 1, 'ano': ano if ano else datetime.now().year}) return response -class ConfirmarEmailView(TemplateView): - template_name = "confirma_email.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) - - OrgaoCrud = CrudAux.build(Orgao, 'orgao') StatusTramitacaoCrud = CrudAux.build(StatusTramitacao, 'status_tramitacao') UnidadeTramitacaoCrud = CrudAux.build(UnidadeTramitacao, 'unidade_tramitacao') diff --git a/sapl/templates/confirma_email.html b/sapl/templates/email/confirma.html similarity index 100% rename from sapl/templates/confirma_email.html rename to sapl/templates/email/confirma.html diff --git a/sapl/templates/materia/layouts.yaml b/sapl/templates/materia/layouts.yaml index 6653abc84..6c0a3742b 100644 --- a/sapl/templates/materia/layouts.yaml +++ b/sapl/templates/materia/layouts.yaml @@ -21,7 +21,7 @@ TipoFimRelatoria: MateriaLegislativa: {% trans 'Identificação Básica' %}: - - tipo numero ano + - tipo ano numero - data_apresentacao numero_protocolo tipo_apresentacao - texto_original {% trans 'Outras Informações' %}: diff --git a/sapl/templates/materia/materialegislativa_filter.html b/sapl/templates/materia/materialegislativa_filter.html index bd69f8ab1..79c9a5a69 100644 --- a/sapl/templates/materia/materialegislativa_filter.html +++ b/sapl/templates/materia/materialegislativa_filter.html @@ -50,11 +50,11 @@ {% if m.registrovotacao_set.exists %} Data Votação: {% if m.registrovotacao_set.last.ordem %} - + {{ m.registrovotacao_set.last.ordem.data_ordem }} {% elif m.registrovotacao_set.last.expediente %} - + {{ m.registrovotacao_set.last.expediente.data_ordem }} {% endif %} diff --git a/sapl/templates/materia/materialegislativa_form.html b/sapl/templates/materia/materialegislativa_form.html index 4e36ce571..335350406 100644 --- a/sapl/templates/materia/materialegislativa_form.html +++ b/sapl/templates/materia/materialegislativa_form.html @@ -10,9 +10,10 @@ function recuperar_numero_ano() { var tipo = $("#id_tipo").val() + var ano = $("#id_ano").val() if (tipo) { - $.get("/materia/recuperar-materia",{tipo: tipo}, + $.get("/materia/recuperar-materia",{tipo: tipo, ano: ano}, function(data, status) { $("#id_numero").val(data.numero); $("#id_ano").val(data.ano); @@ -20,7 +21,7 @@ }); } } - $("#id_tipo").change(recuperar_numero_ano); + $("#id_tipo, #id_ano").change(recuperar_numero_ano); {% endblock %} diff --git a/sapl/templates/painel/index.html b/sapl/templates/painel/index.html index 7e01e9ba7..a7d6dbed8 100644 --- a/sapl/templates/painel/index.html +++ b/sapl/templates/painel/index.html @@ -21,6 +21,10 @@ ul, li { list-style-type: none; } + + #sessao_plenaria, #sessao_plenaria_data, #sessao_plenaria_hora_inicio, #message, #cronometro_discurso, #cronometro_aparte, #cronometro_ordem, #relogio, #parlamentares, #votacao, #materia_legislativa_texto, #observacao_materia, #resultado_votacao{ + font-family: Verdana; + } } @@ -39,26 +43,26 @@

-

-----------------------------------------------

+

________________________________________________

-

-----------------------------------------------

+

________________________________________________

-

Cronômetros

+

Cronômetros

- + - + - +
Discurso: Discurso:
Aparte: Aparte:
Questão de Ordem: Questão de Ordem:
-

-----------------------------------------------

+

________________________________________________

-

Parlamentares e Votos

+

Parlamentares e Votos

@@ -66,9 +70,9 @@
-

-----------------------------------------------

+

________________________________________________

-

Matéria em Votação

+

Matéria em Votação

diff --git a/sapl/test_urls.py b/sapl/test_urls.py index 72c02b251..31855c724 100644 --- a/sapl/test_urls.py +++ b/sapl/test_urls.py @@ -159,7 +159,8 @@ apps_url_patterns_prefixs_and_users = { '/sistema', '/login', '/logout', - '/ajuda' + '/ajuda', + '/email', ]}, 'comissoes': { 'users': {'operador_geral': ['/sistema', '/comissao'], @@ -312,7 +313,7 @@ urls_publicas_excecoes = { '/sistema/ajuda/', '/ajuda/', - '/materia/confirmar/1/1', + '/email/validate/1/1', '/materia/pesquisar-materia', # usado na edição de matérias mas com restrição irrelevante