Browse Source

Permitir o download de documentos acessórios em matéria legislativa (#3139)

* Fix #3127

* Adiciona merger de PDF

* Adiciona pypdf4 em requirements.txt

* Adicionando mensagem de erro caso não tenha documento acessório

* Subido algumas recomendações(logs, exceptions, localização de imports)

* Mudando maneira de pegar o diretorio tmp

* Concertando problema de css

* Arrumando mensagem de erro para quando todos os documentos acessorios não tem pdf cadastrados

* Generalizando tmp file para utils.py

* Adicionando logs de info e quebrando linhas grandes

Co-authored-by: eribeiro <edwardr@senado.leg.br>
Co-authored-by: ulysses <ulysses3353@gmail.com>
pull/3008/head
Edward 5 years ago
committed by GitHub
parent
commit
6bdbf25334
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      requirements/requirements.txt
  2. 6
      sapl/materia/urls.py
  3. 130
      sapl/materia/views.py
  4. 13
      sapl/templates/materia/documentoacessorio_list.html
  5. 6
      sapl/utils.py

2
requirements/requirements.txt

@ -29,7 +29,7 @@ Pillow==6.2.2
gunicorn==19.9.0 gunicorn==19.9.0
more-itertools==8.2.0 more-itertools==8.2.0
pysolr==3.6.0 pysolr==3.6.0
PyPDF4==1.27.0
pyoai==2.5.0 pyoai==2.5.0
git+https://github.com/interlegis/trml2pdf git+https://github.com/interlegis/trml2pdf

6
sapl/materia/urls.py

@ -27,7 +27,7 @@ from sapl.materia.views import (AcompanhamentoConfirmarView,
proposicao_texto, recuperar_materia, proposicao_texto, recuperar_materia,
ExcluirTramitacaoEmLoteView, RetornarProposicao, ExcluirTramitacaoEmLoteView, RetornarProposicao,
MateriaPesquisaSimplesView, MateriaPesquisaSimplesView,
DespachoInicialMultiCreateView) DespachoInicialMultiCreateView, get_zip_docacessorios, get_pdf_docacessorios)
from sapl.norma.views import NormaPesquisaSimplesView from sapl.norma.views import NormaPesquisaSimplesView
from sapl.protocoloadm.views import ( from sapl.protocoloadm.views import (
FichaPesquisaAdmView, FichaSelecionaAdmView) FichaPesquisaAdmView, FichaSelecionaAdmView)
@ -118,6 +118,10 @@ urlpatterns_materia = [
name='tramitacao_em_lote'), name='tramitacao_em_lote'),
url(r'^materia/excluir-tramitacao-em-lote', ExcluirTramitacaoEmLoteView.as_view(), url(r'^materia/excluir-tramitacao-em-lote', ExcluirTramitacaoEmLoteView.as_view(),
name='excluir_tramitacao_em_lote'), name='excluir_tramitacao_em_lote'),
url(r'^materia/docacessorio/zip/(?P<pk>\d+)$', get_zip_docacessorios,
name='compress_docacessorios'),
url(r'^materia/docacessorio/pdf/(?P<pk>\d+)$', get_pdf_docacessorios,
name='merge_docacessorios')
] ]

130
sapl/materia/views.py

@ -6,11 +6,15 @@ import sapl
import shutil import shutil
import tempfile import tempfile
import weasyprint import weasyprint
import time
from crispy_forms.layout import HTML from crispy_forms.layout import HTML
from datetime import datetime from datetime import datetime
from random import choice from random import choice
from string import ascii_letters, digits from string import ascii_letters, digits
from datetime import datetime
from PyPDF4 import PdfFileReader, PdfFileMerger
import zipfile
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
@ -52,7 +56,7 @@ from sapl.settings import MAX_DOC_UPLOAD_SIZE, MEDIA_ROOT
from sapl.utils import (autor_label, autor_modal, gerar_hash_arquivo, get_base_url, from sapl.utils import (autor_label, autor_modal, gerar_hash_arquivo, get_base_url,
get_client_ip, get_mime_type_from_file_extension, lista_anexados, get_client_ip, get_mime_type_from_file_extension, lista_anexados,
mail_service_configured, montar_row_autor, SEPARADOR_HASH_PROPOSICAO, mail_service_configured, montar_row_autor, SEPARADOR_HASH_PROPOSICAO,
show_results_filter_set, YES_NO_CHOICES) show_results_filter_set, YES_NO_CHOICES,get_tempfile_dir)
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
AnexadaEmLoteFilterSet, AdicionarVariasAutoriasFilterSet, AnexadaEmLoteFilterSet, AdicionarVariasAutoriasFilterSet,
@ -2725,3 +2729,127 @@ class TipoMateriaCrud(CrudAux):
self.object.save() self.object.save()
return fv return fv
def create_zip_docacessorios(materia):
logger = logging.getLogger(__name__)
docs = materia.documentoacessorio_set.\
all().values_list('arquivo', flat=True)
if not docs:
return None, None
docs_path = [os.path.join(MEDIA_ROOT, i) for i in docs]
if not docs_path:
raise FileNotFoundError("Não há arquivos PDF cadastrados em documentos acessorios.")
logger.info("Gerando compilado PDF de documentos acessorios com {} documentos".format(docs_path))
zipfilename = '{}/mat_{}_{}_docacessorios.zip'.format(
get_tempfile_dir(),
materia.pk,
time.mktime(datetime.now().timetuple()))
with zipfile.ZipFile(zipfilename, 'w', zipfile.ZIP_DEFLATED) as zipf:
for f in docs_path:
zipf.write(f, f.split(os.sep)[-1])
external_name = "mat_{}_{}_docacessorios.zip".format(materia.numero, materia.ano)
return external_name, zipfilename
def get_zip_docacessorios(request, pk):
logger = logging.getLogger(__name__)
username = request.user.username
materia = get_object_or_404(MateriaLegislativa, pk=pk)
try:
external_name, zipfilename = create_zip_docacessorios(materia)
logger.info("user= {}. Gerou o zip compilado de documento acessorios")
except FileNotFoundError:
logger.error("user= {}.Não há arquivos cadastrados".format(username))
msg=_('Não há arquivos cadastrados nesses documentos acessórios.')
messages.add_message(request, messages.ERROR, msg)
return redirect(reverse('sapl.materia:documentoacessorio_list',
kwargs={'pk': pk}))
except Exception as e:
logger.error("user={}. Um erro inesperado ocorreu na criação do pdf de documentos acessorios: {}"
.format(username,str(e)))
msg=_('Um erro inesperado ocorreu. Entre em contato com o suporte do SAPL.')
messages.add_message(request, messages.ERROR, msg)
return redirect(reverse('sapl.materia:documentoacessorio_list',
kwargs={'pk': pk}))
if not zipfilename:
msg=_('Não há nenhum documento acessório cadastrado.')
messages.add_message(request, messages.ERROR, msg)
return redirect(reverse('sapl.materia:documentoacessorio_list',
kwargs={'pk': pk}))
with open(os.path.join(get_tempfile_dir(), zipfilename), 'rb') as f:
data = f.read()
response = HttpResponse(data, content_type='application/zip')
response['Content-Disposition'] = ('attachment; filename="%s"'
% external_name)
return response
def create_pdf_docacessorios(materia):
logger = logging.getLogger(__name__)
docs = materia.documentoacessorio_set. \
all().values_list('arquivo', flat=True)
if not docs:
return None, None
# TODO: o for-comprehension abaixo filtra os arquivos não PDF.
# TODO: o que fazer com os arquivos não PDF? converter? ignorar?
docs_path = [os.path.join(MEDIA_ROOT, i) for i in docs if i.lower().endswith('pdf')]
if not docs_path:
raise FileNotFoundError("Não há arquivos PDF cadastrados em documentos acessorios.")
logger.info("Gerando compilado PDF de documentos acessorios com {} documentos"
.format(docs_path))
merged_pdf = '{}/mat_{}_{}_docacessorios.pdf'.format(
get_tempfile_dir(),
materia.pk,
time.mktime(datetime.now().timetuple()))
merger = PdfFileMerger()
for f in docs_path:
merger.append(fileobj=f)
merger.write(fileobj=open(merged_pdf, "wb"))
merger.close()
external_name = "mat_{}_{}_docacessorios.pdf".format(materia.numero, materia.ano)
return external_name, merged_pdf
def get_pdf_docacessorios(request, pk):
materia = get_object_or_404(MateriaLegislativa, pk=pk)
logger = logging.getLogger(__name__)
username = request.user.username
try:
external_name, pdffilename = create_pdf_docacessorios(materia)
logger.info("user= {}. Gerou o pdf compilado de documento acessorios")
except FileNotFoundError:
logger.error("user= {}.Não há arquivos cadastrados".format(username))
msg=_('Não há arquivos cadastrados nesses documentos acessórios.')
messages.add_message(request, messages.ERROR, msg)
return redirect(reverse('sapl.materia:documentoacessorio_list',
kwargs={'pk': pk}))
except Exception as e:
logger.error("user= {}.Um erro inesperado ocorreu na criação do pdf de documentos acessorios: {}"
.format(username,str(e)))
msg=_('Um erro inesperado ocorreu. Entre em contato com o suporte do SAPL.')
messages.add_message(request, messages.ERROR, msg)
return redirect(reverse('sapl.materia:documentoacessorio_list',
kwargs={'pk': pk}))
if not pdffilename:
msg=_('Não há nenhum documento acessório PDF cadastrado.')
messages.add_message(request, messages.ERROR, msg)
return redirect(reverse('sapl.materia:documentoacessorio_list',
kwargs={'pk': pk}))
with open(os.path.join(get_tempfile_dir(), pdffilename), 'rb') as f:
data = f.read()
response = HttpResponse(data, content_type='application/pdf')
response['Content-Disposition'] = ('attachment; filename="%s"'
% external_name)
return response

