A continuación se presenta información enfocada a los desarrolladores
Las plataformas de Evaluador, Preparación y presentación de clases, Parque Sabios y portal de presentación de Sabios están integradas en un proyecto con aplicaciones que interactúan.
Para mantener los ambientes de producción y desarrollo funcionales con una base sólida y estable en producción y el ambiente de de desarrollo con los modelos de datos más recientes y funcionalidades actualizadas contando con la posibilidad de aplicar hotfixes a producción o adición de funcionalidades en producción se empleará dos ramas:
La rama master con la integración continua hará el despliegue sobre producción, mientras que la rama dev apuntará a desarrollo.
Siempre que se hagan fixes en master se harán mezclas de master hacia dev, las cuales serán backports.
En la medida de lo posible, se entrega un diccionario con 3 entradas:
{
response_message: "mensaje mostrado al usuario",
response_status: 0,
obj_list: [],
}
obj_list es una lista de objetos; la estructura de cada objeto en la lista está a discreción del programador.
response_status debe ser 0 si el request tuvo éxito, y diferente de 0 en otro caso. Los valores particulares (diferentes de cero) están a discreción del programador.
response_message es una cadena unicode, con el mensaje apropiado para el usuario, bien sea para casos de error o de éxito.
Para minimizar las consultas en la base de datos se está almacenando información de las consignaciones de puntos que se hace a los estudiantes en un campo dentro de la tabla usuario cuyo formato es::
{
'operations': [{
'amount': value
'timestamp': date
'description': char
'game': can be None, game that issued the operation
'user': can be None, user that issued the operation
'transaction_type': retiro o depósito
}]
}
El padre de familia o acudiente va a tener el hijo actual guardado en la variable de session CURRENT_CHILD , cuando se autentica va a buscar la variable de sesión CURRENT_CHILD, en caso de que no esté buscará el primer hijo o acudido y lo colocará en CURRENT_CHILD.
Habrá un método que permitirá que el acudiente pueda cambiar de hijo, se establecerá el hijo que está en la sesión y en caso contrario se obtendrá el primer “hijo” disponible.
El userprofile de un padre de familia deberá proporcionar un método que ofrezca un listado de los hijos del colegio actual.
Para reducir la cantidad de relaciones en la base de datos, las respuestas dadas por los usuarios se serializan en el campo answers de la clase UserAnswers. Para dar un resultado más rápido en los reportes se precalculan los puntajes obtenidos por los estudiantes.
La estructura del campo answers, en el que se almacena el listado de preguntas, y sus respuestas, es:
{
'questions': [
{
'question': DB id of the question,
'subject': DB id of question's subject,
'status': one of: QUESTION_STATUS_UNANSWERED,
QUESTION_STATUS_SKIPPED,
QUESTION_STATUS_ANSWERED
(defined in evaluation/data.py)
'answers_presentation_order': randomized list of the following
elements:
[
'answer', 'distractor_1', 'distractor_2',
'distractor_3'
],
'answer': integer, index for the 'answers_presentation_order'
array; range: [0, 3]; answer will be correct if
element at this position matches the string 'answer'
When no answer has been provided, it holds the
None special value
}
]
}
Si se requiere creación automatizada de preguntas para hacer pruebas, se puede usar:
from django_dynamic_fixture import G
from evaluation.data import QUESTIONSET_CHOICE_NOT_GRADABLE
from evaluation.tests import _create_questions
user = User.objects.get(email='carlos@axiacore.com')
for axiscontent in AxisContent.objects.all():
_create_questions(
user,
axiscontent=axiscontent,
questionset=QUESTIONSET_CHOICE_NOT_GRADABLE
)
Se está empleando Celery para la carga masiva de estudiantes, hay dos etapas en la carga de estudiantes:
- Revisión de consistencia interna del archivo
- Revisión y cargue de datos frente al sistema
La revisión de la consistencia del archivo es rápida y debe tardar menos de 30 segundos para un archivo con miles de registros.
La carga de cada registro tarda entre 2 y 3 segundos y se verifica consistencia de datos para evitar escalamiento de permisos en diferentes colegios, por ejemplo, no es admisible que un administrador sea estudiante de colegio alguno.
Para garantizar que los procesos terminan estos son encolados y solamente puede ejecutarse una carga a la vez en todo el sistema, esto está controlado por un semáforo y reintentos de Sentry.
Además de añadir una respuesta a un foro, es posible responder a una de las respuestas de un foro. Dichas respuestas anidadas, o subrespuestas/subcomentarios, se almacenan como datos JSON dentro de cada respuesta; ver campo related_answers del modelo communication.ForumAnswer. El formato de dicho campo es el siguiente:
El campo contiene un único objeto, un diccionario con una entrada (llave) ‘related_answers’, cuyo contenido es la lista de respuestas (related_answer). Es decir:
{
related_answers: [related_answer, related_answer, ...]
}
Cada related_answer es un diccionario, que fundamentalmente imita la estructura del modelo UserAnswer:
{
description: cadena unicode con texto markdown: el comentario.
status: entero. Es uno de los estados definidos en
communication.data.FORUM_ANS_STATUSES
created_at: marca de tiempo de la creación del subcomentario,
almacenada como una cadena de texto con la fecha en
formato ISO 8601 incluyendo la zona horaria
(YYYY-MM-DD HH:MM:SS.mmmmmm+HH:MM)
created_by: Entero. id del usuario (userprofile.User) que creó el
comentario.
}
En esta sección se presentan algunos estilos para emplear a lo largo de la aplicación
Para que un textarea con id id_description, que esté dentro de un div con id div_id_description tenga la opción de convertirse en un control markdown se usa el siguiente código javascript:
$('#id_description').attach_markdown({
container: '#div_id_description'
});
Para desplegar el contenido se envuelve en un div con un código similar a:
- <div class=”content_text”>
- {{ description|markdown }}
</div>
Para usar un componente de archivo se emplea la función configure_file_field, la cual fue inyectada en la librería jquery, para emplearla:
$.configure_file_field(
'.section_form',
'div.upload_image',
'#id_image',
'.filename_holder'
);
Donde recibe como primer parámetro un selector del contenedor del formulario para en caso de que se recargue por ajax puede mantener las reacciones, como segundo parámetro el div que reemplaza el widget nativo, como tercer parametro el selector del id del componente nativo y finalmente el widget original donde aparecería el nombre del archivo.
Para ofrecer un mensaje en la página emplee la función show_message de la siguiente forma:
$.show_message('No fue posible enviar el mensaje', 'error');
El segundo parámetro es opcional y puede ser también warning.
Los mensajes de confirmación se apoyan en la librería Messi, deberá usar el callback para continuar el flujo de la operación de acuerdo a la respuesta del usuario:
new Messi('¿Estás seguro de que deseas desactivar el evento?', {
title: 'Cancelar',
buttons: [
{id: 0, label: 'Sí', val: 'Y'},
{id: 1, label: 'No', val: 'N'}
],
callback: function(val) {
$.show_message('elegiste ' + val);
}
});
Para llevar el conteo de los eventos por leer de un usuario se estructuró una API que permite:
Aumentar el conteo dada una cantidad de elementos, si no recibe parámetro se incrementa en un elemento:
add_counter(counter, users, quantity)
Donde counter es una cadena de texto ‘messages’|’events’|’news’|’memos’, users es un iterable del ids de usuarios a los que se les incrementará el conteo de eventos, quantity es la cantidad de elemntos que se añadieron para el listado de usuarios. add_counter se ejecutará como una tarea en background para evitar demorar otros procesos como el envío de una circular para todo el colegio o la notificación de una noticia.
reset_counter(counter, user)
**counter es como se especificó anteriormente y user es el usuario de la aplicación al cual se le añadirán los eventos correspondientes.
El almacenamiento de esta información se hará en redis con elemento hkeys, los nombres de las llaves principales serán:
'noti.userid'
Donde se reemplazará userid por el id del usuario.
Adicionalmente se emplea un prefijo para evitar colisionar con otros servicios, la constante que especifica tal prefijo en settings es:
COMMUNICATION_PREFIX
Para incrementar el contador de mensajes:
from communication.signals import add_counter
add_counter.send(
sender=user,
counter='messages',
users=[user.id],
quantity=3,
)
Incrementaría en 3 el contador para el usuario con user.id, cabe notar que users es una lista para permitir que varios usuarios puedan incrementar el contador.
En esta sección se encuentran algunos comandos frecuentes durante el desarrollo
Una vez instalada la aplicación localmente, se debe compilar el sass para que se muestren los estilos y las imágenes correctamente, para hacerlo deberan estar situados en el directorio del proyecto y ejecutar el siguiente comando:
compass compile app/static/