mirror of https://github.com/interlegis/sigi.git
committed by
GitHub
204 changed files with 5687 additions and 548 deletions
@ -0,0 +1,66 @@ |
|||
FROM ubuntu:15.04 |
|||
|
|||
RUN locale-gen en_US.UTF-8 |
|||
ENV LANG en_US.UTF-8 |
|||
ENV LANGUAGE en_US:en |
|||
ENV LC_ALL en_US.UTF-8 |
|||
|
|||
RUN mkdir /sigi |
|||
|
|||
RUN apt-get update && \ |
|||
apt-get install -y -f \ |
|||
build-essential \ |
|||
curl \ |
|||
git \ |
|||
graphviz-dev \ |
|||
graphviz \ |
|||
libz-dev \ |
|||
libffi-dev \ |
|||
libfreetype6-dev \ |
|||
libjpeg62 \ |
|||
libjpeg-dev \ |
|||
libldap2-dev \ |
|||
libpq-dev \ |
|||
libsasl2-dev \ |
|||
libssl-dev \ |
|||
libxft-dev \ |
|||
libxml2-dev \ |
|||
libxslt1-dev \ |
|||
nginx \ |
|||
pkg-config \ |
|||
python-dev \ |
|||
python-setuptools \ |
|||
software-properties-common \ |
|||
npm \ |
|||
nodejs |
|||
|
|||
# install nodejs |
|||
RUN DEBIAN_FRONTEND=noninteractive curl -sL https://deb.nodesource.com/setup_5.x | bash - |
|||
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y nodejs |
|||
|
|||
# install bower |
|||
RUN npm install -g bower |
|||
|
|||
# Bower aceitar root |
|||
RUN touch /root/.bowerrc |
|||
RUN chmod 751 /root/.bowerrc |
|||
RUN echo "{ \"allow_root\": true }" >> /root/.bowerrc |
|||
|
|||
ADD . /sigi |
|||
|
|||
WORKDIR /sigi |
|||
|
|||
RUN easy_install pip |
|||
RUN pip2 install -r requirements/dev-requirements.txt |
|||
RUN pip2 install --upgrade setuptools |
|||
|
|||
RUN mkdir -p /var/log/sigi/ |
|||
RUN touch /var/log/sigi/application.log |
|||
RUN chmod -x /var/log/sigi/application.log |
|||
|
|||
RUN git clone https://github.com/marinho/geraldo.git |
|||
WORKDIR /sigi/geraldo/ |
|||
RUN python setup.py install |
|||
RUN cp -Rfv reporting geraldo `python -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())"` |
|||
WORKDIR /sigi |
|||
RUN rm -rf geraldo/ |
@ -0,0 +1,17 @@ |
|||
#!/bin/bash |
|||
|
|||
# Check if there's some debug breakpoint in codebase |
|||
me=`basename "$0"` |
|||
stmts=`grep --exclude=$me -r -l "ipdb.set_trace()" * | wc -l` |
|||
if [ $stmts != '0' ] |
|||
then |
|||
echo "==================================================================" |
|||
echo "ERROR: ipdb.set_trace() call in codebase! Remove, please." |
|||
grep --exclude=$me -r -n "ipdb.set_trace()" * |
|||
echo "==================================================================" |
|||
fi |
|||
|
|||
# QA checks: run this before every commit |
|||
./manage.py check |
|||
flake8 --exclude='ipython_log.py*,migrations,templates' . |
|||
isort --recursive --check-only --skip='migrations' --skip='templates' --skip='ipython_log.py' . |
@ -0,0 +1,32 @@ |
|||
#localhost: |
|||
# image: postgres |
|||
# environment: |
|||
# POSTGRES_PASSWORD: sigi |
|||
# POSTGRES_USER: sigi |
|||
# POSTGRES_DB: sigi |
|||
# ports: |
|||
# - "5532:5432" |
|||
#web: |
|||
# build: . |
|||
# command: bash -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000" |
|||
# volumes: |
|||
# - .:/sigi |
|||
# ports: |
|||
# - "8000:8000" |
|||
# links: |
|||
# - localhost |
|||
|
|||
osticket: |
|||
image: campbellsoftwaresolutions/osticket |
|||
ports: |
|||
- "80:80" |
|||
links: |
|||
- mysql |
|||
|
|||
mysql: |
|||
image: mysql |
|||
environment: |
|||
- MYSQL_ROOT_PASSWORD=secret |
|||
- MYSQL_DATABASE=osticket |
|||
- MYSQL_USER=osticket |
|||
- MYSQL_PASSWORD=secret |
@ -0,0 +1,11 @@ |
|||
#!/bin/bash |
|||
|
|||
# QA fix: Use ese script para corrigir automaticamente vários |
|||
# problemas de estilo e boas práticas no código. |
|||
# |
|||
# Sempre guarde suas mudanças de alguma forma antes de aplicar esse script, |
|||
# de modo que possa revisar cada alteração que ele fez. |
|||
# Uma forma simples de fazer isso é adicionando antes suas mudanças à |
|||
# "staging area" do git, com `git add .` e após usar o script `git diff`. |
|||
|
|||
isort --recursive --skip='migrations' --skip='templates' --skip='ipython_log.py' . |
@ -0,0 +1 @@ |
|||
dev.py |
@ -1,5 +1,7 @@ |
|||
-r test-requirements.txt |
|||
django-debug-toolbar==1.2.2 |
|||
ipdb==0.8 |
|||
ipython==2.3.1 |
|||
pygraphviz==1.2 |
|||
django-debug-toolbar==1.5 |
|||
ipdb==0.10.0 |
|||
ipython==4.2.0 |
|||
isort==4.2.5 |
|||
model_mommy==1.2.6 |
|||
pygraphviz==1.3.1 |
|||
|
@ -1,23 +1,41 @@ |
|||
-e git://github.com/marinho/geraldo.git@868ebdce67176d9b6205cddc92476f642c783fff#egg=geraldo |
|||
django-bootstrap3==6.2.2 |
|||
django-admin-bootstrapped==2.4.0 |
|||
django-auth-ldap==1.2.7 |
|||
git+git://github.com/hellpanderrr/django-admin-bootstrapped-1.9-compatible.git@master#egg=django_admin_bootstrapped |
|||
git+git://github.com/interlegis/eav-django |
|||
django-auth-ldap==1.2.8 |
|||
django-autoslug==1.9.3 |
|||
django-extensions==1.5.7 |
|||
django-image-cropping==1.0.2 |
|||
django-localflavor==1.1 |
|||
Django==1.7.10 |
|||
easy-thumbnails==2.2 |
|||
eav-django==1.4.7 |
|||
gunicorn==19.3.0 |
|||
django-bootstrap3==7.0.1 |
|||
django-bower==5.1.0 |
|||
django-braces==1.8.1 |
|||
django-compressor==2.0 |
|||
django-crispy-forms==1.6.0 |
|||
dj-database-url==0.4.1 |
|||
django-dotenv==1.4.1 |
|||
django-extensions==1.6.7 |
|||
django-extra-views==0.7.1 |
|||
django-filter==0.13.0 |
|||
django-floppyforms==1.6.1 |
|||
django-image-cropping==1.0.3 |
|||
django-localflavor==1.3 |
|||
django-model-utils==2.4 |
|||
django-sass-processor==0.3.4 |
|||
django-easy-select2==1.3.2 |
|||
django-simple-captcha==0.5.1 |
|||
Django==1.10.1 |
|||
libsass==0.11.0 |
|||
easy-thumbnails==2.3 |
|||
gunicorn==19.6.0 |
|||
html5lib==0.9999999 |
|||
Pillow==2.9.0 |
|||
Pillow==3.2.0 |
|||
pisa==3.0.33 |
|||
psycopg2==2.6.1 |
|||
python-memcached==1.53 |
|||
python-decouple==3.0 |
|||
python-memcached==1.58 |
|||
pytz==2016.3 |
|||
PyYAML==3.11 |
|||
reportlab==2.7 |
|||
requests==2.8.1 |
|||
requests==2.10.0 |
|||
rtyaml==0.0.2 |
|||
unipath==1.1 |
|||
six==1.10.0 |
|||
djangorestframework==2.4.8 |
|||
django-ipware==1.1.6 |
|||
|
@ -1,10 +1,10 @@ |
|||
-r requirements.txt |
|||
coverage==3.7.1 |
|||
django-dynamic-fixture==1.8.1 |
|||
django-webtest==1.7.7 |
|||
git+git://github.com/paulocheque/django-dynamic-fixture/@master |
|||
coverage==4.1 |
|||
django-webtest==1.7.9 |
|||
pyPdf==1.13 |
|||
pyquery==1.2.9 |
|||
pytest-cov==1.8.1 |
|||
pytest-django==2.8.0 |
|||
pytest==2.6.4 |
|||
WebTest==2.0.17 |
|||
pyquery==1.2.13 |
|||
pytest-cov==2.2.1 |
|||
pytest-django==2.9.1 |
|||
pytest==2.9.2 |
|||
WebTest==2.0.21 |
|||
|
@ -0,0 +1,15 @@ |
|||
from django.contrib.auth.models import Group |
|||
|
|||
|
|||
def criar_grupos(): |
|||
# COPLAF = Atestar usuário |
|||
if not Group.objects.filter(name='COPLAF').exists(): |
|||
Group.objects.create(name='COPLAF') |
|||
|
|||
# COADFI = Atestar convênio |
|||
if not Group.objects.filter(name='COADFI').exists(): |
|||
Group.objects.create(name='COADFI') |
|||
|
|||
# Já recebeu aprovação dos dois grupos de cima |
|||
if not Group.objects.filter(name='Usuario_Habilitado').exists(): |
|||
Group.objects.create(name='Usuario_Habilitado') |
@ -0,0 +1,398 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# |
|||
# EAV-Django is a reusable Django application which implements EAV data model |
|||
# Copyright © 2009—2010 Andrey Mikhaylenko |
|||
# |
|||
# This file is part of EAV-Django. |
|||
# |
|||
# EAV-Django is free software: you can redistribute it and/or modify |
|||
# it under the terms of the GNU Lesser General Public License as published |
|||
# by the Free Software Foundation, either version 3 of the License, or |
|||
# (at your option) any later version. |
|||
# |
|||
# EAV-Django is distributed in the hope that it will be useful, |
|||
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|||
# GNU Lesser General Public License for more details. |
|||
# |
|||
# You should have received a copy of the GNU Lesser General Public License |
|||
# along with EAV-Django. If not, see <http://gnu.org/licenses/>. |
|||
""" |
|||
Models |
|||
~~~~~~ |
|||
""" |
|||
|
|||
# django |
|||
from django.contrib.contenttypes.models import ContentType |
|||
from django.contrib.contenttypes import fields |
|||
from django.db.models import (BooleanField, CharField, DateField, FloatField, |
|||
ForeignKey, IntegerField, Model, NullBooleanField, |
|||
TextField) |
|||
from django.utils.translation import ugettext_lazy as _ |
|||
|
|||
# 3rd-party |
|||
from autoslug.fields import AutoSlugField |
|||
from autoslug.settings import slugify |
|||
#from view_shortcuts.decorators import cached_property |
|||
|
|||
# this app |
|||
from managers import BaseEntityManager |
|||
|
|||
|
|||
__all__ = ['BaseAttribute', 'BaseChoice', 'BaseEntity', 'BaseSchema'] |
|||
|
|||
|
|||
def slugify_attr_name(name): |
|||
return slugify(name.replace('_', '-')).replace('-', '_') |
|||
|
|||
|
|||
def get_entity_lookups(entity): |
|||
ctype = ContentType.objects.get_for_model(entity) |
|||
return {'entity_type': ctype, 'entity_id': entity.pk} |
|||
|
|||
|
|||
class BaseSchema(Model): |
|||
""" |
|||
Metadata for an attribute. |
|||
""" |
|||
TYPE_TEXT = 'text' |
|||
TYPE_FLOAT = 'float' |
|||
TYPE_DATE = 'date' |
|||
TYPE_BOOLEAN = 'bool' |
|||
TYPE_ONE = 'one' |
|||
TYPE_MANY = 'many' |
|||
TYPE_RANGE = 'range' |
|||
|
|||
DATATYPE_CHOICES = ( |
|||
(TYPE_TEXT, _('text')), |
|||
(TYPE_FLOAT, _('number')), |
|||
(TYPE_DATE, _('date')), |
|||
(TYPE_BOOLEAN, _('boolean')), |
|||
(TYPE_ONE, _('choice')), |
|||
(TYPE_MANY, _('multiple choices')), |
|||
(TYPE_RANGE, _('numeric range')), |
|||
) |
|||
|
|||
title = CharField(_('title'), max_length=250, help_text=_('user-friendly attribute name')) |
|||
name = AutoSlugField(_('name'), max_length=250, populate_from='title', |
|||
editable=True, blank=True, slugify=slugify_attr_name) |
|||
help_text = CharField(_('help text'), max_length=250, blank=True, |
|||
help_text=_('short description for administrator')) |
|||
datatype = CharField(_('data type'), max_length=5, choices=DATATYPE_CHOICES) |
|||
|
|||
required = BooleanField(_('required'), default=False) |
|||
searched = BooleanField(_('include in search'), default=False) # i.e. full-text search? mb for text only |
|||
filtered = BooleanField(_('include in filters'), default=False) |
|||
sortable = BooleanField(_('allow sorting'), default=False) |
|||
|
|||
class Meta: |
|||
abstract = True |
|||
verbose_name, verbose_name_plural = _('schema'), _('schemata') |
|||
ordering = ['title'] |
|||
|
|||
def __unicode__(self): |
|||
return u'%s (%s)%s' % (self.title, self.get_datatype_display(), |
|||
u' %s'%_('required') if self.required else '') |
|||
|
|||
def get_choices(self): |
|||
""" |
|||
Returns a queryset of choice objects bound to this schema. |
|||
""" |
|||
return self.choices.all() |
|||
|
|||
def get_attrs(self, entity): |
|||
""" |
|||
Returns available attributes for given entity instance. |
|||
Handles many-to-one relations transparently. |
|||
""" |
|||
return self.attrs.filter(**get_entity_lookups(entity)) |
|||
|
|||
def save_attr(self, entity, value): |
|||
""" |
|||
Saves given EAV attribute with given value for given entity. |
|||
|
|||
If schema is not a choice, the value is saved to the corresponding |
|||
Attr instance (which is created or updated). |
|||
|
|||
If schema is an cvhoice (one-to-one or many-to-one), the value is |
|||
processed thusly: |
|||
|
|||
* if value is iterable, all Attr instances for corresponding managed choice |
|||
schemata are updated (those with names from the value list are set to |
|||
True, others to False). If a list item is not in available choices, |
|||
ValueError is raised; |
|||
* if the value is None, all corresponding Attr instances are reset to False; |
|||
* if the value is neither a list nor None, it is wrapped into a list and |
|||
processed as above (i.e. "foo" --> ["foo"]). |
|||
""" |
|||
|
|||
if self.datatype in (self.TYPE_ONE, self.TYPE_MANY): |
|||
self._save_choice_attr(entity, value) |
|||
else: |
|||
self._save_single_attr(entity, value) |
|||
|
|||
def _save_single_attr(self, entity, value=None, schema=None, |
|||
create_nulls=False, extra={}): |
|||
""" |
|||
Creates or updates an EAV attribute for given entity with given value. |
|||
|
|||
:param schema: schema for attribute. Default it current schema instance. |
|||
:param create_nulls: boolean: if True, even attributes with value=None |
|||
are created (by default they are skipped). |
|||
:param extra: dict: additional data for Attr instance (e.g. title). |
|||
""" |
|||
# If schema is not many-to-one, the value is saved to the corresponding |
|||
# Attr instance (which is created or updated). |
|||
|
|||
schema = schema or self |
|||
lookups = dict(get_entity_lookups(entity), schema=schema, **extra) |
|||
try: |
|||
attr = self.attrs.get(**lookups) |
|||
except self.attrs.model.DoesNotExist: |
|||
attr = self.attrs.model(**lookups) |
|||
if create_nulls or value != attr.value: |
|||
attr.value = value |
|||
for k,v in extra.items(): |
|||
setattr(attr, k, v) |
|||
attr.save() |
|||
|
|||
def _save_choice_attr(self, entity, value): |
|||
""" |
|||
Creates or updates BaseChoice(s) attribute(s) for given entity. |
|||
""" |
|||
|
|||
# value can be None to reset choices from schema |
|||
if value == None: |
|||
value = [] |
|||
|
|||
if not hasattr(value, '__iter__'): |
|||
value = [value] |
|||
|
|||
if self.datatype == self.TYPE_ONE and len(value) > 1: |
|||
raise TypeError('Cannot assign multiple values "%s" to TYPE_ONE ' |
|||
'must be only one BaseChoice instance.' |
|||
% value) |
|||
|
|||
if not all(isinstance(x, BaseChoice) for x in value): |
|||
raise TypeError('Cannot assign "%s": "Attr.choice" ' |
|||
'must be a BaseChoice instance.' |
|||
% value) |
|||
|
|||
# drop all attributes for this entity/schema pair |
|||
self.get_attrs(entity).delete() |
|||
|
|||
# Attr instances for corresponding managed choice schemata are updated |
|||
for choice in value: |
|||
self._save_single_attr( |
|||
entity, |
|||
schema = self, |
|||
create_nulls = True, |
|||
extra = {'choice': choice} |
|||
) |
|||
|
|||
|
|||
class BaseEntity(Model): |
|||
""" |
|||
Entity, the "E" in EAV. This model is abstract and must be subclassed. |
|||
See tests for examples. |
|||
""" |
|||
|
|||
objects = BaseEntityManager() |
|||
|
|||
class Meta: |
|||
abstract = True |
|||
|
|||
def save(self, force_eav=False, **kwargs): |
|||
""" |
|||
Saves entity instance and creates/updates related attribute instances. |
|||
|
|||
:param eav: if True (default), EAV attributes are saved along with entity. |
|||
""" |
|||
# save entity |
|||
super(BaseEntity, self).save(**kwargs) |
|||
|
|||
# TODO: think about use cases; are we doing it right? |
|||
#if not self.check_eav_allowed(): |
|||
# import warnings |
|||
# warnings.warn('EAV attributes are going to be saved along with entity' |
|||
# ' despite %s.check_eav_allowed() returned False.' |
|||
# % type(self), RuntimeWarning) |
|||
|
|||
|
|||
# create/update EAV attributes |
|||
for schema in self.get_schemata(): |
|||
value = getattr(self, schema.name, None) |
|||
schema.save_attr(self, value) |
|||
|
|||
def __getattr__(self, name): |
|||
if not name.startswith('_'): |
|||
if name in self.get_schema_names(): |
|||
schema = self.get_schema(name) |
|||
attrs = schema.get_attrs(self) |
|||
if schema.datatype == schema.TYPE_MANY: |
|||
return [a.value for a in attrs if a.value] |
|||
else: |
|||
return attrs[0].value if attrs else None |
|||
raise AttributeError('%s does not have attribute named "%s".' % |
|||
(self._meta.object_name, name)) |
|||
|
|||
def __iter__(self): |
|||
"Iterates over non-empty EAV attributes. Normal fields are not included." |
|||
for attr in self.attrs.select_related(): |
|||
if getattr(self, attr.schema.name, None): |
|||
yield attr |
|||
|
|||
@classmethod |
|||
def get_schemata_for_model(cls): |
|||
return NotImplementedError('BaseEntity subclasses must define method ' |
|||
'"get_schemata_for_model" which returns a ' |
|||
'QuerySet for a BaseSchema subclass.') |
|||
|
|||
def get_schemata_for_instance(self, qs): |
|||
return qs |
|||
|
|||
def get_schemata(self): |
|||
if hasattr(self, '_schemata_cache') and self._schemata_cache is not None: |
|||
return self._schemata_cache |
|||
all_schemata = self.get_schemata_for_model().select_related() |
|||
self._schemata_cache = self.get_schemata_for_instance(all_schemata) |
|||
self._schemata_cache_dict = dict((s.name, s) for s in self._schemata_cache) |
|||
return self._schemata_cache |
|||
|
|||
def get_schema_names(self): |
|||
if not hasattr(self, '_schemata_cache_dict'): |
|||
self.get_schemata() |
|||
return self._schemata_cache_dict.keys() |
|||
|
|||
def get_schema(self, name): |
|||
if not hasattr(self, '_schemata_cache_dict'): |
|||
self.get_schemata() |
|||
return self._schemata_cache_dict[name] |
|||
|
|||
def get_schema_by_id(self, schema_id): |
|||
for schema in self.get_schemata(): |
|||
if schema.pk == schema_id: |
|||
return schema |
|||
|
|||
def check_eav_allowed(self): |
|||
""" |
|||
Returns True if entity instance allows EAV attributes to be attached. |
|||
|
|||
Can be useful if some external data is required to determine available |
|||
schemata and that data may be missing. In such cases this method should |
|||
be overloaded to check whether the data is available. |
|||
""" |
|||
return True |
|||
|
|||
def is_valid(self): |
|||
"Returns True if attributes and their values conform with schema." |
|||
|
|||
raise NotImplementedError() |
|||
|
|||
''' |
|||
schemata = self.rubric.schemata.all() |
|||
return all(x.is_valid for x in self.attributes) |
|||
# 1. check if all required attributes are present |
|||
for schema in schemata: |
|||
pass |
|||
# 2. check if all attributes have appropriate values |
|||
for schema in schemata: |
|||
pass |
|||
return True |
|||
''' |
|||
|
|||
|
|||
class BaseChoice(Model): |
|||
""" Base class for choices. Concrete choice class must overload the |
|||
`schema` attribute. |
|||
""" |
|||
title = CharField(max_length=100) |
|||
schema = NotImplemented |
|||
|
|||
class Meta: |
|||
abstract = True |
|||
ordering = ('title',) |
|||
|
|||
def __unicode__(self): |
|||
return self.title #u'%s "%s"' % (self.schema.title, self.title) |
|||
|
|||
|
|||
class BaseAttribute(Model): |
|||
""" Base class for choices. Concrete choice class must overload the |
|||
`schema` and `choice` attributes. |
|||
""" |
|||
entity_type = ForeignKey(ContentType) |
|||
entity_id = IntegerField() |
|||
entity = fields.GenericForeignKey(ct_field="entity_type", fk_field='entity_id') |
|||
|
|||
value_text = TextField(blank=True, null=True) |
|||
value_float = FloatField(blank=True, null=True) |
|||
value_date = DateField(blank=True, null=True) |
|||
value_bool = NullBooleanField(blank=True) # TODO: ensure that form invalidates null booleans (??) |
|||
value_range_min = FloatField(blank=True, null=True) |
|||
value_range_max = FloatField(blank=True, null=True) |
|||
|
|||
schema = NotImplemented # must be FK |
|||
choice = NotImplemented # must be nullable FK |
|||
|
|||
class Meta: |
|||
abstract = True |
|||
verbose_name, verbose_name_plural = _('attribute'), _('attributes') |
|||
ordering = ['entity_type', 'entity_id', 'schema'] |
|||
unique_together = ('entity_type', 'entity_id', 'schema', 'choice') |
|||
|
|||
def __unicode__(self): |
|||
return u'%s: %s "%s"' % (self.entity, self.schema.title, self.value) |
|||
|
|||
def _get_value(self): |
|||
if self.schema.datatype in (self.schema.TYPE_ONE, self.schema.TYPE_MANY): |
|||
return self.choice |
|||
if self.schema.datatype == self.schema.TYPE_RANGE: |
|||
names = ('value_range_%s' % x for x in ('min', 'max')) |
|||
value = tuple(getattr(self, x, None) for x in names) |
|||
return None if value == (None, None) else value |
|||
return getattr(self, 'value_%s' % self.schema.datatype) |
|||
|
|||
def _set_value(self, new_value): |
|||
if self.schema.datatype == self.schema.TYPE_RANGE: |
|||
new_value = new_value or (None, None) |
|||
|
|||
# validate range value -- expecting a tuple of two numbers |
|||
try: |
|||
validate_range_value(new_value) |
|||
except (TypeError, ValueError): |
|||
raise |
|||
|
|||
for k,v in zip('min max'.split(), new_value): |
|||
v = v if v is None else float(v) |
|||
setattr(self, 'value_range_%s' % k, v) |
|||
else: |
|||
setattr(self, 'value_%s' % self.schema.datatype, new_value) |
|||
|
|||
value = property(_get_value, _set_value) |
|||
|
|||
|
|||
def validate_range_value(value): |
|||
""" |
|||
Validates given value against `Schema.TYPE_RANGE` data type. Raises |
|||
TypeError or ValueError if something is wrong. Returns None if everything |
|||
is OK. |
|||
""" |
|||
if value == (None, None): |
|||
return |
|||
|
|||
if not hasattr(value, '__iter__'): |
|||
raise TypeError('Range value must be an iterable, got "%s".' % value) |
|||
if not 2 == len(value): |
|||
raise ValueError('Range value must consist of two elements, got %d.' % |
|||
len(value)) |
|||
if not all(isinstance(x, (int,float)) for x in value): |
|||
raise TypeError('Range value must consist of two numbers, got "%s" ' |
|||
'and "%s" instead.' % value) |
|||
if not value[0] <= value[1]: |
|||
raise ValueError('Range must consist of min and max values (min <= ' |
|||
'max) but got "%s" and "%s" instead.' % value) |
|||
return |
|||
|
|||
|
|||
# xxx catch signal Attr.post_save() --> update attr.item.attribute_cache (JSONField or such) |
@ -1,38 +1,37 @@ |
|||
# coding: utf-8 |
|||
from django.conf.urls import patterns, url |
|||
from django.conf.urls import url |
|||
from sigi.apps.casas import views |
|||
|
|||
|
|||
urlpatterns = patterns( |
|||
'sigi.apps.casas.views', |
|||
urlpatterns = [ |
|||
|
|||
# Informacoes de uma casa legislativa |
|||
url(r'^casalegislativa/report_complete/$', 'report_complete', name='report-complete-all'), |
|||
url(r'^casalegislativa/(?P<id>\w+)/report_complete/$', 'report_complete', name='report-complete-id'), |
|||
url(r'^casalegislativa/report_complete/$', views.report_complete, name='report-complete-all'), |
|||
url(r'^casalegislativa/(?P<id>\w+)/report_complete/$', views.report_complete, name='report-complete-id'), |
|||
|
|||
# Reports Labels |
|||
url(r'^casalegislativa/labels/$', 'labels_report', name='labels-report-all'), |
|||
url(r'^casalegislativa/(?P<id>\w+)/labels/$', 'labels_report', name='labels-report-id'), |
|||
url(r'^casalegislativa/labels/$', views.labels_report, name='labels-report-all'), |
|||
url(r'^casalegislativa/(?P<id>\w+)/labels/$', views.labels_report, name='labels-report-id'), |
|||
|
|||
# Reports Labels Parlamentar |
|||
url(r'^casalegislativa/labels_parlamentar/$', 'labels_report_parlamentar', name='lebels-report-parlamentar-all'), |
|||
url(r'^casalegislativa/(?P<id>\w+)/labels_parlamentar/$', 'labels_report_parlamentar', name='labels-report-parlamentar-id'), |
|||
url(r'^casalegislativa/labels_parlamentar/$', views.labels_report_parlamentar, name='lebels-report-parlamentar-all'), |
|||
url(r'^casalegislativa/(?P<id>\w+)/labels_parlamentar/$', views.labels_report_parlamentar, name='labels-report-parlamentar-id'), |
|||
|
|||
|
|||
# Reports labels sem presidente |
|||
url(r'^casalegislativa/labels_sem_presidente/$', 'labels_report_sem_presidente', name='labels-report-sem-presidente-all'), |
|||
url(r'^casalegislativa/(?P<id>\w+)/labels_sem_presidente/$', 'labels_report_sem_presidente', name='labels-report-sem-presidente-id'), |
|||
url(r'^casalegislativa/labels_sem_presidente/$', views.labels_report_sem_presidente, name='labels-report-sem-presidente-all'), |
|||
url(r'^casalegislativa/(?P<id>\w+)/labels_sem_presidente/$', views.labels_report_sem_presidente, name='labels-report-sem-presidente-id'), |
|||
|
|||
# Reports casas sem convenio |
|||
url(r'^casalegislativa/reports/$', 'report', name='casa-report'), |
|||
url(r'^casalegislativa/casas_sem_convenio_report/$', 'casas_sem_convenio_report', name='casas-sem-convenio-report'), |
|||
url(r'^casalegislativa/reports/$', views.report, name='casa-report'), |
|||
url(r'^casalegislativa/casas_sem_convenio_report/$', views.casas_sem_convenio_report, name='casas-sem-convenio-report'), |
|||
|
|||
# CSV |
|||
url(r'^casalegislativa/csv/$', 'export_csv', name='casa-export-csv'), # Error |
|||
url(r'^casalegislativa/csv/$', views.export_csv, name='casa-export-csv'), # Error |
|||
|
|||
# Carrinho |
|||
url(r'^casalegislativa/carrinho/$', 'visualizar_carrinho', name='visualizar-carrinho'), |
|||
url(r'^casalegislativa/carrinho/excluir_carrinho/$', 'excluir_carrinho', name='excluir-carrinho'), # Error |
|||
url(r'^casalegislativa/carrinho/deleta_itens_carrinho$', 'deleta_itens_carrinho', name='deleta-itens-carrinho'), # Error |
|||
url(r'^portfolio/$', 'portfolio', name='casas-portfolio'), |
|||
url(r'^carteira/$', 'painel_relacionamento', name='casas-carteira'), |
|||
) |
|||
url(r'^casalegislativa/carrinho/$', views.visualizar_carrinho, name='visualizar-carrinho'), |
|||
url(r'^casalegislativa/carrinho/excluir_carrinho/$', views.excluir_carrinho, name='excluir-carrinho'), # Error |
|||
url(r'^casalegislativa/carrinho/deleta_itens_carrinho$', views.deleta_itens_carrinho, name='deleta-itens-carrinho'), # Error |
|||
url(r'^portfolio/$', views.portfolio, name='casas-portfolio'), |
|||
url(r'^carteira/$', views.painel_relacionamento, name='casas-carteira'), |
|||
] |
|||
|
@ -0,0 +1,20 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.6 on 2016-06-23 08:29 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations, models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('contatos', '0002_auto_20151104_0810'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterField( |
|||
model_name='contato', |
|||
name='email', |
|||
field=models.EmailField(blank=True, max_length=254, verbose_name='e-mail'), |
|||
), |
|||
] |
@ -0,0 +1,38 @@ |
|||
# -*- coding: utf-8 -*- |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import models, migrations |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('convenios', '0001_initial'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterField( |
|||
model_name='anexo', |
|||
name='descricao', |
|||
field=models.CharField(max_length=70, verbose_name='descri\xe7\xe3o'), |
|||
preserve_default=True, |
|||
), |
|||
migrations.AlterField( |
|||
model_name='tramitacao', |
|||
name='observacao', |
|||
field=models.CharField(max_length=512, null=True, verbose_name='observa\xe7\xe3o', blank=True), |
|||
preserve_default=True, |
|||
), |
|||
migrations.AlterField( |
|||
model_name='unidadeadministrativa', |
|||
name='nome', |
|||
field=models.CharField(max_length=100), |
|||
preserve_default=True, |
|||
), |
|||
migrations.AlterField( |
|||
model_name='unidadeadministrativa', |
|||
name='sigla', |
|||
field=models.CharField(max_length=10), |
|||
preserve_default=True, |
|||
), |
|||
] |
@ -1,14 +1,12 @@ |
|||
# coding: utf-8 |
|||
from django.conf.urls import patterns, url |
|||
from django.conf.urls import url |
|||
from sigi.apps.convenios import views |
|||
|
|||
|
|||
urlpatterns = patterns( |
|||
'sigi.apps.convenios.views', |
|||
|
|||
url(r'^convenio/reports/$', 'report', name='convenios-report'), |
|||
url(r'^convenio/carrinho/$', 'visualizar_carrinho', name='visualizar-carrinho'), |
|||
url(r'^convenio/carrinho/excluir_carrinho/$', 'excluir_carrinho', name='excluir-carrinho'), # tagerror |
|||
url(r'^convenio/carrinho/deleta_itens_carrinho$', 'deleta_itens_carrinho', name='deleta-itens-carrinho'), # tagerror |
|||
url(r'^convenio/csv/$', 'export_csv', name='convenios-csv'), |
|||
url(r'^reportsRegiao/(?P<regiao>\w+)/$', 'report_regiao', name='convenios-report_regiao_pdf'), |
|||
) |
|||
urlpatterns = [ |
|||
url(r'^convenio/reports/$', views.report, name='convenios-report'), |
|||
url(r'^convenio/carrinho/$', views.visualizar_carrinho, name='visualizar-carrinho'), |
|||
url(r'^convenio/carrinho/excluir_carrinho/$', views.excluir_carrinho, name='excluir-carrinho'), # tagerror |
|||
url(r'^convenio/carrinho/deleta_itens_carrinho$', views.deleta_itens_carrinho, name='deleta-itens-carrinho'), # tagerror |
|||
url(r'^convenio/csv/$', views.export_csv, name='convenios-csv'), |
|||
url(r'^reportsRegiao/(?P<regiao>\w+)/$', views.report_regiao, name='convenios-report_regiao_pdf'), |
|||
] |
|||
|
@ -0,0 +1,176 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from math import ceil |
|||
from os.path import dirname, join |
|||
|
|||
import rtyaml |
|||
from crispy_forms.bootstrap import FormActions |
|||
from crispy_forms.helper import FormHelper |
|||
from crispy_forms.layout import HTML, Div, Fieldset, Layout, Submit |
|||
from django.utils import formats |
|||
from django.utils.translation import ugettext as _ |
|||
|
|||
|
|||
def heads_and_tails(list_of_lists): |
|||
for alist in list_of_lists: |
|||
yield alist[0], alist[1:] |
|||
|
|||
|
|||
def to_column(name_span): |
|||
fieldname, span = name_span |
|||
return Div(fieldname, css_class='col-md-%d' % span) |
|||
|
|||
|
|||
def to_row(names_spans): |
|||
return Div(*map(to_column, names_spans), css_class='row-fluid') |
|||
|
|||
|
|||
def to_fieldsets(fields): |
|||
for field in fields: |
|||
if isinstance(field, list): |
|||
legend, row_specs = field[0], field[1:] |
|||
rows = [to_row(name_span_list) for name_span_list in row_specs] |
|||
yield Fieldset(legend, *rows) |
|||
else: |
|||
yield field |
|||
|
|||
|
|||
def form_actions(more=[], save_label=_('Salvar')): |
|||
return FormActions( |
|||
Submit('salvar', save_label, css_class='pull-right'), *more) |
|||
|
|||
|
|||
class FormLayout(Layout): |
|||
|
|||
def __init__(self, *fields): |
|||
buttons = form_actions(more=[ |
|||
HTML('<a href="{{ view.cancel_url }}"' |
|||
' class="btn btn-primary" style="background-color:black;">' |
|||
' Cancelar</a>')]) |
|||
_fields = list(to_fieldsets(fields)) + [to_row([(buttons, 12)])] |
|||
super(FormLayout, self).__init__(*_fields) |
|||
|
|||
|
|||
def get_field_display(obj, fieldname): |
|||
field = obj._meta.get_field(fieldname) |
|||
verbose_name = str(field.verbose_name) |
|||
if field.choices: |
|||
value = getattr(obj, 'get_%s_display' % fieldname)() |
|||
else: |
|||
value = getattr(obj, fieldname) |
|||
|
|||
if value is None: |
|||
display = '' |
|||
elif 'date' in str(type(value)): |
|||
display = formats.date_format(value, "SHORT_DATE_FORMAT") |
|||
elif 'bool' in str(type(value)): |
|||
display = _(u'Sim') if value else _(u'Não') |
|||
elif 'ImageFieldFile' in str(type(value)): |
|||
if value: |
|||
display = '<img src="{}" />'.format(value.url) |
|||
else: |
|||
display = '' |
|||
elif 'FieldFile' in str(type(value)): |
|||
if value: |
|||
display = '<a href="{}">{}</a>'.format( |
|||
value.url, |
|||
value.name.split('/')[-1:][0]) |
|||
else: |
|||
display = '' |
|||
else: |
|||
display = str(value) |
|||
return verbose_name, display |
|||
|
|||
|
|||
class CrispyLayoutFormMixin(object): |
|||
|
|||
@property |
|||
def layout_key(self): |
|||
if hasattr(super(CrispyLayoutFormMixin, self), 'layout_key'): |
|||
return super(CrispyLayoutFormMixin, self).layout_key |
|||
else: |
|||
return self.model.__name__ |
|||
|
|||
def get_layout(self): |
|||
filename = join( |
|||
dirname(self.model._meta.app_config.models_module.__file__), |
|||
'layouts.yaml') |
|||
return read_layout_from_yaml(filename, self.layout_key) |
|||
|
|||
@property |
|||
def fields(self): |
|||
if hasattr(self, 'form_class') and self.form_class: |
|||
return None |
|||
else: |
|||
'''Returns all fields in the layout''' |
|||
return [fieldname for legend_rows in self.get_layout() |
|||
for row in legend_rows[1:] |
|||
for fieldname, span in row] |
|||
|
|||
def get_form(self, form_class=None): |
|||
try: |
|||
form = super(CrispyLayoutFormMixin, self).get_form(form_class) |
|||
except AttributeError: |
|||
# simply return None if there is no get_form on super |
|||
pass |
|||
else: |
|||
form.helper = FormHelper() |
|||
form.helper.layout = FormLayout(*self.get_layout()) |
|||
return form |
|||
|
|||
@property |
|||
def list_field_names(self): |
|||
'''The list of field names to display on table |
|||
|
|||
This base implementation returns the field names |
|||
in the first fieldset of the layout. |
|||
''' |
|||
rows = self.get_layout()[0][1:] |
|||
return [fieldname for row in rows for fieldname, __ in row] |
|||
|
|||
def get_column(self, fieldname, span): |
|||
obj = self.get_object() |
|||
verbose_name, text = get_field_display(obj, fieldname) |
|||
return { |
|||
'id': fieldname, |
|||
'span': span, |
|||
'verbose_name': verbose_name, |
|||
'text': text, |
|||
} |
|||
|
|||
@property |
|||
def layout_display(self): |
|||
|
|||
return [ |
|||
{'legend': legend, |
|||
'rows': [[self.get_column(fieldname, span) |
|||
for fieldname, span in row] |
|||
for row in rows] |
|||
} for legend, rows in heads_and_tails(self.get_layout())] |
|||
|
|||
|
|||
def read_yaml_from_file(filename): |
|||
# TODO cache this at application level |
|||
with open(filename, 'r') as yamlfile: |
|||
return rtyaml.load(yamlfile) |
|||
|
|||
|
|||
def read_layout_from_yaml(filename, key): |
|||
# TODO cache this at application level |
|||
yaml = read_yaml_from_file(filename) |
|||
base = yaml[key] |
|||
|
|||
def line_to_namespans(line): |
|||
split = [cell.split(':') for cell in line.split()] |
|||
namespans = [[s[0], int(s[1]) if len(s) > 1 else 0] for s in split] |
|||
remaining = 12 - sum(s for n, s in namespans) |
|||
nondefined = [ns for ns in namespans if not ns[1]] |
|||
while nondefined: |
|||
span = ceil(remaining / len(nondefined)) |
|||
namespan = nondefined.pop(0) |
|||
namespan[1] = span |
|||
remaining = remaining - span |
|||
return list(map(tuple, namespans)) |
|||
|
|||
return [[legend] + [line_to_namespans(l) for l in lines] |
|||
for legend, lines in base.items()] |
@ -0,0 +1,227 @@ |
|||
# -*- coding: utf-8 -*- |
|||
|
|||
from __future__ import absolute_import |
|||
|
|||
from braces.views import FormMessagesMixin |
|||
from django.conf.urls import url |
|||
from django.core.urlresolvers import reverse |
|||
from django.utils.decorators import classonlymethod |
|||
from django.utils.translation import ugettext_lazy as _ |
|||
from django.views.generic import (CreateView, DeleteView, DetailView, ListView, |
|||
UpdateView) |
|||
|
|||
from sigi.apps.crispy_layout_mixin import (CrispyLayoutFormMixin, |
|||
get_field_display) |
|||
|
|||
from .utils import make_pagination |
|||
|
|||
LIST, CREATE, DETAIL, UPDATE, DELETE = \ |
|||
u'list', u'create', u'detail', u'update', u'delete' |
|||
|
|||
|
|||
def _form_invalid_message(msg): |
|||
return u'%s %s' % (_(u'Formulário inválido.'), msg) |
|||
|
|||
FORM_MESSAGES = {CREATE: (_(u'Registro criado com sucesso!'), |
|||
_(u'O registro não foi criado.')), |
|||
UPDATE: (_(u'Registro alterado com sucesso!'), |
|||
_(u'Suas alterações não foram salvas.')), |
|||
DELETE: (_(u'Registro excluído com sucesso!'), |
|||
_(u'O registro não foi excluído.'))} |
|||
FORM_MESSAGES = dict((k, (a, _form_invalid_message(b))) |
|||
for k, (a, b) in FORM_MESSAGES.items()) |
|||
|
|||
|
|||
class CrudBaseMixin(CrispyLayoutFormMixin): |
|||
|
|||
@classmethod |
|||
def url_name(cls, suffix): |
|||
return u'%s_%s' % (cls.model._meta.model_name, suffix) |
|||
|
|||
def resolve_url(self, suffix, args=None): |
|||
namespace = self.model._meta.app_label |
|||
return reverse(u'%s:%s' % (namespace, self.url_name(suffix)), |
|||
args=args) |
|||
|
|||
@property |
|||
def list_url(self): |
|||
return self.resolve_url(LIST) |
|||
|
|||
@property |
|||
def create_url(self): |
|||
return self.resolve_url(CREATE) |
|||
|
|||
@property |
|||
def detail_url(self): |
|||
return self.resolve_url(DETAIL, args=(self.object.id,)) |
|||
|
|||
@property |
|||
def update_url(self): |
|||
return self.resolve_url(UPDATE, args=(self.object.id,)) |
|||
|
|||
@property |
|||
def delete_url(self): |
|||
return self.resolve_url(DELETE, args=(self.object.id,)) |
|||
|
|||
def get_template_names(self): |
|||
names = super(CrudBaseMixin, self).get_template_names() |
|||
names.append(u"crud/%s.html" % |
|||
self.template_name_suffix.lstrip(u'_')) |
|||
return names |
|||
|
|||
@property |
|||
def verbose_name(self): |
|||
return self.model._meta.verbose_name |
|||
|
|||
@property |
|||
def verbose_name_plural(self): |
|||
return self.model._meta.verbose_name_plural |
|||
|
|||
|
|||
class CrudListView(ListView): |
|||
|
|||
@classmethod |
|||
def get_url_regex(cls): |
|||
return ur'^$' |
|||
|
|||
paginate_by = 10 |
|||
no_entries_msg = _(u'Nenhum registro encontrado.') |
|||
|
|||
def get_rows(self, object_list): |
|||
return [self._as_row(obj) for obj in object_list] |
|||
|
|||
def get_headers(self): |
|||
return [self.model._meta.get_field(fieldname).verbose_name |
|||
for fieldname in self.list_field_names] |
|||
|
|||
def _as_row(self, obj): |
|||
return [ |
|||
(get_field_display(obj, name)[1], |
|||
self.resolve_url(DETAIL, args=(obj.id,)) if i == 0 else None) |
|||
for i, name in enumerate(self.list_field_names)] |
|||
|
|||
def get_context_data(self, **kwargs): |
|||
context = super(CrudListView, self).get_context_data(**kwargs) |
|||
context.setdefault(u'title', self.verbose_name_plural) |
|||
|
|||
# pagination |
|||
if self.paginate_by: |
|||
page_obj = context[u'page_obj'] |
|||
paginator = context[u'paginator'] |
|||
context[u'page_range'] = make_pagination( |
|||
page_obj.number, paginator.num_pages) |
|||
|
|||
# rows |
|||
object_list = context[u'object_list'] |
|||
context[u'headers'] = self.get_headers() |
|||
context[u'rows'] = self.get_rows(object_list) |
|||
|
|||
context[u'NO_ENTRIES_MSG'] = self.no_entries_msg |
|||
|
|||
return context |
|||
|
|||
|
|||
class CrudCreateView(FormMessagesMixin, CreateView): |
|||
|
|||
@classmethod |
|||
def get_url_regex(cls): |
|||
return ur'^create$' |
|||
|
|||
form_valid_message, form_invalid_message = FORM_MESSAGES[CREATE] |
|||
|
|||
@property |
|||
def cancel_url(self): |
|||
return '/atendimento' |
|||
|
|||
def get_success_url(self): |
|||
return self.detail_url |
|||
|
|||
def get_context_data(self, **kwargs): |
|||
kwargs.setdefault(u'title', _(u'Adicionar %(verbose_name)s') % { |
|||
u'verbose_name': self.verbose_name}) |
|||
return super(CrudCreateView, self).get_context_data(**kwargs) |
|||
|
|||
|
|||
class CrudDetailView(DetailView): |
|||
|
|||
@classmethod |
|||
def get_url_regex(cls): |
|||
return ur'^(?P<pk>\d+)$' |
|||
|
|||
|
|||
class CrudUpdateView(FormMessagesMixin, UpdateView): |
|||
|
|||
@classmethod |
|||
def get_url_regex(cls): |
|||
return ur'^(?P<pk>\d+)/edit$' |
|||
|
|||
form_valid_message, form_invalid_message = FORM_MESSAGES[UPDATE] |
|||
|
|||
@property |
|||
def cancel_url(self): |
|||
return self.detail_url |
|||
|
|||
def get_success_url(self): |
|||
return self.detail_url |
|||
|
|||
|
|||
class CrudDeleteView(FormMessagesMixin, DeleteView): |
|||
|
|||
@classmethod |
|||
def get_url_regex(cls): |
|||
return ur'^(?P<pk>\d+)/delete$' |
|||
|
|||
form_valid_message, form_invalid_message = FORM_MESSAGES[DELETE] |
|||
|
|||
@property |
|||
def cancel_url(self): |
|||
return self.detail_url |
|||
|
|||
def get_success_url(self): |
|||
return self.list_url |
|||
|
|||
|
|||
class Crud(object): |
|||
BaseMixin = CrudBaseMixin |
|||
ListView = CrudListView |
|||
CreateView = CrudCreateView |
|||
DetailView = CrudDetailView |
|||
UpdateView = CrudUpdateView |
|||
DeleteView = CrudDeleteView |
|||
help_path = u'' |
|||
|
|||
@classonlymethod |
|||
def get_urls(cls): |
|||
|
|||
def _add_base(view): |
|||
class CrudViewWithBase(cls.BaseMixin, view): |
|||
model = cls.model |
|||
help_path = cls.help_path |
|||
crud = cls |
|||
CrudViewWithBase.__name__ = view.__name__ |
|||
return CrudViewWithBase |
|||
|
|||
CrudListView = _add_base(cls.ListView) |
|||
CrudCreateView = _add_base(cls.CreateView) |
|||
CrudDetailView = _add_base(cls.DetailView) |
|||
CrudUpdateView = _add_base(cls.UpdateView) |
|||
CrudDeleteView = _add_base(cls.DeleteView) |
|||
|
|||
return [url(regex, view.as_view(), name=view.url_name(suffix)) |
|||
for regex, view, suffix in [ |
|||
(CrudListView.get_url_regex(), CrudListView, LIST), |
|||
(CrudCreateView.get_url_regex(), CrudCreateView, CREATE), |
|||
(CrudDetailView.get_url_regex(), CrudDetailView, DETAIL), |
|||
(CrudUpdateView.get_url_regex(), CrudUpdateView, UPDATE), |
|||
(CrudDeleteView.get_url_regex(), CrudDeleteView, DELETE), |
|||
]] |
|||
|
|||
@classonlymethod |
|||
def build(cls, _model, _help_path): |
|||
|
|||
class ModelCrud(cls): |
|||
model = _model |
|||
help_path = _help_path |
|||
|
|||
ModelCrud.__name__ = u'%sCrud' % _model.__name__ |
|||
return ModelCrud |
@ -0,0 +1,7 @@ |
|||
from __future__ import absolute_import |
|||
|
|||
from django.conf.urls import include, url |
|||
|
|||
urlpatterns = [ |
|||
url(ur'', include(u'stub_app.urls')), |
|||
] |
@ -0,0 +1,66 @@ |
|||
# -*- coding: utf-8 -*- |
|||
from __future__ import absolute_import |
|||
|
|||
from django.utils.translation import ugettext_lazy as _ |
|||
|
|||
UF = [ |
|||
(u'AC', u'Acre'), |
|||
(u'AL', u'Alagoas'), |
|||
(u'AP', u'Amapá'), |
|||
(u'AM', u'Amazonas'), |
|||
(u'BA', u'Bahia'), |
|||
(u'CE', u'Ceará'), |
|||
(u'DF', u'Distrito Federal'), |
|||
(u'ES', u'Espírito Santo'), |
|||
(u'GO', u'Goiás'), |
|||
(u'MA', u'Maranhão'), |
|||
(u'MT', u'Mato Grosso'), |
|||
(u'MS', u'Mato Grosso do Sul'), |
|||
(u'MG', u'Minas Gerais'), |
|||
(u'PR', u'Paraná'), |
|||
(u'PB', u'Paraíba'), |
|||
(u'PA', u'Pará'), |
|||
(u'PE', u'Pernambuco'), |
|||
(u'PI', u'Piauí'), |
|||
(u'RJ', u'Rio de Janeiro'), |
|||
(u'RN', u'Rio Grande do Norte'), |
|||
(u'RS', u'Rio Grande do Sul'), |
|||
(u'RO', u'Rondônia'), |
|||
(u'RR', u'Roraima'), |
|||
(u'SC', u'Santa Catarina'), |
|||
(u'SE', u'Sergipe'), |
|||
(u'SP', u'São Paulo'), |
|||
(u'TO', u'Tocantins'), |
|||
(u'EX', u'Exterior'), |
|||
] |
|||
|
|||
YES_NO_CHOICES = [(None, _(u'----')), (False, _(u'Não')), (True, _(u'Sim'))] |
|||
|
|||
|
|||
def str2bool(v): |
|||
return v in (u'Sim', u'True') |
|||
|
|||
|
|||
SEXO_CHOICES = [(u'M', _(u'Masculino')), (u'F', _(u'Feminino'))] |
|||
|
|||
|
|||
def from_to(start, end): |
|||
return range(start, end + 1) |
|||
|
|||
|
|||
def make_pagination(index, num_pages): |
|||
PAGINATION_LENGTH = 10 |
|||
if num_pages <= PAGINATION_LENGTH: |
|||
return from_to(1, num_pages) |
|||
else: |
|||
if index - 1 <= 5: |
|||
tail = [num_pages - 1, num_pages] |
|||
head = from_to(1, PAGINATION_LENGTH - 3) |
|||
else: |
|||
if index + 1 >= num_pages - 3: |
|||
tail = from_to(index - 1, num_pages) |
|||
else: |
|||
tail = [index - 1, index, index + 1, |
|||
None, num_pages - 1, num_pages] |
|||
head = from_to(1, PAGINATION_LENGTH - len(tail) - 1) |
|||
return head + [None] + tail |
@ -0,0 +1,34 @@ |
|||
# -*- coding: utf-8 -*- |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import models, migrations |
|||
import autoslug.fields |
|||
import eav.models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('diagnosticos', '0001_initial'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterField( |
|||
model_name='anexo', |
|||
name='descricao', |
|||
field=models.CharField(max_length=70, verbose_name='descri\xe7\xe3o'), |
|||
preserve_default=True, |
|||
), |
|||
migrations.AlterField( |
|||
model_name='escolha', |
|||
name='schema_to_open', |
|||
field=models.ForeignKey(related_name='schema_to_open_related', verbose_name='pergunta para abrir', blank=True, to='diagnosticos.Pergunta', null=True), |
|||
preserve_default=True, |
|||
), |
|||
migrations.AlterField( |
|||
model_name='pergunta', |
|||
name='name', |
|||
field=autoslug.fields.AutoSlugField(populate_from=b'title', editable=True, max_length=250, blank=True, verbose_name='name', slugify=eav.models.slugify_attr_name), |
|||
preserve_default=True, |
|||
), |
|||
] |
@ -1,52 +1,57 @@ |
|||
# -*- coding: utf-8 -*- |
|||
from django.conf.urls import patterns, url |
|||
from django.conf.urls import url |
|||
from django.views.generic import TemplateView |
|||
from sigi.apps.diagnosticos import views as diagnosticos_views |
|||
from django.contrib.auth import views as auth_views |
|||
|
|||
|
|||
LOGIN_REDIRECT_URL = '/diagnosticos/mobile/login' |
|||
|
|||
urlpatterns = patterns( |
|||
'sigi.apps.diagnosticos.views', |
|||
|
|||
urlpatterns = [ |
|||
# Lista de Diagnósticos |
|||
url(r'^mobile/$', 'lista', name='lista_diagnosticos'), |
|||
url(r'^mobile/$', diagnosticos_views.lista, name='lista_diagnosticos'), |
|||
|
|||
# Lista de Categorias |
|||
url(r'^mobile/(?P<id_diagnostico>\d+)/categorias/$', |
|||
'categorias', name='lista_categorias'), |
|||
diagnosticos_views.categorias, name='lista_categorias'), |
|||
|
|||
# Detalhes da Categoria da Casa Legislativa |
|||
url(r'^mobile/(?P<id_diagnostico>\d+)/categorias/1/$', |
|||
'categoria_casa_legislativa', name='detalhes_categoria_casa_legislativa'), |
|||
diagnosticos_views.categoria_casa_legislativa, |
|||
name='detalhes_categoria_casa_legislativa'), |
|||
|
|||
# Detalhes da Categoria de Contatos |
|||
url(r'^mobile/(?P<id_diagnostico>\d+)/categorias/2/$', |
|||
'categoria_contatos', name='detalhes_categoria_contatos'), |
|||
diagnosticos_views.categoria_contatos, |
|||
name='detalhes_categoria_contatos'), |
|||
|
|||
# Detalhes de Categorias Dinamicas |
|||
url(r'^mobile/(?P<id_diagnostico>\d+)/categorias/(?P<id_categoria>\d+)/$', |
|||
'categoria_detalhes', name='detalhes_categoria'), |
|||
diagnosticos_views.categoria_detalhes, name='detalhes_categoria'), |
|||
|
|||
url(r'^mapa/$', TemplateView.as_view(template_name="diagnosticos/mapa.html"), name='template-mapa'), |
|||
url(r'^mundiagjson/$', 'municipios_diagnosticados', name='municipios-diagnosticados'), |
|||
url(r'^mapa/$', |
|||
TemplateView.as_view(template_name="diagnosticos/mapa.html"), |
|||
name='template-mapa'), |
|||
url(r'^mundiagjson/$', diagnosticos_views.municipios_diagnosticados, |
|||
name='municipios-diagnosticados'), |
|||
|
|||
# Reports diagnosticos |
|||
url(r'^diagnostico/(?P<id_diagnostico>\w+).pdf$', 'diagnostico_pdf', name='diagnostico-pdf'), |
|||
url(r'^diagnostico/(?P<id_diagnostico>\w+).pdf$', |
|||
diagnosticos_views.diagnostico_pdf, name='diagnostico-pdf'), |
|||
|
|||
# Graficos de perguntas |
|||
url(r'^graficos/$', 'graficos', name="diagnosticos-graficos"), # tagerror |
|||
url(r'^api/$', 'grafico_api', name="diagnosticos-grafico-api"), # tagerror |
|||
|
|||
) |
|||
|
|||
urlpatterns += patterns( |
|||
'django.contrib.auth.views', |
|||
url(r'^graficos/$', diagnosticos_views.graficos, |
|||
name="diagnosticos-graficos"), # tagerror |
|||
url(r'^api/$', diagnosticos_views.grafico_api, |
|||
name="diagnosticos-grafico-api"), # tagerror |
|||
] |
|||
|
|||
urlpatterns += [ |
|||
# Login do Diagnóstico |
|||
url(r'^mobile/login/$', 'login', {'template_name': |
|||
'diagnosticos/diagnosticos_login.html'}, name='login'), |
|||
url(r'^mobile/login/$', |
|||
auth_views.login, {'template_name': |
|||
'diagnosticos/diagnosticos_login.html'}, |
|||
name='login'), |
|||
|
|||
# Logout do Diagnóstico |
|||
url(r'^mobile/logout/$', 'logout', |
|||
{'next_page': LOGIN_REDIRECT_URL}, name='logout'), |
|||
) |
|||
url(r'^mobile/logout/$', auth_views.logout, |
|||
{'next_page': diagnosticos_views.LOGIN_REDIRECT_URL}, name='logout'), |
|||
] |
|||
|
@ -1,10 +1,9 @@ |
|||
# coding: utf-8 |
|||
from django.conf.urls import patterns, url |
|||
from django.conf.urls import url |
|||
from sigi.apps.eventos import views |
|||
|
|||
|
|||
urlpatterns = patterns( |
|||
'sigi.apps.eventos.views', |
|||
urlpatterns = [ |
|||
# Painel de ocorrencias |
|||
url(r'^calendario/$', 'calendario', name='eventos-calendario'), |
|||
url(r'^alocacaoequipe/$', 'alocacao_equipe', name='eventos-alocacaoequipe'), |
|||
) |
|||
url(r'^calendario/$', views.calendario, name='eventos-calendario'), |
|||
url(r'^alocacaoequipe/$', views.alocacao_equipe, name='eventos-alocacaoequipe'), |
|||
] |
|||
|
@ -1,15 +1,22 @@ |
|||
# coding: utf-8 |
|||
from django.conf.urls import patterns, url |
|||
from django.conf.urls import url |
|||
from django.views.generic.base import TemplateView |
|||
from sigi.apps.home import views |
|||
|
|||
|
|||
urlpatterns = patterns('sigi.apps.home.views', |
|||
url(r'^$', 'index', name='sigi_index'), |
|||
url(r'^home/resumoconvenios/$', 'resumo_convenios', name="home_resumoconvenios"), |
|||
url(r'^home/resumoseit/$', 'resumo_seit', name="home_resumoseit"), |
|||
url(r'^home/chartseit/$', 'chart_seit', name="home_chartseit"), |
|||
url(r'^home/chartconvenios/$', 'chart_convenios', name="home_chartconvenios"), |
|||
url(r'^home/chartcarteira/$', 'chart_carteira', name="home_chartcarteira"), |
|||
url(r'^home/chartperformance/$', 'chart_performance', name="home_chartperformance"), |
|||
url(r'^home/report/semconvenio/$', 'report_sem_convenio', name="home_reportsemconvenio"), |
|||
|
|||
) |
|||
urlpatterns = [ |
|||
url(r'^atendimento', TemplateView.as_view( |
|||
template_name='index_atendimento.html'), |
|||
name='index_atendimento'), |
|||
url(r'^$', views.index, name='sigi_index'), |
|||
url(r'^home/resumoconvenios/$', views.resumo_convenios, |
|||
name="home_resumoconvenios"), |
|||
url(r'^home/resumoseit/$', views.resumo_seit, name="home_resumoseit"), |
|||
url(r'^home/chartseit/$', views.chart_seit, name="home_chartseit"), |
|||
url(r'^home/chartconvenios/$', views.chart_convenios, |
|||
name="home_chartconvenios"), |
|||
url(r'^home/chartcarteira/$', views.chart_carteira, name="home_chartcarteira"), |
|||
url(r'^home/chartperformance/$', views.chart_performance, |
|||
name="home_chartperformance"), |
|||
url(r'^home/report/semconvenio/$', views.report_sem_convenio, |
|||
name="home_reportsemconvenio"), |
|||
] |
|||
|
@ -0,0 +1,20 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.6 on 2016-06-23 08:29 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations, models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('inventario', '0001_initial'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterField( |
|||
model_name='fornecedor', |
|||
name='email', |
|||
field=models.EmailField(blank=True, max_length=254, verbose_name='e-mail'), |
|||
), |
|||
] |
@ -1,14 +1,13 @@ |
|||
# coding: utf-8 |
|||
from django.conf.urls import patterns, url |
|||
from django.conf.urls import url |
|||
from sigi.apps.metas import views |
|||
|
|||
|
|||
urlpatterns = patterns( |
|||
'sigi.apps.metas.views', |
|||
|
|||
url(r'^$', 'dashboard', name='metas-dashboardsss'), # tagerror |
|||
url(r'^mapa/$', 'mapa', name='metas-mapa'), # tagerror |
|||
url(r'^mapdata/$', 'map_data', name='metas-map_data'), |
|||
url(r'^mapsearch/$', 'map_search', name='metas-map_search'), |
|||
url(r'^mapsum/$', 'map_sum', name='metas-map_sum'), |
|||
url(r'^maplist/$', 'map_list', name='metas-map_list'), |
|||
) |
|||
urlpatterns = [ |
|||
url(r'^$', views.dashboard, name='metas-dashboardsss'), # tagerror |
|||
url(r'^mapa/$', views.mapa, name='metas-mapa'), # tagerror |
|||
url(r'^mapdata/$', views.map_data, name='metas-map_data'), |
|||
url(r'^mapsearch/$', views.map_search, name='metas-map_search'), |
|||
url(r'^mapsum/$', views.map_sum, name='metas-map_sum'), |
|||
url(r'^maplist/$', views.map_list, name='metas-map_list'), |
|||
] |
|||
|
@ -0,0 +1,20 @@ |
|||
# -*- coding: utf-8 -*- |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import models, migrations |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('ocorrencias', '0002_auto_20160308_0828'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterField( |
|||
model_name='anexo', |
|||
name='descricao', |
|||
field=models.CharField(max_length=70, verbose_name='descri\xe7\xe3o do anexo'), |
|||
preserve_default=True, |
|||
), |
|||
] |
@ -1,19 +1,18 @@ |
|||
# coding: utf-8 |
|||
from django.conf.urls import patterns, url |
|||
from django.conf.urls import url |
|||
from sigi.apps.ocorrencias import views |
|||
|
|||
|
|||
urlpatterns = patterns( |
|||
'sigi.apps.ocorrencias.views', |
|||
urlpatterns = [ |
|||
# Painel de ocorrencias |
|||
url(r'^painel/$', 'painel_ocorrencias', name='painel-ocorrencias'), |
|||
url(r'^painel/buscanominal/$', 'busca_nominal', {"origin": "tudo"}, name='painel-buscanominal'), |
|||
url(r'^painel/buscanominal/casa/$', 'busca_nominal', {"origin": "casa"}, name='painel-buscacasa'), |
|||
url(r'^painel/buscanominal/servidor/$', 'busca_nominal', {"origin": "servidor"}, name='painel-buscaservidor'), |
|||
url(r'^painel/buscanominal/servico/$', 'busca_nominal', {"origin": "servico"}, name='painel-buscaservico'), |
|||
url(r'^mudaprioridade/$', 'muda_prioridade', name='ocorrencia-mudaprioridade'), |
|||
url(r'^excluianexo/$', 'exclui_anexo', name='ocorrencia-excluianexo'), |
|||
url(r'^incluianexo/$', 'inclui_anexo', name='ocorrencia-incluianexo'), |
|||
url(r'^anexosnippet/$', 'anexo_snippet', name='ocorrencia-anexosnippet'), |
|||
url(r'^incluicomentario/$', 'inclui_comentario', name='ocorrencia-incluicomentario'), |
|||
url(r'^incluiocorrencia/$', 'inclui_ocorrencia', name='ocorrencia-incluiocorrencia'), |
|||
) |
|||
url(r'^painel/$', views.painel_ocorrencias, name='painel-ocorrencias'), |
|||
url(r'^painel/buscanominal/$', views.busca_nominal, {"origin": "tudo"}, name='painel-buscanominal'), |
|||
url(r'^painel/buscanominal/casa/$', views.busca_nominal, {"origin": "casa"}, name='painel-buscacasa'), |
|||
url(r'^painel/buscanominal/servidor/$', views.busca_nominal, {"origin": "servidor"}, name='painel-buscaservidor'), |
|||
url(r'^painel/buscanominal/servico/$', views.busca_nominal, {"origin": "servico"}, name='painel-buscaservico'), |
|||
url(r'^mudaprioridade/$', views.muda_prioridade, name='ocorrencia-mudaprioridade'), |
|||
url(r'^excluianexo/$', views.exclui_anexo, name='ocorrencia-excluianexo'), |
|||
url(r'^incluianexo/$', views.inclui_anexo, name='ocorrencia-incluianexo'), |
|||
url(r'^anexosnippet/$', views.anexo_snippet, name='ocorrencia-anexosnippet'), |
|||
url(r'^incluicomentario/$', views.inclui_comentario, name='ocorrencia-incluicomentario'), |
|||
url(r'^incluiocorrencia/$', views.inclui_ocorrencia, name='ocorrencia-incluiocorrencia'), |
|||
] |
|||
|
@ -0,0 +1,20 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.6 on 2016-06-23 08:29 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations, models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('parlamentares', '0001_initial'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterField( |
|||
model_name='parlamentar', |
|||
name='email', |
|||
field=models.EmailField(blank=True, max_length=254, verbose_name='e-mail'), |
|||
), |
|||
] |
@ -0,0 +1,20 @@ |
|||
# -*- coding: utf-8 -*- |
|||
# Generated by Django 1.9.6 on 2016-08-11 15:53 |
|||
from __future__ import unicode_literals |
|||
|
|||
from django.db import migrations, models |
|||
|
|||
|
|||
class Migration(migrations.Migration): |
|||
|
|||
dependencies = [ |
|||
('parlamentares', '0002_auto_20160623_0829'), |
|||
] |
|||
|
|||
operations = [ |
|||
migrations.AlterField( |
|||
model_name='parlamentar', |
|||
name='foto', |
|||
field=models.ImageField(blank=True, height_field=b'foto_altura', null=True, upload_to=b'fotos/parlamentares', width_field=b'foto_largura'), |
|||
), |
|||
] |
@ -1,17 +1,16 @@ |
|||
# coding: utf-8 |
|||
from django.conf.urls import patterns, url |
|||
|
|||
urlpatterns = patterns( |
|||
'sigi.apps.parlamentares.views', |
|||
from django.conf.urls import url |
|||
from sigi.apps.parlamentares import views |
|||
|
|||
urlpatterns = [ |
|||
# Reports labels parlamentares |
|||
url(r'^parlamentar/labels/$', 'labels_report', name='labels-report-all'), |
|||
url(r'^parlamentar/(?P<id>\w+)/labels/$', 'labels_report', name='labels-report-id'), |
|||
url(r'^parlamentar/labels/$', views.labels_report, name='labels-report-all'), |
|||
url(r'^parlamentar/(?P<id>\w+)/labels/$', views.labels_report, name='labels-report-id'), |
|||
|
|||
# Carrinho |
|||
url(r'^parlamentar/carrinho/$', 'visualizar_carrinho', name='visualizar-carrinho'), |
|||
url(r'^parlamentar/carrinho/deleta_itens_carrinho$', 'deleta_itens_carrinho', name='deleta-itens-carrinho'), |
|||
url(r'^parlamentar/carrinho/$', views.visualizar_carrinho, name='visualizar-carrinho'), |
|||
url(r'^parlamentar/carrinho/deleta_itens_carrinho$', views.deleta_itens_carrinho, name='deleta-itens-carrinho'), |
|||
|
|||
# A view excluir_carrinho n existe ainda. |
|||
# url(r'^parlamentar/carrinho/exluir_carrinho$', 'excluir_carrinho', name='excluir-carrinho'), |
|||
) |
|||
# url(r'^parlamentar/carrinho/exluir_carrinho$', views.excluir_carrinho, name='excluir-carrinho'), |
|||
] |
|||
|
@ -1,14 +1,11 @@ |
|||
# coding: utf-8 |
|||
from django.conf.urls import patterns, url |
|||
from django.conf.urls import url |
|||
from sigi.apps.saberes import views |
|||
|
|||
from .views import cursos_sem_tutoria, cursos_com_tutoria, dashboard, pentaho_proxy |
|||
|
|||
|
|||
urlpatterns = patterns( |
|||
'sigi.apps.saberes.views', |
|||
|
|||
url(r'^dashboard/cursos-sem-turoria/?$', cursos_sem_tutoria, name="saberes-cursos-sem-tutoria"), |
|||
url(r'^dashboard/cursos-com-turoria/?$', cursos_com_tutoria, name="saberes-cursos-com-tutoria"), |
|||
url(r'^dashboard/?$', dashboard, name="saberes-dashboard-view"), |
|||
url(r'^(?P<path>(plugin|api)/.*)$', pentaho_proxy), |
|||
) |
|||
urlpatterns = [ |
|||
url(r'^dashboard/cursos-sem-turoria/?$', views.cursos_sem_tutoria, name="saberes-cursos-sem-tutoria"), |
|||
url(r'^dashboard/cursos-com-turoria/?$', views.cursos_com_tutoria, name="saberes-cursos-com-tutoria"), |
|||
url(r'^dashboard/?$', views.dashboard, name="saberes-dashboard-view"), |
|||
url(r'^(?P<path>(plugin|api)/.*)$', views.pentaho_proxy), |
|||
] |
|||
|
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue