# -*- coding: utf-8 -*-
"""
Sistema de Consulta Pública
Copyleft (@) 2017 CENDITEL nodo Mérida - https://planificacion.cenditel.gob.ve/trac/wiki/ModeladoTopicos_2017
"""
## @package consulta.views
#
# Vistas correspondientes a la aplicación consulta
# @author Rodrigo Boet (rboet at cenditel.gob.ve)
# @author Centro Nacional de Desarrollo e Investigación en Tecnologías Libres
# (CENDITEL) nodo Mérida - Venezuela
# @copyright GNU Public License versión 2 (GPLv2)
# @version 1.0
import json
from django.shortcuts import render
from django.core.urlresolvers import reverse_lazy
from django.http import JsonResponse
from django.contrib.auth.models import User
from django.views.generic import CreateView, ListView, TemplateView, DeleteView, DetailView, UpdateView
from django.contrib.messages.views import SuccessMessageMixin
from django.contrib.auth.mixins import LoginRequiredMixin
from braces.views import GroupRequiredMixin
from .models import Consulta, Pregunta, TipoPregunta, Opcion
from .forms import ConsultaForm, ConsultaPreguntaForm
from participacion.models import RespuestaSino, RespuestaOpciones, RespuestaAbierta
class ConsultaIndex(GroupRequiredMixin, LoginRequiredMixin, TemplateView):
"""!
Clase que gestiona la vista principal de la consulta
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU Public License versión 2 (GPLv2)
@date 15-02-2017
@version 1.0.0
"""
template_name = "consulta.index.html"
group_required = u"Administrador"
class ConsultaCreate(GroupRequiredMixin, LoginRequiredMixin,SuccessMessageMixin,CreateView):
"""!
Clase que gestiona la creación de consultas
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU Public License versión 2 (GPLv2)
@date 15-02-2017
@version 1.0.0
"""
model = Consulta
form_class = ConsultaPreguntaForm
template_name = "consulta.create.html"
success_message = "Se creó la consulta con éxito"
success_url = reverse_lazy('consulta_index')
group_required = u"Administrador"
def get_context_data(self, **kwargs):
"""!
Metodo que permite cargar de nuevo valores en los datos de contexto de la vista
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU/GPLv2
@date 16-02-2017
@param self {object} Objeto que instancia la clase
@param kwargs {object} Objeto que contiene los datos de contexto
@return Retorna los datos de contexto
"""
if 'tipo_pregunta_modal' in self.request.POST and 'texto_pregunta_modal' in self.request.POST:
post_data = dict(self.request.POST.lists())
if ((len(post_data['tipo_pregunta_modal'])>0 and len(post_data['texto_pregunta_modal'])>0) and (len(post_data['texto_pregunta_modal']) == len(post_data['tipo_pregunta_modal']))):
valores = {}
for i in range(len(post_data['tipo_pregunta_modal'])):
valores[i] = {'texto_pregunta':post_data['texto_pregunta_modal'][i],'tipo_pregunta':post_data['tipo_pregunta_modal'][i]}
kwargs['opciones'] = json.dumps(valores)
return super(ConsultaCreate, self).get_context_data(**kwargs)
def form_valid(self,form):
"""!
Metodo que valida si el formulario es valido
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU/GPLv2
@date 15-02-2017
@param self {object} Objeto que instancia la clase
@param form {object} Objeto que contiene el formulario de registro
@return Retorna el formulario validado
"""
post_data = dict(self.request.POST.lists())
user = User.objects.get(pk=self.request.user.id)
## Se crea el objeto de la consulta
self.object = form.save(commit=False)
self.object.nombre_consulta = form.cleaned_data['nombre_consulta']
self.object.activa = form.cleaned_data['activa']
self.object.user = user
self.object.save()
## Se crea la pregunta que se pide por defecto
tipo = TipoPregunta.objects.get(pk=form.cleaned_data['tipo_pregunta'])
pregunta = Pregunta()
pregunta.texto_pregunta = form.cleaned_data['texto_pregunta']
pregunta.tipo_pregunta = tipo
pregunta.consulta = self.object
pregunta.save()
## Si se agregaron más preguntas se crean
if 'tipo_pregunta_modal' in self.request.POST and 'texto_pregunta_modal' in self.request.POST:
self.create_questions(self.object,post_data)
return super(ConsultaCreate, self).form_valid(form)
def create_questions(self,objeto,data):
"""!
Metodo para crear preguntas adicionales
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU/GPLv2
@date 16-02-2017
@param self {object} Objeto que instancia la clase
@param objeto {object} Objeto de la consulta
@param data {dict} Diccionario con los valores a guardar
"""
if len(data['texto_pregunta_modal']) == len(data['tipo_pregunta_modal']):
print data['texto_pregunta_modal']
for i in range(len(data['texto_pregunta_modal'])):
tipo = TipoPregunta.objects.get(pk=data['tipo_pregunta_modal'][i])
pregunta = Pregunta()
pregunta.texto_pregunta = data['texto_pregunta_modal'][i]
pregunta.tipo_pregunta = tipo
pregunta.consulta = objeto
pregunta.save()
class ConsultaList(GroupRequiredMixin, LoginRequiredMixin,ListView):
"""!
Clase que gestiona la lista de consultas
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU Public License versión 2 (GPLv2)
@date 15-02-2017
@version 1.0.0
"""
model = Consulta
template_name = "consulta.list.html"
group_required = u"Administrador"
class ConsultaDetail(GroupRequiredMixin, LoginRequiredMixin,DetailView):
"""!
Clase que gestiona el detalle de una consulta
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU Public License versión 2 (GPLv2)
@date 17-02-2017
@version 1.0.0
"""
model = Consulta
template_name = "consulta.detail.html"
group_required = u"Administrador"
def get_context_data(self, **kwargs):
"""!
Metodo que permite cargar de nuevo valores en los datos de contexto de la vista
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU/GPLv2
@date 17-02-2017
@param self {object} Objeto que instancia la clase
@param kwargs {object} Objeto que contiene los datos de contexto
@return Retorna los datos de contexto
"""
kwargs['preguntas'] = Pregunta.objects.filter(consulta_id=kwargs['object'].id).all()
kwargs['respuestas'] = True if RespuestaSino.objects.filter(pregunta__consulta=kwargs['object'].id) else False
kwargs['respuestas'] = True if RespuestaOpciones.objects.filter(opcion__pregunta__consulta=kwargs['object'].id) else kwargs['respuestas']
kwargs['respuestas_abierta'] = True if RespuestaAbierta.objects.filter(pregunta__consulta=kwargs['object'].id) else False
return super(ConsultaDetail, self).get_context_data(**kwargs)
class ConsultaDelete(GroupRequiredMixin, LoginRequiredMixin,SuccessMessageMixin,DeleteView):
"""!
Clase que gestiona el borrado de consultas
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU Public License versión 2 (GPLv2)
@date 15-02-2017
@version 1.0.0
"""
model = Consulta
template_name = "consulta.delete.html"
success_message = "Se eliminó la consulta con éxito"
success_url = reverse_lazy('consulta_index')
group_required = u"Administrador"
class ConsultaUpdate(GroupRequiredMixin, LoginRequiredMixin,SuccessMessageMixin,UpdateView):
"""!
Clase que gestiona la actualización de consultas
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU Public License versión 2 (GPLv2)
@date 17-02-2017
@version 1.0.0
"""
model = Consulta
form_class = ConsultaForm
template_name = "consulta.update.html"
success_message = "Se actualizó la consulta con éxito"
success_url = reverse_lazy('consulta_list')
group_required = u"Administrador"
def get_context_data(self, **kwargs):
"""!
Metodo que permite cargar de nuevo valores en los datos de contexto de la vista
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU/GPLv2
@date 17-02-2017
@param self {object} Objeto que instancia la clase
@param kwargs {object} Objeto que contiene los datos de contexto
@return Retorna los datos de contexto
"""
preguntas = Pregunta.objects.filter(consulta_id=self.object.id).all()
kwargs['preguntas'] = preguntas
return super(ConsultaUpdate, self).get_context_data(**kwargs)
class ConsultaStats(GroupRequiredMixin, LoginRequiredMixin,TemplateView):
"""!
Clase que gestiona las estadísticas de la consulta
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU Public License versión 2 (GPLv2)
@date 18-04-2017
@version 1.0.0
"""
template_name = "consulta.stats.html"
group_required = u"Administrador"
def get_context_data(self, **kwargs):
"""!
Metodo que permite cargar de nuevo valores en los datos de contexto de la vista
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU/GPLv2
@date 18-04-2017
@param self {object} Objeto que instancia la clase
@param kwargs {object} Objeto que contiene los datos de contexto
@return Retorna los datos de contexto
"""
preguntas_opciones = []
preguntas_sino = []
for pregunta in Pregunta.objects.filter(consulta_id=self.kwargs['pk']).exclude(tipo_pregunta_id=5).all():
if pregunta.tipo_pregunta_id<3:
preguntas_opciones.append(self.get_pregunta_opciones(pregunta.id,pregunta.texto_pregunta))
elif pregunta.tipo_pregunta_id<5:
preguntas_sino.append(self.get_pregunta_sino(pregunta.id,pregunta.texto_pregunta))
kwargs['preguntas_opciones'] = preguntas_opciones
kwargs['preguntas_sino'] = preguntas_sino
return super(ConsultaStats, self).get_context_data(**kwargs)
def get_pregunta_opciones(self,id,titulo):
"""!
Metodo que permite cargar las opciones para una pregunta simple o múltiple
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU/GPLv2
@date 18-04-2017
@param self {object} Objeto que instancia la clase
@param id {int} Entero con el id de la consulta
@return Retorna los datos de contexto
"""
options = []
values = []
for opcion in Opcion.objects.filter(pregunta_id=id).all():
options.append(opcion.texto_opcion.encode('utf8'))
values.append(RespuestaOpciones.objects.filter(opcion_id=opcion.id).count())
data = {}
data['titulo'] = titulo
data['opciones'] = options
data['valores'] = values
return data
def get_pregunta_sino(self,id,titulo):
"""!
Metodo que permite cargar las opciones para una pregunta si o no
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU/GPLv2
@date 18-04-2017
@param self {object} Objeto que instancia la clase
@param id {int} Entero con el id de la consulta
@return Retorna los datos de contexto
"""
Si = RespuestaSino.objects.filter(respuesta=True).count()
No = RespuestaSino.objects.filter(respuesta=False).count()
data = {}
data['titulo'] = titulo
data['opciones'] = ['Si','No']
data['valores'] = [Si, No]
return data
class OpcionesCreate(GroupRequiredMixin, LoginRequiredMixin,CreateView):
"""!
Clase que gestiona la creación de opciones
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU Public License versión 2 (GPLv2)
@date 20-02-2017
@version 1.0.0
"""
model = Opcion
fields = ['texto_opcion']
template_name = "consulta.create.html"
success_url = reverse_lazy('consulta_index')
group_required = u"Administrador"
def form_valid(self,form):
"""!
Metodo que valida si el formulario es valido
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU/GPLv2
@date 20-02-2017
@param self {object} Objeto que instancia la clase
@param form {object} Objeto que contiene el formulario de registro
@return Retorna el formulario validado
"""
post_data = dict(self.request.POST.lists())
pregunta = Pregunta.objects.get(id=int(self.kwargs['pk']))
## Se guarda la primera opcion
self.object = form.save(commit=False)
self.object.texto_opcion = form.cleaned_data['texto_opcion']
self.object.pregunta = pregunta
self.object.save()
## Se guardan las demás opciones si existen
for i in range(len(post_data['texto_opcion'])-1):
opcion = Opcion()
opcion.texto_opcion = post_data['texto_opcion'][i]
opcion.pregunta = pregunta
opcion.save()
if self.request.is_ajax():
return JsonResponse({"code":True})
return super(OpcionesCreate, self).form_valid(form)
def form_invalid(self,form):
"""!
Metodo que valida si el formulario es invalido
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU/GPLv2
@date 20-02-2017
@param self {object} Objeto que instancia la clase
@param form {object} Objeto que contiene el formulario de registro
@return Retorna el formulario inválido
"""
if self.request.is_ajax():
return JsonResponse({"code":False,'errors':form.errors})
return super(OpcionesCreate, self).form_invalid(form)
class OpcionesUpdate(GroupRequiredMixin, LoginRequiredMixin,UpdateView):
"""!
Clase que gestiona la actualización de las opciones
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU Public License versión 2 (GPLv2)
@date 20-02-2017
@version 1.0.0
"""
model = Opcion
fields = ['texto_opcion']
template_name = "consulta.update.html"
success_url = reverse_lazy('consulta_list')
group_required = u"Administrador"
def post(self, request):
"""!
Metodo que sobreescribe la acción por POST
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU/GPLv2
@date 20-02-2017
@param self {object} Objeto que instancia la clase
@param request {object} Objeto que contiene la petición
@return Retorna los datos de contexto
"""
post_data = dict(self.request.POST.lists())
for i in range(len(post_data['texto_opcion'])):
opcion = Opcion.objects.filter(id=int(post_data['texto_opcion_id'][i]))
if(opcion):
opcion = opcion.get()
opcion.texto_opcion = post_data['texto_opcion'][i]
opcion.save()
if self.request.is_ajax():
return JsonResponse({"code":True})
class OpcionesDelete(GroupRequiredMixin, LoginRequiredMixin,DeleteView):
"""!
Clase que gestiona el borrado de una opción
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU Public License versión 2 (GPLv2)
@date 20-02-2017
@version 1.0.0
"""
model = Opcion
template_name = "consulta.update.html"
success_url = reverse_lazy('consulta_list')
group_required = u"Administrador"
def post(self, request, pk):
"""!
Metodo que sobreescribe la acción por POST
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU/GPLv2
@date 20-02-2017
@param self {object} Objeto que instancia la clase
@param request {object} Objeto que contiene la petición
@param pk {int} Recibe el id para filtrar
@return Retorna los datos de contexto
"""
opcion = Opcion.objects.filter(id=int(pk))
if(opcion):
opcion = opcion.get()
opcion.delete()
return JsonResponse({'success':True})
return JsonResponse({'success':False,'mensaje':'Opción inválida'})
class PreguntaDelete(GroupRequiredMixin, LoginRequiredMixin,DeleteView):
"""!
Clase que gestiona el borrado de una pregunta
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU Public License versión 2 (GPLv2)
@date 20-02-2017
@version 1.0.0
"""
model = Pregunta
template_name = "consulta.update.html"
success_url = reverse_lazy('consulta_list')
group_required = u"Administrador"
def post(self, request, pk):
"""!
Metodo que sobreescribe la acción por POST
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU/GPLv2
@date 20-02-2017
@param self {object} Objeto que instancia la clase
@param request {object} Objeto que contiene la petición
@param pk {int} Recibe el id para filtrar
@return Retorna los datos de contexto
"""
pregunta = Pregunta.objects.filter(id=int(pk))
if(pregunta):
pregunta = pregunta.get()
## Si tiene opciones, se buscan y se borran
if(pregunta.tipo_pregunta_id==1):
opciones = Opcion.objects.filter(pregunta_id=pregunta.id)
if (opciones):
for item in opciones.all():
item.delete()
pregunta.delete()
return JsonResponse({'success':True})
return JsonResponse({'success':False,'mensaje':'Pregunta inválida'})
class PreguntaCreate(GroupRequiredMixin, LoginRequiredMixin,CreateView):
"""!
Clase que gestiona la creación de preguntas
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU Public License versión 2 (GPLv2)
@date 21-02-2017
@version 1.0.0
"""
model = Pregunta
fields = ['texto_pregunta','tipo_pregunta']
template_name = "consulta.create.html"
success_url = reverse_lazy('consulta_index')
group_required = u"Administrador"
def form_valid(self,form):
"""!
Metodo que valida si el formulario es valido
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU/GPLv2
@date 21-02-2017
@param self {object} Objeto que instancia la clase
@param form {object} Objeto que contiene el formulario de registro
@return Retorna el formulario validado
"""
post_data = dict(self.request.POST.lists())
consulta = Consulta.objects.get(id=int(self.kwargs['pk']))
## Se guarda la primera opcion
self.object = form.save(commit=False)
self.object.texto_opcion = form.cleaned_data['texto_pregunta']
self.object.tipo_pregunta = form.cleaned_data['tipo_pregunta']
self.object.consulta = consulta
self.object.save()
## Se guardan las demás opciones si existen
for i in range(len(post_data['texto_pregunta'])-1):
tipo_pregunta = TipoPregunta.objects.get(id=int(post_data['tipo_pregunta'][i]))
pregunta = Pregunta()
pregunta.texto_opcion = post_data['texto_pregunta'][i]
pregunta.tipo_pregunta = post_data['tipo_pregunta'][i]
pregunta.consulta = consulta
pregunta.save()
if self.request.is_ajax():
return JsonResponse({"code":True})
return super(OpcionesCreate, self).form_valid(form)
def form_invalid(self,form):
"""!
Metodo que valida si el formulario es invalido
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU/GPLv2
@date 21-02-2017
@param self {object} Objeto que instancia la clase
@param form {object} Objeto que contiene el formulario de registro
@return Retorna el formulario inválido
"""
if self.request.is_ajax():
return JsonResponse({"code":False,'errors':form.errors})
return super(OpcionesCreate, self).form_invalid(form)
class PreguntaUpdate(GroupRequiredMixin, LoginRequiredMixin, UpdateView):
"""!
Clase que gestiona la actualización de las preguntas
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU Public License versión 2 (GPLv2)
@date 23-02-2017
@version 1.0.0
"""
model = Pregunta
fields = ['texto_pregunta','tipo_pregunta']
template_name = "consulta.update.html"
success_url = reverse_lazy('consulta_list')
group_required = u"Administrador"
def post(self, request):
"""!
Metodo que sobreescribe la acción por POST
@author Rodrigo Boet (rboet at cenditel.gob.ve)
@copyright GNU/GPLv2
@date 23-02-2017
@param self {object} Objeto que instancia la clase
@param request {object} Objeto que contiene la petición
@return Retorna los datos de contexto
"""
post_data = dict(self.request.POST.lists())
for i in range(len(post_data['texto_pregunta_modal'])):
pregunta = Pregunta.objects.filter(id=int(post_data['texto_pregunta_id'][i]))
if(pregunta):
pregunta = pregunta.get()
salvar = False
if(pregunta.texto_pregunta != post_data['texto_pregunta_modal'][i]):
pregunta.texto_pregunta = post_data['texto_pregunta_modal'][i]
salvar = True
if(pregunta.tipo_pregunta != post_data['tipo_pregunta_modal'][i]):
tipo_pregunta = TipoPregunta.objects.filter(id=int(post_data['tipo_pregunta_modal'][i])).get()
pregunta.tipo_pregunta = tipo_pregunta
salvar = True
if(salvar):
pregunta.save()
if self.request.is_ajax():
return JsonResponse({"code":True})