Browse Source

Merge branch '3.1.x'

pull/1828/merge
João Pedro Sconetto 8 years ago
parent
commit
c997309be3
  1. 6
      .travis.yml
  2. 2
      docker-compose.yml
  3. 6
      docs/instalacao31.rst
  4. 4
      release.sh
  5. 2
      requirements/requirements.txt
  6. 3
      sapl/base/forms.py
  7. 20
      sapl/base/migrations/0017_appconfig_cronometro_consideracoes.py
  8. 5
      sapl/base/models.py
  9. 3
      sapl/comissoes/forms.py
  10. 1
      sapl/legacy/migracao.py
  11. 12
      sapl/legacy/migracao_dados.py
  12. 5
      sapl/legacy/scripts/exporta_zope/exporta_zope.py
  13. 20
      sapl/painel/migrations/0002_auto_20180523_1430.py
  14. 3
      sapl/painel/models.py
  15. 1
      sapl/painel/views.py
  16. 2
      sapl/parlamentares/forms.py
  17. 115
      sapl/protocoloadm/forms.py
  18. 8
      sapl/protocoloadm/urls.py
  19. 48
      sapl/protocoloadm/views.py
  20. 3
      sapl/relatorios/views.py
  21. 4
      sapl/sessao/forms.py
  22. 14
      sapl/sessao/views.py
  23. 2
      sapl/templates/base/layouts.yaml
  24. 30
      sapl/templates/painel/index.html
  25. 12
      sapl/templates/parlamentares/layouts.yaml
  26. 2
      sapl/templates/protocoloadm/protocoloadm_detail.html
  27. 6
      sapl/templates/sessao/blocos_resumo/conteudo_multimidia.html
  28. 92
      sapl/templates/sessao/painel.html
  29. 11
      sapl/utils.py
  30. 10
      scripts/django/check_migrations.sh
  31. 4
      scripts/django/check_qa.sh
  32. 2
      scripts/django/fix_qa.sh
  33. 3
      scripts/django/gerar_grafico_apps.sh
  34. 5
      scripts/django/reset_all_migrations.sh
  35. 5
      scripts/django/test_and_check_qa.sh
  36. 2
      scripts/hooks/pre-commit
  37. 14
      scripts/redbaron.py
  38. 2
      setup.py

6
.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:

2
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

6
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::

4
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

2
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

3
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(

20
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'),
),
]

5
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?'))

3
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']):

1
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():

12
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):

5
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')

20
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'),
),
]

3
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 = (

1
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
}

2
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,

115
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("&nbsp;"),
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("&nbsp;"),
form_actions(label='Desvincular')
)
)

8
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'),

48
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())

3
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, '<table', 'table>', 6, 6, 'expedientes')
txt_expedientes = TrocaTag(txt_expedientes, '<table', 'table>', 6, 6,
'expedientes', '</para><blockTable style = "', 'blockTable><para>')
lst_expedientes[idx]['txt_expediente'] = txt_expedientes
pdf = pdf_sessao_plenaria_gerar.principal(

4
sapl/sessao/forms.py

@ -124,7 +124,7 @@ class BancadaForm(ModelForm):
bancada = super(BancadaForm, self).save(commit)
content_type = ContentType.objects.get_for_model(Bancada)
object_id = bancada.pk
tipo = TipoAutor.objects.get(descricao='Bancada Parlamentar')
tipo = TipoAutor.objects.get(descricao__icontains='Bancada')
Autor.objects.create(
content_type=content_type,
object_id=object_id,
@ -159,7 +159,7 @@ class BlocoForm(ModelForm):
bloco = super(BlocoForm, self).save(commit)
content_type = ContentType.objects.get_for_model(Bloco)
object_id = bloco.pk
tipo = TipoAutor.objects.get(descricao='Bloco Parlamentar')
tipo = TipoAutor.objects.get(descricao__icontains='Bloco')
Autor.objects.create(
content_type=content_type,
object_id=object_id,

14
sapl/sessao/views.py

@ -277,8 +277,8 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
else:
resultado = '''Não há resultado'''
else:
resultado = obj.registrovotacao_set.get(
materia_id=obj.materia_id)
resultado = obj.registrovotacao_set.filter(
materia_id=obj.materia_id).last()
resultado_descricao = resultado.tipo_resultado_votacao.nome
resultado_observacao = resultado.observacao
@ -761,6 +761,7 @@ class PainelView(PermissionRequiredForAppCrudMixin, TemplateView):
request.session['discurso'] = 'stop'
request.session['aparte'] = 'stop'
request.session['ordem'] = 'stop'
request.session['consideracoes'] = 'stop'
return TemplateView.get(self, request, *args, **kwargs)
@ -768,9 +769,10 @@ class PainelView(PermissionRequiredForAppCrudMixin, TemplateView):
cronometro_discurso = AppsAppConfig.attr('cronometro_discurso')
cronometro_aparte = AppsAppConfig.attr('cronometro_aparte')
cronometro_ordem = AppsAppConfig.attr('cronometro_ordem')
cronometro_consideracoes = AppsAppConfig.attr('cronometro_consideracoes')
if (not cronometro_discurso or not cronometro_aparte
or not cronometro_ordem):
or not cronometro_ordem or not cronometro_consideracoes):
msg = _(
'Você precisa primeiro configurar os cronômetros \
nas Configurações da Aplicação')
@ -786,6 +788,9 @@ class PainelView(PermissionRequiredForAppCrudMixin, TemplateView):
m, s, x = cronometro_ordem.isoformat().split(':')
cronometro_ordem = int(m) * 60 + int(s)
m, s, x = cronometro_consideracoes.isoformat().split(':')
cronometro_consideracoes = int(m) * 60 + int(s)
context = TemplateView.get_context_data(self, **kwargs)
context.update({
'head_title': str(_('Painel Plenário')),
@ -794,7 +799,8 @@ class PainelView(PermissionRequiredForAppCrudMixin, TemplateView):
'sessaoplenaria': SessaoPlenaria.objects.get(pk=kwargs['pk']),
'cronometro_discurso': cronometro_discurso,
'cronometro_aparte': cronometro_aparte,
'cronometro_ordem': cronometro_ordem})
'cronometro_ordem': cronometro_ordem,
'cronometro_consideracoes': cronometro_consideracoes})
return context

