Browse Source

Merge branch 'app-contatos' into develop

stable/2.0
Breno Teixeira 11 years ago
parent
commit
c638856cf9
  1. 0
      sigi/apps/__init__.py
  2. 0
      sigi/apps/contatos/__init__.py
  3. 51
      sigi/apps/contatos/admin.py
  4. 89312
      sigi/apps/contatos/fixtures/initial_data.json
  5. 278
      sigi/apps/contatos/models.py
  6. 31
      sigi/apps/utils/__init__.py
  7. 16
      sigi/apps/utils/admin_widgets.py
  8. 71
      sigi/apps/utils/decorators.py
  9. 33
      sigi/apps/utils/email.py
  10. 42
      sigi/apps/utils/validators.py
  11. 3
      sigi/settings.py

0
sigi/apps/__init__.py

0
sigi/apps/contatos/__init__.py

51
sigi/apps/contatos/admin.py

@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
from sigi.apps.contatos.models import (UnidadeFederativa, Municipio, Telefone,
Contato)
from sigi.apps.utils import queryset_ascii
class UnidadeFederativaAdmin(admin.ModelAdmin):
actions = None
list_display = ('codigo_ibge', 'nome', 'sigla', 'regiao', 'populacao')
list_display_links = ('codigo_ibge', 'nome')
list_filter = ('regiao', 'populacao')
search_fields = ('search_text', 'codigo_ibge', 'sigla', 'regiao')
queryset = queryset_ascii
class MunicipioAdmin(admin.ModelAdmin):
actions = None
list_display = ('codigo_ibge', 'codigo_tse', 'nome', 'uf', 'is_capital', 'populacao', 'is_polo', 'idh', 'pib_ano',
'pib_total', 'pib_percapita')
list_display_links = ('codigo_ibge', 'codigo_tse', 'nome')
list_filter = ('is_capital', 'is_polo', 'idh', 'populacao', 'uf', )
queryset = queryset_ascii
fieldsets = (
(None, {
'fields': ('codigo_ibge', 'codigo_tse', 'codigo_mesorregiao',
'codigo_microrregiao', 'nome', 'data_criacao', 'uf',
'is_capital', 'populacao', 'is_polo', 'idh', 'pib_ano', 'pib_total', 'pib_percapita')
}),
('Posição geográfica', {
'fields': ('latitude', 'longitude'),
}),
)
search_fields = ('search_text', 'codigo_ibge', 'codigo_tse', 'codigo_mesorregiao',
'codigo_microrregiao', 'uf__sigla')
class TelefoneAdmin(admin.ModelAdmin):
list_display = ('numero', 'tipo', 'nota')
list_display_links = ('numero',)
list_filter = ('tipo',)
radio_fields = {'tipo': admin.VERTICAL}
search_fields = ('numero', 'tipo', 'nota')
class ContatoAdmin(admin.ModelAdmin):
list_display = ('nome', 'nota', 'email', 'municipio')
list_display_links = ('nome',)
list_filter = ('nome',)
search_fields = ('nome', 'nota', 'email', 'municipio__nome', 'municipio__uf__nome')
admin.site.register(UnidadeFederativa, UnidadeFederativaAdmin)
admin.site.register(Municipio, MunicipioAdmin)
admin.site.register(Telefone, TelefoneAdmin)
admin.site.register(Contato, ContatoAdmin)

89312
sigi/apps/contatos/fixtures/initial_data.json

File diff suppressed because it is too large

278
sigi/apps/contatos/models.py

