mirror of https://github.com/interlegis/sigi.git
22 changed files with 413 additions and 0 deletions
@ -0,0 +1,15 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
from django.contrib import admin |
||||
|
from sigi.forms_builder.forms.admin import FieldAdmin, FormAdmin |
||||
|
from sigi.apps.pesquisas.models import Pesquisa, Pergunta, Formulario, Resposta |
||||
|
|
||||
|
class PerguntaAdmin(FieldAdmin): |
||||
|
model = Pergunta |
||||
|
|
||||
|
class PesquisaAdmin(FormAdmin): |
||||
|
formentry_model = Formulario |
||||
|
fieldentry_model = Resposta |
||||
|
inlines = (PerguntaAdmin,) |
||||
|
|
||||
|
admin.site.register(Pesquisa, PesquisaAdmin) |
@ -0,0 +1,11 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
from sigi.forms_builder.forms.forms import FormForForm |
||||
|
from sigi.apps.pesquisas.models import Formulario, Resposta |
||||
|
|
||||
|
class PesquisaForm(FormForForm): |
||||
|
field_entry_model = Resposta |
||||
|
|
||||
|
class Meta(FormForForm.Meta): |
||||
|
model = Formulario |
||||
|
fields = ['casa_legislativa',] |
@ -0,0 +1,44 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
from django.db import models |
||||
|
from django.utils.translation import ungettext, ugettext_lazy as _ |
||||
|
from sigi.forms_builder.forms.models import AbstractForm, AbstractField, AbstractFormEntry, AbstractFieldEntry |
||||
|
from sigi.apps.casas.models import CasaLegislativa |
||||
|
from sigi.apps.servidores.models import Servidor |
||||
|
|
||||
|
class Pesquisa(AbstractForm): |
||||
|
class Meta: |
||||
|
verbose_name = _("Pesquisa") |
||||
|
verbose_name_plural = _("Pesquisas") |
||||
|
|
||||
|
class Pergunta(AbstractField): |
||||
|
""" |
||||
|
Implements automated field ordering. |
||||
|
""" |
||||
|
|
||||
|
form = models.ForeignKey("Pesquisa", related_name="fields") |
||||
|
order = models.IntegerField(_("Order"), null=True, blank=True) |
||||
|
|
||||
|
class Meta(AbstractField.Meta): |
||||
|
ordering = ("order",) |
||||
|
|
||||
|
def save(self, *args, **kwargs): |
||||
|
if self.order is None: |
||||
|
self.order = self.form.fields.count() |
||||
|
super(Pergunta, self).save(*args, **kwargs) |
||||
|
|
||||
|
def delete(self, *args, **kwargs): |
||||
|
fields_after = self.form.fields.filter(order__gte=self.order) |
||||
|
fields_after.update(order=models.F("order") - 1) |
||||
|
super(Pergunta, self).delete(*args, **kwargs) |
||||
|
|
||||
|
class Formulario(AbstractFormEntry): |
||||
|
form = models.ForeignKey("Pesquisa", related_name="entries") |
||||
|
casa_legislativa = models.ForeignKey(CasaLegislativa, verbose_name=u"Casa legislativa") |
||||
|
#operador = models.ForeignKey(Servidor, verbose_name=u"Operador") |
||||
|
|
||||
|
class Meta(AbstractFormEntry.Meta): |
||||
|
unique_together = ('form', 'casa_legislativa') |
||||
|
|
||||
|
class Resposta(AbstractFieldEntry): |
||||
|
entry = models.ForeignKey("Formulario", related_name="fields") |
@ -0,0 +1,30 @@ |
|||||
|
{% extends "admin/change_form.html" %} |
||||
|
|
||||
|
{% load i18n %} |
||||
|
{% load url from future %} |
||||
|
|
||||
|
{% block object-tools %} |
||||
|
{% if change %}{% if not is_popup %} |
||||
|
<ul class="object-tools"> |
||||
|
<li> |
||||
|
<a href="{% url "admin:form_entries" object_id %}">{% trans "View entries" %}</a> |
||||
|
</li> |
||||
|
<li> |
||||
|
<a href="history/" class="historylink">{% trans "History" %}</a> |
||||
|
</li> |
||||
|
{% if has_absolute_url %} |
||||
|
<li> |
||||
|
<a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">{% trans "View on site" %}</a> |
||||
|
</li> |
||||
|
{% endif%} |
||||
|
</ul> |
||||
|
<style> |
||||
|
#fields-group .vTextField {width: 13.5em;} |
||||
|
#fields-group .vIntegerField {width: 2em;} |
||||
|
#fields-group .field-required, |
||||
|
#fields-group .field-visible, |
||||
|
#fields-group .delete {text-align: center;} |
||||
|
form .aligned p.help {padding-left: 24px;} |
||||
|
</style> |
||||
|
{% endif %}{% endif %} |
||||
|
{% endblock %} |
@ -0,0 +1,167 @@ |
|||||
|
{% extends "admin/base_site.html" %} |
||||
|
|
||||
|
{% load i18n %} |
||||
|
|
||||
|
{% block extrahead %} |
||||
|
{{ block.super }} |
||||
|
<style> |
||||
|
#content-main table {margin:10px 0 20px 0;} |
||||
|
#content-main ul, #content-main li {display:inline; padding:0;} |
||||
|
#content-main label {cursor:pointer;} |
||||
|
h1 {margin-top:20px;} |
||||
|
#content-main h1 {margin:30px 0 0 0;} |
||||
|
table {border:1px solid #ddd; width:100%;} |
||||
|
th, td {border-right:1px solid #ddd; padding:5px 15px;} |
||||
|
.last {border-right:0;} |
||||
|
td.include, th.include-all, td.include-all {text-align:center; width:10px;} |
||||
|
.empty {margin-top:10px;} |
||||
|
.field {padding-top:8px;} |
||||
|
.filter select {width:140px;} |
||||
|
.options {vertical-align:middle; white-space:nowrap;} |
||||
|
.options label {margin:0 10px; font-weight:normal; vertical-align:middle;} |
||||
|
.options-div {visibility:hidden;} |
||||
|
.options select {min-width:0;} |
||||
|
.on {background:#eee;} |
||||
|
.off {background:#fff;} |
||||
|
.button {float:left !important; margin-right:10px; cursor:pointer;} |
||||
|
</style> |
||||
|
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js"></script> |
||||
|
<script> |
||||
|
$(function() { |
||||
|
// Show the filter criteria fields when a filter option is selected. |
||||
|
$('.filter select').change(function() { |
||||
|
var filtering = this.selectedIndex > 0; |
||||
|
var options = $(this).parent().parent().find('.options-div'); |
||||
|
options.css('visibility', filtering ? 'visible' : 'hidden'); |
||||
|
// Focus the first field. |
||||
|
if (filtering) { |
||||
|
var input = options.find('input:first'); |
||||
|
if (input.length === 1) { |
||||
|
input.focus(); |
||||
|
} else { |
||||
|
options.find('select:first').focus(); |
||||
|
} |
||||
|
} |
||||
|
}).change(); |
||||
|
// Toggle the include `All` checkboxes - grouped within table tags. |
||||
|
$('#content-main table').each(function(i, table) { |
||||
|
table = $(table); |
||||
|
var all = table.find('.include-all :checkbox'); |
||||
|
var others = table.find('.include :checkbox'); |
||||
|
others.change(function() { |
||||
|
var len = table.find('.include :checkbox:not(:checked)').length; |
||||
|
all.attr('checked', len === 0); |
||||
|
}); |
||||
|
all.change(function() { |
||||
|
others.attr('checked', !!all.attr('checked')); |
||||
|
}); |
||||
|
}); |
||||
|
// Add a confirmation prompt for deleting entries. |
||||
|
$('input[name="delete"]').click(function() { |
||||
|
if ( $('input[name="selected"]:checked').length === 0 ) { |
||||
|
alert('{% trans "No entries selected" %}'); |
||||
|
return false; |
||||
|
} else { |
||||
|
return confirm('{% trans "Delete selected entries?" %}'); |
||||
|
} |
||||
|
}); |
||||
|
}); |
||||
|
</script> |
||||
|
{% endblock %} |
||||
|
|
||||
|
{% block breadcrumbs %} |
||||
|
<div class="breadcrumbs"> |
||||
|
<a href="../../../../">{% trans "Home" %}</a> › |
||||
|
<a href="../../../">{{ opts.app_label|capfirst|escape }}</a> › |
||||
|
<a href="../../">{{ opts.verbose_name_plural|capfirst }}</a> › |
||||
|
<a href="../">{{ original|truncatewords:"18" }}</a> › |
||||
|
{{ title }} |
||||
|
</div> |
||||
|
{% endblock %} |
||||
|
|
||||
|
{% block content %} |
||||
|
<div id="content-main"> |
||||
|
<form method="post"> |
||||
|
{% csrf_token %} |
||||
|
<table> |
||||
|
<tr> |
||||
|
<th>{% trans "Field" %}</th> |
||||
|
<th>{% trans "Include" %}</th> |
||||
|
<th class="last" colspan="2">{% trans "Filter by" %}</th> |
||||
|
</tr> |
||||
|
{% for include_field, filter_field, filter_option_fields in entries_form %} |
||||
|
<tr class="{% cycle on,off as row %}"> |
||||
|
<td class="field">{{ include_field.label_tag }}</td> |
||||
|
<td class="include">{{ include_field }}</td> |
||||
|
<td class="filter last">{{ filter_field }}</td> |
||||
|
<td class="options last"> |
||||
|
<div class="options-div"> |
||||
|
{% for option_field in filter_option_fields %} |
||||
|
{{ option_field.label_tag }} {{ option_field }} |
||||
|
{% endfor %} |
||||
|
</div> |
||||
|
</td> |
||||
|
</tr> |
||||
|
{% endfor %} |
||||
|
<tr class="{% cycle row %}"> |
||||
|
<td class="field" style="text-align:right;"> |
||||
|
<label for="include-all">{% trans "All" %}</label> |
||||
|
</td> |
||||
|
<td class="include-all"> |
||||
|
<input type="checkbox" id="include-all" class="include-all" checked="checked"> |
||||
|
</td> |
||||
|
<td class="last" colspan="2"> </td> |
||||
|
</tr> |
||||
|
</table> |
||||
|
<input type="submit" name="back" class="button" value="{% trans "Back to form" %}"> |
||||
|
<input type="submit" class="button default" value="{% trans "View entries" %}"> |
||||
|
<input type="submit" class="button default" name="export" value="{% trans "Export CSV" %}"> |
||||
|
{% if xlwt_installed %} |
||||
|
<input type="submit" class="button default" name="export_xls" value="{% trans "Export XLS" %}"> |
||||
|
{% endif %} |
||||
|
{% if submitted %} |
||||
|
<br clear="both" /> |
||||
|
<h1 id="entries-title">{% trans "Entries" %}</h1> |
||||
|
{% for row in entries_form.rows %} |
||||
|
{% if forloop.first %} |
||||
|
<table id="entries-table"> |
||||
|
<tr> |
||||
|
{% if can_delete_entries %} |
||||
|
<th class="include-all"><input type="checkbox"></th> |
||||
|
{% endif %} |
||||
|
{% for column in entries_form.columns %} |
||||
|
<th{% if forloop.last %} class="last"{% endif %}>{{ column }}</th> |
||||
|
{% endfor %} |
||||
|
</tr> |
||||
|
{% endif %} |
||||
|
<tr class="{% cycle on,off %}"> |
||||
|
{% if can_delete_entries %} |
||||
|
<td class="include"> |
||||
|
<input type="checkbox" name="selected" value="{{ row.0 }}"> |
||||
|
</td> |
||||
|
{% endif %} |
||||
|
{% for field in row %} |
||||
|
{% if not forloop.first %} |
||||
|
<td{% if forloop.last %} class="last"{% endif %}>{{ field }}</td> |
||||
|
{% endif %} |
||||
|
{% endfor %} |
||||
|
</tr> |
||||
|
{% if forloop.last %} |
||||
|
</table> |
||||
|
<!-- |
||||
|
count is injected into the title here with the :after selector |
||||
|
to avoid calling the expensive "entries_form.rows" twice. |
||||
|
--> |
||||
|
<style>#entries-title:after {content: ' ({{ forloop.counter }})';}</style> |
||||
|
{% if can_delete_entries %} |
||||
|
<input type="submit" name="back" class="button" value="{% trans "Back to form" %}"> |
||||
|
<input type="submit" name="delete" class="button default" value="{% trans "Delete selected" %}"> |
||||
|
{% endif %} |
||||
|
{% endif %} |
||||
|
{% empty %} |
||||
|
<p class="empty">{% trans "No entries to display" %}</p> |
||||
|
{% endfor %} |
||||
|
{% endif %} |
||||
|
</form> |
||||
|
</div> |
||||
|
{% endblock %} |
@ -0,0 +1,3 @@ |
|||||
|
{% block main %}{% endblock %} |
||||
|
|
||||
|
<br><a href="http://{{ request.get_host }}">http://{{ request.get_host }}</a> |
@ -0,0 +1,3 @@ |
|||||
|
{% block main %}{% endblock %} |
||||
|
|
||||
|
http://{{ request.get_host }} |
@ -0,0 +1,13 @@ |
|||||
|
{% extends "email_extras/base.html" %} |
||||
|
|
||||
|
{% block main %} |
||||
|
{% if message %}<p>{{ message }}</p>{% endif %} |
||||
|
<table border="0"> |
||||
|
{% for field, value in fields %} |
||||
|
<tr> |
||||
|
<td><b>{{ field }}:</b></td> |
||||
|
<td>{{ value|linebreaks }}</td> |
||||
|
</tr> |
||||
|
{% endfor %} |
||||
|
</table> |
||||
|
{% endblock %} |
@ -0,0 +1,9 @@ |
|||||
|
{% extends "email_extras/base.txt" %} |
||||
|
|
||||
|
{% block main %}{% if message %} |
||||
|
{{ message }} |
||||
|
|
||||
|
{% endif %}{% for field, value in fields %} |
||||
|
{{ field }}: {{ value|safe }} |
||||
|
{% endfor %} |
||||
|
{% endblock %} |
@ -0,0 +1,5 @@ |
|||||
|
{% extends "email_extras/form_response.html" %} |
||||
|
|
||||
|
{% block main %} |
||||
|
{{ block.super }} |
||||
|
{% endblock %} |
@ -0,0 +1,5 @@ |
|||||
|
{% extends "email_extras/form_response.txt" %} |
||||
|
|
||||
|
{% block main %} |
||||
|
{{ block.super }} |
||||
|
{% endblock %} |
@ -0,0 +1,17 @@ |
|||||
|
<!doctype html> |
||||
|
{% load forms_builder_tags %} |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<title>{{ form.title }}</title> |
||||
|
<style> |
||||
|
body {font-family:sans-serif; padding:1em 2em;} |
||||
|
p {width:50em; clear:both;} |
||||
|
label {display:block; float:left; width:8em; margin:0 1.2em 1.2em 0;} |
||||
|
li {list-style-type:none;} |
||||
|
li label {width:auto; cursor:pointer;} |
||||
|
.errorlist {color:#f00;} |
||||
|
</style> |
||||
|
</head> |
||||
|
<body> |
||||
|
{% render_built_form form %} |
||||
|
</body> |
@ -0,0 +1,17 @@ |
|||||
|
<!doctype html> |
||||
|
<head> |
||||
|
<meta charset="utf-8"> |
||||
|
<title>{{ form.title }}</title> |
||||
|
<style> |
||||
|
body {font-family:sans-serif; padding:1em 2em;} |
||||
|
p {width:50em;} |
||||
|
label {display:block; float:left; width:10em;} |
||||
|
.errorlist {color:#f00;} |
||||
|
</style> |
||||
|
</head> |
||||
|
<body> |
||||
|
<h1>{{ form.title }}</h1> |
||||
|
{% if form.response %} |
||||
|
<p>{{ form.response }}</p> |
||||
|
{% endif %} |
||||
|
</body> |
@ -0,0 +1,11 @@ |
|||||
|
<h1>{{ form.title }}</h1> |
||||
|
{% if form.intro %} |
||||
|
<p>{{ form.intro }}</p> |
||||
|
{% endif %} |
||||
|
<form action="{{ form.get_absolute_url }}" method="post" |
||||
|
{% if form_for_form.is_multipart %}enctype="multipart/form-data"{% endif %}> |
||||
|
{% csrf_token %} |
||||
|
{{ form_for_form.as_p }} |
||||
|
<div style="clear:left;"> </div> |
||||
|
<input type="submit" value="{{ form.button_text }}"> |
||||
|
</form> |
@ -0,0 +1,33 @@ |
|||||
|
from django import template |
||||
|
from sigi.forms_builder.forms.templatetags.forms_builder_tags import BuiltFormNode |
||||
|
from sigi.apps.pesquisas.models import Pesquisa |
||||
|
from sigi.apps.pesquisas.forms import PesquisaForm |
||||
|
|
||||
|
register = template.Library() |
||||
|
|
||||
|
class BuiltPesquisaNode(BuiltFormNode): |
||||
|
form_class = Pesquisa |
||||
|
form_for_form_class = PesquisaForm |
||||
|
|
||||
|
@register.tag |
||||
|
def render_built_form(parser, token): |
||||
|
""" |
||||
|
render_build_form takes one argument in one of the following formats: |
||||
|
|
||||
|
{% render_build_form form_instance %} |
||||
|
{% render_build_form form=form_instance %} |
||||
|
{% render_build_form id=form_instance.id %} |
||||
|
{% render_build_form slug=form_instance.slug %} |
||||
|
|
||||
|
""" |
||||
|
try: |
||||
|
_, arg = token.split_contents() |
||||
|
if "=" not in arg: |
||||
|
arg = "form=" + arg |
||||
|
name, value = arg.split("=", 1) |
||||
|
if name not in ("form", "id", "slug"): |
||||
|
raise ValueError |
||||
|
except ValueError: |
||||
|
e = () |
||||
|
raise template.TemplateSyntaxError(render_built_form.__doc__) |
||||
|
return BuiltPesquisaNode(name, value) |
@ -0,0 +1,3 @@ |
|||||
|
from django.test import TestCase |
||||
|
|
||||
|
# Create your tests here. |
@ -0,0 +1,9 @@ |
|||||
|
from __future__ import unicode_literals |
||||
|
|
||||
|
from django.conf.urls import patterns, url |
||||
|
|
||||
|
|
||||
|
urlpatterns = patterns("apps.pesquisas.views", |
||||
|
url(r"(?P<slug>.*)/sent/$", "form_sent", name="form_sent"), |
||||
|
url(r"(?P<slug>.*)/$", "form_detail", name="form_detail"), |
||||
|
) |
@ -0,0 +1,15 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
|
||||
|
from sigi.forms_builder.forms.views import FormDetail, FormSent |
||||
|
from sigi.apps.pesquisas.models import Pesquisa |
||||
|
from sigi.apps.pesquisas.forms import PesquisaForm |
||||
|
|
||||
|
class PesquisaDetail(FormDetail): |
||||
|
form_class = Pesquisa |
||||
|
form_for_form_class = PesquisaForm |
||||
|
|
||||
|
class PesquisaSent(FormSent): |
||||
|
form_class = Pesquisa |
||||
|
|
||||
|
form_detail = PesquisaDetail.as_view() |
||||
|
form_sent = PesquisaSent.as_view() |
Loading…
Reference in new issue