]> git.llucax.com Git - software/sercom.git/blobdiff - sercom/subcontrollers/curso/grupo/__init__.py
simplifico logica de colores y pagino las entregas de una instancia de entrega.
[software/sercom.git] / sercom / subcontrollers / curso / grupo / __init__.py
index 8dad4a7500eefd14b4021a2659dadeefc8491bef..a38234012ae6be371bb6c114b5e0253e411c48c8 100644 (file)
@@ -7,14 +7,19 @@ from turbogears import validate, flash, error_handler
 from turbogears import validators as V
 from turbogears import widgets as W
 from turbogears import identity
-from turbogears import paginate
+from turbogears import paginate, url
 from docutils.core import publish_parts
 from sercom.subcontrollers import validate as val
 from sercom.model import Curso, AlumnoInscripto, Docente, DocenteInscripto, Grupo, Alumno, Miembro
 from sqlobject import *
+from sqlobject.dberrors import *
 
 from sercom.widgets import *
 
+import logging
+
+log = logging.getLogger('sercom.curso.grupo.admin')
+
 #}}}
 
 #{{{ Configuración
@@ -42,9 +47,7 @@ def get_docentes():
     return [(fk1.id, fk1.shortrepr()) for fk1 in Docente.select()]
 
 def get_docentes_inscriptos(id):
-    def func():
-        return [(fk1.id, fk1.shortrepr()) for fk1 in DocenteInscripto.select(DocenteInscripto.q.cursoID==id)]
-    return func
+    return [(fk1.id, fk1.shortrepr()) for fk1 in DocenteInscripto.select(DocenteInscripto.q.cursoID==id)]
 
 ajax = u"""
     function alumnos_agregar_a_la_lista(texto, lista)
@@ -122,11 +125,11 @@ ajax = u"""
 
 class GrupoForm(W.TableForm):
     class Fields(W.WidgetsList):
-        cursoID = W.HiddenField()
+        cursoID = W.HiddenField(validator=V.Int)
         nombre = W.TextField(label=_(u'Nombre'), validator=V.UnicodeString(not_empty=True,strip=True))
         responsable = CustomTextField(label=_(u'Responsable'), validator=V.UnicodeString(), attrs=dict(size='8'))
         miembros = AjaxMultiSelect(label=_(u'Miembros'), validator=V.Int(), on_add="alumnos_agregar_a_la_lista")
-        tutores = W.MultipleSelectField(label=_(u'Tutores'), validator=V.Int(), options=get_docentes)
+        tutores = W.MultipleSelectField(label=_(u'Tutores'), validator=V.Int)
 
     fields = Fields()
     javascript = [W.JSSource("MochiKit.DOM.focusOnLoad('form_nombre');"), W.JSSource(ajax)]
@@ -134,6 +137,154 @@ class GrupoForm(W.TableForm):
 
 form = GrupoForm()
 
