mirror of https://github.com/interlegis/sigi.git
59 changed files with 2695 additions and 2 deletions
@ -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, |
||||
|
), |
||||
|
] |
@ -0,0 +1,175 @@ |
|||||
|
# -*- 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, label_cancel=_("Cancelar"), *fields): |
||||
|
buttons = form_actions(more=[ |
||||
|
HTML('<a href="{{ view.cancel_url }}"' |
||||
|
' class="btn btn-inverse">%s</a>' % label_cancel)]) |
||||
|
_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 = _('Sim') if value else _('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,224 @@ |
|||||
|
# -*- 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 .utils import make_pagination |
||||
|
from sigi.apps.crispy_layout_mixin import CrispyLayoutFormMixin, get_field_display |
||||
|
|
||||
|
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 self.list_url |
||||
|
|
||||
|
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,6 @@ |
|||||
|
from __future__ import absolute_import |
||||
|
from django.conf.urls import include, url |
||||
|
|
||||
|
urlpatterns = [ |
||||
|
url(ur'', include(u'stub_app.urls')), |
||||
|
] |
@ -0,0 +1,65 @@ |
|||||
|
# -*- 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, |
||||
|
), |
||||
|
] |
@ -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, |
||||
|
), |
||||
|
] |
@ -0,0 +1,20 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
from django.db import models, migrations |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('servicos', '0002_tiposervico_modo'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterField( |
||||
|
model_name='tiposervico', |
||||
|
name='sigla', |
||||
|
field=models.CharField(max_length=12, verbose_name='Sigla'), |
||||
|
preserve_default=True, |
||||
|
), |
||||
|
] |
@ -0,0 +1,3 @@ |
|||||
|
# from django.contrib import admin |
||||
|
|
||||
|
# Register your models here. |
@ -0,0 +1,10 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
from __future__ import absolute_import |
||||
|
from django import apps |
||||
|
from django.utils.translation import ugettext_lazy as _ |
||||
|
|
||||
|
|
||||
|
class AppConfig(apps.AppConfig): |
||||
|
name = u'solicitacoes' |
||||
|
verbose_name = _(u'Solicitações') |
@ -0,0 +1,43 @@ |
|||||
|
from __future__ import absolute_import |
||||
|
from django import forms |
||||
|
from django.forms import ModelForm |
||||
|
|
||||
|
from .models import Sistema, Solicitacao |
||||
|
|
||||
|
|
||||
|
class SolicitacaoForm(ModelForm): |
||||
|
|
||||
|
resumo = forms.CharField( |
||||
|
label=u'Resumo', |
||||
|
max_length=500, |
||||
|
widget=forms.Textarea) |
||||
|
|
||||
|
class Meta(object): |
||||
|
model = Solicitacao |
||||
|
fields = [u'codigo', u'usuario', u'sistema', |
||||
|
u'email_contato', u'telefone_contato', |
||||
|
u'casa_legislativa', u'titulo', u'resumo'] |
||||
|
widgets = {u'codigo': forms.HiddenInput(), |
||||
|
u'usuario': forms.HiddenInput()} |
||||
|
|
||||
|
|
||||
|
class SolicitacaoEditForm(ModelForm): |
||||
|
|
||||
|
resumo = forms.CharField( |
||||
|
label=u'Resumo', |
||||
|
max_length=500, |
||||
|
widget=forms.Textarea) |
||||
|
|
||||
|
class Meta(object): |
||||
|
model = Solicitacao |
||||
|
fields = [u'codigo', u'usuario', u'sistema', |
||||
|
u'casa_legislativa', u'titulo', u'resumo'] |
||||
|
widgets = {u'codigo': forms.TextInput(attrs={u'readonly': u'readonly'}), |
||||
|
u'usuario': forms.HiddenInput()} |
||||
|
|
||||
|
|
||||
|
class SistemaForm(ModelForm): |
||||
|
|
||||
|
class Meta(object): |
||||
|
model = Sistema |
||||
|
fields = [u'sigla', u'nome'] |
@ -0,0 +1,33 @@ |
|||||
|
|
||||
|
Sistema: |
||||
|
Sistema: |
||||
|
- sigla |
||||
|
- nome |
||||
|
|
||||
|
Solicitacao: |
||||
|
Solicitação: |
||||
|
- codigo |
||||
|
- usuario |
||||
|
- sistema |
||||
|
- casa_legislativa |
||||
|
- email_contato telefone_contato |
||||
|
- titulo |
||||
|
- resumo |
||||
|
|
||||
|
SolicitacaoEdit: |
||||
|
Solicitação: |
||||
|
- codigo |
||||
|
- usuario |
||||
|
- sistema |
||||
|
- titulo |
||||
|
- resumo |
||||
|
|
||||
|
SolicitacaoList: |
||||
|
Solicitação: |
||||
|
- codigo |
||||
|
- usuario |
||||
|
- sistema |
||||
|
- casa_legislativa |
||||
|
- email_contato telefone_contato |
||||
|
- titulo |
||||
|
- data_criacao |
@ -0,0 +1,53 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Generated by Django 1.9.5 on 2016-06-16 16:34 |
||||
|
from __future__ import absolute_import |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
import django.db.models.deletion |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
initial = True |
||||
|
|
||||
|
dependencies = [ |
||||
|
(u'usuarios', u'__first__'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.CreateModel( |
||||
|
name=u'Sistema', |
||||
|
fields=[ |
||||
|
(u'id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name=u'ID')), |
||||
|
(u'sigla', models.CharField(max_length=10, verbose_name=u'Sigla')), |
||||
|
(u'nome', models.CharField(max_length=100, verbose_name=u'Nome Sistema')), |
||||
|
(u'descricao', models.TextField(blank=True, null=True, verbose_name=u'Descrição')), |
||||
|
], |
||||
|
options={ |
||||
|
u'verbose_name_plural': u'Sistemas', |
||||
|
u'verbose_name': u'Sistema', |
||||
|
}, |
||||
|
), |
||||
|
migrations.CreateModel( |
||||
|
name=u'Solicitacao', |
||||
|
fields=[ |
||||
|
(u'id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name=u'ID')), |
||||
|
(u'codigo', models.PositiveIntegerField(unique=True)), |
||||
|
(u'titulo', models.CharField(max_length=100, verbose_name=u'Título')), |
||||
|
(u'resumo', models.CharField(max_length=50, verbose_name=u'Resumo')), |
||||
|
(u'casa_legislativa', models.CharField(max_length=200, verbose_name=u'Casa Legislativa')), |
||||
|
(u'email_contato', models.EmailField(blank=True, max_length=254, null=True, verbose_name=u'Email de contato')), |
||||
|
(u'telefone_contato', models.CharField(blank=True, max_length=15, null=True, verbose_name=u'Telefone de contato')), |
||||
|
(u'data_criacao', models.DateTimeField(auto_now_add=True, verbose_name=u'Data de criação')), |
||||
|
(u'descricao', models.TextField(blank=True, null=True, verbose_name=u'Descrição')), |
||||
|
(u'sistema', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=u'solicitacoes.Sistema')), |
||||
|
(u'usuario', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=u'usuarios.Usuario')), |
||||
|
], |
||||
|
options={ |
||||
|
u'ordering': [u'data_criacao'], |
||||
|
u'verbose_name_plural': u'Solicitações de Novos Serviços', |
||||
|
u'verbose_name': u'Solicitação de Novo Serviço', |
||||
|
}, |
||||
|
), |
||||
|
] |
@ -0,0 +1,20 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
from django.db import models, migrations |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('solicitacoes', '0001_initial'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterField( |
||||
|
model_name='solicitacao', |
||||
|
name='email_contato', |
||||
|
field=models.EmailField(max_length=75, null=True, verbose_name='Email de contato', blank=True), |
||||
|
preserve_default=True, |
||||
|
), |
||||
|
] |
@ -0,0 +1,54 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
from __future__ import absolute_import |
||||
|
from django.db import models |
||||
|
from django.utils.translation import ugettext_lazy as _ |
||||
|
|
||||
|
from sigi.apps.usuarios.models import Usuario |
||||
|
|
||||
|
|
||||
|
class Sistema(models.Model): |
||||
|
sigla = models.CharField(verbose_name=_(u'Sigla'), max_length=10) |
||||
|
nome = models.CharField(verbose_name=_(u'Nome Sistema'), |
||||
|
max_length=100) |
||||
|
descricao = models.TextField(null=True, |
||||
|
blank=True, |
||||
|
verbose_name=_(u'Descrição')) |
||||
|
|
||||
|
class Meta(object): |
||||
|
verbose_name = _(u'Sistema') |
||||
|
verbose_name_plural = _(u'Sistemas') |
||||
|
|
||||
|
def __str__(self): |
||||
|
return u"%s - %s" % (self.sigla, self.nome) |
||||
|
|
||||
|
|
||||
|
class Solicitacao(models.Model): |
||||
|
codigo = models.PositiveIntegerField(unique=True) |
||||
|
usuario = models.ForeignKey(Usuario) |
||||
|
sistema = models.ForeignKey(Sistema) |
||||
|
titulo = models.CharField(verbose_name=_(u'Título'), max_length=100) |
||||
|
resumo = models.CharField(verbose_name=_(u'Resumo'), max_length=50) |
||||
|
casa_legislativa = models.CharField(verbose_name=_(u'Casa Legislativa'), |
||||
|
max_length=200) |
||||
|
email_contato = models.EmailField(blank=True, |
||||
|
null=True, |
||||
|
verbose_name=_(u'Email de contato')) |
||||
|
# Substituir por usuarios.models.Telefone? |
||||
|
telefone_contato = models.CharField(max_length=15, |
||||
|
null=True, |
||||
|
blank=True, |
||||
|
verbose_name=_(u'Telefone de contato')) |
||||
|
|
||||
|
data_criacao = models.DateTimeField(auto_now_add=True, |
||||
|
verbose_name=_(u'Data de criação')) |
||||
|
descricao = models.TextField(blank=True, |
||||
|
null=True, |
||||
|
verbose_name=_(u'Descrição')) |
||||
|
|
||||
|
class Meta(object): |
||||
|
verbose_name = _(u'Solicitação de Novo Serviço') |
||||
|
verbose_name_plural = _(u'Solicitações de Novos Serviços') |
||||
|
ordering = [u'data_criacao'] |
||||
|
|
||||
|
def __str__(self): |
||||
|
return u"%s - %s" % (self.codigo, self.resumo) |
@ -0,0 +1,3 @@ |
|||||
|
# from django.test import TestCase |
||||
|
|
||||
|
# Create your tests here. |
@ -0,0 +1,13 @@ |
|||||
|
from __future__ import absolute_import |
||||
|
from django.conf.urls import include, url |
||||
|
|
||||
|
from sigi.apps.solicitacoes.views import SistemaCrud, SolicitacaoCrud |
||||
|
|
||||
|
from .apps import AppConfig |
||||
|
|
||||
|
app_name = AppConfig.name |
||||
|
|
||||
|
urlpatterns = [ |
||||
|
url(ur'sistema/', include(SistemaCrud.get_urls())), |
||||
|
url(ur'solicitacao/', include(SolicitacaoCrud.get_urls())), |
||||
|
] |
@ -0,0 +1,56 @@ |
|||||
|
from __future__ import absolute_import |
||||
|
import random |
||||
|
|
||||
|
from django.contrib.auth.mixins import LoginRequiredMixin |
||||
|
|
||||
|
import sigi.apps.crud.base |
||||
|
from sigi.apps.crud.base import Crud, CrudCreateView, CrudListView, CrudCreateView, CrudUpdateView |
||||
|
from sigi.apps.usuarios.models import Usuario |
||||
|
|
||||
|
from .forms import SistemaForm, SolicitacaoEditForm, SolicitacaoForm |
||||
|
from .models import Sistema, Solicitacao |
||||
|
|
||||
|
|
||||
|
class SolicitacaoCrud(LoginRequiredMixin, Crud): |
||||
|
model = Solicitacao |
||||
|
help_path = u'' |
||||
|
|
||||
|
class CreateView(LoginRequiredMixin, CrudCreateView): |
||||
|
form_class = SolicitacaoForm |
||||
|
|
||||
|
def get_initial(self): |
||||
|
try: |
||||
|
usuario = Usuario.objects.get(user=self.request.user) |
||||
|
self.initial[u'usuario'] = usuario |
||||
|
self.initial[u'codigo'] = random.randint(0, 65500) |
||||
|
self.initial[u'email_contato'] = usuario.email |
||||
|
self.initial[u'telefone_contato'] = usuario.primeiro_telefone |
||||
|
except Usuario.DoesNotExist: |
||||
|
pass |
||||
|
return self.initial.copy() # TODO: por que? |
||||
|
|
||||
|
class UpdateView(LoginRequiredMixin, CrudUpdateView): |
||||
|
form_class = SolicitacaoEditForm |
||||
|
|
||||
|
@property |
||||
|
def layout_key(self): |
||||
|
return u'SolicitacaoEdit' |
||||
|
|
||||
|
class ListView(LoginRequiredMixin, CrudListView): |
||||
|
@property |
||||
|
def layout_key(self): |
||||
|
return u'SolicitacaoList' |
||||
|
|
||||
|
|
||||
|
class SistemaCrud(Crud): |
||||
|
model = Sistema |
||||
|
help_path = u'' |
||||
|
|
||||
|
class CreateView(LoginRequiredMixin, CrudCreateView): |
||||
|
form_class = SistemaForm |
||||
|
|
||||
|
class UpdateView(LoginRequiredMixin, CrudUpdateView): |
||||
|
form_class = SistemaForm |
||||
|
|
||||
|
class ListView(LoginRequiredMixin, CrudListView): |
||||
|
pass |
@ -0,0 +1,12 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
{% load i18n %} |
||||
|
|
||||
|
{% block title %} |
||||
|
<h1 class="page-header">Bem-vindo ao Centro de Suporte</h1> |
||||
|
{% endblock %} |
||||
|
|
||||
|
{% block base_content %} |
||||
|
Através deste sistema, você poderá solicitar novos serviços a serem |
||||
|
hospedados em nosso Data Center e acompanhar as solicitações já em aberto. |
||||
|
Cadastre-se para continuar. |
||||
|
{% endblock %} |
@ -0,0 +1,3 @@ |
|||||
|
# from django.contrib import admin |
||||
|
|
||||
|
# Register your models here. |
@ -0,0 +1,10 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
from __future__ import absolute_import |
||||
|
from django import apps |
||||
|
from django.utils.translation import ugettext_lazy as _ |
||||
|
|
||||
|
|
||||
|
class AppConfig(apps.AppConfig): |
||||
|
name = u'usuarios' |
||||
|
verbose_name = _(u'Usuários') |
@ -0,0 +1,450 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
from __future__ import absolute_import |
||||
|
from datetime import datetime |
||||
|
|
||||
|
from captcha.fields import CaptchaField |
||||
|
from crispy_forms.helper import FormHelper |
||||
|
from crispy_forms.layout import Fieldset, Layout, Submit |
||||
|
from django import forms |
||||
|
from django.conf import settings |
||||
|
from django.contrib.auth.forms import (AuthenticationForm, PasswordResetForm, |
||||
|
SetPasswordForm) |
||||
|
from django.contrib.auth.models import User |
||||
|
from django.contrib.auth.password_validation import validate_password |
||||
|
from django.contrib.auth.tokens import default_token_generator |
||||
|
from django.core.exceptions import ValidationError |
||||
|
from django.core.mail import send_mail |
||||
|
from django.core.urlresolvers import reverse |
||||
|
from django.db import transaction |
||||
|
from django.forms import ModelForm |
||||
|
from django.utils.encoding import force_bytes |
||||
|
from django.utils.http import urlsafe_base64_encode |
||||
|
from django.utils.translation import ugettext_lazy as _ |
||||
|
|
||||
|
|
||||
|
import sigi.apps.crispy_layout_mixin |
||||
|
from sigi.apps.crud.utils import YES_NO_CHOICES |
||||
|
from sigi.apps.crispy_layout_mixin import form_actions |
||||
|
|
||||
|
from .models import Telefone, Usuario, ConfirmaEmail |
||||
|
|
||||
|
|
||||
|
class LoginForm(AuthenticationForm): |
||||
|
username = forms.CharField( |
||||
|
label=u"Username", max_length=30, |
||||
|
widget=forms.TextInput( |
||||
|
attrs={u'class': u'form-control', u'name': u'username'})) |
||||
|
|
||||
|
password = forms.CharField( |
||||
|
label=u"Password", max_length=30, |
||||
|
widget=forms.PasswordInput( |
||||
|
attrs={u'class': u'form-control', u'name': u'password'})) |
||||
|
|
||||
|
|
||||
|
class UsuarioForm(ModelForm): |
||||
|
# Telefone |
||||
|
TIPO_TELEFONE = [(u'FIXO', u'FIXO'), (u'CELULAR', u'CELULAR')] |
||||
|
|
||||
|
# Primeiro Telefone |
||||
|
primeiro_tipo = forms.ChoiceField( |
||||
|
widget=forms.Select(), |
||||
|
choices=TIPO_TELEFONE, |
||||
|
label=_(u'Tipo Telefone')) |
||||
|
primeiro_ddd = forms.CharField(max_length=2, label=_(u'DDD')) |
||||
|
primeiro_numero = forms.CharField(max_length=10, label=_(u'Número')) |
||||
|
primeiro_principal = forms.TypedChoiceField( |
||||
|
widget=forms.Select(), |
||||
|
label=_(u'Telefone Principal?'), |
||||
|
choices=YES_NO_CHOICES) |
||||
|
|
||||
|
# Primeiro Telefone |
||||
|
segundo_tipo = forms.ChoiceField( |
||||
|
required=False, |
||||
|
widget=forms.Select(), |
||||
|
choices=TIPO_TELEFONE, |
||||
|
label=_(u'Tipo Telefone')) |
||||
|
segundo_ddd = forms.CharField(required=False, max_length=2, label=_(u'DDD')) |
||||
|
segundo_numero = forms.CharField( |
||||
|
required=False, max_length=10, label=_(u'Número')) |
||||
|
segundo_principal = forms.ChoiceField( |
||||
|
required=False, |
||||
|
widget=forms.Select(), |
||||
|
label=_(u'Telefone Principal?'), |
||||
|
choices=YES_NO_CHOICES) |
||||
|
|
||||
|
# Usuário |
||||
|
password = forms.CharField( |
||||
|
max_length=20, |
||||
|
label=_(u'Senha'), |
||||
|
widget=forms.PasswordInput()) |
||||
|
|
||||
|
password_confirm = forms.CharField( |
||||
|
max_length=20, |
||||
|
label=_(u'Confirmar Senha'), |
||||
|
widget=forms.PasswordInput()) |
||||
|
|
||||
|
email_confirm = forms.EmailField( |
||||
|
required=True, |
||||
|
widget=forms.TextInput(attrs={u'style': u'text-transform:lowercase;'}), |
||||
|
label=_(u'Confirmar Email')) |
||||
|
|
||||
|
captcha = CaptchaField() |
||||
|
|
||||
|
class Meta(object): |
||||
|
model = Usuario |
||||
|
fields = [u'username', u'email', u'nome_completo', u'password', u'vinculo', |
||||
|
u'password_confirm', u'email_confirm', u'captcha', u'cpf', u'rg', |
||||
|
u'cargo', u'casa_legislativa'] |
||||
|
|
||||
|
widgets = {u'email': forms.TextInput( |
||||
|
attrs={u'style': u'text-transform:lowercase;'}),} |
||||
|
|
||||
|
def __init__(self, *args, **kwargs): |
||||
|
super(UsuarioForm, self).__init__(*args, **kwargs) |
||||
|
self.fields[u'rg'].widget.attrs[u'class'] = u'rg' |
||||
|
self.fields[u'cpf'].widget.attrs[u'class'] = u'cpf' |
||||
|
self.fields[u'primeiro_numero'].widget.attrs[u'class'] = u'telefone' |
||||
|
self.fields[u'primeiro_ddd'].widget.attrs[u'class'] = u'ddd' |
||||
|
self.fields[u'segundo_numero'].widget.attrs[u'class'] = u'telefone' |
||||
|
self.fields[u'segundo_ddd'].widget.attrs[u'class'] = u'ddd' |
||||
|
|
||||
|
def valida_igualdade(self, texto1, texto2, msg): |
||||
|
if texto1 != texto2: |
||||
|
raise ValidationError(msg) |
||||
|
return True |
||||
|
|
||||
|
def clean_primeiro_numero(self): |
||||
|
cleaned_data = self.cleaned_data |
||||
|
|
||||
|
telefone = Telefone() |
||||
|
telefone.tipo = self.data[u'primeiro_tipo'] |
||||
|
telefone.ddd = self.data[u'primeiro_ddd'] |
||||
|
telefone.numero = self.data[u'primeiro_numero'] |
||||
|
telefone.principal = self.data[u'primeiro_principal'] |
||||
|
|
||||
|
cleaned_data[u'primeiro_telefone'] = telefone |
||||
|
return cleaned_data |
||||
|
|
||||
|
def clean_segundo_numero(self): |
||||
|
cleaned_data = self.cleaned_data |
||||
|
|
||||
|
telefone = Telefone() |
||||
|
telefone.tipo = self.data[u'segundo_tipo'] |
||||
|
telefone.ddd = self.data[u'segundo_ddd'] |
||||
|
telefone.numero = self.data[u'segundo_numero'] |
||||
|
telefone.principal = self.data[u'segundo_principal'] |
||||
|
|
||||
|
cleaned_data[u'segundo_telefone'] = telefone |
||||
|
return cleaned_data |
||||
|
|
||||
|
def valida_email_existente(self): |
||||
|
return Usuario.objects.filter( |
||||
|
email=self.cleaned_data[u'email']).exists() |
||||
|
|
||||
|
def clean(self): |
||||
|
|
||||
|
if (u'password' not in self.cleaned_data or |
||||
|
u'password_confirm' not in self.cleaned_data): |
||||
|
raise ValidationError(_(u'Favor informar senhas atuais ou novas')) |
||||
|
|
||||
|
msg = _(u'As senhas não conferem.') |
||||
|
self.valida_igualdade( |
||||
|
self.cleaned_data[u'password'], |
||||
|
self.cleaned_data[u'password_confirm'], |
||||
|
msg) |
||||
|
|
||||
|
if (u'email' not in self.cleaned_data or |
||||
|
u'email_confirm' not in self.cleaned_data): |
||||
|
raise ValidationError(_(u'Favor informar endereços de email')) |
||||
|
|
||||
|
msg = _(u'Os emails não conferem.') |
||||
|
self.valida_igualdade( |
||||
|
self.cleaned_data[u'email'], |
||||
|
self.cleaned_data[u'email_confirm'], |
||||
|
msg) |
||||
|
|
||||
|
email_existente = self.valida_email_existente() |
||||
|
|
||||
|
if email_existente: |
||||
|
msg = _(u'Esse email já foi cadastrado.') |
||||
|
raise ValidationError(msg) |
||||
|
|
||||
|
try: |
||||
|
validate_password(self.cleaned_data[u'password']) |
||||
|
except ValidationError, error: |
||||
|
raise ValidationError(error) |
||||
|
|
||||
|
return self.cleaned_data |
||||
|
|
||||
|
@transaction.atomic |
||||
|
def save(self, commit=False): |
||||
|
usuario = super(UsuarioForm, self).save(commit) |
||||
|
|
||||
|
# Cria telefones |
||||
|
tel = Telefone.objects.create( |
||||
|
tipo=self.data[u'primeiro_tipo'], |
||||
|
ddd=self.data[u'primeiro_ddd'], |
||||
|
numero=self.data[u'primeiro_numero'], |
||||
|
principal=self.data[u'primeiro_principal'] |
||||
|
) |
||||
|
usuario.primeiro_telefone = tel |
||||
|
|
||||
|
tel = self.cleaned_data[u'segundo_telefone'] |
||||
|
if (tel.tipo and tel.ddd and tel.numero and tel.principal): |
||||
|
tel = Telefone.objects.create( |
||||
|
tipo=self.data[u'segundo_tipo'], |
||||
|
ddd=self.data[u'segundo_ddd'], |
||||
|
numero=self.data[u'segundo_numero'], |
||||
|
principal=self.data[u'segundo_principal'] |
||||
|
) |
||||
|
usuario.segundo_telefone = tel |
||||
|
|
||||
|
# Cria User |
||||
|
u = User.objects.create(username=usuario.username, email=usuario.email) |
||||
|
u.set_password(self.cleaned_data[u'password']) |
||||
|
u.is_active = False |
||||
|
|
||||
|
u.save() |
||||
|
usuario.user = u |
||||
|
usuario.save() |
||||
|
|
||||
|
|
||||
|
class UsuarioEditForm(UsuarioForm): |
||||
|
|
||||
|
class Meta(object): |
||||
|
model = Usuario |
||||
|
fields = [u'username', u'email', u'nome_completo', u'vinculo', |
||||
|
u'email_confirm', u'captcha', u'cpf', u'rg', |
||||
|
u'cargo', u'casa_legislativa'] |
||||
|
widgets = {u'username': forms.TextInput(attrs={u'readonly': u'readonly'}), |
||||
|
u'email': forms.TextInput( |
||||
|
attrs={u'style': u'text-transform:lowercase;'}), |
||||
|
} |
||||
|
|
||||
|
def __init__(self, *args, **kwargs): |
||||
|
super(UsuarioEditForm, self).__init__(*args, **kwargs) |
||||
|
self.fields[u'email_confirm'].initial = self.instance.email |
||||
|
self.fields.pop(u'password') |
||||
|
self.fields.pop(u'password_confirm') |
||||
|
|
||||
|
def valida_email_existente(self): |
||||
|
u'''Não permite atualizar emails para |
||||
|
emails existentes de outro usuário |
||||
|
''' |
||||
|
return Usuario.objects.filter( |
||||
|
email=self.cleaned_data[u'email']).exclude( |
||||
|
user__username=self.cleaned_data[u'username']).exists() |
||||
|
|
||||
|
def clean(self): |
||||
|
|
||||
|
if (u'email' not in self.cleaned_data or |
||||
|
u'email_confirm' not in self.cleaned_data): |
||||
|
raise ValidationError(_(u'Favor informar endereços de email')) |
||||
|
|
||||
|
msg = _(u'Os emails não conferem.') |
||||
|
self.valida_igualdade( |
||||
|
self.cleaned_data[u'email'], |
||||
|
self.cleaned_data[u'email_confirm'], |
||||
|
msg) |
||||
|
|
||||
|
email_existente = self.valida_email_existente() |
||||
|
|
||||
|
if email_existente: |
||||
|
msg = _(u'Esse email já foi cadastrado.') |
||||
|
raise ValidationError(msg) |
||||
|
|
||||
|
return self.cleaned_data |
||||
|
|
||||
|
@transaction.atomic |
||||
|
def save(self, commit=False): |
||||
|
|
||||
|
usuario = super(UsuarioForm, self).save(commit) |
||||
|
|
||||
|
# Primeiro telefone |
||||
|
tel = usuario.primeiro_telefone |
||||
|
|
||||
|
tel.tipo = self.data[u'primeiro_tipo'] |
||||
|
tel.ddd = self.data[u'primeiro_ddd'] |
||||
|
tel.numero = self.data[u'primeiro_numero'] |
||||
|
tel.principal = self.data[u'primeiro_principal'] |
||||
|
tel.save() |
||||
|
|
||||
|
usuario.primeiro_telefone = tel |
||||
|
|
||||
|
# Segundo telefone |
||||
|
tel = usuario.segundo_telefone |
||||
|
|
||||
|
if tel: |
||||
|
tel.tipo = self.data[u'segundo_tipo'] |
||||
|
tel.ddd = self.data[u'segundo_ddd'] |
||||
|
tel.numero = self.data[u'segundo_numero'] |
||||
|
tel.principal = self.data[u'segundo_principal'] |
||||
|
tel.save() |
||||
|
usuario.segundo_telefone = tel |
||||
|
|
||||
|
tel = self.cleaned_data[u'segundo_telefone'] |
||||
|
if (tel.tipo and tel.ddd and tel.numero and tel.principal): |
||||
|
tel = Telefone.objects.create( |
||||
|
tipo=self.data[u'segundo_tipo'], |
||||
|
ddd=self.data[u'segundo_ddd'], |
||||
|
numero=self.data[u'segundo_numero'], |
||||
|
principal=self.data[u'segundo_principal'] |
||||
|
) |
||||
|
usuario.segundo_telefone = tel |
||||
|
|
||||
|
# User |
||||
|
u = usuario.user |
||||
|
u.email = usuario.email |
||||
|
u.save() |
||||
|
|
||||
|
usuario.data_ultima_atualizacao = datetime.now() |
||||
|
usuario.save() |
||||
|
return usuario |
||||
|
|
||||
|
|
||||
|
class HabilitarEditForm(ModelForm): |
||||
|
habilitado = forms.ChoiceField( |
||||
|
widget=forms.Select(), |
||||
|
required=True, |
||||
|
choices=YES_NO_CHOICES) |
||||
|
|
||||
|
class Meta(object): |
||||
|
model = Usuario |
||||
|
fields = [u'cpf', u'nome_completo', u'email', u'habilitado'] |
||||
|
widgets = { |
||||
|
u'cpf': forms.TextInput(attrs={u'readonly': u'readonly'}), |
||||
|
u'nome_completo': forms.TextInput(attrs={u'readonly': u'readonly'}), |
||||
|
u'email': forms.TextInput(attrs={u'readonly': u'readonly'}) |
||||
|
} |
||||
|
|
||||
|
def __init__(self, *args, **kwargs): |
||||
|
super(HabilitarEditForm, self).__init__(*args, **kwargs) |
||||
|
row1 = crispy_layout_mixin.to_row( |
||||
|
[(u'nome_completo', 4), |
||||
|
(u'cpf', 4), |
||||
|
(u'email', 4)]) |
||||
|
row2 = crispy_layout_mixin.to_row([(u'habilitado', 12)]) |
||||
|
self.helper = FormHelper() |
||||
|
self.helper.layout = Layout( |
||||
|
Fieldset( |
||||
|
_(u'Editar usuário'), row1, row2, form_actions( |
||||
|
more=[ |
||||
|
Submit( |
||||
|
u'Cancelar', |
||||
|
u'Cancelar', |
||||
|
style=u'background-color:black; color:white;')]) |
||||
|
) |
||||
|
) |
||||
|
|
||||
|
|
||||
|
class MudarSenhaForm(ModelForm): |
||||
|
|
||||
|
password = forms.CharField( |
||||
|
max_length=20, |
||||
|
label=_(u'Nova Senha'), |
||||
|
widget=forms.PasswordInput()) |
||||
|
|
||||
|
password_confirm = forms.CharField( |
||||
|
max_length=20, |
||||
|
label=_(u'Confirmar Nova Senha'), |
||||
|
widget=forms.PasswordInput()) |
||||
|
|
||||
|
captcha = CaptchaField() |
||||
|
|
||||
|
def valida_igualdade(self, texto1, texto2, msg): |
||||
|
if texto1 != texto2: |
||||
|
raise ValidationError(msg) |
||||
|
return True |
||||
|
|
||||
|
def clean(self): |
||||
|
if (u'password' not in self.cleaned_data or |
||||
|
u'password_confirm' not in self.cleaned_data): |
||||
|
raise ValidationError(_(u'Favor informar senhas atuais \ |
||||
|
ou novas')) |
||||
|
|
||||
|
msg = _(u'As senhas não conferem.') |
||||
|
self.valida_igualdade( |
||||
|
self.cleaned_data[u'password'], |
||||
|
self.cleaned_data[u'password_confirm'], |
||||
|
msg) |
||||
|
|
||||
|
try: |
||||
|
validate_password(self.cleaned_data[u'password']) |
||||
|
except ValidationError, error: |
||||
|
raise ValidationError(error) |
||||
|
|
||||
|
class Meta(object): |
||||
|
model = Usuario |
||||
|
fields = [u'password', u'password_confirm', u'captcha'] |
||||
|
|
||||
|
def __init__(self, *args, **kwargs): |
||||
|
super(MudarSenhaForm, self).__init__(*args, **kwargs) |
||||
|
row1 = crispy_layout_mixin.to_row( |
||||
|
[(u'password', 6), |
||||
|
(u'password_confirm', 6)]) |
||||
|
row2 = crispy_layout_mixin.to_row([(u'captcha', 12)]) |
||||
|
self.helper = FormHelper() |
||||
|
self.helper.layout = Layout( |
||||
|
Fieldset( |
||||
|
_(u'Mudar Senha'), row1, row2, |
||||
|
form_actions( |
||||
|
more=[ |
||||
|
Submit( |
||||
|
u'Cancelar', |
||||
|
u'Cancelar', |
||||
|
style=u'background-color:black; color:white;')]) |
||||
|
) |
||||
|
) |
||||
|
|
||||
|
|
||||
|
class RecuperarSenhaEmailForm(PasswordResetForm): |
||||
|
|
||||
|
def __init__(self, *args, **kwargs): |
||||
|
super(RecuperarSenhaEmailForm, self).__init__(*args, **kwargs) |
||||
|
row1 = crispy_layout_mixin.to_row( |
||||
|
[(u'email', 6)]) |
||||
|
self.helper = FormHelper() |
||||
|
self.helper.layout = Layout( |
||||
|
Fieldset(_(u'Recuperar Senha'), |
||||
|
row1, |
||||
|
form_actions( |
||||
|
more=[ |
||||
|
Submit( |
||||
|
u'Cancelar', |
||||
|
u'Cancelar', |
||||
|
style=u'background-color:black; color:white;')]) |
||||
|
) |
||||
|
) |
||||
|
|
||||
|
def clean(self): |
||||
|
email_existente_usuario = Usuario.objects.filter( |
||||
|
email=self.cleaned_data[u'email']) |
||||
|
email_existente_user = User.objects.filter( |
||||
|
email=self.cleaned_data[u'email']) |
||||
|
|
||||
|
if not email_existente_usuario and not email_existente_user: |
||||
|
msg = _(u'Não existe nenhum usuário cadastrado com este e-mail.') |
||||
|
raise ValidationError(msg) |
||||
|
|
||||
|
return self.cleaned_data |
||||
|
|
||||
|
|
||||
|
class RecuperacaoMudarSenhaForm(SetPasswordForm): |
||||
|
def __init__(self, *args, **kwargs): |
||||
|
super(RecuperacaoMudarSenhaForm, self).__init__(*args, **kwargs) |
||||
|
self.fields[u'new_password1'].help_text = u'' |
||||
|
row1 = crispy_layout_mixin.to_row( |
||||
|
[(u'new_password1', 6), |
||||
|
(u'new_password2', 6)]) |
||||
|
self.helper = FormHelper() |
||||
|
self.helper.layout = Layout( |
||||
|
Fieldset(_(u''), |
||||
|
row1, |
||||
|
form_actions( |
||||
|
more=[ |
||||
|
Submit( |
||||
|
u'Cancelar', |
||||
|
u'Cancelar', |
||||
|
style=u'background-color:black; color:white;')]) |
||||
|
) |
||||
|
) |
@ -0,0 +1,46 @@ |
|||||
|
|
||||
|
CasaLegislativa: |
||||
|
Casa Legislativa: |
||||
|
- sigla:4 nome |
||||
|
- endereco:8 cep |
||||
|
- municipio:8 uf |
||||
|
- email |
||||
|
- telefone |
||||
|
- endereco_web |
||||
|
|
||||
|
Subsecretaria: |
||||
|
Subsecretaria: |
||||
|
- nome:8 sigla |
||||
|
|
||||
|
Usuario: |
||||
|
Usuário: |
||||
|
- username nome_completo:9 |
||||
|
- password password_confirm |
||||
|
- email email_confirm |
||||
|
- cpf rg casa_legislativa |
||||
|
- cargo vinculo |
||||
|
Primeiro Telefone: |
||||
|
- primeiro_tipo primeiro_ddd:2 primeiro_numero:6 primeiro_principal |
||||
|
Segundo Telefone: |
||||
|
- segundo_tipo segundo_ddd:2 segundo_numero:6 segundo_principal |
||||
|
Prove que você é um humano: |
||||
|
- captcha |
||||
|
|
||||
|
UsuarioEdit: |
||||
|
Usuário: |
||||
|
- username nome_completo:9 |
||||
|
- email email_confirm |
||||
|
- cpf rg casa_legislativa |
||||
|
- cargo vinculo |
||||
|
Primeiro Telefone: |
||||
|
- primeiro_tipo primeiro_ddd:2 primeiro_numero:6 primeiro_principal |
||||
|
Segundo Telefone: |
||||
|
- segundo_tipo segundo_ddd:2 segundo_numero:6 segundo_principal |
||||
|
Prove que você é um humano: |
||||
|
- captcha |
||||
|
|
||||
|
UsuarioDetail: |
||||
|
Perfil: |
||||
|
- nome_completo email |
||||
|
- cargo vinculo |
||||
|
- cpf rg casa_legislativa |
@ -0,0 +1,93 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Generated by Django 1.9.5 on 2016-06-16 16:34 |
||||
|
from __future__ import absolute_import |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
from django.conf import settings |
||||
|
from django.db import migrations, models |
||||
|
import django.db.models.deletion |
||||
|
import django.utils.timezone |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
initial = True |
||||
|
|
||||
|
dependencies = [ |
||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.CreateModel( |
||||
|
name=u'CasaLegislativa', |
||||
|
fields=[ |
||||
|
(u'id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name=u'ID')), |
||||
|
(u'nome', models.CharField(max_length=100, verbose_name=u'Nome')), |
||||
|
(u'sigla', models.CharField(max_length=100, verbose_name=u'Sigla')), |
||||
|
(u'endereco', models.CharField(max_length=100, verbose_name=u'Endereço')), |
||||
|
(u'cep', models.CharField(max_length=100, verbose_name=u'CEP')), |
||||
|
(u'municipio', models.CharField(max_length=100, verbose_name=u'Município')), |
||||
|
(u'uf', models.CharField(choices=[(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')], max_length=100, verbose_name=u'UF')), |
||||
|
(u'telefone', models.CharField(blank=True, max_length=100, verbose_name=u'Telefone')), |
||||
|
(u'endereco_web', models.URLField(blank=True, max_length=100, verbose_name=u'HomePage')), |
||||
|
(u'email', models.EmailField(blank=True, max_length=100, verbose_name=u'E-mail')), |
||||
|
], |
||||
|
options={ |
||||
|
u'verbose_name': u'Casa Legislativa', |
||||
|
u'verbose_name_plural': u'Casas Legislativas', |
||||
|
}, |
||||
|
), |
||||
|
migrations.CreateModel( |
||||
|
name=u'Subsecretaria', |
||||
|
fields=[ |
||||
|
(u'id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name=u'ID')), |
||||
|
(u'nome', models.CharField(max_length=100, null=True, verbose_name=u'Nome')), |
||||
|
(u'sigla', models.CharField(max_length=10, null=True, verbose_name=u'Sigla')), |
||||
|
], |
||||
|
options={ |
||||
|
u'verbose_name': u'Subsecretaria', |
||||
|
u'ordering': (u'nome', u'sigla'), |
||||
|
u'verbose_name_plural': u'Subsecretarias', |
||||
|
}, |
||||
|
), |
||||
|
migrations.CreateModel( |
||||
|
name=u'Telefone', |
||||
|
fields=[ |
||||
|
(u'id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name=u'ID')), |
||||
|
(u'tipo', models.CharField(choices=[(u'FIXO', u'FIXO'), (u'CELULAR', u'CELULAR')], max_length=7, verbose_name=u'Tipo Telefone')), |
||||
|
(u'ddd', models.CharField(max_length=2, verbose_name=u'DDD')), |
||||
|
(u'numero', models.CharField(max_length=10, verbose_name=u'Número')), |
||||
|
(u'principal', models.CharField(choices=[(None, u'----'), (False, u'Não'), (True, u'Sim')], max_length=10, verbose_name=u'Telefone Principal?')), |
||||
|
], |
||||
|
options={ |
||||
|
u'verbose_name': u'Telefone', |
||||
|
u'verbose_name_plural': u'Telefones', |
||||
|
}, |
||||
|
), |
||||
|
migrations.CreateModel( |
||||
|
name=u'Usuario', |
||||
|
fields=[ |
||||
|
(u'id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name=u'ID')), |
||||
|
(u'username', models.CharField(max_length=50, unique=True, verbose_name=u'Nome de Usuário')), |
||||
|
(u'nome_completo', models.CharField(max_length=128, verbose_name=u'Nome Completo')), |
||||
|
(u'data_criacao', models.DateTimeField(default=django.utils.timezone.now, verbose_name=u'Data Criação')), |
||||
|
(u'data_ultima_atualizacao', models.DateTimeField(default=django.utils.timezone.now, verbose_name=u'Última atualização')), |
||||
|
(u'email', models.EmailField(max_length=254, unique=True, verbose_name=u'Email')), |
||||
|
(u'habilitado', models.BooleanField(default=False, verbose_name=u'Habilitado?')), |
||||
|
(u'conveniado', models.BooleanField(default=False)), |
||||
|
(u'responsavel', models.BooleanField(default=False)), |
||||
|
(u'rg', models.CharField(max_length=9, null=True, verbose_name=u'RG')), |
||||
|
(u'cpf', models.CharField(default=u'00000000000', max_length=11, verbose_name=u'CPF')), |
||||
|
(u'cargo', models.CharField(default=u'--------', max_length=30, verbose_name=u'Cargo')), |
||||
|
(u'vinculo', models.CharField(choices=[(u'Tercerizado', u'Tercerizado'), (u'Efetivo', u'Efetivo'), (u'Contratado', u'Contratado')], default=u'--------', max_length=30, verbose_name=u'Vinculo')), |
||||
|
(u'casa_legislativa', models.CharField(default=u'--------', max_length=30, verbose_name=u'Casa Legislativa')), |
||||
|
(u'primeiro_telefone', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name=u'primeiro_telefone', to=u'usuarios.Telefone')), |
||||
|
(u'segundo_telefone', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name=u'segundo_telefone', to=u'usuarios.Telefone')), |
||||
|
(u'user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), |
||||
|
], |
||||
|
options={ |
||||
|
u'verbose_name': u'Usuário', |
||||
|
u'verbose_name_plural': u'Usuários', |
||||
|
}, |
||||
|
), |
||||
|
] |
@ -0,0 +1,35 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# Generated by Django 1.9.5 on 2016-06-16 17:00 |
||||
|
from __future__ import absolute_import |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
(u'usuarios', u'0001_initial'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.CreateModel( |
||||
|
name=u'ConfirmaEmail', |
||||
|
fields=[ |
||||
|
(u'id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name=u'ID')), |
||||
|
(u'email', models.EmailField(max_length=254, unique=True, verbose_name=u'Email')), |
||||
|
(u'confirmado', models.BooleanField(default=False)), |
||||
|
(u'token', models.CharField(max_length=50, verbose_name=u'Hash do Email')), |
||||
|
(u'user_id', models.TextField(blank=True, verbose_name=u'ID do Usuário')), |
||||
|
], |
||||
|
options={ |
||||
|
u'verbose_name': u'Email', |
||||
|
u'verbose_name_plural': u'Emails', |
||||
|
}, |
||||
|
), |
||||
|
migrations.AddField( |
||||
|
model_name=u'usuario', |
||||
|
name=u'email_confirmado', |
||||
|
field=models.BooleanField(default=False, verbose_name=u'Email confirmado?'), |
||||
|
), |
||||
|
] |
@ -0,0 +1,26 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
from django.db import models, migrations |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('usuarios', '0002_auto_20160616_1400'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterField( |
||||
|
model_name='confirmaemail', |
||||
|
name='email', |
||||
|
field=models.EmailField(unique=True, max_length=75, verbose_name='Email'), |
||||
|
preserve_default=True, |
||||
|
), |
||||
|
migrations.AlterField( |
||||
|
model_name='usuario', |
||||
|
name='email', |
||||
|
field=models.EmailField(unique=True, max_length=75, verbose_name='Email'), |
||||
|
preserve_default=True, |
||||
|
), |
||||
|
] |
@ -0,0 +1,148 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
from __future__ import absolute_import |
||||
|
import base64 |
||||
|
from django.contrib.auth.models import User |
||||
|
from django.db import models |
||||
|
from django.utils import timezone |
||||
|
from django.utils.translation import ugettext_lazy as _ |
||||
|
|
||||
|
from sigi.apps.crud.utils import UF, YES_NO_CHOICES |
||||
|
|
||||
|
|
||||
|
class CasaLegislativa(models.Model): |
||||
|
nome = models.CharField(max_length=100, verbose_name=_(u'Nome')) |
||||
|
sigla = models.CharField(max_length=100, verbose_name=_(u'Sigla')) |
||||
|
endereco = models.CharField(max_length=100, verbose_name=_(u'Endereço')) |
||||
|
cep = models.CharField(max_length=100, verbose_name=_(u'CEP')) |
||||
|
municipio = models.CharField(max_length=100, verbose_name=_(u'Município')) |
||||
|
uf = models.CharField(max_length=100, |
||||
|
choices=UF, |
||||
|
verbose_name=_(u'UF')) |
||||
|
telefone = models.CharField( |
||||
|
max_length=100, blank=True, verbose_name=_(u'Telefone')) |
||||
|
endereco_web = models.URLField( |
||||
|
max_length=100, blank=True, verbose_name=_(u'HomePage')) |
||||
|
email = models.EmailField( |
||||
|
max_length=100, blank=True, verbose_name=_(u'E-mail')) |
||||
|
|
||||
|
class Meta(object): |
||||
|
verbose_name = _(u'Casa Legislativa') |
||||
|
verbose_name_plural = _(u'Casas Legislativas') |
||||
|
|
||||
|
def __str__(self): |
||||
|
return u'[%s] %s' % (self.sigla, self.nome) |
||||
|
|
||||
|
|
||||
|
class Subsecretaria(models.Model): |
||||
|
|
||||
|
nome = models.CharField(verbose_name=_(u'Nome'), max_length=100, null=True) |
||||
|
sigla = models.CharField(verbose_name=_(u'Sigla'), max_length=10, null=True) |
||||
|
|
||||
|
class Meta(object): |
||||
|
ordering = (u'nome', u'sigla') |
||||
|
verbose_name = _(u'Subsecretaria') |
||||
|
verbose_name_plural = _(u'Subsecretarias') |
||||
|
|
||||
|
def __str__(self): |
||||
|
return u'[%s] %s' % (self.sigla, self.nome) |
||||
|
|
||||
|
|
||||
|
class Telefone(models.Model): |
||||
|
TIPO_TELEFONE = [(u'FIXO', u'FIXO'), (u'CELULAR', u'CELULAR')] |
||||
|
|
||||
|
tipo = models.CharField( |
||||
|
max_length=7, |
||||
|
choices=TIPO_TELEFONE, |
||||
|
verbose_name=_(u'Tipo Telefone'),) |
||||
|
ddd = models.CharField(max_length=2, verbose_name=_(u'DDD')) |
||||
|
numero = models.CharField(max_length=10, verbose_name=_(u'Número')) |
||||
|
principal = models.CharField( |
||||
|
max_length=10, |
||||
|
verbose_name=_(u'Telefone Principal?'), |
||||
|
choices=YES_NO_CHOICES) |
||||
|
|
||||
|
class Meta(object): |
||||
|
verbose_name = _(u'Telefone') |
||||
|
verbose_name_plural = _(u'Telefones') |
||||
|
|
||||
|
def __str__(self): |
||||
|
return u'(%s) %s' % (self.ddd, self.numero) |
||||
|
|
||||
|
|
||||
|
class ConfirmaEmail(models.Model): |
||||
|
u""" |
||||
|
Classe de email |
||||
|
""" |
||||
|
email = models.EmailField(unique=True, verbose_name=_(u'Email')) |
||||
|
confirmado = models.BooleanField(default=False) |
||||
|
token = models.CharField( |
||||
|
max_length=50, verbose_name=_(u'Hash do Email')) |
||||
|
user_id = models.TextField(blank=True, verbose_name=_(u'ID do Usuário')) |
||||
|
|
||||
|
class Meta(object): |
||||
|
verbose_name = _(u'Email') |
||||
|
verbose_name_plural = _(u'Emails') |
||||
|
|
||||
|
|
||||
|
class Usuario(models.Model): |
||||
|
u''' |
||||
|
Usuário cadastrado via web |
||||
|
''' |
||||
|
|
||||
|
TIPO_VINCULO = [(u'Tercerizado', u'Tercerizado'), |
||||
|
(u'Efetivo', u'Efetivo'), |
||||
|
(u'Contratado', u'Contratado')] |
||||
|
|
||||
|
user = models.ForeignKey(User) |
||||
|
username = models.CharField( |
||||
|
verbose_name=_(u'Nome de Usuário'), |
||||
|
unique=True, |
||||
|
max_length=50) |
||||
|
nome_completo = models.CharField( |
||||
|
verbose_name=_(u'Nome Completo'), |
||||
|
max_length=128) |
||||
|
data_criacao = models.DateTimeField( |
||||
|
_(u'Data Criação'), |
||||
|
default=timezone.now) |
||||
|
data_ultima_atualizacao = models.DateTimeField( |
||||
|
default=timezone.now, verbose_name=_(u'Última atualização')) |
||||
|
email = email = models.EmailField(unique=True, verbose_name=_(u'Email')) |
||||
|
email_confirmado = models.BooleanField( |
||||
|
default=False, verbose_name=_(u'Email confirmado?')) |
||||
|
habilitado = models.BooleanField( |
||||
|
default=False, |
||||
|
verbose_name=_(u'Habilitado?')) |
||||
|
conveniado = models.BooleanField(default=False) |
||||
|
responsavel = models.BooleanField(default=False) |
||||
|
rg = models.CharField( |
||||
|
max_length=9, |
||||
|
null=True, |
||||
|
verbose_name=_(u'RG')) |
||||
|
cpf = models.CharField( |
||||
|
max_length=11, |
||||
|
verbose_name=_(u'CPF'), |
||||
|
default=u'00000000000') |
||||
|
cargo = models.CharField( |
||||
|
max_length=30, |
||||
|
verbose_name=_(u'Cargo'), |
||||
|
default=u'--------') |
||||
|
vinculo = models.CharField( |
||||
|
max_length=30, |
||||
|
verbose_name=_(u'Vinculo'), |
||||
|
choices=TIPO_VINCULO, |
||||
|
default=u'--------') |
||||
|
casa_legislativa = models.CharField( |
||||
|
max_length=30, |
||||
|
verbose_name=_(u'Casa Legislativa'), |
||||
|
default=u'--------') |
||||
|
primeiro_telefone = models.ForeignKey( |
||||
|
Telefone, null=True, related_name=u'primeiro_telefone') |
||||
|
segundo_telefone = models.ForeignKey( |
||||
|
Telefone, null=True, related_name=u'segundo_telefone') |
||||
|
|
||||
|
class Meta(object): |
||||
|
verbose_name = _(u'Usuário') |
||||
|
verbose_name_plural = _(u'Usuários') |
||||
|
|
||||
|
def __str__(self): |
||||
|
return self.username |
@ -0,0 +1,3 @@ |
|||||
|
# from django.test import TestCase |
||||
|
|
||||
|
# Create your tests here. |
@ -0,0 +1,61 @@ |
|||||
|
from __future__ import absolute_import |
||||
|
from django.conf.urls import include, url |
||||
|
from django.contrib.auth.views import (login, logout, password_reset, |
||||
|
password_reset_done, |
||||
|
password_reset_confirm, |
||||
|
password_reset_complete) |
||||
|
#from atendimento.settings import EMAIL_SEND_USER |
||||
|
from sigi.apps.usuarios.forms import (LoginForm, RecuperarSenhaEmailForm, |
||||
|
RecuperacaoMudarSenhaForm) |
||||
|
from sigi.apps.usuarios.views import (HabilitarDetailView, HabilitarEditView, |
||||
|
MudarSenhaView, UsuarioCrud, ConfirmarEmailView) |
||||
|
|
||||
|
from .apps import AppConfig |
||||
|
|
||||
|
app_name = AppConfig.name |
||||
|
|
||||
|
EMAIL_SEND_USER='atendimento@interlegis.leg.br' |
||||
|
|
||||
|
recuperar_email = [ |
||||
|
url(ur'^recuperar/recuperar_senha/$', |
||||
|
password_reset, |
||||
|
{u'template_name': u'usuarios/recuperar_senha.html', |
||||
|
u'password_reset_form': RecuperarSenhaEmailForm, |
||||
|
u'post_reset_redirect': u'usuarios:recuperar_senha_finalizado', |
||||
|
u'email_template_name': u'usuarios/recuperar_senha_email.html', |
||||
|
u'from_email': EMAIL_SEND_USER, |
||||
|
u'html_email_template_name': u'usuarios/recuperar_senha_email.html'}, |
||||
|
name=u'recuperar_senha'), |
||||
|
url(ur'^recuperar/recuperar_recuperar/finalizado/$', |
||||
|
password_reset_done, |
||||
|
{u'template_name': u'usuarios/recuperar_senha_enviado.html'}, |
||||
|
name=u'recuperar_senha_finalizado'), |
||||
|
url(ur'^recuperar/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$', |
||||
|
password_reset_confirm, |
||||
|
{u'post_reset_redirect': u'usuarios:recuperar_senha_completo', |
||||
|
u'template_name': u'usuarios/recuperacao_senha_form.html', |
||||
|
u'set_password_form': RecuperacaoMudarSenhaForm}, |
||||
|
name=u'recuperar_senha_confirma'), |
||||
|
url(ur'^recuperar/completo/$', |
||||
|
password_reset_complete, |
||||
|
{u'template_name': u'usuarios/recuperacao_senha_completo.html'}, |
||||
|
name=u'recuperar_senha_completo'), |
||||
|
] |
||||
|
|
||||
|
urlpatterns = recuperar_email + [ |
||||
|
url(ur'^login/$', login, { |
||||
|
u'template_name': u'usuarios/login.html', |
||||
|
u'authentication_form': LoginForm}, |
||||
|
name=u'login'), |
||||
|
url(ur'^logout/$', logout, {u'next_page': u'/login'}, name=u'logout'), |
||||
|
url(ur'^usuario/', include(UsuarioCrud.get_urls())), |
||||
|
|
||||
|
url(ur'^habilitar/(?P<pk>\d+)$', |
||||
|
HabilitarDetailView.as_view(), name=u'habilitar_detail'), |
||||
|
url(ur'^habilitar/(?P<pk>\d+)/edit$', |
||||
|
HabilitarEditView.as_view(), name=u'habilitar_edit'), |
||||
|
url(ur'^usuario/(?P<pk>\d+)/mudar_senha$', |
||||
|
MudarSenhaView.as_view(), name=u'mudar_senha'), |
||||
|
url(ur'^usuario/confirmar/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})$', |
||||
|
ConfirmarEmailView.as_view(), name=u'confirmar_email'), |
||||
|
] |
@ -0,0 +1,65 @@ |
|||||
|
# -*- 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,183 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
from __future__ import absolute_import |
||||
|
from braces.views import FormValidMessageMixin |
||||
|
from django.conf import settings |
||||
|
from django.contrib.auth.mixins import LoginRequiredMixin |
||||
|
from django.core.urlresolvers import reverse |
||||
|
from django.utils import timezone |
||||
|
from django.views.generic import DetailView, FormView, TemplateView |
||||
|
import sigi.apps.crud.base |
||||
|
from django.core.mail import send_mail |
||||
|
from sigi.apps.crud.utils import str2bool |
||||
|
from django.contrib.auth.tokens import default_token_generator |
||||
|
from django.utils.http import urlsafe_base64_encode, urlsafe_base64_decode |
||||
|
from django.utils.encoding import force_bytes |
||||
|
from sigi.apps.crud.base import Crud, CrudBaseMixin, CrudCreateView, CrudListView, CrudUpdateView, CrudDetailView |
||||
|
|
||||
|
from .forms import (HabilitarEditForm, MudarSenhaForm, UsuarioEditForm, |
||||
|
UsuarioForm) |
||||
|
from .models import Usuario, ConfirmaEmail, User |
||||
|
|
||||
|
|
||||
|
class UsuarioCrud(Crud): |
||||
|
model = Usuario |
||||
|
help_path = u'' |
||||
|
|
||||
|
class CreateView(CrudCreateView): |
||||
|
form_class = UsuarioForm |
||||
|
form_valid_message = u'Cadastro realizado com sucesso. Aguarde a \ |
||||
|
validação do seu perfil.' |
||||
|
|
||||
|
def get_success_url(self): |
||||
|
kwargs = {} |
||||
|
user = User.objects.get(email=self.request.POST.get(u'email')) |
||||
|
confirmar_email = ConfirmaEmail( |
||||
|
email=user.email, |
||||
|
token=default_token_generator.make_token(user), |
||||
|
user_id=urlsafe_base64_encode(force_bytes(user.pk))) |
||||
|
confirmar_email.save() |
||||
|
|
||||
|
kwargs[u'token'] = confirmar_email.token |
||||
|
kwargs[u'uidb64'] = confirmar_email.user_id |
||||
|
assunto = u"Cadastro no Sistema de Atendimento ao Usuário" |
||||
|
full_url = self.request.get_raw_uri(), |
||||
|
url_base = full_url[0][:full_url[0].find(u'usuario') - 1], |
||||
|
mensagem = (u"Este e-mail foi utilizado para fazer cadastro no " + |
||||
|
u"Sistema de Atendimento ao Usuário do Interlegis.\n" + |
||||
|
u"Caso você não tenha feito este cadastro, por favor " + |
||||
|
u"ignore esta mensagem.\n" + url_base[0] + |
||||
|
reverse(u'usuarios:confirmar_email', kwargs=kwargs)) |
||||
|
remetente = settings.EMAIL_HOST_USER |
||||
|
destinatario = [confirmar_email.email, |
||||
|
settings.EMAIL_HOST_USER] |
||||
|
send_mail(assunto, mensagem, remetente, destinatario, |
||||
|
fail_silently=False) |
||||
|
return reverse(u'home') |
||||
|
|
||||
|
class ListView(LoginRequiredMixin, CrudListView): |
||||
|
pass |
||||
|
|
||||
|
class UpdateView(LoginRequiredMixin, CrudUpdateView): |
||||
|
form_class = UsuarioEditForm |
||||
|
|
||||
|
def get_initial(self): |
||||
|
if self.get_object(): |
||||
|
|
||||
|
tel1 = self.get_object().primeiro_telefone |
||||
|
self.initial[u'primeiro_tipo'] = tel1.tipo |
||||
|
self.initial[u'primeiro_ddd'] = tel1.ddd |
||||
|
self.initial[u'primeiro_numero'] = tel1.numero |
||||
|
self.initial[u'primeiro_principal'] = tel1.principal |
||||
|
|
||||
|
tel2 = self.get_object().segundo_telefone |
||||
|
if tel2: |
||||
|
self.initial[u'segundo_tipo'] = tel2.tipo |
||||
|
self.initial[u'segundo_ddd'] = tel2.ddd |
||||
|
self.initial[u'segundo_numero'] = tel2.numero |
||||
|
self.initial[u'segundo_principal'] = tel2.principal |
||||
|
|
||||
|
return self.initial.copy() |
||||
|
|
||||
|
@property |
||||
|
def layout_key(self): |
||||
|
return u'UsuarioEdit' |
||||
|
|
||||
|
class DetailView(LoginRequiredMixin, CrudDetailView): |
||||
|
|
||||
|
def get_context_data(self, **kwargs): |
||||
|
context = super(DetailView, self).get_context_data(**kwargs) |
||||
|
|
||||
|
tel1 = context[u'object'].primeiro_telefone |
||||
|
tel1 = [(u'Primeiro Telefone'), |
||||
|
(u'[%s] - %s' % (tel1.ddd, tel1.numero))] |
||||
|
|
||||
|
tel2 = context[u'object'].segundo_telefone or u'' |
||||
|
if tel2: |
||||
|
tel2 = [(u'Segundo Telefone'), |
||||
|
(u'[%s] - %s' % (tel2.ddd, tel2.numero))] |
||||
|
|
||||
|
context[u'telefones'] = [tel1, tel2] |
||||
|
return context |
||||
|
|
||||
|
@property |
||||
|
def layout_key(self): |
||||
|
return u'UsuarioDetail' |
||||
|
|
||||
|
class BaseMixin(CrudBaseMixin): |
||||
|
list_field_names = [u'username', u'nome_completo', |
||||
|
u'data_criacao', u'habilitado', |
||||
|
u'data_ultima_atualizacao'] |
||||
|
|
||||
|
|
||||
|
class HabilitarDetailView(CrudDetailView): |
||||
|
template_name = u"usuarios/habilitar_detail.html" |
||||
|
|
||||
|
def get(self, request, *args, **kwargs): |
||||
|
context = {} |
||||
|
context[u'pk'] = self.kwargs[u'pk'] |
||||
|
context[u'usuario'] = Usuario.objects.get(pk=self.kwargs[u'pk']) |
||||
|
return self.render_to_response(context) |
||||
|
|
||||
|
|
||||
|
class HabilitarEditView(FormView): |
||||
|
template_name = u"crud/form.html" |
||||
|
|
||||
|
def get(self, request, *args, **kwargs): |
||||
|
context = {} |
||||
|
|
||||
|
usuario = Usuario.objects.get(pk=self.kwargs[u'pk']) |
||||
|
form = HabilitarEditForm(instance=usuario) |
||||
|
|
||||
|
context[u'pk'] = self.kwargs[u'pk'] |
||||
|
context[u'form'] = form |
||||
|
return self.render_to_response(context) |
||||
|
|
||||
|
def post(self, request, *args, **kwargs): |
||||
|
form = HabilitarEditForm(request.POST) |
||||
|
usuario = Usuario.objects.get(pk=self.kwargs[u'pk']) |
||||
|
usuario.habilitado = str2bool(form.data[u'habilitado']) |
||||
|
usuario.data_ultima_atualizacao = timezone.now() |
||||
|
|
||||
|
usuario.save() |
||||
|
return self.form_valid(form) |
||||
|
|
||||
|
def get_success_url(self): |
||||
|
return reverse(u'usuarios:usuario_list') |
||||
|
|
||||
|
|
||||
|
class MudarSenhaView(FormValidMessageMixin, FormView): |
||||
|
template_name = u"crud/form.html" |
||||
|
form_class = MudarSenhaForm |
||||
|
form_valid_message = u'Senha alterada com sucesso. É necessário fazer \ |
||||
|
login novamente.' |
||||
|
|
||||
|
def get(self, request, *args, **kwargs): |
||||
|
context = {} |
||||
|
usuario = Usuario.objects.get(pk=self.kwargs[u'pk']) |
||||
|
form = MudarSenhaForm(instance=usuario) |
||||
|
context[u'pk'] = self.kwargs[u'pk'] |
||||
|
context[u'form'] = self.get_form() |
||||
|
return self.render_to_response(context) |
||||
|
|
||||
|
def form_valid(self, form): |
||||
|
usuario = Usuario.objects.get(pk=self.kwargs[u'pk']) |
||||
|
u = usuario.user |
||||
|
u.set_password(form.cleaned_data[u'password']) |
||||
|
u.save() |
||||
|
return super(MudarSenhaView, self).form_valid(form) |
||||
|
|
||||
|
def get_success_url(self): |
||||
|
return reverse(u'home') |
||||
|
|
||||
|
|
||||
|
class ConfirmarEmailView(TemplateView): |
||||
|
template_name = u"usuarios/confirma_email.html" |
||||
|
|
||||
|
def get(self, request, *args, **kwargs): |
||||
|
uid = urlsafe_base64_decode(self.kwargs[u'uidb64']) |
||||
|
user = User.objects.get(id=uid) |
||||
|
user.is_active = True |
||||
|
user.save() |
||||
|
context = self.get_context_data(**kwargs) |
||||
|
return self.render_to_response(context) |
@ -0,0 +1,155 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
{% load staticfiles i18n sass_tags%} |
||||
|
<html class="no-js" lang="pt-br"> |
||||
|
|
||||
|
<head> |
||||
|
<meta charset="utf-8" name="viewport" content="width=device-width, initial-scale=1.0"> |
||||
|
<title>Sistema de Atendimento</title> |
||||
|
{% block head_content %} |
||||
|
<link rel="icon" href="{% static 'img/favicon.ico' %}" type="image/png" > |
||||
|
<!-- Bootstrap --> |
||||
|
<link href="{% static 'css/bootstrap-fluid-adj.css' %}" rel="stylesheet"> |
||||
|
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet" media="screen"> |
||||
|
<link href="{% static 'css/bootstrap-responsive.css' %}" rel="stylesheet"> |
||||
|
<link href="{% sass_src 'bootstrap-sass/assets/stylesheets/_bootstrap.scss' %}" rel="stylesheet"> |
||||
|
{% endblock head_content %} |
||||
|
</head> |
||||
|
|
||||
|
{% block navigation %} |
||||
|
<div class="navbar navbar-inverse navbar-fixed-top"> |
||||
|
<div class="navbar-inner"> |
||||
|
<div class="container"> |
||||
|
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"> |
||||
|
<span class="icon-bar"></span> |
||||
|
<span class="icon-bar"></span> |
||||
|
<span class="icon-bar"></span> |
||||
|
</button> |
||||
|
|
||||
|
<div class="nav-collapse collapse"> |
||||
|
<ul class="nav pull-right"> |
||||
|
{% if user.is_authenticated %} |
||||
|
<li class="dropdown"> |
||||
|
<a href="" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{{ user.username }}<span class="caret"></span></a> |
||||
|
<ul class="dropdown-menu"> |
||||
|
<li class="nav__sub-item"><a class="nav__sub-link" href="{% url 'usuarios:usuario_detail' usuario_pk %}">Perfil</a></li> |
||||
|
<li class="nav__sub-item"><a class="nav__sub-link" href="{% url 'usuarios:mudar_senha' usuario_pk %}">Mudar Senha</a></li> |
||||
|
</ul> |
||||
|
</li> |
||||
|
<li><a href="{% url 'usuarios:logout' %}">Sair</a></li> |
||||
|
{% else %} |
||||
|
<li><a href="{% url 'usuarios:usuario_create' %}">Cadastre-se</a></li> |
||||
|
<li><a href="{% url 'usuarios:login' %}">Login</a></li> |
||||
|
{% endif %} |
||||
|
</ul> |
||||
|
<ul class="nav"> |
||||
|
{% if user.is_authenticated %} |
||||
|
<li><a href="{% url 'solicitacoes:solicitacao_list' %}">Solicitação</a></li> |
||||
|
<li><a href="{% url 'solicitacoes:sistema_list' %}">Sistema</a></li> |
||||
|
<li><a href="{% url 'usuarios:usuario_list' %}">Habilitar</a></li> |
||||
|
{% endif %} |
||||
|
<li><a href="">Contato</a></li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
{% endblock navigation %} |
||||
|
|
||||
|
<body> |
||||
|
{% block body_block %} |
||||
|
{# Header #} |
||||
|
{% block main_header %} |
||||
|
<div class="jumbotron"> |
||||
|
<header class="masthead"> |
||||
|
<div class="container"> |
||||
|
<div class="navbar-header"> |
||||
|
<a href="/"> |
||||
|
<img align="left" height="120" width="120" src="{% static 'img/logo.png' %}" alt="Logo" class="img-responsive visible-lg-inline-block vcenter" > |
||||
|
<span class="vcenter" style="display:inline-block; color:black;" align="right"> |
||||
|
<h2>Interlegis</h4><small><p>Sistema de Solicitação de Serviços</p></small> |
||||
|
</span> |
||||
|
</a> |
||||
|
</div> |
||||
|
</div> |
||||
|
</header> |
||||
|
</div> |
||||
|
{% endblock main_header %} |
||||
|
|
||||
|
{# Main content #} |
||||
|
{% block content_container %} |
||||
|
<main id="content" class="content page__row"> |
||||
|
<div class="container"> |
||||
|
{# Feedback messages #} |
||||
|
{% for message in messages %} |
||||
|
<div class="alert alert-{% if message.tags == 'error' %}danger{% else %}{{ message.tags }}{% endif %} alert-dismissible fade in" role="alert"> |
||||
|
<button type="button" class="close" data-dismiss="alert" aria-label="Close"> |
||||
|
<span class="glyphicon glyphicon-remove" aria-hidden="true"></span> |
||||
|
</button> |
||||
|
{{ message|safe }} |
||||
|
</div> |
||||
|
{% endfor %} |
||||
|
|
||||
|
{# Content header #} |
||||
|
{% block base_header %} |
||||
|
<div class="clearfix"> |
||||
|
<div class="clearfix"> |
||||
|
{% block title %} |
||||
|
<h1 class="page-header"> |
||||
|
{% if title %} |
||||
|
{{ title|safe|linebreaksbr }} |
||||
|
{% elif object %} |
||||
|
{{ object|safe|linebreaksbr }} |
||||
|
{% endif %} |
||||
|
</h1> |
||||
|
{% endblock %} |
||||
|
</div> |
||||
|
</div> |
||||
|
{% endblock base_header %} |
||||
|
|
||||
|
{# Content per se #} |
||||
|
{% block base_content %}{% endblock %} |
||||
|
</div> |
||||
|
</main> |
||||
|
{% endblock content_container %} |
||||
|
{% endblock %} |
||||
|
{% block foot_js %} |
||||
|
<script src="{% static 'jquery/dist/jquery.min.js' %}"></script> |
||||
|
<script src="{% static 'jquery-ui/jquery-ui.min.js' %}"></script> |
||||
|
<script src="{% static 'jquery-mask-plugin/dist/jquery.mask.js' %}"></script> |
||||
|
|
||||
|
<script src="{% static 'js/bootstrap.min.js' %}"></script> |
||||
|
<script src="{% static 'js/app.js' %}"></script> |
||||
|
{% block extra_js %}{% endblock extra_js %} |
||||
|
{% endblock foot_js %} |
||||
|
</body> |
||||
|
|
||||
|
{% block footer %} |
||||
|
<hr> |
||||
|
<footer id="footer" class="footer page__row"> |
||||
|
<div class="container"> |
||||
|
<div class="row"> |
||||
|
<div style="float:left"> |
||||
|
<a class="footer__logo" href="#"> |
||||
|
<img src="{% static 'img/logo_interlegis.jpg' %}" alt="{% trans 'Logo do Interlegis' %} "> |
||||
|
</a> |
||||
|
<p> |
||||
|
<small> |
||||
|
Desenvolvido pelo <a href="">Interlegis</a> em software livre e aberto. |
||||
|
</small> |
||||
|
</p> |
||||
|
</div> |
||||
|
<div style="float:right"> |
||||
|
<a class="footer__logo" href=""> |
||||
|
<img src="{% static 'img/logo_cc.jpg' %}" alt="{% trans 'Logo do Creative Commons BY SA' %}"> |
||||
|
</a> |
||||
|
<p> |
||||
|
<small> |
||||
|
Conteúdo e dados sob licença <a href="#">Creative Commons</a> 4.0 <a href="#">Atribuir Fonte - Compartilhar Igual</a> |
||||
|
</small> |
||||
|
</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</footer> |
||||
|
{% endblock footer %} |
||||
|
</html> |
@ -0,0 +1,18 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
{% load i18n %} |
||||
|
|
||||
|
{% block base_content %} |
||||
|
<form action="" method="post">{% csrf_token %} |
||||
|
<div class="panel panel-danger"> |
||||
|
<div class="panel-heading text-center"> |
||||
|
{% blocktrans %} |
||||
|
Confirma exclusão de "{{ object }}"? |
||||
|
{% endblocktrans %} |
||||
|
</div> |
||||
|
<div class="panel-body text-center"> |
||||
|
<a href="{{ view.cancel_url }}" class="btn btn-inverse">{% trans 'Cancelar' %}</a> |
||||
|
<input name="submit" value="{% trans 'Confirmar' %}" class="btn btn-danger" type="submit"></li> |
||||
|
</div> |
||||
|
</div> |
||||
|
</form> |
||||
|
{% endblock %} |
@ -0,0 +1,38 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
{% load i18n %} |
||||
|
|
||||
|
{% block base_content %} |
||||
|
<div class="clearfix"> |
||||
|
{% block actions %} |
||||
|
<div class="actions btn-group pull-right" role="group"> |
||||
|
<a href="{{ view.update_url }}" class="btn btn-default">{% trans 'Editar' %}</a> |
||||
|
<a href="{{ view.delete_url }}" class="btn btn-default">{% trans 'Excluir' %}</a> |
||||
|
</div> |
||||
|
{% endblock actions %} |
||||
|
</div> |
||||
|
|
||||
|
{% block msg %} {% endblock msg %} |
||||
|
|
||||
|
{% block detail_content %} |
||||
|
{% for fieldset in view.layout_display %} |
||||
|
<h2 class="legend">{{ fieldset.legend }}</h2> |
||||
|
{% for row in fieldset.rows %} |
||||
|
<div class="row-fluid"> |
||||
|
{% for column in row %} |
||||
|
<div class="col-sm-{{ column.span }}"> |
||||
|
<div id="div_id_{{ column.id }}" class="form-group"> |
||||
|
<p class="control-label">{{ column.verbose_name }}</p> |
||||
|
<div class="controls"> |
||||
|
<p class="form-control-static">{{ column.text|safe }}</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
{% endfor %} |
||||
|
</div> |
||||
|
{% endfor %} |
||||
|
{% endfor %} |
||||
|
{% endblock detail_content %} |
||||
|
|
||||
|
{% block extrablock %}{% endblock %} |
||||
|
|
||||
|
{% endblock base_content %} |
@ -0,0 +1,15 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
{% load i18n crispy_forms_tags %} |
||||
|
{% block base_content %} |
||||
|
{% crispy form %} |
||||
|
{% endblock %} |
||||
|
|
||||
|
{% block extra_js %} |
||||
|
<script type="text/javascript"> |
||||
|
$(document).ready(function (){ |
||||
|
$('#id_captcha_1').keyup(function(){ |
||||
|
this.value = this.value.toUpperCase(); |
||||
|
}); |
||||
|
}); |
||||
|
</script> |
||||
|
{% endblock %} |
@ -0,0 +1,51 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
{% load i18n %} |
||||
|
|
||||
|
{% block base_content %} |
||||
|
|
||||
|
{% block buttons %} |
||||
|
<div class="actions btn-group pull-right" role="group"> |
||||
|
<a href="{{ view.create_url }}" class="btn btn-default"> |
||||
|
{% blocktrans with verbose_name=view.verbose_name %} Adicionar {{ verbose_name }} {% endblocktrans %} |
||||
|
</a> |
||||
|
{% block more_buttons %}{% endblock more_buttons %} |
||||
|
</div> |
||||
|
{% endblock buttons %} |
||||
|
|
||||
|
|
||||
|
{% block content %} |
||||
|
|
||||
|
{% block extra_content %} {% endblock extra_content %} |
||||
|
|
||||
|
{% if not rows %} |
||||
|
<p>{{ NO_ENTRIES_MSG }}</p> |
||||
|
{% else %} |
||||
|
<table class="table table-striped table-hover"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
{% for name in headers %} |
||||
|
<th>{{ name }}</th> |
||||
|
{% endfor %} |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
{% for value_list in rows %} |
||||
|
<tr> |
||||
|
{% for value, href in value_list %} |
||||
|
<td> |
||||
|
{% if href %} |
||||
|
<a href="{{ href }}">{{ value }}</a> |
||||
|
{% else %} |
||||
|
{{ value|safe }} |
||||
|
{% endif %} |
||||
|
</td> |
||||
|
{% endfor %} |
||||
|
</tr> |
||||
|
{% endfor %} |
||||
|
</tbody> |
||||
|
</table> |
||||
|
{% endif %} |
||||
|
|
||||
|
{% include "paginacao.html" %} |
||||
|
{% endblock content %} |
||||
|
{% endblock %} |
@ -0,0 +1,23 @@ |
|||||
|
{% load i18n %} |
||||
|
|
||||
|
{% if menu %} |
||||
|
<ul class="nav nav-pills navbar-right"> |
||||
|
|
||||
|
{% for item in menu %} |
||||
|
{% if item.children %} |
||||
|
<li class="dropdown"> |
||||
|
<a class="dropdown-toggle" data-toggle="dropdown" href="#fakeLink"> |
||||
|
{% trans item.title %} |
||||
|
<span class="fa-chevron-down fa"></span> |
||||
|
</a> |
||||
|
<ul class="dropdown-menu" role="menu">{% for subitem in item.children %} |
||||
|
<li><a href="{{ subitem.url }}">{% trans subitem.title %}</a></li>{% endfor %} |
||||
|
</ul> |
||||
|
</li> |
||||
|
{% else %} |
||||
|
<li><a href="{{ item.url }}">{% trans item.title %}</a></li> |
||||
|
{% endif %} |
||||
|
{% endfor %} |
||||
|
|
||||
|
</ul> |
||||
|
{% endif %} |
@ -0,0 +1,37 @@ |
|||||
|
{% if is_paginated %} |
||||
|
<nav class="text-center"> |
||||
|
<ul class="pagination"> |
||||
|
{% if page_obj.has_previous %} |
||||
|
<li class="page-item"> |
||||
|
<a class="page-link" href="?page={{ page_obj.previous_page_number }}{{filter_url}}"> |
||||
|
<span class="pager-prev">Anterior</span> |
||||
|
</a> |
||||
|
</li> |
||||
|
{% else %} |
||||
|
<li class="pager-prev disabled"><a href="">Anterior</a></li> |
||||
|
{% endif %} |
||||
|
|
||||
|
{% for page in page_range %} |
||||
|
{% if page == None or page == 'None' %} |
||||
|
<li class="page-item disabled"> |
||||
|
<a class="page-link" href="">...</a> |
||||
|
</li> |
||||
|
{% else %} |
||||
|
<li {% if page == page_obj.number %} class="page-item active" {% endif %}> |
||||
|
<a class="page-link" href="?page={{ page }}{{filter_url}}">{{ page }}</a> |
||||
|
</li> |
||||
|
{% endif %} |
||||
|
{% endfor %} |
||||
|
|
||||
|
{% if page_obj.has_next %} |
||||
|
<li class="page-item"> |
||||
|
<a class="page-link" href="?page={{ page_obj.next_page_number }}{{filter_url}}"> |
||||
|
<span class="pager-next">Próxima</span> |
||||
|
</a> |
||||
|
</li> |
||||
|
{% else %} |
||||
|
<li class="pager-next disabled"><a href="">Próxima</a></li> |
||||
|
{% endif %} |
||||
|
</ul> |
||||
|
</nav> |
||||
|
{% endif %} |
@ -0,0 +1,38 @@ |
|||||
|
from compressor.utils import get_class |
||||
|
from django import template |
||||
|
|
||||
|
register = template.Library() |
||||
|
|
||||
|
|
||||
|
@register.simple_tag |
||||
|
def field_verbose_name(instance, field_name): |
||||
|
return instance._meta.get_field(field_name).verbose_name |
||||
|
|
||||
|
|
||||
|
@register.simple_tag |
||||
|
def fieldclass_verbose_name(class_name, field_name): |
||||
|
cls = get_class(class_name) |
||||
|
return cls._meta.get_field(field_name).verbose_name |
||||
|
|
||||
|
|
||||
|
@register.simple_tag |
||||
|
def model_verbose_name(class_name): |
||||
|
model = get_class(class_name) |
||||
|
return model._meta.verbose_name |
||||
|
|
||||
|
|
||||
|
@register.simple_tag |
||||
|
def model_verbose_name_plural(class_name): |
||||
|
model = get_class(class_name) |
||||
|
return model._meta.verbose_name_plural |
||||
|
|
||||
|
|
||||
|
@register.filter |
||||
|
def lookup(d, key): |
||||
|
return d[key] if key in d else [] |
||||
|
|
||||
|
|
||||
|
@register.filter |
||||
|
def isinst(value, class_str): |
||||
|
classe = value.__class__.__name__ |
||||
|
return classe == class_str |
@ -0,0 +1,51 @@ |
|||||
|
import os |
||||
|
|
||||
|
import yaml |
||||
|
from django import template |
||||
|
from django.core.urlresolvers import reverse |
||||
|
|
||||
|
from sapl.settings import BASE_DIR |
||||
|
|
||||
|
register = template.Library() |
||||
|
TEMPLATES_DIR = BASE_DIR.child("templates") |
||||
|
|
||||
|
|
||||
|
@register.inclusion_tag('menus/subnav.html', takes_context=True) |
||||
|
def subnav(context, path=None): |
||||
|
"""Renders a subnavigation for views of a certain object. |
||||
|
|
||||
|
If not provided, path defaults to <app_name>/subnav.yaml |
||||
|
""" |
||||
|
# TODO: 118n !!!!!!!!!!!!!! |
||||
|
# How to internationalize yaml files???? |
||||
|
menu = None |
||||
|
root_pk = context.get('root_pk', None) |
||||
|
if not root_pk: |
||||
|
obj = context.get('object', None) |
||||
|
if obj: |
||||
|
root_pk = obj.pk |
||||
|
if root_pk: |
||||
|
request = context['request'] |
||||
|
app = request.resolver_match.app_name |
||||
|
# Esse IF elimina o bug do subnav em Tabelas Auxiliares |
||||
|
# e também em proposições |
||||
|
if request.path.find(app) == -1: |
||||
|
return |
||||
|
default_path = '%s/subnav.yaml' % app |
||||
|
path = os.path.join(TEMPLATES_DIR, path or default_path) |
||||
|
if os.path.exists(path): |
||||
|
menu = yaml.load(open(path, 'r')) |
||||
|
resolve_urls_inplace(menu, root_pk, app) |
||||
|
return {'menu': menu} |
||||
|
|
||||
|
|
||||
|
def resolve_urls_inplace(menu, pk, app): |
||||
|
if isinstance(menu, list): |
||||
|
for item in menu: |
||||
|
resolve_urls_inplace(item, pk, app) |
||||
|
else: |
||||
|
if 'url' in menu: |
||||
|
menu['url'] = reverse('%s:%s' % (app, menu['url']), |
||||
|
kwargs={'pk': pk}) |
||||
|
if 'children' in menu: |
||||
|
resolve_urls_inplace(menu['children'], pk, app) |
@ -0,0 +1,7 @@ |
|||||
|
{% extends "crud/detail.html" %} |
||||
|
{% load i18n %} |
||||
|
|
||||
|
{% block detail_content %} |
||||
|
Sua conta foi confirmada via e-mail. Clique <a href="{% url 'usuarios:login' %}">aqui</a> para fazer seu login. |
||||
|
|
||||
|
{% endblock %} |
@ -0,0 +1,41 @@ |
|||||
|
{% extends "crud/detail.html" %} |
||||
|
{% load i18n %} |
||||
|
|
||||
|
{% block actions %} |
||||
|
<div class="actions btn-group pull-right" role="group"> |
||||
|
<a href="{% url 'usuarios:habilitar_edit' pk %}" class="btn btn-default">{% trans 'Editar' %}</a> |
||||
|
</div> |
||||
|
{% endblock actions %} |
||||
|
|
||||
|
{% block msg %} |
||||
|
{% if not usuario.habilitado %} |
||||
|
<h4><font face="verdana" color="red"><p>Esse perfil ainda <strong>não está habilitado</strong> para uso das funcionalidades.</p></font></h4> |
||||
|
{% else %} |
||||
|
<h4><font face="verdana" color="green"><p>Esse perfil já <strong>está habilitado</strong> para uso das funcionalidades.</p></font></h4> |
||||
|
{% endif %} |
||||
|
{% endblock msg %} |
||||
|
|
||||
|
{% block title %} |
||||
|
<h1 class="page-header"> Habilitar </h1> |
||||
|
{% endblock %} |
||||
|
|
||||
|
{% block detail_content %} |
||||
|
<br /> |
||||
|
<dl> |
||||
|
<dt>Nome completo: </dt> |
||||
|
<dd> - {{ usuario.nome_completo }}</dd> |
||||
|
<dt>Email: </dt> |
||||
|
<dd> - {{ usuario.email }}</dd> |
||||
|
<dt>CPF: </dt> |
||||
|
<dd> - {{ usuario.cpf }}</dd> |
||||
|
<dt>Cargo: </dt> |
||||
|
<dd> - {{ usuario.cargo }}</dd> |
||||
|
<dt>Vinculo: </dt> |
||||
|
<dd> - {{ usuario.vinculo }}</dd> |
||||
|
<dt>Casa Legislativa: </dt> |
||||
|
<dd> - {{ usuario.casa_legislativa }}</dd> |
||||
|
<dt>Telefones: </dt> |
||||
|
<dd> - [{{ usuario.primeiro_telefone.ddd }}] - {{usuario.primeiro_telefone.numero}}</dd> |
||||
|
<dd> - [{{ usuario.segundo_telefone.ddd }}] - {{usuario.segundo_telefone.numero}}</dd> |
||||
|
</dl> |
||||
|
{% endblock detail_content %} |
@ -0,0 +1,34 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
{% load i18n %} |
||||
|
|
||||
|
{% block base_content %} |
||||
|
<div class="hero-unit"> |
||||
|
<h1>Login</h1> |
||||
|
<div class="container"> |
||||
|
<form id="login-form" method="post" action=""> |
||||
|
{% csrf_token %} |
||||
|
<p class="bs-component"> |
||||
|
<table> |
||||
|
{% if form.errors %} |
||||
|
<p><strong>Usuário e/ou Senha inválidos.</strong></p> |
||||
|
{% endif %} |
||||
|
|
||||
|
<tr> |
||||
|
<td><b>Usuário</b></td> |
||||
|
<td>{{ form.username }}</td> |
||||
|
</tr> |
||||
|
<tr> |
||||
|
<td><b>Senha</b></td> |
||||
|
<td>{{ form.password }}</td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
</p> |
||||
|
<p class="bs-component"> |
||||
|
<input class="btn btn-success btn-sm" type="submit" value="Entrar" /> |
||||
|
</p> |
||||
|
<h5><a href="{% url 'usuarios:recuperar_senha' %}"> Esqueceu sua senha? </a></h5> |
||||
|
<input type="hidden" name="next" value="{{ next }}" /> |
||||
|
</form> |
||||
|
</div> |
||||
|
</div> |
||||
|
{% endblock %} |
@ -0,0 +1,10 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
{% load i18n %} |
||||
|
|
||||
|
{% block base_content %} |
||||
|
|
||||
|
<p>{% trans "Sua senha foi alterada corretamente. Agora você pode fazer o login." %}</p> |
||||
|
|
||||
|
<p><a href="{% url 'usuarios:login' %}">{% trans 'Entrar' %}</a></p> |
||||
|
|
||||
|
{% endblock %} |
@ -0,0 +1,13 @@ |
|||||
|
{% extends "crud/form.html" %} |
||||
|
{% load i18n crispy_forms_tags %} |
||||
|
|
||||
|
{% block base_content %} |
||||
|
{% if validlink %} |
||||
|
<p>{% trans "Por favor, insira duas vezes para verificarmos se está correta." %}</p> |
||||
|
{% crispy form %} |
||||
|
{% else %} |
||||
|
<h1>{% trans 'A recuperação de senha não obteve sucesso' %}</h1> |
||||
|
<p>{% trans "O link é inválido, possivelmente este link já foi utilizado. Por favor, refaça o pedido de recuperação de senha." %}</p> |
||||
|
{% endif %} |
||||
|
|
||||
|
{% endblock %} |
@ -0,0 +1,5 @@ |
|||||
|
{% extends "crud/form.html" %} |
||||
|
{% load i18n crispy_forms_tags %} |
||||
|
{% block base_content %} |
||||
|
{% crispy form %} |
||||
|
{% endblock %} |
@ -0,0 +1,14 @@ |
|||||
|
{% load i18n %}{% autoescape off %} |
||||
|
{% blocktrans %}Você está recebendo este e-mail porque fez a solicitação de recuperação de senha no seguinte website <b>{{ site_name }}</b>.</br>{% endblocktrans %} |
||||
|
|
||||
|
{% trans "Clique no link abaixo para redefinir sua senha:" %}</br> |
||||
|
{% block reset_link %} |
||||
|
<a href="{{ protocol }}://{{ domain }}{% url 'usuarios:recuperar_senha_confirma' uidb64=uid token=token %}"> Clique aqui</a></br> |
||||
|
{% endblock %} |
||||
|
{% trans "Seu nome de usuário, caso você tenha esquecido:" %} <b>{{ user.get_username }}</b></br> |
||||
|
|
||||
|
{% trans "Obrigado por acessar nosso site!" %}</br> |
||||
|
|
||||
|
{% blocktrans %}Atenciosamente, equipe <b>Atendimento<b> {% endblocktrans %}</br> |
||||
|
|
||||
|
{% endautoescape %} |
@ -0,0 +1,9 @@ |
|||||
|
{% extends "base.html" %} |
||||
|
{% load i18n %} |
||||
|
|
||||
|
{% block base_content %} |
||||
|
|
||||
|
<p>{% trans "Foi enviado um e-mail com as instruções para recuperação de senha. Você deve recebê-lo em breve." %}</p> |
||||
|
<p>{% trans "Caso você não receba, verifique se você inseriu o e-mail em que você está cadastrado e verifique, também, sua caixa de SPAM." %}</p> |
||||
|
|
||||
|
{% endblock %} |
@ -0,0 +1,31 @@ |
|||||
|
{% extends "crud/detail.html" %} |
||||
|
{% load i18n %} |
||||
|
|
||||
|
{% block actions %} |
||||
|
<div class="actions btn-group pull-right" role="group"> |
||||
|
<a href="{{ view.update_url }}" class="btn btn-default">{% trans 'Editar Perfil' %}</a> |
||||
|
</div> |
||||
|
{% endblock actions %} |
||||
|
|
||||
|
{% block msg %} |
||||
|
{% if not usuario.habilitado %} |
||||
|
<h4><font face="verdana" color="red"><p>Esse perfil ainda <strong>não está habilitado</strong> para uso das funcionalidades.</p></font></h4> |
||||
|
{% else %} |
||||
|
<h4><font face="verdana" color="green"><p>Esse perfil já <strong>está habilitado</strong> para uso das funcionalidades.</p></font></h4> |
||||
|
{% endif %} |
||||
|
{% endblock msg %} |
||||
|
|
||||
|
{% block extrablock %} |
||||
|
|
||||
|
{% for tel in telefones %} |
||||
|
<div class="col-sm-span"> |
||||
|
<div class="form-group"> |
||||
|
<p class="control-label">{{tel|first}}</p> |
||||
|
<div class="controls"> |
||||
|
<p class="form-control-static">{{ tel|last }}</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
{% endfor %} |
||||
|
|
||||
|
{% endblock %} |
@ -0,0 +1,38 @@ |
|||||
|
{% extends "crud/list.html" %} |
||||
|
{% load i18n %} |
||||
|
|
||||
|
{% block buttons %}{% endblock buttons %} |
||||
|
|
||||
|
{% block content %} |
||||
|
|
||||
|
{% if not rows %} |
||||
|
<p>{{ NO_ENTRIES_MSG }}</p> |
||||
|
{% else %} |
||||
|
<table class="table table-striped table-hover"> |
||||
|
<thead> |
||||
|
<tr> |
||||
|
{% for name in headers %} |
||||
|
<th>{{ name }}</th> |
||||
|
{% endfor %} |
||||
|
</tr> |
||||
|
</thead> |
||||
|
<tbody> |
||||
|
{% for value_list in rows %} |
||||
|
<tr> |
||||
|
{% for value, href in value_list %} |
||||
|
<td> |
||||
|
{% if href %} |
||||
|
<a href="/habilitar{{ value_list|first|last|cut:'usuario/' }}">{{ value }}</a> |
||||
|
{% else %} |
||||
|
{{ value|safe }} |
||||
|
{% endif %} |
||||
|
</td> |
||||
|
{% endfor %} |
||||
|
</tr> |
||||
|
{% endfor %} |
||||
|
</tbody> |
||||
|
</table> |
||||
|
{% endif %} |
||||
|
|
||||
|
{% include "paginacao.html" %} |
||||
|
{% endblock content %} |
Loading…
Reference in new issue