Nuevo Widget con 2 listas para pasar datos de una a otra.
Esta lista tiene el objetivo de pasar cosas de FROM a TO dando un layout horizontal
que queda mas piolas ;).
Crea 2 listas ${name}_from y {$name}_to que son pasadas al controller (previamente hay que
seleccionar desde JS todos los items de las listas que se deseen leer, puede ser una sola o
ambas). Como propiedades utiles tiene :
* title_from : El titulo que va arriba de la lista FROM (la de la derecha)
* title_to : El titulo que va arriba de la lista FROM (la de la izquierda)
* El resto igual que MultiSelectField
No puse el texto de los botones configurable porque se rompe muy facil el layour :S, pero creo
que con los titulitos se da a entender.
Desde JS se accede con form_${name}_from y form_${name}_to a FROM y TO respectivamente. Para inicializar
los valores de FROM se usa directamente el atributo options de MultipleSelectField y a TO se lo debe
inicializar desde JS.
Cambiar modelo para que almacene archivos.
Ahora las clases Entrega, ComandoFuente, ComandoPrueba y CasoDePrueba guardan
los archivos como un stream de bytes en formato .zip. Además se vuela el código
de Entrega que no tenía mucho más sentido y se pone como notNone=True y
default='' a algunas observaciones donde tiene más sentido para concatenar.
Mejorar model.Grupo para manejo de miembros y tutores.
Ahora los métodos remove_miembro() y remove_alumno() en vez de eliminar las
clases de la DB les setea la fecha de baja. También se agregan las propiedades
'alumnos' y 'docentes' que devuelven una lista de AlumnoInscripto y
DocenteInscripto respectivamente (no devuelve Miembro/Tutor!) con los objetos
*activos* (es decir, baja=None).
Actualizar parte de tareas y pruebas del modelo.
Nuevo modelo de la parte de pruebas. Ahora un enunciado tiene tareas: "tareas
de fuente" (TareaFuente) y "tareas de prueba" (TareaPrueba). Ambos no son mucho
más que contenedores de Comandos (ComandoFuente y ComandoPrueba), pero con un
cierto orden. Las cosas "de fuente" se aplican a los fuentes, una sola vez. Un
Comando/TareaFuente podría ser compilar. O pasar un analizador estático de
complejidad, o un detector de copias. Un Comando/TareaPrueba, se corre sobre
cada CasoDePrueba que tenga el Enunciado y podría ser una prueba llana y
sencilla, o correrlo con valgrind, etc.
Cada entrega tiene ComandoFuenteEjecutado, que es el resultado de correr un
ComandoFuente sobre una cierta entrega. También cada entrega tiene varias
Pruebas, cada una con información de la corrida de un CasoDePrueba. Cada
prueba, tiene a su vez varios ComandoPruebaEjecutado, que representan como fue
corrido cada ComandoPrueba sobre ese CasoDePrueba para esa entrega.
Faltaría resolver el tema de los archivos, que seguramente van a ser guardados
en el filesystem, pero conceptualmente, cada comando tiene archivos de entrada
(entrada para el comando) y archivos de salida (archivos generados por el
comando). Además la entraga tiene que tener archivos asociados, el código fuente
que entrega el alumno.
Poner en castellano datos de instancia de entrega en el dashboard.
Utiliza el locale del usuario para que el strftime traduzca los strings y pone
cuanto tiempo falta de forma más human readable.
Mejorar y arreglar dashboard.
- Hace que el dashboard pida que se esté logueado en el sistema.
- Reporta todas las instancias de entrega en curso, diciendo cuando vencen
(contando cuantos días faltan al estilo CRONICA =P). Para esto se arregla el
query.
- Se pasan las variables por separado (no se usa el dict "records").
Paso el select-all como responsabilidad del usuario del widget.
No quedan muchas opciones, asi que quien use el AjaxMultiSelect debera implementar un onsubmit
en el form para seleccionar todos los elementos de la lista de manera que sean pasados al controller.
Agregar integridad referencial.
No está pensado muy a fondo pero es algo como para empezar. Traté de ser
conservador en un principio (que chille si borrás algo que tiene asociaciones,
en particular con la parte de entregas de tps), pero se puede ver sobre la
marcha según las necesidades. Hay cosas que tal vez sería mejor ponerlas en
cascada y limitar la interfaz web (poner una confirmación muy, muy grande).
Aceptar IDs en métodos add_xxx() donde tiene sentido.
Gracias a esto, los constructores y el set() ahora también pueden tomar como
parámetro listas de IDs en vez de listas de objetos. Muy útil para usarse con
diccionarios que vienen directo de la web.
También se agrega el método byPadron() a Alumno para consistencia.
Selecciono el enunciado correcto al editar un ejercicio.
Como el combo Enunciado se actualiza on the fly tengo que usar un wait pedorro
para esperar un toque a que todo se realice bien en el browser
Simplifico el url del widget.
Cambio de planes, el parametro do_add ahora es un simple callback que recibe la ID del campo de texto y de la lista
y debe retornar el URL a llamar para obtener los datos (simplificando mucho el manejo del loading y la llamada a JSON).
Del lado del modelo se debe retornar un diccionario con :
* error = True|False : indica si hubo o no error
* msg
- Si error == True el texto de error a mostrar
- Si error == False un diccionario con id y value para el option a agregar de manera que queda
<option value="id">value</option> (si, poco feliz lo de value :P)
AjaxMultiSelect widget generico.
Widget puleta para crear una lista de objetitos para agregar a nuestros objetos.
El widget funciona como un MultipleSelectField con algunos agregados ajaxosos que funcionan out-of-the-box.
Pasa usar el widget el unico requisito es pasar el parametro on_add, que debe ser el nombre de una funcion
javascript que se crea junto con el form (externa al widget y que tiene la logica de validacion prellamada
AJAXosa y la llamada en si).
Ejemplo : en Curso queremos poder agregar la lista de miembros del widget, entonces agregarmos al form lo siguiente :
alumnos = AjaxMultiSelect(name='alumnos', label=_(u'Integrantes'), validator=V.Int(), on_add="alumnos_agregar_a_la_lista")
javascript = [W.JSSource(ajax)]
Definiendo en ajax nuestra funcion como sigue :
function alumnos_agregar_a_la_lista(texto, lista, loading)
{
}
texto contiene el ID (como string) de donde leer el valor a agregar. Lista corresponde al ID de la lista en si y
loading del icono que muestra que se esta haciendo algo.
Para mas detalles como lanzar el JSON y eso ver el ejemplo en Curso.
TODO : hacer que este metodo sea mas facil de implementar :)
Mejorar modelo.
- Agregar varios métodos remove_xxx() correspondientes a los add_xxx().
- Sobrecargar el método set() para objetos con constructor sobrecargado.
- Usar nombres tipo PEP8 en métodos autogenerados.
- Agregar algunas PK que faltaban.
- Agregar algún que otro método add_xxx() que faltaba.
- Agregar algún que otro campo que debería haber estado desde antes (como
CasoDePrueba.privado y CasoDePrueba.activo).
- Eliminar algún que otro JOIN que era copy&paste y no correspondía.
- Tal vez algún fix más.
hago ajaxoso el agregado de alumnos a la lista
por ahora usa el metodo /grupos/de_curso que no deberia estar ahi.
calculo que lo movere a /curso/existe_alumno o algo asi, despues veo
Empiezo a hacer un widget para seleccionar alumnos de forma facil.
La idea es que uno mete padrones y ajaxosamente se valida y si esta ok se agrega a la lista
tambien se pueden borrar y eso. Not big deal todavia, falta lo mas divertido
Remover ByObject.
SQLObject agrega un método getOne() a SelectResult (lo que devuelve el select()
y selectBy), así que ahora en vez de hacer: MySQLObject.by(algo=1), hay
que hacer: MySQLObject.selectBy(algo=1).getOne(). Si el query devuelve más de un
elemento, lanza una excepción SQLObjectIntegrityError. Si se especifica un
default, si no se encontró nada devuelve el default
(A.select(algo=1).getOne(None) devuelve None si no se encontró nada, por
ejemplo), si no lanza un SQLObjectNotFound.
Más info: http://www.sqlobject.org/News.html#id1
Agrego Responsable del curso
Se ingresa solo el padron y el sistema busca que exista el AlumnosInscripto para el curso
seleccionado.
Ademas se agrega un CustomTextField que es un TextField normal con un <span> para ponerle
un mensajito. En este caso se usa para poner el error si no se encontro el alumno o poner
el nombre del Alumno que corresponde al padron.