Browse Source

Add func de corte de fotografia de parlamentar (#1689)

* Add func de corte de fotografia de parlamentar

* add size warning
pull/1696/head
Leandro Roberto da Silva 7 years ago
committed by Edward
parent
commit
310af251bd
  1. 1
      requirements/requirements.txt
  2. 5
      sapl/crud/base.py
  3. 18
      sapl/parlamentares/forms.py
  4. 30
      sapl/parlamentares/migrations/0016_auto_20180202_1331.py
  5. 21
      sapl/parlamentares/migrations/0017_auto_20180202_1528.py
  6. 17
      sapl/parlamentares/models.py
  7. 33
      sapl/parlamentares/views.py
  8. 10
      sapl/settings.py
  9. 1
      sapl/static/js/app.js
  10. 4
      sapl/static/styles/app.scss
  11. 2
      sapl/templates/base.html
  12. 17
      sapl/templates/parlamentares/layouts.yaml
  13. 47
      sapl/templates/parlamentares/parlamentares_list.html
  14. 4
      sapl/templates/parlamentares/public_composicaomesa_form.html

1
requirements/requirements.txt

@ -19,6 +19,7 @@ django-sass-processor==0.5.4
djangorestframework==3.4.0 djangorestframework==3.4.0
drfdocs==0.0.11 drfdocs==0.0.11
easy-thumbnails==2.3 easy-thumbnails==2.3
django-image-cropping==1.1.0
git+git://github.com/interlegis/trml2pdf.git git+git://github.com/interlegis/trml2pdf.git
libsass==0.11.1 libsass==0.11.1
psycopg2==2.7.3 psycopg2==2.7.3

5
sapl/crud/base.py

@ -17,8 +17,8 @@ from django.http.response import Http404
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils.decorators import classonlymethod from django.utils.decorators import classonlymethod
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import string_concat from django.utils.translation import string_concat
from django.utils.translation import ugettext_lazy as _
from django.views.generic import (CreateView, DeleteView, DetailView, ListView, from django.views.generic import (CreateView, DeleteView, DetailView, ListView,
UpdateView) UpdateView)
from django.views.generic.base import ContextMixin from django.views.generic.base import ContextMixin
@ -30,6 +30,7 @@ from sapl.rules.map_rules import (RP_ADD, RP_CHANGE, RP_DELETE, RP_DETAIL,
from sapl.settings import BASE_DIR from sapl.settings import BASE_DIR
from sapl.utils import normalize from sapl.utils import normalize
logger = logging.getLogger(BASE_DIR.name) logger = logging.getLogger(BASE_DIR.name)
ACTION_LIST, ACTION_CREATE, ACTION_DETAIL, ACTION_UPDATE, ACTION_DELETE = \ ACTION_LIST, ACTION_CREATE, ACTION_DETAIL, ACTION_UPDATE, ACTION_DELETE = \
@ -39,6 +40,7 @@ ACTION_LIST, ACTION_CREATE, ACTION_DETAIL, ACTION_UPDATE, ACTION_DELETE = \
def _form_invalid_message(msg): def _form_invalid_message(msg):
return '%s %s' % (_('Formulário inválido.'), msg) return '%s %s' % (_('Formulário inválido.'), msg)
FORM_MESSAGES = {ACTION_CREATE: (_('Registro criado com sucesso!'), FORM_MESSAGES = {ACTION_CREATE: (_('Registro criado com sucesso!'),
_('O registro não foi criado.')), _('O registro não foi criado.')),
ACTION_UPDATE: (_('Registro alterado com sucesso!'), ACTION_UPDATE: (_('Registro alterado com sucesso!'),
@ -79,6 +81,7 @@ def make_pagination(index, num_pages):
head = from_to(1, PAGINATION_LENGTH - len(tail) - 1) head = from_to(1, PAGINATION_LENGTH - len(tail) - 1)
return head + [None] + tail return head + [None] + tail
""" """
variáveis do crud: variáveis do crud:
help_topic help_topic

18
sapl/parlamentares/forms.py

@ -13,6 +13,7 @@ from django.forms import ModelForm
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from floppyforms.widgets import ClearableFileInput from floppyforms.widgets import ClearableFileInput
from image_cropping.widgets import ImageCropWidget, CropWidget
from sapl.crispy_layout_mixin import form_actions, to_row from sapl.crispy_layout_mixin import form_actions, to_row
from sapl.rules import SAPL_GROUP_VOTANTE from sapl.rules import SAPL_GROUP_VOTANTE
@ -26,6 +27,18 @@ class ImageThumbnailFileInput(ClearableFileInput):
template_name = 'floppyforms/image_thumbnail.html' template_name = 'floppyforms/image_thumbnail.html'
class CustomImageCropWidget(ImageCropWidget):
"""
Custom ImageCropWidget that doesn't show the initial value of the field.
We use this trick, and place it right under the CropWidget so that
it looks like the user is seeing the image and clearing the image.
"""
template_with_initial = (
# '%(initial_text)s: <a href="%(initial_url)s">%(initial)s</a> '
'%(clear_template)s<br />%(input_text)s: %(input)s'
)
def validar_datas_legislatura(eleicao, inicio, fim, pk=None): def validar_datas_legislatura(eleicao, inicio, fim, pk=None):
# Verifica se data de eleição < inicio < fim # Verifica se data de eleição < inicio < fim
@ -128,7 +141,10 @@ class ParlamentarForm(ModelForm):
class Meta: class Meta:
model = Parlamentar model = Parlamentar
exclude = [] exclude = []
widgets = {'fotografia': ImageThumbnailFileInput,
widgets = {
'fotografia': CustomImageCropWidget(),
'cropping': CropWidget(),
'biografia': forms.Textarea( 'biografia': forms.Textarea(
attrs={'id': 'texto-rico'})} attrs={'id': 'texto-rico'})}

30
sapl/parlamentares/migrations/0016_auto_20180202_1331.py

@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.13 on 2018-02-02 15:31
from __future__ import unicode_literals
from django.db import migrations
import image_cropping.fields
import sapl.parlamentares.models
import sapl.utils
class Migration(migrations.Migration):
dependencies = [
('parlamentares', '0015_auto_20180131_1629'),
]
operations = [
migrations.AddField(
model_name='parlamentar',
name='cropping',
field=image_cropping.fields.ImageRatioField('fotografia', '128x128', adapt_rotation=False, allow_fullsize=False, free_crop=False,
help_text='A configuração do Avatar é possível após a atualização da fotografia.', hide_image_field=False, size_warning=False, verbose_name='Avatar'),
),
migrations.AlterField(
model_name='parlamentar',
name='fotografia',
field=image_cropping.fields.ImageCropField(blank=True, null=True, upload_to=sapl.parlamentares.models.foto_upload_path, validators=[
sapl.utils.restringe_tipos_de_arquivo_img], verbose_name='Fotografia'),
),
]

21
sapl/parlamentares/migrations/0017_auto_20180202_1528.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.13 on 2018-02-02 17:28
from __future__ import unicode_literals
from django.db import migrations
import image_cropping.fields
class Migration(migrations.Migration):
dependencies = [
('parlamentares', '0016_auto_20180202_1331'),
]
operations = [
migrations.AlterField(
model_name='parlamentar',
name='cropping',
field=image_cropping.fields.ImageRatioField('fotografia', '128x128', adapt_rotation=False, allow_fullsize=False, free_crop=False, help_text='A configuração do Avatar é possível após a atualização da fotografia.', hide_image_field=False, size_warning=True, verbose_name='Avatar'),
),
]

17
sapl/parlamentares/models.py

@ -1,9 +1,10 @@
import reversion
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from image_cropping.fields import ImageCropField, ImageRatioField
from model_utils import Choices from model_utils import Choices
import reversion
from sapl.base.models import Autor from sapl.base.models import Autor
from sapl.decorators import vigencia_atual from sapl.decorators import vigencia_atual
@ -262,12 +263,14 @@ class Parlamentar(models.Model):
blank=True, verbose_name=_('Biografia')) blank=True, verbose_name=_('Biografia'))
# XXX Esse atribuito foi colocado aqui para não atrapalhar a migração # XXX Esse atribuito foi colocado aqui para não atrapalhar a migração
fotografia = models.ImageField( fotografia = ImageCropField(
blank=True, verbose_name=_('Fotografia'), upload_to=foto_upload_path,
null=True, validators=[restringe_tipos_de_arquivo_img], null=True, blank=True)
upload_to=foto_upload_path,
verbose_name=_('Fotografia'), cropping = ImageRatioField(
validators=[restringe_tipos_de_arquivo_img]) 'fotografia', '128x128', verbose_name=_('Avatar'), size_warning=True,
help_text=_('A configuração do Avatar '
'é possível após a atualização da fotografia.'))
# campo conceitual de reversão genérica para o model Autor que dá a # campo conceitual de reversão genérica para o model Autor que dá a
# o meio possível de localização de tipos de autores. # o meio possível de localização de tipos de autores.

33
sapl/parlamentares/views.py

@ -1,5 +1,5 @@
import json
from datetime import datetime from datetime import datetime
import json
from django.contrib import messages from django.contrib import messages
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
@ -33,6 +33,7 @@ from .models import (CargoMesa, Coligacao, ComposicaoColigacao, ComposicaoMesa,
NivelInstrucao, Parlamentar, Partido, SessaoLegislativa, NivelInstrucao, Parlamentar, Partido, SessaoLegislativa,
SituacaoMilitar, TipoAfastamento, TipoDependente, Votante) SituacaoMilitar, TipoAfastamento, TipoDependente, Votante)
CargoMesaCrud = CrudAux.build(CargoMesa, 'cargo_mesa') CargoMesaCrud = CrudAux.build(CargoMesa, 'cargo_mesa')
PartidoCrud = CrudAux.build(Partido, 'partidos') PartidoCrud = CrudAux.build(Partido, 'partidos')
SessaoLegislativaCrud = CrudAux.build(SessaoLegislativa, 'sessao_legislativa') SessaoLegislativaCrud = CrudAux.build(SessaoLegislativa, 'sessao_legislativa')
@ -396,7 +397,6 @@ class ParlamentarCrud(Crud):
class BaseMixin(Crud.BaseMixin): class BaseMixin(Crud.BaseMixin):
ordered_list = False ordered_list = False
list_field_names = [ list_field_names = [
'avatar_html',
'nome_parlamentar', 'nome_parlamentar',
'filiacao_atual', 'filiacao_atual',
'ativo', 'ativo',
@ -421,6 +421,10 @@ class ParlamentarCrud(Crud):
class UpdateView(Crud.UpdateView): class UpdateView(Crud.UpdateView):
form_class = ParlamentarForm form_class = ParlamentarForm
@property
def layout_key(self):
return 'ParlamentarUpdate'
class CreateView(Crud.CreateView): class CreateView(Crud.CreateView):
form_class = ParlamentarCreateForm form_class = ParlamentarCreateForm
@ -477,8 +481,7 @@ class ParlamentarCrud(Crud):
mandato_titular=F('mandato__titular')) mandato_titular=F('mandato__titular'))
def get_headers(self): def get_headers(self):
return ['', return [_('Parlamentar'), _('Partido'),
_('Parlamentar'), _('Partido'),
_('Ativo?'), _('Titular?')] _('Ativo?'), _('Titular?')]
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
@ -489,26 +492,19 @@ class ParlamentarCrud(Crud):
context['legislaturas'] = legislaturas context['legislaturas'] = legislaturas
context['legislatura_id'] = self.take_legislatura_id() context['legislatura_id'] = self.take_legislatura_id()
# Tira Link do avatar_html e coloca no nome
for row in context['rows']: for row in context['rows']:
# preenche coluna foto, se vazia
if not row[0][0]:
img = "<center><img width='50px' \
height='50px' src='%s'/></center>" \
% static('img/avatar.png')
row[0] = (img, row[0][1])
# Coloca a filiação atual ao invés da última
if row[0][1]:
# Pega o Parlamentar por meio da pk # Pega o Parlamentar por meio da pk
parlamentar = Parlamentar.objects.get( parlamentar = Parlamentar.objects.get(
id=(row[0][1].split('/')[-1])) id=(row[0][1].split('/')[-1]))
row[0] += (parlamentar, )
# Pega a Legislatura # Pega a Legislatura
legislatura = Legislatura.objects.get( legislatura = Legislatura.objects.get(
id=context['legislatura_id']) id=context['legislatura_id'])
# Coloca a filiação atual ao invés da última
# As condições para mostrar a filiação são: # As condições para mostrar a filiação são:
# A data de filiacao deve ser menor que a data de fim # A data de filiacao deve ser menor que a data de fim
# da legislatura e data de desfiliação deve nula, ou maior, # da legislatura e data de desfiliação deve nula, ou maior,
@ -522,21 +518,18 @@ class ParlamentarCrud(Crud):
# Caso não exista filiação com essas condições # Caso não exista filiação com essas condições
except ObjectDoesNotExist: except ObjectDoesNotExist:
row[2] = ('Não possui filiação', None) row[1] = ('Não possui filiação', None)
# Caso exista mais de uma filiação nesse intervalo # Caso exista mais de uma filiação nesse intervalo
# Entretanto, NÃO DEVE OCORRER # Entretanto, NÃO DEVE OCORRER
except MultipleObjectsReturned: except MultipleObjectsReturned:
row[2] = ( row[1] = (
'O Parlamentar possui duas filiações conflitantes', 'O Parlamentar possui duas filiações conflitantes',
None) None)
# Caso encontre UMA filiação nessas condições # Caso encontre UMA filiação nessas condições
else: else:
row[2] = (filiacao.partido.sigla, None) row[1] = (filiacao.partido.sigla, None)
row[1] = (row[1][0], row[0][1])
row[0] = (row[0][0], None)
return context return context

10
sapl/settings.py

@ -17,11 +17,13 @@ import logging
from decouple import config from decouple import config
from dj_database_url import parse as db_url from dj_database_url import parse as db_url
from easy_thumbnails.conf import Settings as thumbnail_settings
from unipath import Path from unipath import Path
from .temp_suppress_crispy_form_warnings import \ from .temp_suppress_crispy_form_warnings import \
SUPRESS_CRISPY_FORM_WARNINGS_LOGGING SUPRESS_CRISPY_FORM_WARNINGS_LOGGING
BASE_DIR = Path(__file__).ancestor(1) BASE_DIR = Path(__file__).ancestor(1)
PROJECT_DIR = Path(__file__).ancestor(2) PROJECT_DIR = Path(__file__).ancestor(2)
@ -79,6 +81,7 @@ INSTALLED_APPS = (
'bootstrap3', # basically for django_admin_bootstrapped 'bootstrap3', # basically for django_admin_bootstrapped
'crispy_forms', 'crispy_forms',
'easy_thumbnails', 'easy_thumbnails',
'image_cropping',
'floppyforms', 'floppyforms',
'haystack', 'haystack',
'sass_processor', 'sass_processor',
@ -181,6 +184,12 @@ DATABASES = {
) )
} }
IMAGE_CROPPING_JQUERY_URL = None
THUMBNAIL_PROCESSORS = (
'image_cropping.thumbnail_processors.crop_corners',
) + thumbnail_settings.THUMBNAIL_PROCESSORS
# troque no caso de reimplementação da classe User conforme # troque no caso de reimplementação da classe User conforme
# https://docs.djangoproject.com/en/1.9/topics/auth/customizing/#substituting-a-custom-user-model # https://docs.djangoproject.com/en/1.9/topics/auth/customizing/#substituting-a-custom-user-model
AUTH_USER_MODEL = 'auth.User' AUTH_USER_MODEL = 'auth.User'
@ -300,6 +309,7 @@ def excepthook(*args):
# sys.excepthook = excepthook # sys.excepthook = excepthook
PASSWORD_HASHERS = [ PASSWORD_HASHERS = [
'django.contrib.auth.hashers.PBKDF2PasswordHasher', # default 'django.contrib.auth.hashers.PBKDF2PasswordHasher', # default
'sapl.hashers.ZopeSHA1PasswordHasher', 'sapl.hashers.ZopeSHA1PasswordHasher',

1
sapl/static/js/app.js

@ -1,3 +1,4 @@
function initTinymce(elements, readonly=false) { function initTinymce(elements, readonly=false) {
removeTinymce(); removeTinymce();
var config_tinymce = { var config_tinymce = {

4
sapl/static/styles/app.scss

@ -252,8 +252,8 @@ fieldset {
} }
.avatar-parlamentar { .avatar-parlamentar {
height: 106px; height: 128px;
width: 141px; width: 128px;
margin: 0 auto; margin: 0 auto;
display: table; display: table;
} }

2
sapl/templates/base.html

@ -20,6 +20,7 @@
<link rel="stylesheet" href="{% sass_src 'styles/app.scss' %}" type="text/css"> <link rel="stylesheet" href="{% sass_src 'styles/app.scss' %}" type="text/css">
<link rel="stylesheet" href="{% static 'jquery-ui/themes/cupertino/jquery-ui.min.css' %}"> <link rel="stylesheet" href="{% static 'jquery-ui/themes/cupertino/jquery-ui.min.css' %}">
<script type="text/javascript" src="{% static 'jquery/dist/jquery.min.js' %}"></script>
{# Scripts #} {# Scripts #}
{# modernizr must be in head (see http://modernizr.com/docs/#installing) #} {# modernizr must be in head (see http://modernizr.com/docs/#installing) #}
@ -224,7 +225,6 @@
{% block foot_js %} {% block foot_js %}
<!-- Bootstrap core JavaScript ================================================== --> <!-- Bootstrap core JavaScript ================================================== -->
<!-- Placed at the end of the document so the pages load faster --> <!-- Placed at the end of the document so the pages load faster -->
<script type="text/javascript" src="{% static 'jquery/dist/jquery.min.js' %}"></script>
<script type="text/javascript" src="{% static 'bootstrap-sass/assets/javascripts/bootstrap.min.js' %}"></script> <script type="text/javascript" src="{% static 'bootstrap-sass/assets/javascripts/bootstrap.min.js' %}"></script>
<script type="text/javascript" src="{% static 'jquery-ui/jquery-ui.min.js' %}"></script> <script type="text/javascript" src="{% static 'jquery-ui/jquery-ui.min.js' %}"></script>

17
sapl/templates/parlamentares/layouts.yaml

@ -45,6 +45,23 @@ Parlamentar:
- fotografia - fotografia
- biografia - biografia
ParlamentarUpdate:
{% trans 'Cadastro do Parlamentar' %}:
- nome_parlamentar:8 ativo
- nome_completo
- nivel_instrucao sexo data_nascimento
- cpf rg titulo_eleitor
- situacao_militar profissao
- endereco_web
- email
- numero_gab_parlamentar telefone fax
- endereco_residencia cep_residencia
- municipio_residencia uf_residencia
- telefone_residencia fax_residencia
- locais_atuacao
- fotografia cropping
- biografia
ParlamentarCreate: ParlamentarCreate:
{% trans 'Dados do Mandato' %}: {% trans 'Dados do Mandato' %}:
- legislatura data_expedicao_diploma - legislatura data_expedicao_diploma

47
sapl/templates/parlamentares/parlamentares_list.html

@ -1,6 +1,6 @@
{% extends "crud/list.html" %} {% extends "crud/list.html" %}
{% load i18n %} {% load i18n %}
{% load crispy_forms_tags %} {% load crispy_forms_tags cropping%}
{% block extra_content %} {% block extra_content %}
<fieldset class="form-group"> <fieldset class="form-group">
<legend>Selecione o Período</legend> <legend>Selecione o Período</legend>
@ -16,3 +16,48 @@
</fieldset> </fieldset>
<br/> <br/>
{% endblock %} {% endblock %}
{% block container_table_list %}
{% if not rows %}
<p>{{ NO_ENTRIES_MSG }}</p>
{% else %}
<div class="container-table">
<div class="result-count">{% blocktrans with verbose_name_plural=view.verbose_name_plural %}Total de {{ verbose_name_plural }}: <strong>{{count}}</strong>{% endblocktrans %}</div>
<table class="table table-striped table-hover table-link-ordering">
<thead>
<tr>
{% for name in headers %}
{% if forloop.first %}
<th colspan=2>
{% else %}
<th>
{% endif %}
{{ name }}
</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for value_list in rows %}
<tr>
{% for value, href, obj in value_list %}
{% if forloop.first %}
<td>
<img class="avatar-parlamentar" src="{% cropped_thumbnail obj "cropping" %}">
</td>
{% endif %}
<td>
{% if href %}
<a href="{{ href }}">{{ value|safe|default:"" }}</a>
{% else %}
{{ value|safe|default:"" }}
{% endif %}
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
{% endblock %}

4
sapl/templates/parlamentares/public_composicaomesa_form.html

@ -1,5 +1,5 @@
{% extends "crud/detail.html" %} {% extends "crud/detail.html" %}
{% load i18n %} {% load i18n cropping%}
{% block actions %} {% endblock %} {% block actions %} {% endblock %}
{% block detail_content %} {% block detail_content %}
@ -46,7 +46,7 @@
{% for p in composicao_mesa %} {% for p in composicao_mesa %}
<tr> <tr>
{% if p.parlamentar.fotografia %} {% if p.parlamentar.fotografia %}
<td><img class="avatar-parlamentar" src="{{ p.parlamentar.fotografia.url }}"></td> <td><img class="avatar-parlamentar" src="{% cropped_thumbnail p.parlamentar "cropping" %}"></td>
{% else %} {% else %}
<td></td> <td></td>
{% endif %} {% endif %}

Loading…
Cancel
Save