+def get_gruposA(cursoID):
+    return [(0, u'---')] + [(g.id, g.shortrepr()) for g in Grupo.select(Grupo.q.cursoID==cursoID)]
+
+def get_gruposB(cursoID):
+    return [(0, u'Nuevo Grupo')] + [(g.id, g.shortrepr()) for g in Grupo.select(Grupo.q.cursoID==cursoID)]
+
+ajaxadmin = u"""
+    function err (err)
+    {
+        alert("The metadata for MochiKit.Async could not be fetched :(");
+    }
+
+    function doSubmit()
+    {
+        /* TODO : Validar datos y evitar el submit si no esta completo */
+
+        /* Selecciono todos los miembros si no, no llegan al controllere*/
+        l = MochiKit.DOM.getElement('form_grupos_to');
+        for (i=0; i<l.options.length; i++) {
+            l.options[i].selected = true;
+        }
+        /* Selecciono todos los miembros si no, no llegan al controllere*/
+        l = MochiKit.DOM.getElement('form_grupos_from');
+        for (i=0; i<l.options.length; i++) {
+            l.options[i].selected = true;
+        }
+
+        return true; // Dejo hacer el submit
+    }
+
+    function initWidgets(disabled) {
+        if ( disabled ) {
+            MochiKit.DOM.getElement('form_listaGrupoA').selectedIndex = 0;
+        }
+        MochiKit.DOM.getElement('form_listaGrupoB').selectedIndex = 0;
+        MochiKit.DOM.getElement('form_grupos_to').options.length = 0;
+        MochiKit.DOM.getElement('form_grupos_from').options.length = 0;
+        MochiKit.DOM.getElement('form_listaGrupoB').disabled = disabled;
+        MochiKit.DOM.getElement('form_grupos_to').disabled = disabled;
+        MochiKit.DOM.getElement('form_grupos_from').disabled = disabled;
+        MochiKit.DOM.getElement('form_tutoresA').disabled = true;
+        MochiKit.DOM.getElement('form_tutoresB').disabled = true;
+        MochiKit.DOM.getElement('form_responsableA').disabled = true;
+        MochiKit.DOM.getElement('form_responsableB').disabled = true;
+    }
+
+    function onListaAChange() {
+        lista = MochiKit.DOM.getElement('form_listaGrupoA');
+        if ( lista.selectedIndex != '0' ) {
+            initWidgets(false);
+        } else {
+            initWidgets(true);
+            return;
+        }
+        // carga el grupo en el multiple select
+        grupoA = MochiKit.DOM.getElement('form_grupos_from');
+        id = lista.options[lista.selectedIndex].value
+        cargarGrupo(id, grupoA);
+    }
+
+    function onListaBChange() {
+        lista = MochiKit.DOM.getElement('form_listaGrupoB');
+        listaA =  MochiKit.DOM.getElement('form_listaGrupoA');
+        MochiKit.DOM.getElement('form_grupos_to').options.length = 0;
+        if ( lista.selectedIndex == 0 ) {
+            return;
+        }
+        if ( lista.selectedIndex != '0' ) {
+            if ( lista.selectedIndex == listaA.selectedIndex ) {
+                window.alert('Debe seleccionar 2 grupos distintos');
+                MochiKit.DOM.getElement('form_grupos_to').options.length = 0;
+                return;
+            }
+            grupoB = MochiKit.DOM.getElement('form_grupos_to');
+            id = lista.options[lista.selectedIndex].value
+            cargarGrupo(id, grupoB);
+        }
+    }
+    
+    function makeOption(option) {
+        return OPTION({"value": option.value}, option.text);
+    }
+
+    function cargarGrupo(grupoid, lista) {
+        var result = loadJSONDoc('/curso/grupo/get_alumnos?grupoid='+id);
+        result.addCallbacks(partial(cargarLista, lista), err)
+    }
+
+    function err (err)
+    {
+        alert("The metadata for MochiKit.Async could not be fetched :(");
+    }
+
+    function cargarLista(lista, result) {
+        var alumnos = result.msg;
+        if (result.error) {
+            window.alert(result.msg);
+            return;
+        }
+        for (i in alumnos) {
+            id = alumnos[i].id;
+            label = alumnos[i].label;
+            MochiKit.DOM.appendChildNodes(lista, OPTION({"value":id}, label))
+        }
+        ActualizarResponsables();
+    }
+
+    function ActualizarResponsables()
+    {
+        replaceChildNodes('form_responsableA', '');
+        replaceChildNodes('form_responsableB', '');
+        appendChildNodes('form_responsableA', map(makeOption, $('form_grupos_from').options));
+        appendChildNodes('form_responsableB', map(makeOption, $('form_grupos_to').options));
+
+        if (getElement('form_grupos_from').options.length == 0) {
+            getElement('form_tutoresA').disabled = true;
+            getElement('form_responsableA').disabled = true;
+        } else {
+            getElement('form_tutoresA').disabled = false;
+            getElement('form_responsableA').disabled = false;
+        }
+        if (getElement('form_grupos_to').options.length == 0) {
+            getElement('form_tutoresB').disabled = true;
+            getElement('form_responsableB').disabled = true;
+        } else {
+            getElement('form_tutoresB').disabled = false;
+            getElement('form_responsableB').disabled = false;
+        }
+    }
+"""
+
+class GrupoAdminForm(W.TableForm):
+    class Fields(W.WidgetsList):
+        cursoID = W.HiddenField()
+        listaGrupoA = W.SingleSelectField(label=_(u'Grupo A'), attrs = dict(onChange='onListaAChange()'), validator = V.Int(not_empty=True))
+        listaGrupoB = W.SingleSelectField(label=_(u'Grupo B'), attrs = dict(onChange='onListaBChange()'), validator = V.Int(not_empty=True))
+        grupos = AjaxDosListasSelect(label=_(u'Grupos'),title_from=u"Grupo A", size=8, move_signal="ActualizarResponsables();", title_to=u"Grupo B", validator=V.Int(not_empty=True))
+        responsableA = W.SingleSelectField(label=_(u'Responsable A'), validator = V.Int())
+        responsableB = W.SingleSelectField(label=_(u'Responsable B'), validator = V.Int())
+        tutoresA = W.MultipleSelectField(label=_(u'Tutores A'), validator = V.Int(not_empty=True))
+        tutoresB = W.MultipleSelectField(label=_(u'Tutores B'), validator = V.Int(not_empty=True))
+
+    fields = Fields()
+    javascript = [W.JSSource("MochiKit.DOM.focusOnLoad('listaGrupoA');"), W.JSSource(ajaxadmin)]
+    form_attrs = dict(onsubmit='return doSubmit();')
+
+formadmin = GrupoAdminForm()
+
 #}}}
 
 #{{{ Controlador
