Browse Source

Merge master

pull/271/head
Marcio Mazza 9 years ago
parent
commit
5a4a83d1fa
  1. 12
      README.rst
  2. 25
      base/forms.py
  3. 21
      compilacao/migrations/0045_auto_20160404_1411.py
  4. 3
      compilacao/models.py
  5. 11
      materia/forms.py
  6. 27
      materia/migrations/0027_auto_20160404_1409.py
  7. 9
      materia/models.py
  8. 11
      materia/views.py
  9. 29
      parlamentares/forms.py
  10. 22
      parlamentares/migrations/0016_auto_20160404_1409.py
  11. 5
      parlamentares/models.py
  12. 8
      parlamentares/test_parlamentares.py
  13. 20
      parlamentares/views.py
  14. 4
      requirements/requirements.txt
  15. 29
      sapl/settings.py
  16. 18
      sapl/test_general.py
  17. 119
      sapl/utils.py
  18. 27
      sessao/migrations/0016_auto_20160404_1409.py
  19. 8
      sessao/models.py
  20. 14
      templates/materia/proposicao/proposicao_list.html
  21. 2
      templates/sessao/sessao_list.html

12
README.rst

@ -56,6 +56,18 @@ Development Environment Installation
* Either run ``./manage.py migrate`` (for an empty database) or restore a database dump.
* In ``sapl/sapl`` directory create one file called ``.env``. Write the following attributes in it:
- DATABASE_URL = postgresql://USER:PASSWORD@HOST:PORT/NAME
- SECRET_KEY = Generate some key and paste here
- DEBUG = [True/False]
- EMAIL_USE_TLS = [True/False]
- EMAIL_PORT = [Set this parameter]
- EMAIL_HOST = [Set this parameter]
- EMAIL_HOST_USER = [Set this parameter]
- EMAIL_HOST_PASSWORD = [Set this parameter]
`Generate your secret key here <https://docs.djangoproject.com/es/1.9/ref/settings/#std:setting-SECRET_KEY>`_
Instructions for Translators
============================

25
base/forms.py

@ -88,18 +88,19 @@ class CasaLegislativaTabelaAuxForm(ModelForm):
row3,
row4,
row5,
HTML("""<div class="col-md-12">
{% if form.logotipo.value %}
<img class="img-responsive" width="225" height="300"
src="{{ MEDIA_URL }}{{ form.logotipo.value }}">
<br />
<input type="submit"
name="remover"
id="remover"
class="btn btn-warning"
value="Remover Logo"/>
{% endif %}
</div>"""),
HTML("""
<div class="col-md-12">
{% if not form.fotografia.errors and form.fotografia.value %}
<img class="img-responsive" width="225" height="300"
src="{{ MEDIA_URL }}{{ form.logotipo.value }}">
<br />
<input type="submit"
name="remover"
id="remover"
class="btn btn-warning"
value="Remover Logo"/>
{% endif %}
</div>"""),
row6,
row7,
row8,

21
compilacao/migrations/0045_auto_20160404_1411.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-04-04 17:11
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0044_auto_20160307_0918'),
]
operations = [
migrations.AlterField(
model_name='textoarticulado',
name='observacao',
field=models.TextField(blank=True, default='', verbose_name='Observação'),
preserve_default=False,
),
]

3
compilacao/models.py

@ -90,8 +90,7 @@ PARTICIPACAO_SOCIAL_CHOICES = [
class TextoArticulado(TimestampedMixin):
data = models.DateField(blank=True, null=True, verbose_name=_('Data'))
ementa = models.TextField(verbose_name=_('Ementa'))
observacao = models.TextField(
blank=True, null=True, verbose_name=_('Observação'))
observacao = models.TextField(blank=True, verbose_name=_('Observação'))
numero = models.PositiveIntegerField(verbose_name=_('Número'))
ano = models.PositiveSmallIntegerField(verbose_name=_('Ano'))
tipo_ta = models.ForeignKey(

11
materia/forms.py

@ -70,6 +70,17 @@ class ProposicaoForm(ModelForm):
self.helper.layout = Layout(
Fieldset(_('Incluir Proposição'),
row1, row2, row3, row4,
HTML("""
<div class="img-responsive" width="225" height="300"
src="{{ MEDIA_URL }}{{ form.texto_original.value }}">
<br /><br />
<input type="submit"
name="remover-texto"
id="remover-texto"
class="btn btn-warning"
value="Remover Texto"/>
<p></p>
""", ),
form_actions(more=more))
)
super(ProposicaoForm, self).__init__(

27
materia/migrations/0027_auto_20160404_1409.py

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-04-04 17:09
from __future__ import unicode_literals
from django.db import migrations, models
import materia.models
import sapl.utils
class Migration(migrations.Migration):
dependencies = [
('materia', '0026_auto_20160322_1514'),
]
operations = [
migrations.AlterField(
model_name='materialegislativa',
name='texto_original',
field=models.FileField(blank=True, null=True, upload_to=materia.models.texto_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_txt], verbose_name='Texto Original (PDF)'),
),
migrations.AlterField(
model_name='proposicao',
name='texto_original',
field=models.FileField(blank=True, null=True, upload_to=materia.models.texto_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_txt], verbose_name='Texto Original (PDF)'),
),
]

9
materia/models.py

@ -4,7 +4,8 @@ from model_utils import Choices
from comissoes.models import Comissao
from parlamentares.models import Parlamentar, Partido
from sapl.utils import RANGE_ANOS, YES_NO_CHOICES, xstr
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
restringe_tipos_de_arquivo_txt, xstr)
class TipoMateriaLegislativa(models.Model):
@ -122,7 +123,8 @@ class MateriaLegislativa(models.Model):
blank=True,
null=True,
upload_to=texto_upload_path,
verbose_name=_('Texto Original (PDF)'))
verbose_name=_('Texto Original (PDF)'),
validators=[restringe_tipos_de_arquivo_txt])
class Meta:
verbose_name = _('Matéria Legislativa')
@ -457,7 +459,8 @@ class Proposicao(models.Model):
blank=True,
null=True,
upload_to=texto_upload_path,
verbose_name=_('Texto Original (PDF)'))
verbose_name=_('Texto Original (PDF)'),
validators=[restringe_tipos_de_arquivo_txt])
class Meta:
verbose_name = _('Proposição')

11
materia/views.py

@ -1,3 +1,4 @@
import os
from datetime import datetime
from random import choice
from string import ascii_letters, digits
@ -1359,8 +1360,10 @@ class ProposicaoEditView(CreateView):
proposicao.save()
else:
proposicao.delete()
elif 'salvar' in request.POST:
if 'salvar' or "remover-foto" in request.POST:
if 'texto_original' in request.FILES:
# if os.unlink(proposicao.texto_original.path):
# proposicao.texto_original = None
proposicao.texto_original = request.FILES['texto_original']
tipo = TipoProposicao.objects.get(id=form.data['tipo'])
proposicao.tipo = tipo
@ -1380,6 +1383,12 @@ class ProposicaoEditView(CreateView):
proposicao.materia = materia
if not proposicao.data_envio:
proposicao.data_envio = datetime.now()
if "remover-texto" in request.POST:
try:
os.unlink(proposicao.texto_original.path)
except OSError:
pass # Should log this error!!!!!
proposicao.texto_original = None
proposicao.save()
return redirect(self.get_success_url())
else:

29
parlamentares/forms.py

@ -60,12 +60,12 @@ class ParlamentaresForm (ModelForm):
'cpf': forms.TextInput(attrs={'class': 'cpf'}),
'rg': forms.TextInput(attrs={'class': 'rg'}),
'titulo_eleitor': forms.TextInput(attrs={
'class': 'titulo_eleitor'}),
'class': 'titulo_eleitor'}),
'telefone': forms.TextInput(attrs={'class': 'telefone'}),
'fax': forms.TextInput(attrs={'class': 'telefone'}),
'cep_residencia': forms.TextInput(attrs={'class': 'cep'}),
'telefone_residencia': forms.TextInput(attrs={
'class': 'telefone'}),
'class': 'telefone'}),
'fax_residencia': forms.TextInput(attrs={'class': 'telefone'}),
'fotografia': forms.FileInput,
'biografia': forms.Textarea(attrs={'id': 'biografia-parlamentar'})
@ -131,18 +131,19 @@ class ParlamentaresForm (ModelForm):
row6, row7, row8, row9, row10,
row11, row12, row13,
HTML("""<div class="col-md-12">
{% if form.fotografia.value %}
<img class="img-responsive"
width="225" height="300"
src="{{MEDIA_URL}}{{form.fotografia.value}}">
<br />
<input type="submit"
name="remover"
id="remover"
class="btn btn-warning"
value="Remover Foto"/>
{% endif %}
</div>""", ),
{% if not form.fotografia.errors %}
{% if form.fotografia.value %}
<img class="img-responsive" width="225" height="300"
src="{{ MEDIA_URL }}{{ form.fotografia.value }}">
<br /><br />
<input type="submit"
name="remover-foto"
id="remover-foto"
class="btn btn-warning"
value="Remover Foto"/>
{% endif %}
{% endif %}
</div>""", ),
row14,
form_actions())
)

22
parlamentares/migrations/0016_auto_20160404_1409.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-04-04 17:09
from __future__ import unicode_literals
from django.db import migrations, models
import parlamentares.models
import sapl.utils
class Migration(migrations.Migration):
dependencies = [
('parlamentares', '0015_auto_20160322_1401'),
]
operations = [
migrations.AlterField(
model_name='parlamentar',
name='fotografia',
field=models.ImageField(blank=True, null=True, upload_to=parlamentares.models.foto_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_img], verbose_name='Fotografia'),
),
]

5
parlamentares/models.py

@ -4,7 +4,7 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
from sapl.utils import UF, YES_NO_CHOICES
from sapl.utils import UF, YES_NO_CHOICES, restringe_tipos_de_arquivo_img
class Legislatura(models.Model):
@ -244,7 +244,8 @@ class Parlamentar(models.Model):
blank=True,
null=True,
upload_to=foto_upload_path,
verbose_name=_('Fotografia'))
verbose_name=_('Fotografia'),
validators=[restringe_tipos_de_arquivo_img])
class Meta:
verbose_name = _('Parlamentar')

8
parlamentares/test_parlamentares.py

@ -6,19 +6,19 @@ from .models import (Dependente, Filiacao, Legislatura, Mandato, Parlamentar,
Partido, TipoDependente)
# vamos refazer a funcionalidade adicionando os campos ogrigatórios de mandato
@pytest.mark.django_db(transaction=False)
def test_cadastro_parlamentar(client):
def TODO_DESLIGADO_RELIGAR_test_cadastro_parlamentar(client):
mommy.make(Legislatura, pk=5)
response = client.get(reverse('parlamentares_cadastro', kwargs={'pk': 5}))
assert response.status_code == 200
response = client.post(reverse('parlamentares_cadastro', kwargs={'pk': 5}),
{'nome_completo': 'Teresa Barbosa',
'nome_parlamentar': 'Terezinha',
'sexo': 'F',
'ativo': 'True',
})
'ativo': 'True'}, follow=True)
parlamentar = Parlamentar.objects.first()
assert "Terezinha" == parlamentar.nome_parlamentar
if not parlamentar.ativo:

20
parlamentares/views.py

@ -72,7 +72,7 @@ def validate(form, parlamentar, filiacao, request):
break
if (data_desfiliacao and
data_init < data_desfiliacao < data_fim):
data_init < data_desfiliacao < data_fim):
error_msg = _("A data de filiação e \
desfiliação não podem estar no intervalo \
@ -186,10 +186,6 @@ class ParlamentaresCadastroView(CreateView):
def form_valid(self, form):
form.save()
mandato = Mandato()
mandato.parlamentar = form.instance
mandato.legislatura = Legislatura.objects.get(id=self.kwargs['pk'])
mandato.save()
return redirect(self.get_success_url())
@ -206,7 +202,7 @@ class ParlamentaresEditarView(UpdateView):
elif 'excluir' in self.request.POST:
Mandato.objects.get(parlamentar=parlamentar).delete()
parlamentar.delete()
elif "remover" in self.request.POST:
elif "remover-foto" in self.request.POST:
try:
os.unlink(parlamentar.fotografia.path)
except OSError:
@ -228,7 +224,7 @@ class ParlamentaresDependentesView(CreateView):
def get_context_data(self, **kwargs):
context = super(ParlamentaresDependentesView, self).\
get_context_data(**kwargs)
get_context_data(**kwargs)
pk = self.kwargs['pk']
parlamentar = Parlamentar.objects.get(pk=pk)
dependentes = Dependente.objects.filter(
@ -267,12 +263,12 @@ class ParlamentaresDependentesEditView(UpdateView):
def get_context_data(self, **kwargs):
context = super(ParlamentaresDependentesEditView, self).\
get_context_data(**kwargs)
get_context_data(**kwargs)
parlamentar = Parlamentar.objects.get(id=self.kwargs['pk'])
context.update({
'object': parlamentar,
'legislatura_id': parlamentar.mandato_set.last(
).legislatura_id})
'object': parlamentar,
'legislatura_id': parlamentar.mandato_set.last(
).legislatura_id})
return context
def form_valid(self, form):
@ -527,7 +523,7 @@ class MandatoEditView(UpdateView):
context.update(
{'object': parlamentar,
'legislatura_id': parlamentar.mandato_set.last(
).legislatura_id})
).legislatura_id})
return context
def form_valid(self, form):

4
requirements/requirements.txt

@ -1,10 +1,11 @@
dj-database-url
django-admin-bootstrapped==2.5.7
django-bootstrap3==7.0.0
django-bower==5.1.0
django-braces==1.8.1
django-compressor==2.0
django-crispy-forms==1.6.0
python-decouple==3.0
django-extra-views==0.7.1
django-model-utils==2.4
django-sass-processor==0.3.4
@ -17,3 +18,4 @@ pytz==2015.7
pyyaml==3.11
rtyaml==0.0.2
unipath==1.1
python-magic==0.4.10

29
sapl/settings.py

@ -9,6 +9,8 @@ https://docs.djangoproject.com/en/1.8/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.8/ref/settings/
"""
from decouple import config
from dj_database_url import parse as db_url
from unipath import Path
from .temp_suppress_crispy_form_warnings import \
@ -16,14 +18,15 @@ from .temp_suppress_crispy_form_warnings import \
BASE_DIR = Path(__file__).ancestor(2)
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '!9g1-#la+#(oft(v-y1qhy$jk-2$24pdk69#b_jfqyv!*%a_)t'
SECRET_KEY = config('SECRET_KEY')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True
DEBUG = config('DEBUG', default=False, cast=bool)
ALLOWED_HOSTS = ['*']
@ -105,21 +108,17 @@ WSGI_APPLICATION = 'sapl.wsgi.application'
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': 'sapl',
'USER': 'sapl',
'PASSWORD': 'sapl',
'HOST': 'localhost',
'PORT': '5432',
}
'default': config(
'DATABASE_URL',
cast=db_url,
)
}
EMAIL_USE_TLS = True
EMAIL_HOST = ''
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''
EMAIL_PORT = 587
EMAIL_USE_TLS = config('EMAIL_USE_TLS', cast=bool)
EMAIL_HOST = config('EMAIL_HOST', cast=str)
EMAIL_HOST_USER = config('EMAIL_HOST_USER', cast=str)
EMAIL_HOST_PASSWORD = config('EMAIL_HOST_PASSWORD', cast=str)
EMAIL_PORT = config('EMAIL_PORT', cast=int)
MAX_DOC_UPLOAD_SIZE = 5*1024*1024 # 5MB
MAX_IMAGE_UPLOAD_SIZE = 2*1024*1024 # 2MB

18
sapl/test_general.py

@ -1,16 +1,32 @@
import pytest
from django.apps import apps
from django.db.models import CharField, TextField
from model_mommy import mommy
from .settings import SAPL_APPS
pytestmark = pytest.mark.django_db
sapl_appconfs = [apps.get_app_config(n) for n in SAPL_APPS]
def test_charfiled_textfield():
for app in sapl_appconfs:
for model in app.get_models():
fields = model._meta.local_fields
for field in fields:
if isinstance(field, (CharField, TextField)):
msg = 'Model = %s || Field = %s - %s - %s' % (
model.__name__,
field.attname,
type(field).__name__,
field.null)
assert not field.null, msg
def test_str_sanity():
# this simply a sanity check
# __str__ semantics is not considered and should be tested separetely
sapl_appconfs = [apps.get_app_config(n) for n in SAPL_APPS]
for app in sapl_appconfs:
for model in app.get_models():
obj = mommy.prepare(model)

119
sapl/utils.py

@ -1,8 +1,10 @@
from datetime import date
from functools import wraps
import magic
from django.apps import apps
from django.contrib import admin
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
@ -92,34 +94,93 @@ def listify(function):
return f
UF = [
('AC', 'Acre'),
('AL', 'Alagoas'),
('AP', 'Amapá'),
('AM', 'Amazonas'),
('BA', 'Bahia'),
('CE', 'Ceará'),
('DF', 'Distrito Federal'),
('ES', 'Espírito Santo'),
('GO', 'Goiás'),
('MA', 'Maranhão'),
('MT', 'Mato Grosso'),
('MS', 'Mato Grosso do Sul'),
('MG', 'Minas Gerais'),
('PR', 'Paraná'),
('PB', 'Paraíba'),
('PA', 'Pará'),
('PE', 'Pernambuco'),
('PI', 'Piauí'),
('RJ', 'Rio de Janeiro'),
('RN', 'Rio Grande do Norte'),
('RS', 'Rio Grande do Sul'),
('RO', 'Rondônia'),
('RR', 'Roraima'),
('SC', 'Santa Catarina'),
('SE', 'Sergipe'),
('SP', 'São Paulo'),
('TO', 'Tocantins'),
('EX', 'Exterior'),
]
('AC', 'Acre'),
('AL', 'Alagoas'),
('AP', 'Amapá'),
('AM', 'Amazonas'),
('BA', 'Bahia'),
('CE', 'Ceará'),
('DF', 'Distrito Federal'),
('ES', 'Espírito Santo'),
('GO', 'Goiás'),
('MA', 'Maranhão'),
('MT', 'Mato Grosso'),
('MS', 'Mato Grosso do Sul'),
('MG', 'Minas Gerais'),
('PR', 'Paraná'),
('PB', 'Paraíba'),
('PA', 'Pará'),
('PE', 'Pernambuco'),
('PI', 'Piauí'),
('RJ', 'Rio de Janeiro'),
('RN', 'Rio Grande do Norte'),
('RS', 'Rio Grande do Sul'),
('RO', 'Rondônia'),
('RR', 'Roraima'),
('SC', 'Santa Catarina'),
('SE', 'Sergipe'),
('SP', 'São Paulo'),
('TO', 'Tocantins'),
('EX', 'Exterior'),
]
RANGE_ANOS = [(year, year) for year in range(date.today().year, 1889, -1)]
TIPOS_TEXTO_PERMITIDOS = (
'application/vnd.oasis.opendocument.text',
'application/x-vnd.oasis.opendocument.text',
'application/pdf',
'application/x-pdf',
'application/acrobat',
'applications/vnd.pdf',
'text/pdf',
'text/x-pdf',
'text/plain',
'application/txt',
'browser/internal',
'text/anytext',
'widetext/plain',
'widetext/paragraph',
'application/msword',
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'application/xml',
'text/xml',
'text/html',
)
TIPOS_IMG_PERMITIDOS = (
'image/jpeg',
'image/jpg',
'image/jpe_',
'image/pjpeg',
'image/vnd.swiftview-jpeg',
'application/jpg',
'application/x-jpg',
'image/pjpeg',
'image/pipeg',
'image/vnd.swiftview-jpeg',
'image/x-xbitmap',
'image/bmp',
'image/x-bmp',
'image/x-bitmap',
'image/png',
'application/png',
'application/x-png',
)
def fabrica_validador_de_tipos_de_arquivo(lista, nome):
def restringe_tipos_de_arquivo(value):
mime = magic.from_buffer(value.read(), mime=True)
mime = mime.decode()
if mime not in lista:
raise ValidationError(_('Tipo de arquivo não suportado'))
# o nome é importante para as migrations
restringe_tipos_de_arquivo.__name__ = nome
return restringe_tipos_de_arquivo
restringe_tipos_de_arquivo_txt = fabrica_validador_de_tipos_de_arquivo(
TIPOS_TEXTO_PERMITIDOS, 'restringe_tipos_de_arquivo_txt')
restringe_tipos_de_arquivo_img = fabrica_validador_de_tipos_de_arquivo(
TIPOS_IMG_PERMITIDOS, 'restringe_tipos_de_arquivo_img')

