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. 22
      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. 89
      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. 73
      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
drfdocs==0.0.11
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

5
sapl/crud/base.py

@ -17,8 +17,8 @@ from django.http.response import Http404
from django.shortcuts import redirect
from django.utils.decorators import classonlymethod
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 ugettext_lazy as _
from django.views.generic import (CreateView, DeleteView, DetailView, ListView,
UpdateView)
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.utils import normalize
logger = logging.getLogger(BASE_DIR.name)
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):
return '%s %s' % (_('Formulário inválido.'), msg)
FORM_MESSAGES = {ACTION_CREATE: (_('Registro criado com sucesso!'),
_('O registro não foi criado.')),
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)
return head + [None] + tail
"""
variáveis do crud:
help_topic

22
sapl/parlamentares/forms.py

@ -13,6 +13,7 @@ from django.forms import ModelForm
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from floppyforms.widgets import ClearableFileInput
from image_cropping.widgets import ImageCropWidget, CropWidget
from sapl.crispy_layout_mixin import form_actions, to_row
from sapl.rules import SAPL_GROUP_VOTANTE
@ -26,6 +27,18 @@ class ImageThumbnailFileInput(ClearableFileInput):
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):
# Verifica se data de eleição < inicio < fim
@ -128,9 +141,12 @@ class ParlamentarForm(ModelForm):
class Meta:
model = Parlamentar
exclude = []
widgets = {'fotografia': ImageThumbnailFileInput,
'biografia': forms.Textarea(
attrs={'id': 'texto-rico'})}
widgets = {
'fotografia': CustomImageCropWidget(),
'cropping': CropWidget(),
'biografia': forms.Textarea(
attrs={'id': 'texto-rico'})}
class ParlamentarCreateForm(ParlamentarForm):

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.utils import timezone
from django.utils.translation import ugettext_lazy as _
from image_cropping.fields import ImageCropField, ImageRatioField
from model_utils import Choices
import reversion
from sapl.base.models import Autor
from sapl.decorators import vigencia_atual
@ -262,12 +263,14 @@ class Parlamentar(models.Model):
blank=True, verbose_name=_('Biografia'))
# XXX Esse atribuito foi colocado aqui para não atrapalhar a migração
fotografia = models.ImageField(
blank=True,
null=True,
upload_to=foto_upload_path,
verbose_name=_('Fotografia'),
validators=[restringe_tipos_de_arquivo_img])
fotografia = ImageCropField(
verbose_name=_('Fotografia'), upload_to=foto_upload_path,
validators=[restringe_tipos_de_arquivo_img], null=True, blank=True)
cropping = ImageRatioField(
'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
# o meio possível de localização de tipos de autores.

89
sapl/parlamentares/views.py

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

10
sapl/settings.py

@ -17,11 +17,13 @@ import logging
from decouple import config
from dj_database_url import parse as db_url
from easy_thumbnails.conf import Settings as thumbnail_settings
from unipath import Path
from .temp_suppress_crispy_form_warnings import \
SUPRESS_CRISPY_FORM_WARNINGS_LOGGING
BASE_DIR = Path(__file__).ancestor(1)
PROJECT_DIR = Path(__file__).ancestor(2)
@ -79,6 +81,7 @@ INSTALLED_APPS = (
'bootstrap3', # basically for django_admin_bootstrapped
'crispy_forms',
'easy_thumbnails',
'image_cropping',
'floppyforms',
'haystack',
'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
# https://docs.djangoproject.com/en/1.9/topics/auth/customizing/#substituting-a-custom-user-model
AUTH_USER_MODEL = 'auth.User'
@ -300,6 +309,7 @@ def excepthook(*args):
# sys.excepthook = excepthook
PASSWORD_HASHERS = [
'django.contrib.auth.hashers.PBKDF2PasswordHasher', # default
'sapl.hashers.ZopeSHA1PasswordHasher',

1
sapl/static/js/app.js

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

4
sapl/static/styles/app.scss

@ -252,8 +252,8 @@ fieldset {
}
.avatar-parlamentar {
height: 106px;
width: 141px;
height: 128px;
width: 128px;
margin: 0 auto;
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="{% static 'jquery-ui/themes/cupertino/jquery-ui.min.css' %}">
<script type="text/javascript" src="{% static 'jquery/dist/jquery.min.js' %}"></script>
{# Scripts #}
{# modernizr must be in head (see http://modernizr.com/docs/#installing) #}
@ -224,7 +225,6 @@
{% block foot_js %}
<!-- Bootstrap core JavaScript ================================================== -->
<!-- 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 'jquery-ui/jquery-ui.min.js' %}"></script>

17
sapl/templates/parlamentares/layouts.yaml

@ -45,6 +45,23 @@ Parlamentar:
- fotografia
- 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:
{% trans 'Dados do Mandato' %}:
- legislatura data_expedicao_diploma

73
sapl/templates/parlamentares/parlamentares_list.html

@ -1,18 +1,63 @@
{% extends "crud/list.html" %}
{% load i18n %}
{% load crispy_forms_tags %}
{% load crispy_forms_tags cropping%}
{% block extra_content %}
<fieldset class="form-group">
<legend>Selecione o Período</legend>
<form method="GET">
<select name="pk" class="form-control" onChange="form.submit();">
{% for l in legislaturas %}
<option value="{{l.id}}" {% if l.id == legislatura_id %} selected {% endif %}>
{{l}}
</option>
{% endfor %}
</select>
</form>
</fieldset>
<br/>
<fieldset class="form-group">
<legend>Selecione o Período</legend>
<form method="GET">
<select name="pk" class="form-control" onChange="form.submit();">
{% for l in legislaturas %}
<option value="{{l.id}}" {% if l.id == legislatura_id %} selected {% endif %}>
{{l}}
</option>
{% endfor %}
</select>
</form>
</fieldset>
<br/>
{% 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" %}
{% load i18n %}
{% load i18n cropping%}
{% block actions %} {% endblock %}
{% block detail_content %}
@ -46,7 +46,7 @@
{% for p in composicao_mesa %}
<tr>
{% 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 %}
<td></td>
{% endif %}

Loading…
Cancel
Save