2
sapl/templates/base/layouts.yaml

@ -21,7 +21,7 @@ AppConfig:
- texto_articulado_proposicao texto_articulado_materia texto_articulado_norma
{% trans 'Cronômetros do Painel' %}:
- cronometro_discurso cronometro_aparte cronometro_ordem
- cronometro_discurso cronometro_aparte cronometro_ordem cronometro_consideracoes
{% trans 'Configurações do Painel' %}:
- mostrar_brasao_painel

30
sapl/templates/painel/index.html

@ -28,7 +28,7 @@
ul, li {
list-style-type: none;
}
#date, #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, #orador {
#date, #sessao_plenaria, #sessao_plenaria_data, #sessao_plenaria_hora_inicio, #message, #cronometro_discurso, #cronometro_aparte, #cronometro_ordem, #cronometro_consideracoes, #relogio, #parlamentares, #votacao, #materia_legislativa_texto, #observacao_materia, #resultado_votacao, #orador {
font-family: Verdana;
}
}
@ -108,6 +108,9 @@
<tr>
<td style="font-family:Verdana; text-align:center;"><font size="5" color="white">Questão de Ordem: <span id="cronometro_ordem"></span></font></td>
</tr>
<tr>
<td style="font-family:Verdana; text-align:center;"><font size="5" color="white">Considerações Finais: <span id="cronometro_consideracoes"></span></font></td>
</tr>
</table>
</div>
@ -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"]);
}

12
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

2
sapl/templates/protocoloadm/protocoloadm_detail.html

@ -5,5 +5,7 @@
<a href="{% url 'sapl.protocoloadm:protocolar_mat' %}" class="btn btn-default">{% trans 'Protocolar Matéria' %}</a>
<a href="{% url 'sapl.protocoloadm:protocolar_doc' %}" class="btn btn-default">{% trans 'Protocolar Documento' %}</a>
<a href="{% url 'sapl.protocoloadm:anular_protocolo' %}" class="btn btn-default btn-excluir">{% trans 'Anular Protocolo' %}</a>
<a href="{% url 'sapl.protocoloadm:desvincular_documento' %}" class="btn btn-default btn-excluir">{% trans 'Desvincular Documentos' %}</a>
<a href="{% url 'sapl.protocoloadm:desvincular_materia' %}" class="btn btn-default btn-excluir">{% trans 'Desvincular Matérias' %}</a>
</div>
{% endblock editions %}

6
sapl/templates/sessao/blocos_resumo/conteudo_multimidia.html

@ -1,8 +1,8 @@
<fieldset>
<legend>Conteúdo Multimídia</legend>
<div class="row">
<div class="col-md-6">{{multimidia_audio}}</div>
<div class="col-md-6">{{multimidia_video}}</div>
<div class="col-md-6">Audio: <a href={{multimidia_audio|slice:"6:"}}>{{multimidia_audio|slice:"6:"}}</a></div>
<div class="col-md-6">Video: <a href={{multimidia_video|slice:"6:"}}>{{multimidia_video|slice:"6:"}}</a></div>
</div>
</fieldset>
<br /><br /><br />
<br /><br /><br />

92
sapl/templates/sessao/painel.html

@ -69,6 +69,20 @@
</div>
<br/>
<br/>
<div class="row">
<div class="col-md-12"><h3>Cronômetro de Considerações Finais</h3></div>
</div>
<div class="row">
<div class="col-xs-2"><input size="2" id="consideracoes" name="consideracoes" value="" readyonly="true" class="form-control"></div>
</div>
<br />
<div class="row">
<div class="col-md-6"><button type="button" id="consideracoesStart" class="btn btn-success">Iniciar</button></div>
<div class="col-md-6"><button type="button" id="consideracoesReset" class="btn btn-success">Reiniciar</button></div>
</div>
<br /><br >
<div class="row">
<div class="col-md-6"><button type="button" id="sinalSonoro" class="btn btn-success" onclick="document.getElementById('audio').play();">Sinal Sonoro</button></div>
</div>
@ -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) {

11
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 '<tbody>' in texto:
texto = texto.replace('<tbody>', '')
texto = texto.replace('</tbody>', '')
if '<p>' in texto:
texto = texto.replace('<p>', '')
texto = texto.replace('</p>', '')
while (i < len(texto)):
shard = texto[i:i + sizeStart]
if (shard == startTag):
i = ExtraiTag(texto, i)
textoSaida += '</para><blockTable style = "' + styleName + '">'
textoSaida += subinitiTag + styleName + '">'
insideTag = 1
else:
if (insideTag == 1):
if (texto[i:i + sizeEnd] == endTag):
textoSaida += 'blockTable><para>'
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()
return unicodedata.normalize('NFKD', string).encode('ASCII', 'ignore').decode()

10
check_migrations.sh → 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 <arquivo>' ou semelhante.${NC}"
echo
exit 1
fi
fi

4
check_qa.sh → 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" ]

2
fix_qa.sh → 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*'

3
scripts/gerar_grafico_apps.sh → 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

5
scripts/reset_all_migrations.sh → 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

5
test_and_check_qa.sh → 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

2
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

14
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

2
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',

Loading…
Cancel
Save