diff --git a/.travis.yml b/.travis.yml index eb6abe0c3..f54ee6d20 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,7 @@ language: python python: - - 3.4.3 + - 3.5 services: - postgresql @@ -14,13 +14,13 @@ before_script: - cp sapl/.env_test sapl/.env - psql -c "CREATE USER sapl WITH PASSWORD 'sapl'" -U postgres; - psql -c "CREATE DATABASE sapl OWNER sapl;" -U postgres - - ./check_migrations.sh + - ./scripts/django/check_migrations.sh script: - ./manage.py migrate - ./manage.py bower install - py.test --create-db - # - ./test_and_check_qa.sh + # - ./scripts/django/test_and_check_qa.sh addons: hosts: diff --git a/docker-compose.yml b/docker-compose.yml index 55a6b2359..68ab20687 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -11,7 +11,7 @@ sapldb: ports: - "5432:5432" sapl: - image: interlegis/sapl:3.1.77 + image: interlegis/sapl:3.1.81 restart: always environment: ADMIN_PASSWORD: interlegis diff --git a/docs/instalacao31.rst b/docs/instalacao31.rst index 0b159b91d..e904f8d6c 100644 --- a/docs/instalacao31.rst +++ b/docs/instalacao31.rst @@ -28,10 +28,10 @@ Instalar as seguintes dependências do sistema:: pkg-config postgresql postgresql-contrib pgadmin3 python-psycopg2 \ software-properties-common build-essential libxml2-dev libjpeg-dev \ libmysqlclient-dev libssl-dev libffi-dev libxslt1-dev python3-setuptools \ - python3-pip curl poppler-utils antiword default-jre + python3-pip curl poppler-utils antiword default-jre python3-venv sudo -i - curl -sL https://deb.nodesource.com/setup_6.x | bash - + curl -sL https://deb.nodesource.com/setup_8.x | bash - exit sudo apt-get install nodejs @@ -184,6 +184,8 @@ Copie a chave que aparecerá, edite o arquivo .env e altere o valor do parâmetr * Instalar as dependências do ``bower``:: eval $(echo "sudo chown -R $USER:$USER /home/$USER/") + sudo chown -R $USER:$GROUP ~/.npm + sudo chown -R $USER:$GROUP ~/.config ./manage.py bower install * Atualizar e/ou criar as tabelas da base de dados para refletir o modelo da versão clonada:: diff --git a/release.sh b/release.sh index 437355e57..cc3a172b5 100755 --- a/release.sh +++ b/release.sh @@ -29,7 +29,7 @@ function commit_and_push { } case "$1" in - --dryrun) + --dry-run) echo "Dry run" bump_version echo "done." @@ -37,7 +37,7 @@ case "$1" in exit 0 ;; - --a) + --publish) echo "generating release" bump_version commit_and_push diff --git a/requirements/requirements.txt b/requirements/requirements.txt index fe2e139c8..4b80ad130 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -22,7 +22,7 @@ easy-thumbnails==2.3 django-image-cropping==1.1.0 git+git://github.com/interlegis/trml2pdf.git libsass==0.11.1 -psycopg2==2.7.3 +psycopg2-binary==2.7.4 python-decouple==3.0 pytz==2016.4 pyyaml==3.11 diff --git a/sapl/base/forms.py b/sapl/base/forms.py index 513c3a7ca..5410ee3fe 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -834,6 +834,7 @@ class ConfiguracoesAppForm(ModelForm): 'cronometro_discurso', 'cronometro_aparte', 'cronometro_ordem', + 'cronometro_consideracoes', 'mostrar_brasao_painel', 'receber_recibo_proposicao'] @@ -842,6 +843,8 @@ class ConfiguracoesAppForm(ModelForm): self.fields['cronometro_discurso'].widget.attrs['class'] = 'cronometro' self.fields['cronometro_aparte'].widget.attrs['class'] = 'cronometro' self.fields['cronometro_ordem'].widget.attrs['class'] = 'cronometro' + self.fields['cronometro_consideracoes'].widget.attrs['class'] = 'cronometro' + def clean_mostrar_brasao_painel(self): mostrar_brasao_painel = self.cleaned_data.get( diff --git a/sapl/base/migrations/0017_appconfig_cronometro_consideracoes.py b/sapl/base/migrations/0017_appconfig_cronometro_consideracoes.py new file mode 100644 index 000000000..057344d9c --- /dev/null +++ b/sapl/base/migrations/0017_appconfig_cronometro_consideracoes.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-05-23 17:30 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('base', '0016_auto_20180326_1840'), + ] + + operations = [ + migrations.AddField( + model_name='appconfig', + name='cronometro_consideracoes', + field=models.TimeField(blank=True, null=True, verbose_name='Cronômetro de Considerações Finais'), + ), + ] diff --git a/sapl/base/models.py b/sapl/base/models.py index d2a6035a8..bbc03b6c7 100644 --- a/sapl/base/models.py +++ b/sapl/base/models.py @@ -113,6 +113,11 @@ class AppConfig(models.Model): blank=True, null=True) + cronometro_consideracoes = models.TimeField( + verbose_name=_('Cronômetro de Considerações Finais'), + blank=True, + null=True) + mostrar_brasao_painel = models.BooleanField( default=False, verbose_name=_('Mostrar brasão da Casa no painel?')) diff --git a/sapl/comissoes/forms.py b/sapl/comissoes/forms.py index 3576873b7..05a0a97b9 100644 --- a/sapl/comissoes/forms.py +++ b/sapl/comissoes/forms.py @@ -241,6 +241,9 @@ class ComissaoForm(forms.ModelForm): if not self.is_valid(): return self.cleaned_data + if len(self.cleaned_data['nome']) > 50: + msg = _('Nome da Comissão deve ter no máximo 50 caracteres.') + raise ValidationError(msg) if self.cleaned_data['data_extincao']: if (self.cleaned_data['data_extincao'] < self.cleaned_data['data_criacao']): diff --git a/sapl/legacy/migracao.py b/sapl/legacy/migracao.py index 059e49164..ffd0d2a18 100644 --- a/sapl/legacy/migracao.py +++ b/sapl/legacy/migracao.py @@ -28,6 +28,7 @@ def migrar(interativo=False): migrar_usuarios(REPO.working_dir) migrar_documentos(REPO) gravar_marco() + compactar_media() def compactar_media(): diff --git a/sapl/legacy/migracao_dados.py b/sapl/legacy/migracao_dados.py index 0f1e4d6dc..88758c8b1 100644 --- a/sapl/legacy/migracao_dados.py +++ b/sapl/legacy/migracao_dados.py @@ -1210,10 +1210,9 @@ def adjust_autor(new, old): break if old.col_username: - user_model = get_user_model() - if not user_model.objects.filter(username=old.col_username).exists(): - # cria um novo ususaŕio para o autor - user = user_model(username=old.col_username) + user, created = get_user_model().objects.get_or_create( + username=old.col_username) + if created: # gera uma senha inutilizável, que precisará ser trocada user.set_password(None) with reversion.create_revision(): @@ -1221,8 +1220,9 @@ def adjust_autor(new, old): reversion.set_comment( 'Usuário criado pela migração para o autor {}'.format( old.cod_autor)) - grupo_autor = Group.objects.get(name="Autor") - user.groups.add(grupo_autor) + grupo_autor = Group.objects.get(name="Autor") + user.groups.add(grupo_autor) + new.user = user def adjust_comissao(new, old): diff --git a/sapl/legacy/scripts/exporta_zope/exporta_zope.py b/sapl/legacy/scripts/exporta_zope/exporta_zope.py index 63d0ed09e..20c7d21e7 100755 --- a/sapl/legacy/scripts/exporta_zope/exporta_zope.py +++ b/sapl/legacy/scripts/exporta_zope/exporta_zope.py @@ -151,13 +151,14 @@ enumerate_properties = partial(enumerate_by_key_list, def enumerate_btree(folder): contagem_esperada = folder['_count'].value tree = folder['_tree'] + contagem_real = 0 # para o caso em que não haja itens for contagem_real, (id, obj) in enumerate(tree.iteritems(), start=1): obj, meta_type = br(obj), type(obj).__name__ yield id, obj, meta_type # verificação de consistência if contagem_esperada != contagem_real: print('ATENÇÃO: contagens diferentes na btree: ' - '{} esperada: {} real: {}'.format(folder, + '{} esperada: {} real: {}'.format(folder['title'], contagem_esperada, contagem_real)) @@ -362,7 +363,7 @@ def dump_sapl(sigla): destino.mkdir(parents=True) repo = git.Repo.init(destino) if TAG_ZOPE in repo.tags: - print('A exportação de documentos já está feita -- abortando') + print('{}: A exportação de documentos já está feita -- abortando'.format(sigla)) return repo_execute(repo, 'git annex init') diff --git a/sapl/painel/migrations/0002_auto_20180523_1430.py b/sapl/painel/migrations/0002_auto_20180523_1430.py new file mode 100644 index 000000000..52074acd1 --- /dev/null +++ b/sapl/painel/migrations/0002_auto_20180523_1430.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-05-23 17:30 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('painel', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='cronometro', + name='tipo', + field=models.CharField(choices=[('A', 'Aparte'), ('D', 'Discurso'), ('O', 'Ordem do dia'), ('C', 'Considerações finais')], max_length=1, verbose_name='Tipo Cronômetro'), + ), + ] diff --git a/sapl/painel/models.py b/sapl/painel/models.py index 097981520..f999ca480 100644 --- a/sapl/painel/models.py +++ b/sapl/painel/models.py @@ -26,7 +26,8 @@ class Cronometro(models.Model): CRONOMETRO_TYPES = ( ('A', _('Aparte')), ('D', _('Discurso')), - ('O', _('Ordem do dia')) + ('O', _('Ordem do dia')), + ('C', _('Considerações finais')) ) CRONOMETRO_STATUS = ( diff --git a/sapl/painel/views.py b/sapl/painel/views.py index d3f7fc5cc..0cb151382 100644 --- a/sapl/painel/views.py +++ b/sapl/painel/views.py @@ -464,6 +464,7 @@ def get_dados_painel(request, pk): 'cronometro_aparte': get_cronometro_status(request, 'aparte'), 'cronometro_discurso': get_cronometro_status(request, 'discurso'), 'cronometro_ordem': get_cronometro_status(request, 'ordem'), + 'cronometro_consideracoes': get_cronometro_status(request, 'consideracoes'), 'status_painel': sessao.painel_aberto, 'brasao': brasao } diff --git a/sapl/parlamentares/forms.py b/sapl/parlamentares/forms.py index e5b8d7d58..a7e042037 100644 --- a/sapl/parlamentares/forms.py +++ b/sapl/parlamentares/forms.py @@ -321,7 +321,7 @@ class FrenteForm(ModelForm): frente = super(FrenteForm, self).save(commit) content_type = ContentType.objects.get_for_model(Frente) object_id = frente.pk - tipo = TipoAutor.objects.get(descricao='Frente Parlamentar') + tipo = TipoAutor.objects.get(descricao__icontains='Frente') Autor.objects.create( content_type=content_type, object_id=object_id, diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index e85e9ecf2..7d68ad9c3 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -757,3 +757,118 @@ class DocumentoAdministrativoForm(ModelForm): row6, row7)) super(DocumentoAdministrativoForm, self).__init__( *args, **kwargs) + + +class DesvincularDocumentoForm(ModelForm): + + numero = forms.CharField(required=True, + label=DocumentoAdministrativo._meta. + get_field('numero').verbose_name + ) + ano = forms.ChoiceField(required=True, + label=DocumentoAdministrativo._meta. + get_field('ano').verbose_name, + choices=RANGE_ANOS, + widget=forms.Select(attrs={'class': 'selector'})) + + def clean(self): + super(DesvincularDocumentoForm, self).clean() + + cleaned_data = self.cleaned_data + + if not self.is_valid(): + return cleaned_data + + numero = cleaned_data['numero'] + ano = cleaned_data['ano'] + tipo = cleaned_data['tipo'] + + try: + documento = DocumentoAdministrativo.objects.get(numero=numero, ano=ano, tipo=tipo) + if not documento.protocolo: + raise forms.ValidationError( + _("%s %s/%s não se encontra vinculado a nenhum protocolo" % (tipo, numero, ano))) + except ObjectDoesNotExist: + raise forms.ValidationError( + _("%s %s/%s não existe" % (tipo, numero, ano))) + + return cleaned_data + + class Meta: + model = DocumentoAdministrativo + fields = ['tipo', + 'numero', + 'ano', + ] + + def __init__(self, *args, **kwargs): + + row1 = to_row( + [('numero', 4), + ('ano', 4), + ('tipo', 4)]) + + self.helper = FormHelper() + self.helper.layout = Layout( + Fieldset(_('Identificação do Documento'), + row1, + HTML(" "), + form_actions(label='Desvincular') + ) + ) + super(DesvincularDocumentoForm, self).__init__( + *args, **kwargs) + + +class DesvincularMateriaForm(forms.Form): + + numero = forms.CharField(required=True, + label=_('Número da Matéria')) + ano = forms.ChoiceField(required=True, + label=_('Ano da Matéria'), + choices=RANGE_ANOS, + widget=forms.Select(attrs={'class': 'selector'})) + tipo = forms.ModelChoiceField(label=_('Tipo de Matéria'), + required=True, + queryset=TipoMateriaLegislativa.objects.all(), + empty_label='------') + + def clean(self): + super(DesvincularMateriaForm, self).clean() + + cleaned_data = self.cleaned_data + + if not self.is_valid(): + return cleaned_data + + numero = cleaned_data['numero'] + ano = cleaned_data['ano'] + tipo = cleaned_data['tipo'] + + try: + materia = MateriaLegislativa.objects.get(numero=numero, ano=ano, tipo=tipo) + if not materia.numero_protocolo: + raise forms.ValidationError( + _("%s %s/%s não se encontra vinculada a nenhum protocolo" % (tipo, numero, ano))) + except ObjectDoesNotExist: + raise forms.ValidationError( + _("%s %s/%s não existe" % (tipo, numero, ano))) + + return cleaned_data + + def __init__(self, *args, **kwargs): + super(DesvincularMateriaForm, self).__init__(*args, **kwargs) + + row1 = to_row( + [('numero', 4), + ('ano', 4), + ('tipo', 4)]) + + self.helper = FormHelper() + self.helper.layout = Layout( + Fieldset(_('Identificação da Matéria'), + row1, + HTML(" "), + form_actions(label='Desvincular') + ) + ) diff --git a/sapl/protocoloadm/urls.py b/sapl/protocoloadm/urls.py index 46fec9980..223c38014 100644 --- a/sapl/protocoloadm/urls.py +++ b/sapl/protocoloadm/urls.py @@ -15,7 +15,9 @@ from sapl.protocoloadm.views import (AnularProtocoloAdmView, TipoDocumentoAdministrativoCrud, TramitacaoAdmCrud, atualizar_numero_documento, - doc_texto_integral) + doc_texto_integral, + DesvincularDocumentoView, + DesvincularMateriaView) from .apps import AppConfig @@ -61,6 +63,10 @@ urlpatterns_protocolo = [ url(r'^protocoloadm/anular-protocolo', AnularProtocoloAdmView.as_view(), name='anular_protocolo'), + url(r'^protocoloadm/desvincular-documento', + DesvincularDocumentoView.as_view(), name='desvincular_documento'), + url(r'^protocoloadm/desvincular-materia', + DesvincularMateriaView.as_view(), name='desvincular_materia'), url(r'^protocoloadm/protocolar-mat', ProtocoloMateriaView.as_view(), name='protocolar_mat'), diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index d4f7e96d9..7dd7206c7 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -13,6 +13,7 @@ from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from django.views.generic import CreateView, ListView from django.views.generic.base import RedirectView, TemplateView +from django.views.generic.edit import FormView from django_filters.views import FilterView import sapl @@ -30,7 +31,7 @@ from .forms import (AnularProcoloAdmForm, DocumentoAcessorioAdministrativoForm, DocumentoAdministrativoFilterSet, DocumentoAdministrativoForm, ProtocoloDocumentForm, ProtocoloFilterSet, ProtocoloMateriaForm, - TramitacaoAdmEditForm, TramitacaoAdmForm) + TramitacaoAdmEditForm, TramitacaoAdmForm, DesvincularDocumentoForm, DesvincularMateriaForm) from .models import (DocumentoAcessorioAdministrativo, DocumentoAdministrativo, StatusTramitacaoAdministrativo, TipoDocumentoAdministrativo, TramitacaoAdministrativo) @@ -451,10 +452,11 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): if not protocolo.numero: protocolo.numero = (numero['numero__max'] + 1) if numero['numero__max'] else 1 - if protocolo.numero < (numero['numero__max'] + 1): - msg = _('Número de protocolo deve ser maior que {}').format(numero['numero__max']) - messages.add_message(self.request, messages.ERROR, msg) - return self.render_to_response(self.get_context_data()) + if numero['numero__max']: + if protocolo.numero < (numero['numero__max'] + 1): + msg = _('Número de protocolo deve ser maior que {}').format(numero['numero__max']) + messages.add_message(self.request, messages.ERROR, msg) + return self.render_to_response(self.get_context_data()) protocolo.ano = timezone.now().year protocolo.data = timezone.now().date() protocolo.hora = timezone.now().time() @@ -720,3 +722,39 @@ def atualizar_numero_documento(request): {'numero': 1, 'ano': ano}) return response + + +class DesvincularDocumentoView(PermissionRequiredMixin, CreateView): + template_name = 'protocoloadm/anular_protocoloadm.html' + form_class = DesvincularDocumentoForm + form_valid_message = _('Documento desvinculado com sucesso!') + permission_required = ('protocoloadm.action_anular_protocolo', ) + + def get_success_url(self): + return reverse('sapl.protocoloadm:protocolo') + + def form_valid(self, form): + documento = DocumentoAdministrativo.objects.get(numero=form.cleaned_data['numero'], + ano=form.cleaned_data['ano'], + tipo=form.cleaned_data['tipo']) + documento.protocolo = None + documento.save() + return redirect(self.get_success_url()) + + +class DesvincularMateriaView(PermissionRequiredMixin, FormView): + template_name = 'protocoloadm/anular_protocoloadm.html' + form_class = DesvincularMateriaForm + form_valid_message = _('Matéria desvinculado com sucesso!') + permission_required = ('protocoloadm.action_anular_protocolo', ) + + def get_success_url(self): + return reverse('sapl.protocoloadm:protocolo') + + def form_valid(self, form): + materia = MateriaLegislativa.objects.get(numero=form.cleaned_data['numero'], + ano=form.cleaned_data['ano'], + tipo=form.cleaned_data['tipo']) + materia.numero_protocolo = None + materia.save() + return redirect(self.get_success_url()) \ No newline at end of file diff --git a/sapl/relatorios/views.py b/sapl/relatorios/views.py index 9f46450b8..0bad27889 100644 --- a/sapl/relatorios/views.py +++ b/sapl/relatorios/views.py @@ -795,7 +795,8 @@ def relatorio_sessao_plenaria(request, pk): for idx in range(len(lst_expedientes)): txt_expedientes = lst_expedientes[idx]['txt_expediente'] - txt_expedientes = TrocaTag(txt_expedientes, '', 6, 6, 'expedientes') + txt_expedientes = TrocaTag(txt_expedientes, '', 6, 6, + 'expedientes', 'Questão de Ordem: + + Considerações Finais: + @@ -195,9 +198,20 @@ audioAlertFinish.play(); }); + $('#cronometro_consideracoes').runner({ + autostart: false, + countdown: true, + startAt: {{ 'consideracoes'|cronometro_to_seconds }} * 1000, + stopAt: 0, + milliseconds: false + }).on('runnerFinish', function(eventObject, info){ + audioAlertFinish.play(); + }); + var discurso_previous; var ordem_previous; var aparte_previous; + var consideracoes_previous; var counter = 1; (function poll() { @@ -325,6 +339,16 @@ ordem_previous = ordem_current; } + var consideracoes_current = data["cronometro_consideracoes"]; + if (!consideracoes_previous){ + consideracoes_previous = '' + } + + if (consideracoes_current != consideracoes_previous) { + $('#cronometro_consideracoes').runner(consideracoes_current); + consideracoes_previous = consideracoes_current; + } + if($('#cronometro_discurso').runner('info').formattedTime == 30) { audioAlertFinish.play(); } @@ -337,6 +361,10 @@ audioAlertFinish.play(); } + if($('#cronometro_consideracoes').runner('info').formattedTime == 30) { + audioAlertFinish.play(); + } + if (data['materia_legislativa_texto']){ $("#materia_legislativa_texto").text(data["materia_legislativa_texto"]); } diff --git a/sapl/templates/parlamentares/layouts.yaml b/sapl/templates/parlamentares/layouts.yaml index ba7767cd2..2c21ade8d 100644 --- a/sapl/templates/parlamentares/layouts.yaml +++ b/sapl/templates/parlamentares/layouts.yaml @@ -37,10 +37,10 @@ Parlamentar: - situacao_militar profissao - endereco_web - email - - numero_gab_parlamentar telefone fax + - numero_gab_parlamentar telefone - endereco_residencia cep_residencia - municipio_residencia uf_residencia - - telefone_residencia fax_residencia + - telefone_residencia - locais_atuacao - fotografia:5 - biografia @@ -54,10 +54,10 @@ ParlamentarUpdate: - situacao_militar profissao - endereco_web - email - - numero_gab_parlamentar telefone fax + - numero_gab_parlamentar telefone - endereco_residencia cep_residencia - municipio_residencia uf_residencia - - telefone_residencia fax_residencia + - telefone_residencia - locais_atuacao - fotografia cropping - biografia @@ -73,10 +73,10 @@ ParlamentarCreate: - situacao_militar profissao - endereco_web - email - - numero_gab_parlamentar telefone fax + - numero_gab_parlamentar telefone - endereco_residencia cep_residencia - municipio_residencia - - telefone_residencia fax_residencia + - telefone_residencia - locais_atuacao - fotografia - biografia diff --git a/sapl/templates/protocoloadm/protocoloadm_detail.html b/sapl/templates/protocoloadm/protocoloadm_detail.html index 5a3fe05d0..3db9ea6d8 100644 --- a/sapl/templates/protocoloadm/protocoloadm_detail.html +++ b/sapl/templates/protocoloadm/protocoloadm_detail.html @@ -5,5 +5,7 @@ {% trans 'Protocolar Matéria' %} {% trans 'Protocolar Documento' %} {% trans 'Anular Protocolo' %} + {% trans 'Desvincular Documentos' %} + {% trans 'Desvincular Matérias' %} {% endblock editions %} diff --git a/sapl/templates/sessao/blocos_resumo/conteudo_multimidia.html b/sapl/templates/sessao/blocos_resumo/conteudo_multimidia.html index 4749f5ad2..b275ebd79 100644 --- a/sapl/templates/sessao/blocos_resumo/conteudo_multimidia.html +++ b/sapl/templates/sessao/blocos_resumo/conteudo_multimidia.html @@ -1,8 +1,8 @@
Conteúdo Multimídia
-
{{multimidia_audio}}
-
{{multimidia_video}}
+ +
-