27
sessao/migrations/0016_auto_20160404_1409.py

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9 on 2016-04-04 17:09
from __future__ import unicode_literals
from django.db import migrations, models
import sapl.utils
import sessao.models
class Migration(migrations.Migration):
dependencies = [
('sessao', '0015_auto_20160307_0918'),
]
operations = [
migrations.AlterField(
model_name='sessaoplenaria',
name='upload_ata',
field=models.FileField(blank=True, null=True, upload_to=sessao.models.ata_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_txt], verbose_name='Ata da Sessão'),
),
migrations.AlterField(
model_name='sessaoplenaria',
name='upload_pauta',
field=models.FileField(blank=True, null=True, upload_to=sessao.models.pauta_upload_path, validators=[sapl.utils.restringe_tipos_de_arquivo_txt], verbose_name='Pauta da Sessão'),
),
]

8
sessao/models.py

@ -5,7 +5,7 @@ from model_utils import Choices
from materia.models import MateriaLegislativa
from parlamentares.models import (CargoMesa, Legislatura, Parlamentar,
SessaoLegislativa)
from sapl.utils import YES_NO_CHOICES
from sapl.utils import YES_NO_CHOICES, restringe_tipos_de_arquivo_txt
class TipoSessaoPlenaria(models.Model):
@ -63,12 +63,14 @@ class SessaoPlenaria(models.Model):
blank=True,
null=True,
upload_to=pauta_upload_path,
verbose_name=_('Pauta da Sessão'))
verbose_name=_('Pauta da Sessão'),
validators=[restringe_tipos_de_arquivo_txt])
upload_ata = models.FileField(
blank=True,
null=True,
upload_to=ata_upload_path,
verbose_name=_('Ata da Sessão'))
verbose_name=_('Ata da Sessão'),
validators=[restringe_tipos_de_arquivo_txt])
iniciada = models.NullBooleanField(blank=True,
choices=YES_NO_CHOICES,
verbose_name=_('Sessão iniciada?'))

14
templates/materia/proposicao/proposicao_list.html

@ -3,16 +3,16 @@
{% load crispy_forms_tags %}
{% block actions %}<!-- Remvoer botões 'Editar' e 'Excluir' -->{% endblock %}
<!--
{% block sections_nav %}
<h2><b>Proposições</b></h2>
<br />
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'materia:adicionar_proposicao' %}" class="btn btn-default">Nova Proposição</a>
</div>
{% endblock %}
{% endblock %} -->
{% block detail_content %}
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'adicionar_proposicao' %}" class="btn btn-default">Nova Proposição</a>
</div>
<h2><b>Proposições</b></h2>
<table class="table table-striped table-bordered">
<thead class="thead-default">
<tr>

2
templates/sessao/sessao_list.html

@ -3,8 +3,8 @@
{% load crispy_forms_tags %}
{% block base_content %}
<h2><b>Sessões Plenárias</b></h2>
<div class="actions btn-group pull-right" role="group">
<h2>Sessões Plenárias</h2>
<a href="{% url 'sessao:sessao_cadastro' %}" class="btn btn-default">
{% blocktrans with verbose_name=view.verbose_name %} Adicionar Sessão Plenária {% endblocktrans %}
</a>

Loading…
Cancel
Save