@@ -151,18 +302,20 @@ class GrupoController(controllers.Controller, identity.SecureResource):
         raise redirect(tg.url('/curso/list'))
 
     @expose(template='kid:%s.templates.list' % __name__)
+    @validate(validators=dict(curso=V.Int))
     @paginate('records')
-    def list(self, cursoID):
+    def list(self, curso):
         """List records in model"""
-        r = cls.select(cls.q.cursoID == cursoID)
-        return dict(records=r, name=name, namepl=namepl, cursoID=int(cursoID))
+        r = cls.selectBy(cursoID=curso)
+        return dict(records=r, name=name, namepl=namepl.capitalize(), curso=Curso.get(curso))
 
     @expose(template='kid:%s.templates.new' % __name__)
-    def new(self, cursoID, **kw):
+    @validate(validators=dict(curso=V.Int))
+    def new(self, curso, **kw):
         """Create new records in model"""
-        form.fields[0].attrs['value'] = cursoID
-        form.fields[4].options = get_docentes_inscriptos(cursoID)
-        return dict(name=name, namepl=namepl, cursoID=int(cursoID), form=form, values=kw)
+        kw['cursoID'] = curso # FIXME esto está roto porque los widgets son stateless
+        options = dict(tutores=get_docentes_inscriptos(curso))
+        return dict(name=name, namepl=namepl, form=form, options=options, values=kw)
 
     @validate(form=form)
     @error_handler(new)
@@ -190,7 +343,7 @@ class GrupoController(controllers.Controller, identity.SecureResource):
         # de manera comoda y facil de formatear segun lo que espera la UI (que
         # en este caso es super particular). Ese EmptyClass no se si hay algo estandar
         # en python que usar, puse {} y [] pero cuando quiero hacer values.id = XX explota.
-        form.fields[4].options = get_docentes_inscriptos(r.curso.id)
+        options = dict(tutores=get_docentes_inscriptos(r.curso.id))
         class EmptyClass:
             pass
         values = EmptyClass()
@@ -202,7 +355,7 @@ class GrupoController(controllers.Controller, identity.SecureResource):
             values.responsable = r.responsable.alumno.padron
         values.miembros = [{"id":i.alumno.id, "label":i.alumno.alumno.nombre} for i in filter(lambda x: x.baja is None, r.miembros)]
         values.tutores = [a.docenteID for a in r.tutores]
-        return dict(name=name, namepl=namepl, record=values, form=form)
+        return dict(name=name, namepl=namepl, record=values, options=options, form=form)
 
     @validate(form=form)
     @error_handler(edit)
@@ -276,5 +429,135 @@ class GrupoController(controllers.Controller, identity.SecureResource):
             integrantes = []
             integrantes.append(msg)
         return dict(msg=integrantes, error=error)