\ No newline at end of file +


diff --git a/sapl/templates/sessao/painel.html b/sapl/templates/sessao/painel.html index 22dc62dda..d83c99e86 100644 --- a/sapl/templates/sessao/painel.html +++ b/sapl/templates/sessao/painel.html @@ -69,6 +69,20 @@

+
+

Cronômetro de Considerações Finais

+
+ +
+
+
+
+ +
+
+
+
+

@@ -102,6 +116,7 @@ $(function() { $('#discurso').prop('disabled', true); $('#aparte').prop('disabled', true); $('#ordem').prop('disabled', true); + $('#consideracoes').prop('disabled', true); $('#discurso').runner({ autostart: false, @@ -119,6 +134,8 @@ $(function() { $('#aparteReset').prop('disabled', false); $('#ordemStart').prop('disabled', false); $('#ordemReset').prop('disabled', false); + $('#consideracoesStart').prop('disabled', false); + $('#consideracoesReset').prop('disabled', false); }); @@ -135,6 +152,8 @@ $(function() { $('#aparteReset').prop('disabled', false); $('#ordemStart').prop('disabled', false); $('#ordemReset').prop('disabled', false); + $('#consideracoesStart').prop('disabled', false); + $('#consideracoesReset').prop('disabled', false); } else { @@ -147,6 +166,8 @@ $(function() { $('#aparteReset').prop('disabled', false); $('#ordemStart').prop('disabled', false); $('#ordemReset').prop('disabled', false); + $('#consideracoesStart').prop('disabled', false); + $('#consideracoesReset').prop('disabled', false); } }); @@ -174,6 +195,8 @@ $(function() { $('#discursoReset').prop('disabled', false); $('#ordemStart').prop('disabled', false); $('#ordemReset').prop('disabled', false); + $('#consideracoesStart').prop('disabled', false); + $('#consideracoesReset').prop('disabled', false); }); @@ -189,6 +212,8 @@ $(function() { $('#discursoReset').prop('disabled', false); $('#ordemStart').prop('disabled', false); $('#ordemReset').prop('disabled', false); + $('#consideracoesStart').prop('disabled', false); + $('#consideracoesReset').prop('disabled', false); } else { $.get('/painel/cronometro', { tipo: 'aparte', action: 'stop' } ); @@ -200,6 +225,8 @@ $(function() { $('#discursoReset').prop('disabled', false); $('#ordemStart').prop('disabled', false); $('#ordemReset').prop('disabled', false); + $('#consideracoesStart').prop('disabled', false); + $('#consideracoesReset').prop('disabled', false); } }); @@ -227,6 +254,8 @@ $(function() { $('#discursoReset').prop('disabled', false); $('#aparteStart').prop('disabled', false); $('#aparteReset').prop('disabled', false); + $('#consideracoesStart').prop('disabled', false); + $('#consideracoesReset').prop('disabled', false); }); $('#ordemStart').click(function() { @@ -241,6 +270,8 @@ $(function() { $('#discursoReset').prop('disabled', false); $('#aparteStart').prop('disabled', false); $('#aparteReset').prop('disabled', false); + $('#consideracoesStart').prop('disabled', false); + $('#consideracoesReset').prop('disabled', false); } else { @@ -253,6 +284,8 @@ $(function() { $('#discursoReset').prop('disabled', false); $('#aparteStart').prop('disabled', false); $('#aparteReset').prop('disabled', false); + $('#consideracoesStart').prop('disabled', false); + $('#consideracoesReset').prop('disabled', false); } }); @@ -264,6 +297,65 @@ $(function() { $('#ordem').runner('reset'); }); + $('#consideracoes').runner({ + autostart: false, + countdown: true, + startAt: {{cronometro_consideracoes}} * 1000, + stopAt: 0, + milliseconds: false + }).on('runnerFinish', function(eventObject, info){ + $.get('/painel/cronometro', { tipo: 'consideracoes', action: 'stop' } ); + + $('#consideracoesReset').show(); + $('#consideracoes').runner('stop'); + $('#consideracoesStart').text('Iniciar'); + $('#discursoStart').prop('disabled', false); + $('#discursoReset').prop('disabled', false); + $('#ordemStart').prop('disabled', false); + $('#ordemReset').prop('disabled', false); + $('#aparteStart').prop('disabled', false); + $('#aparteReset').prop('disabled', false); + + }); + + $('#consideracoesStart').click(function(){ + if ($('#consideracoesStart').text() == 'Iniciar') { + + $.get('/painel/cronometro', { tipo: 'consideracoes', action: 'start' } ); + + $('#consideracoesReset').hide(); + $('#consideracoes').runner('start'); + $('#consideracoesStart').text('Parar'); + $('#discursoStart').prop('disabled', false); + $('#discursoReset').prop('disabled', false); + $('#ordemStart').prop('disabled', false); + $('#ordemReset').prop('disabled', false); + $('#aparteStart').prop('disabled', false); + $('#aparteReset').prop('disabled', false); + } else { + + $.get('/painel/cronometro', { tipo: 'consideracoes', action: 'stop' } ); + + $('#consideracoesReset').show(); + $('#consideracoes').runner('stop'); + $('#consideracoesStart').text('Iniciar'); + $('#discursoStart').prop('disabled', false); + $('#discursoReset').prop('disabled', false); + $('#ordemStart').prop('disabled', false); + $('#ordemReset').prop('disabled', false); + $('#aparteStart').prop('disabled', false); + $('#aparteReset').prop('disabled', false); + } + }); + + $('#consideracoesReset').click(function() { + + $.get('/painel/cronometro', { tipo: 'consideracoes', action: 'reset' } ); + + $('#consideracoes').runner('stop'); + $('#consideracoes').runner('reset'); + }); + }); function switch_painel(aberto) { diff --git a/sapl/utils.py b/sapl/utils.py index 69ea53dfc..b674481c3 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -688,7 +688,7 @@ def ExtraiTag(texto, posicao): return i + 1 -def TrocaTag(texto, startTag, endTag, sizeStart, sizeEnd, styleName): +def TrocaTag(texto, startTag, endTag, sizeStart, sizeEnd, styleName, subinitiTag, subendTag): textoSaida = '' insideTag = 0 i = 0 @@ -697,16 +697,19 @@ def TrocaTag(texto, startTag, endTag, sizeStart, sizeEnd, styleName): if '' in texto: texto = texto.replace('', '') texto = texto.replace('', '') + if '

' in texto: + texto = texto.replace('

', '') + texto = texto.replace('

', '') while (i < len(texto)): shard = texto[i:i + sizeStart] if (shard == startTag): i = ExtraiTag(texto, i) - textoSaida += '' + textoSaida += subinitiTag + styleName + '">' insideTag = 1 else: if (insideTag == 1): if (texto[i:i + sizeEnd] == endTag): - textoSaida += 'blockTable>' + textoSaida += subendTag insideTag = 0 i += sizeEnd else: @@ -735,4 +738,4 @@ def RemoveTag(texto): return textoSaida def remover_acentos(string): - return unicodedata.normalize('NFKD', string).encode('ASCII', 'ignore').decode() \ No newline at end of file + return unicodedata.normalize('NFKD', string).encode('ASCII', 'ignore').decode() diff --git a/check_migrations.sh b/scripts/django/check_migrations.sh similarity index 61% rename from check_migrations.sh rename to scripts/django/check_migrations.sh index 9db8143b2..dc78641cd 100755 --- a/check_migrations.sh +++ b/scripts/django/check_migrations.sh @@ -11,13 +11,15 @@ # A chamada do django 1.10 INVERTE ISSO. # # https://docs.djangoproject.com/en/1.10/ref/django-admin/#cmdoption-makemigrations-check -if python manage.py makemigrations --dry-run --exit > /dev/null; then + +git_project_root=$(git rev-parse --show-toplevel) +if python ${git_project_root}/manage.py makemigrations --dry-run --exit > /dev/null; then NC='\033[0m' RED='\033[0;31m' echo echo -e "${RED}ALGUMAS ALTERAÇÕES EXIGEM MIGRAÇÃO.${NC}" - echo -e "${RED}RODE 'python manage.py makemigrations' ANTES DE SUBMETER SEU CÓDIGO...${NC}" - echo -e "${RED}lembre de adicionar os arquivos criados ao git com 'git add .' ou semelhante.${NC}" + echo -e "${RED}Execute o comando 'python manage.py makemigrations' ANTES DE SUBMETER SEU CÓDIGO...${NC}" + echo -e "${RED}Lembre de adicionar os arquivos criados ao git com 'git add ' ou semelhante.${NC}" echo exit 1 -fi \ No newline at end of file +fi diff --git a/check_qa.sh b/scripts/django/check_qa.sh similarity index 89% rename from check_qa.sh rename to scripts/django/check_qa.sh index 47f2b56d3..a145bee7a 100755 --- a/check_qa.sh +++ b/scripts/django/check_qa.sh @@ -2,6 +2,10 @@ # Verifica se um breakpoint foi esquecido no código me=`basename "$0"` + +git_project_root=$(git rev-parse --show-toplevel) +cd ${git_project_root} + busca=`grep --color=auto --exclude=$me --exclude=ipython_log.py* -r -l "pdb.set_trace()" .` if [ ! -z "$busca" ] diff --git a/fix_qa.sh b/scripts/django/fix_qa.sh similarity index 88% rename from fix_qa.sh rename to scripts/django/fix_qa.sh index 264c01676..cb0f24001 100755 --- a/fix_qa.sh +++ b/scripts/django/fix_qa.sh @@ -8,5 +8,7 @@ # Uma forma simples de fazer isso é adicionando antes suas mudanças à # "staging area" do git, com `git add .` e após usar o script `git diff`. +git_project_root=$(git rev-parse --show-toplevel) +cd ${git_project_root} isort --recursive --skip='migrations' --skip='templates' --skip='ipython_log.py*' . autopep8 --in-place --recursive . --exclude='migrations,ipython_log.py*' diff --git a/scripts/gerar_grafico_apps.sh b/scripts/django/gerar_grafico_apps.sh similarity index 69% rename from scripts/gerar_grafico_apps.sh rename to scripts/django/gerar_grafico_apps.sh index 312f04b0c..ab6bf9a84 100755 --- a/scripts/gerar_grafico_apps.sh +++ b/scripts/django/gerar_grafico_apps.sh @@ -1,3 +1,6 @@ #!/bin/bash +git_project_root=$(git rev-parse --show-toplevel) +cd ${git_project_root} + python -c "from sapl.settings import SAPL_APPS; print(*[s.split('.')[-1] for s in SAPL_APPS])" | xargs -t ./manage.py graph_models -d -g -o zzz.png -l fdp diff --git a/scripts/reset_all_migrations.sh b/scripts/django/reset_all_migrations.sh similarity index 57% rename from scripts/reset_all_migrations.sh rename to scripts/django/reset_all_migrations.sh index 53e274fe9..d3f2cfbe4 100755 --- a/scripts/reset_all_migrations.sh +++ b/scripts/django/reset_all_migrations.sh @@ -3,6 +3,11 @@ # Sends all django migrations to the trash bin # Requires trash-cli. To install: # sudo apt-get install trash-cli +hash trash-put 2>/dev/null || { echo >&2 "I require trash-put but it's not installed. Aborting."; exit 1; } + +git_project_root=$(git rev-parse --show-toplevel) +cd ${git_project_root} + find -name 00*.py | grep /migrations/ | xargs trash-put # Make all migrations from scratch diff --git a/test_and_check_qa.sh b/scripts/django/test_and_check_qa.sh similarity index 53% rename from test_and_check_qa.sh rename to scripts/django/test_and_check_qa.sh index 14231ce80..024139bba 100755 --- a/test_and_check_qa.sh +++ b/scripts/django/test_and_check_qa.sh @@ -2,6 +2,9 @@ # QA checks: run this before every commit +git_project_root=$(git rev-parse --show-toplevel) +cd ${git_project_root} + py.test py.test --ds=sapl.crud.tests.settings sapl/crud/tests -./check_qa.sh +./scripts/django/check_qa.sh diff --git a/scripts/hooks/pre-commit b/scripts/hooks/pre-commit index de82032c1..d8efe2cf5 100644 --- a/scripts/hooks/pre-commit +++ b/scripts/hooks/pre-commit @@ -4,5 +4,5 @@ if git diff --cached --name-status | grep -q '^M.*models\.py$'; then # se a checagem de migrations falhar impedimos o commit set -e - ./check_migrations.sh + ./scripts/django/check_migrations.sh fi diff --git a/scripts/redbaron.py b/scripts/redbaron.py index 3229872bc..b02e4cdfa 100644 --- a/scripts/redbaron.py +++ b/scripts/redbaron.py @@ -1,10 +1,14 @@ import os import re +import subprocess from redbaron import RedBaron from redbaron.nodes import EndlNode, ReturnNode, StringNode -root = '/home/mazza/work/sapl' +git_project_root = subprocess.Popen( + ["git", "rev-parse", "--show-toplevel"], + stdout=subprocess.PIPE + ).communicate()[0].decode('utf-8').replace('\n', '') def ignorado(path, name): @@ -13,13 +17,13 @@ def ignorado(path, name): 'relatorios/templates.*', '.*/migrations', ]: - if re.match(os.path.join(root, pattern), path): + if re.match(os.path.join(git_project_root, pattern), path): return True return name.startswith('ipython_log.py') or name == 'manage.py' filenames = [os.path.join(path, name) - for path, subdirs, files in os.walk(root) + for path, subdirs, files in os.walk(git_project_root) for name in files if name.endswith('.py') and not ignorado(path, name)] @@ -37,7 +41,7 @@ def build_red(filename): def write(node): - red = node.root + red = node.git_project_root with open(red.__filename__, "w") as source_code: source_code.write(red.dumps()) @@ -82,7 +86,7 @@ def fix(n): def local(node): - res = '%s:%s' % (node.root.__filename__, + res = '%s:%s' % (node.git_project_root.__filename__, node.absolute_bounding_box.top_left.line) os.system("echo '%s' | xclip -selection c" % res) return res diff --git a/setup.py b/setup.py index af5b2c7d2..9e5c5315d 100644 --- a/setup.py +++ b/setup.py @@ -49,7 +49,7 @@ install_requires = [ ] setup( name='interlegis-sapl', - version='3.1.77', + version='3.1.81', packages=find_packages(), include_package_data=True, license='GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007',