@ -0,0 +1,278 @@
# -*- coding: utf-8 -*-
from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from sigi.apps.utils import SearchField
from django.core.validators import MaxValueValidator, MinValueValidator
class UnidadeFederativa(models.Model):
""" Modelo que representa um estado brasileiro
"""
REGIAO_CHOICES = (
('SL', 'Sul'),
('SD', 'Sudeste'),
('CO', 'Centro-Oeste'),
('NE', 'Nordeste'),
('NO', 'Norte'),
)
codigo_ibge = models.PositiveIntegerField(
u'código IBGE',
primary_key=True,
unique=True,
help_text='Código do estado segundo IBGE.'
)
nome = models.CharField(max_length=25)
# Campo de busca em caixa baixa sem acento
search_text = SearchField(field_names=['nome'])
sigla = models.CharField(
max_length=2,
unique=True,
help_text="Exemplo: <em>MG</em>.",
)
regiao = models.CharField('região', max_length=2, choices=REGIAO_CHOICES)
populacao = models.PositiveIntegerField('população')
populacao.list_filter_range = [100000, 1000000, 10000000]
class Meta:
ordering = ('nome',)
verbose_name = 'Unidade Federativa'
verbose_name_plural = 'Unidades Federativas'
def __unicode__(self):
return self.nome
class Municipio(models.Model):
""" Modelo para representar as cidades brasileiras
"""
codigo_ibge = models.PositiveIntegerField(
u'código IBGE',
primary_key=True,
unique=True,
help_text='Código do município segundo IBGE.'
)
# agrupamento baseado em similaridades econômicas e sociais
codigo_mesorregiao = models.PositiveIntegerField(
u'código mesorregião',
blank=True,
null=True
)
# agrupamento baseado em similaridades econômicas e sociais
codigo_microrregiao = models.PositiveIntegerField(
u'código microrregião',
blank=True,
null=True
)
# codio designado pelo Tribunal Superior Eleitoral
codigo_tse = models.PositiveIntegerField(
u'código TSE',
unique=True,
null=True,
help_text='Código do município segundo TSE.'
)
nome = models.CharField(max_length=50)
search_text = SearchField(field_names=['nome', 'uf'])
uf = models.ForeignKey(UnidadeFederativa, verbose_name='UF')
# verdadeiro se o município é capital do estado
is_capital = models.BooleanField('capital')
populacao = models.PositiveIntegerField(u'população')
populacao.list_filter_range = [10000, 100000, 1000000]
is_polo = models.BooleanField(u'pólo')
data_criacao = models.DateField(u'data de criação do município', null=True, blank=True)
# posição geográfica do município
latitude = models.DecimalField(
max_digits=10,
decimal_places=8,
null=True,
blank=True,
help_text='Exemplo: <em>-20,464</em>.'
)
longitude = models.DecimalField(
max_digits=11,
decimal_places=8,
null=True,
blank=True,
help_text='Exemplo: <em>-45,426</em>.'
)
idh = models.DecimalField(u'IDH', help_text=u'Índice de desenvolvimento Humano', max_digits=4, decimal_places=3,
validators=[MinValueValidator(0), MaxValueValidator(1)])
idh.list_filter_range = [0.500, 0.800]
pib_total = models.DecimalField(u'PIB total', max_digits=18, decimal_places=3, blank=True, null=True)
pib_percapita = models.DecimalField(u'PIB per capita', max_digits=18, decimal_places=3, blank=True, null=True)
pib_ano = models.IntegerField(u'Ano de apuração do PIB', blank=True, null=True)
class Meta:
ordering = ('nome', 'codigo_ibge')
verbose_name = 'município'
verbose_name_plural = 'municípios'
def __unicode__(self):
return "%s - %s" % (self.nome, self.uf)
def get_google_maps_url(self):
return "http://maps.google.com.br/maps/mm?ie=UTF8&hl=pt-BR&t=h&ll=%s,%s&spn=1.61886,1.812744&z=9&source=embed" % \
(self.latitude, self.longitude)
class Telefone(models.Model):
""" Modelo genérico para agrupar telefones dos modulos do sistema
"""
TELEFONE_CHOICES = (
('F', 'Fixo'),
('M', 'Móvel'),
('X', 'Fax'),
('I', 'Indefinido'),
)
numero = models.CharField(
'número',
max_length=64, # TODO: diminuir tamanho de campo após migração de dados
help_text='Exemplo: <em>(31)8851-9898</em>.',
)
tipo = models.CharField(
max_length=1,
choices=TELEFONE_CHOICES,
default= 'I'
)
nota = models.CharField(max_length=70, null=True, blank=True)
ult_alteracao = models.DateTimeField(u'Última alteração', null=True, blank=True, editable=False, auto_now=True)
# guarda o tipo do objeto (classe) vinculado a esse registro
content_type = models.ForeignKey(ContentType)
# identificador do registro na classe vinculado a esse registro
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
class Meta:
ordering = ('numero',)
unique_together = ('numero', 'tipo')
def __unicode__(self):
return unicode(self.numero)
class Contato(models.Model):
""" Modelo generico para registrar contatos vinculados aos
modulos do sistema
"""
nome = models.CharField('nome completo', max_length=120)
nome.alphabetic_filter = True
nota = models.CharField(max_length=70, blank=True)
email = models.EmailField('e-mail', blank=True)
telefones = generic.GenericRelation(Telefone)
municipio = models.ForeignKey(
Municipio,
verbose_name='município',
blank=True,
null=True,
)
# guarda o tipo do objeto (classe) vinculado a esse registro
content_type = models.ForeignKey(ContentType)
# identificador do registro na classe vinculado a esse registro
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
class Meta:
ordering = ('nome',)
verbose_name = 'contato Interlegis'
verbose_name_plural = 'contatos Interlegis'
def __unicode__(self):
return self.nome
class Endereco(models.Model):
TIPO_CHOICES = (
('aeroporto','Aeroporto'),
('alameda','Alameda'),
('area',u'Área'),
('avenida','Avenida'),
('campo','Campo'),
('chacara',u'Chácara'),
('colonia',u'Colônia'),
('condominio',u'Condomínio'),
('conjunto','Conjunto'),
('distrito','Distrito'),
('esplanada','Esplanada'),
('estacao',u'Estação'),
('estrada','Estrada'),
('favela','Favela'),
('fazenda','Fazenda'),
('feira','Feira'),
('jardim','Jardim'),
('ladeira','Ladeira'),
('lago','Lago'),
('lagoa','Lagoa'),
('largo','Largo'),
('loteamento','Loteamento'),
('morro','Morro'),
('nucleo',u'Núcleo'),
('parque','Parque'),
('passarela','Passarela'),
('patio',u'Pátio'),
('praca',u'Praça'),
('quadra','Quadra'),
('recanto','Recanto'),
('residencial','Residencial'),
('rodovia','Rodovia'),
('rua','Rua'),
('setor','Setor'),
('sitio',u'Sítio'),
('travessa','Travessa'),
('trecho','Trecho'),
('trevo','Trevo'),
('vale','Vale'),
('vereda','Vereda'),
('via','Via'),
('viaduto','Viaduto'),
('viela','Viela'),
('vila','Vila'),
('outro','Outro'),
)
# tipo do endereço obtido no site dos correios
tipo = models.CharField(max_length=15,choices=TIPO_CHOICES)
logradouro = models.CharField(
max_length=100,
)
logradouro.alphabetic_filter = True
numero= models.CharField(max_length=15, blank=True)
complemento= models.CharField(max_length=15, blank=True)
# campo de texto livre
referencia = models.CharField(max_length=100, blank=True)
bairro = models.CharField(max_length=100, blank=True)
cep = models.CharField(
'CEP',
max_length=9,
blank=True,
null=True,
help_text="Formato: <em>XXXXX-XXX</em>."
)
municipio = models.ForeignKey(
Municipio,
verbose_name='município',
blank=True,
null=True,
)
municipio.uf_filter = True
# guarda o tipo do objeto (classe) vinculado a esse registro
content_type = models.ForeignKey(ContentType)
# identificador do registro na classe vinculado a esse registro
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey('content_type', 'object_id')
class Meta:
ordering = ('logradouro', 'numero')
verbose_name = u'endereço'
verbose_name_plural = u'endereços'
def __unicode__(self):
return self.tipo + ' ' + self.logradouro + ', ' + self.numero \
+ ' ' + self.complemento + ' - ' + self.bairro

31
sigi/apps/utils/__init__.py

@ -0,0 +1,31 @@
# -*- coding: utf-8 -*-
from django.contrib import admin
from django.db import models
from unicodedata import normalize
class SearchField(models.TextField):
def pre_save(self, model_instance, add):
search_text = []
for field_name in self.field_names:
val = unicode(to_ascii(getattr(model_instance, field_name)))
search_text.append(val)
value = u' '.join(search_text)
setattr(model_instance, self.name, value)
return value
def __init__(self, field_names, *args, **kwargs):
self.field_names = field_names
kwargs['editable'] = False
super(self.__class__, self).__init__(*args, **kwargs)
def to_ascii(txt, codif='utf-8'):
if not isinstance(txt, basestring):
txt = unicode(txt)
if isinstance(txt, unicode):
txt = txt.encode('utf-8')
return normalize('NFKD', txt.decode(codif)).encode('ASCII','ignore')
def queryset_ascii(self, request):
if 'q' in request.GET:
request.GET._mutable = True
request.GET['q'] = to_ascii(request.GET['q'])
return admin.ModelAdmin.queryset(self, request)

16
sigi/apps/utils/admin_widgets.py

@ -0,0 +1,16 @@
from django.contrib.admin.widgets import AdminFileWidget
from django.utils.translation import ugettext as _
from django.utils.safestring import mark_safe
class AdminImageWidget(AdminFileWidget):
def render(self, name, value, attrs=None):
output = []
if value and getattr(value, "url", None):
image_url = value.url
file_name=str(value)
output.append(
u''' <a href="%s" target="_blank"><img src="%s" width="100"
height="100" alt="%s"/></a> <br/> %s''' % \
(image_url, image_url, file_name, _('Change:')))
output.append(super(AdminFileWidget, self).render(name, value, attrs))
return mark_safe(u''.join(output))

71
sigi/apps/utils/decorators.py

@ -0,0 +1,71 @@
# -*- coding: utf8 -*-
"""
Script baseado no arquivo decorators.py do django 1.3.
Ele foi copiado para usar o decorador ``login_required``
que possui o argumento ``login_url``, responsável por
redirecionar ao template de login desejado.
No ato de atualizar o framework, esse script torna-se
obsoleto.
"""
import urlparse
try:
from functools import wraps
except ImportError:
from django.utils.functional import wraps # Python 2.4 fallback.
from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.utils.decorators import available_attrs
def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME):
"""
Decorator for views that checks that the user passes the given test,
redirecting to the log-in page if necessary. The test should be a callable
that takes the user object and returns True if the user passes.
"""
def decorator(view_func):
@wraps(view_func, assigned=available_attrs(view_func))
def _wrapped_view(request, *args, **kwargs):
if test_func(request.user):
return view_func(request, *args, **kwargs)
path = request.build_absolute_uri()
# If the login url is the same scheme and net location then just
# use the path as the "next" url.
login_scheme, login_netloc = urlparse.urlparse(login_url or
settings.LOGIN_URL)[:2]
current_scheme, current_netloc = urlparse.urlparse(path)[:2]
if ((not login_scheme or login_scheme == current_scheme) and
(not login_netloc or login_netloc == current_netloc)):
path = request.get_full_path()
from django.contrib.auth.views import redirect_to_login
return redirect_to_login(path, login_url, redirect_field_name)
return _wrapped_view
return decorator
def login_required(function=None, redirect_field_name=REDIRECT_FIELD_NAME, login_url=None):
"""
Decorator for views that checks that the user is logged in, redirecting
to the log-in page if necessary.
"""
actual_decorator = user_passes_test(
lambda u: u.is_authenticated(),
login_url=login_url,
redirect_field_name=redirect_field_name
)
if function:
return actual_decorator(function)
return actual_decorator
def permission_required(perm, login_url=None):
"""
Decorator for views that checks whether a user has a particular permission
enabled, redirecting to the log-in page if necessary.
"""
return user_passes_test(lambda u: u.has_perm(perm), login_url=login_url)

33
sigi/apps/utils/email.py

@ -0,0 +1,33 @@
# -*- coding: utf8 -*-
from django.template.loader import render_to_string
from django.core.mail import EmailMessage
from django.conf import settings
def enviar_email(from_email, subject, template, tags):
"""Envia o email para o destinatário definido, a partir do template
definido para ser renderizado. Os argumentos são:
* from_email - Email do remetente
* subject - Assunto da Mensagem
* template - Template que será usado para gerar o corpo
da mensagem
* tags - Variáveis de contexto para ser renderizado no
template.
"""
if from_email is None:
raise ValueError("Insira o email do remetente.")
elif subject is None:
raise ValueError("Insira o assunto da mensagem.")
elif template is None:
raise ValueError(u"Template da mensagem não encontrado")
elif tags is None:
raise ValueError("Insira o conteúdo da mensagem.")
# Gerando a mensagem
mensagem = render_to_string(template, tags)
# Enviando a mensagem
email = EmailMessage(settings.EMAIL_SUBJECT_PREFIX + " " + subject, mensagem,
from_email, [from_email])
email.send()

42
sigi/apps/utils/validators.py

@ -0,0 +1,42 @@
# -*- coding: utf8 -*-
def valida_data(data_inicio, data_final):
"""Função responsável por validar se o intervalo das
datas estão erradas, ou seja, se a data de início está
maior ou igual a data final.
Caso seja maior ou igual retornará ``True``, caso contrário
retornará ``False``.
"""
if data_inicio >= data_final:
return True
else:
return False
def valida_periodo_data(di01, df01, di02, df02):
"""Função responsável por validar dois períodos de datas.
Isso é usado para verificar se determinado servidor exerceu
mais de uma função dentro de determinados períodos descritos
abaixo:
1 - A segunda função não pode ter exercido ao mesmo tempo que
a primeira função. Exemplo:
Primeiro Função: 01/05/2011 -- 01/11/2011
Segundo Função: 01/05/2011 -- 01/11/2011
2 - A segunda função não pode ter exercido, dentro do período
da primeira função. Exemplo:
Primeira Função: 01/05/2011 -- 01/11/2011
Segunda Função: 02/05/2011 -- 30/10/2011
"""
# Verificando a primeira situação
if di01 == di02 and df01 == df02:
return True
elif ((di01 >= di02) or (di02 <= df01)) and df01 <= df02:
return True
else:
return False

3
sigi/settings.py

@ -36,6 +36,9 @@ INSTALLED_APPS = (
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# Local apps
'sigi.apps.contatos',
)
MIDDLEWARE_CLASSES = (

Loading…
Cancel
Save