+
+    @expose(template='kid:%s.templates.admin' % __name__)
+    def admin(self, cursoID, **kw):
+        """Create new records in model"""
+        options = dict(
+            listaGrupoA=get_gruposA(cursoID),
+            listaGrupoB=get_gruposB(cursoID),
+            tutoresA=get_docentes_inscriptos(cursoID),
+            tutoresB=get_docentes_inscriptos(cursoID),
+        )
+        kw['cursoID'] = cursoID
+        return dict(name=name, namepl=namepl, options=options, form=formadmin, values=kw, cursoID=int(cursoID))
+
+    @validate(form=formadmin)
+    @error_handler(admin)
+    @expose()
+    def adminupdate(self, **kw):
+        """Save or create record to model"""
+        cursoID = int(kw['cursoID'])
+        log.debug(kw)
+        grupoAId = kw['listaGrupoA']
+        grupoBId = kw['listaGrupoB']
+        miembrosA = kw.get('grupos_from', [])
+        miembrosB = kw.get('grupos_to', [])
+        responsableA = kw['responsableA']
+        responsableB = kw['responsableB']
+        tutoresA = kw.get('tutoresA', [])
+        tutoresB = kw.get('tutoresB', [])
+
+        # por las dudas de que no sea una lista
+        if not isinstance(miembrosA, list):
+            miembrosA = [miembrosA]
+        if not isinstance(miembrosB, list):
+            miembrosB = [miembrosB]
+        if not isinstance(tutoresA, list):
+            tutoresA = [tutoresA]
+        if not isinstance(tutoresB, list):
+            tutoresB = [tutoresB]
+
+
+        """ levanto los grupos originales """
+        grupoAorig = validate_get(int(grupoAId))
+        log.debug(miembrosA)
+        log.debug(Miembro.selectBy(grupo=grupoAorig, baja=None))
+        """ Si el grupo A quedo vacio deberia eliminarlo (primero
+            genero los otros para que no elimine los alumnos)"""
+        for mA in Miembro.selectBy(grupo=grupoAorig, baja=None):
+            if str(mA.alumno.id) not in miembrosA:
+                grupoAorig.remove_miembro(mA.alumno.id)
+
+        try:
+            grupoA = validate_get(grupoAId)
+            for a in miembrosA:
+                try:
+                    grupoA.add_miembro(a, baja=None)
+                except DuplicateEntryError:
+                    continue
+        except Exception, e:
+            log.debug(e)
+            flash(_(u'Error A %s.' % e))
+            raise redirect(url('/curso/grupo/list' % int(cursoID)))
+        # seteo el reponsable del grupo
+        if responsableA and int(responsableA) != 0:
+            grupoA.responsable = AlumnoInscripto.get(int(responsableA))
+
+        for t in tutoresA:
+            try:
+                grupoA.add_tutor(int(t))
+            except:
+                #TODO ver por que no anda el duplicate error, por ahora cacheo silencioso
+                pass
+
+
+        #Elimino el grupo si quedo vacio
+        if len(miembrosA) == 0:
+            try:
+                validate_del(grupoAId)
+            except:
+                pass
+
+        # si se selecciono un grupo nuevo
+        if int(grupoBId) == 0:
+            # creo un grupo nuevo
+            nuevosMiembros = []
+            for m in miembrosB:
+                nuevosMiembros.append(AlumnoInscripto.get(int(m)))
+            nuevosTutores = []
+            for t in tutoresB:
+                nuevosTutores.append(DocenteInscripto.get(t))
+            #Creo el nuevo grupo
+            Grupo(miembros = nuevosMiembros, tutores = nuevosTutores, cursoID=cursoID, nombre='NuevoGrupo'+str(cursoID))
+        else:
+            grupoBorig = validate_get(int(grupoBId))
+            log.debug(miembrosB)
+            b = list(Miembro.selectBy(grupo=grupoBorig, baja=None))
+            log.debug(b)
+            #borro todos y los vuelvo a agregar
+            for mB in Miembro.selectBy(grupo=grupoBorig, baja=None):
+                if str(mB.alumno.id) not in miembrosB:
+                    grupoBorig.remove_miembro(mB.alumno.id)
+            try:
+                grupoB = validate_get(grupoBId)
+                for b in miembrosB:
+                    try:
+                        grupoB.add_miembro(b, baja=None)
+                    except DuplicateEntryError:
+                        continue
+            except Exception, e:
+                log.debug(e)
+                flash(_(u'Error B %s.' % e))
+                raise redirect(url('/curso/grupo/list/%d' % int(cursoID)))
+            # seteo el reponsable del grupo
+            if responsableB and int(responsableB) != 0:
+                grupoB.responsable = AlumnoInscripto.get(int(responsableB))
+
+            #Elimino el grupo si quedo vacio
+            if len(miembrosB) == 0:
+                try:
+                    validate_del(grupoBId)
+                except:
+                    pass
+
+            for t in tutoresB:
+                try:
+                    grupoB.add_tutor(int(t))
+                except:
+                    #TODO ver por que no anda el duplicate error, por ahora cahceo silencioso
+                    pass
+        flash(_(u'Los grupos fueron actualizado.'))
+        raise redirect(url('/curso/grupo/list/%d' % int(cursoID)))
 #}}}