13
sapl/templates/materia/documentoacessorio_list.html

@ -0,0 +1,13 @@
{% extends "crud/list.html" %}
{% load i18n %}
{% block base_content %}
{{ block.super }}
<div style="display:flex;padding-left: 600px;padding-top: 10px;">
<div class="actions btn-group float-right" role="group">
<a href="{% url 'sapl.materia:merge_docacessorios' root_pk %}" class="btn btn-outline-primary">{% trans 'Baixar documentos como PDF único' %}</a>
</div>
<div class="actions btn-group float-right" role="group">
<a href="{% url 'sapl.materia:compress_docacessorios' root_pk %}" class="btn btn-outline-primary">{% trans 'Baixar documentos compactados' %}</a>
</div>
</div>
{% endblock %}

6
sapl/utils.py

@ -7,7 +7,8 @@ import magic
import os import os
import re import re
import unicodedata import unicodedata
import platform
import tempfile
from crispy_forms.layout import Button, HTML from crispy_forms.layout import Button, HTML
from easy_thumbnails import source_generators from easy_thumbnails import source_generators
from floppyforms import ClearableFileInput from floppyforms import ClearableFileInput
@ -1061,3 +1062,6 @@ class OverwriteStorage(FileSystemStorage):
if self.exists(name): if self.exists(name):
os.remove(os.path.join(settings.MEDIA_ROOT, name)) os.remove(os.path.join(settings.MEDIA_ROOT, name))
return name return name
def get_tempfile_dir():
return '/tmp' if platform.system() == 'Darwin' else tempfile.gettempdir()

Loading…
Cancel
Save