================================== Documentación para desarrolladores ================================== A continuación se presenta información enfocada a los desarrolladores Proceso de desarrollo ===================== 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: * master * dev 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. Estructura de datos JSON en respuestas AJAX =========================================== 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. Usuarios ======== 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 }] } Padres de familia ----------------- 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. Exámenes ======== 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 } ] } Creación automatizada de preguntas ---------------------------------- 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 ) Carga Masiva ============ 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. Juegos ====== Comentarios de foro =================== 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. } Estilos ======= En esta sección se presentan algunos estilos para emplear a lo largo de la aplicación Menús ----- Para hacer sobresalir a un menú o submenú, se le añade la clase *current* Para ubicar las pestañas de los menús a izquierda, centra o derecha se usan respectivamente las clases *popup_content left*, *popup_content* y *popup_content right* Uso de componentes js ===================== Uso de componente Markdown -------------------------- 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: