]> git.llucax.com Git - z.facultad/75.52/sercom.git/blob - sercom/subcontrollers/curso/grupo/__init__.py
dc162383886cd68abe5664ab61f20d73e4182886
[z.facultad/75.52/sercom.git] / sercom / subcontrollers / curso / grupo / __init__.py
1 # vim: set et sw=4 sts=4 encoding=utf-8 foldmethod=marker :
2
3 #{{{ Imports
4 import cherrypy
5 from turbogears import controllers, expose, redirect
6 from turbogears import validate, flash, error_handler
7 from turbogears import validators as V
8 from turbogears import widgets as W
9 from turbogears import identity
10 from turbogears import paginate, url
11 from docutils.core import publish_parts
12 from sercom.subcontrollers import validate as val
13 from sercom.model import Curso, AlumnoInscripto, Docente, DocenteInscripto, Grupo, Alumno, Miembro
14 from sqlobject import *
15
16 from sercom.widgets import *
17
18 import logging
19
20 log = logging.getLogger('sercom.curso.grupo.admin')
21
22 #}}}
23
24 #{{{ Configuración
25 cls = Grupo
26 name = 'grupo'
27 namepl = 'grupos'
28 #}}}
29
30 #{{{ Validación
31 def validate_get(id):
32     return val.validate_get(cls, name, id)
33
34 def validate_set(id, data):
35     return val.validate_set(cls, name, id, data)
36
37 def validate_new(data):
38     return val.validate_new(cls, name, data)
39
40 def validate_del(id):
41     return val.validate_del(cls, name, id)
42 #}}}
43
44 #{{{ Formulario
45 def get_docentes():
46     return [(fk1.id, fk1.shortrepr()) for fk1 in Docente.select()]
47
48 def get_docentes_inscriptos(id):
49     return [(fk1.id, fk1.shortrepr()) for fk1 in DocenteInscripto.select(DocenteInscripto.q.cursoID==id)]
50
51 ajax = u"""
52     function alumnos_agregar_a_la_lista(texto, lista)
53     {
54         t = MochiKit.DOM.getElement(texto);
55
56         curso = MochiKit.DOM.getElement('form_cursoID');
57         if (!curso) {
58             alert("No deberias ver esto, y quiere decir que tu form esta roto.\\nTe falta un combo de curso");
59             return;
60         }
61         if (curso.value <= 0) {
62             alert('Debes seleccionar un curso primero');
63             return;
64         }
65         url = "/curso/grupo/get_inscripto?cursoid="+curso.value+"&padron="+t.value;
66         t.value = "";
67         return url;
68     }
69
70     function err (err)
71     {
72         alert("The metadata for MochiKit.Async could not be fetched :(");
73     }
74
75     function procesar(result)
76     {
77         l = MochiKit.DOM.getElement('form_responsable_info');
78         if (result.error)
79             l.innerHTML = result.msg;
80         else
81             l.innerHTML = result.msg.value;
82     }
83
84     function buscar_alumno()
85     {
86         /* Obtengo el padron ingresado */
87         p = MochiKit.DOM.getElement('form_responsable');
88         padron = p.value;
89         if (padron == '') {
90             return;
91         }
92         /* Obtengo el curso */
93         l = MochiKit.DOM.getElement('form_cursoID');
94         cursoid = l.value;
95         if (cursoid <= 0) {
96             alert('Debe seleccionar un curso');
97             return;
98         }
99         url = "/curso/grupo/get_inscripto?cursoid="+cursoid+'&padron='+padron;
100         var d = loadJSONDoc(url);
101         d.addCallbacks(procesar, err);
102     }
103
104     function prepare()
105     {
106         connect('form_responsable', 'onblur', buscar_alumno);
107     }
108
109     function doSubmit()
110     {
111         /* TODO : Validar datos y evitar el submit si no esta completo */
112
113         /* Selecciono todos los miembros si no, no llegan al controllere*/
114         l = MochiKit.DOM.getElement('form_miembros');
115         for (i=0; i<l.options.length; i++) {
116             l.options[i].selected = true;
117         }
118         return true; // Dejo hacer el submit
119     }
120
121     MochiKit.DOM.addLoadEvent(prepare)
122
123 """
124
125 class GrupoForm(W.TableForm):
126     class Fields(W.WidgetsList):
127         cursoID = W.HiddenField()
128         nombre = W.TextField(label=_(u'Nombre'), validator=V.UnicodeString(not_empty=True,strip=True))
129         responsable = CustomTextField(label=_(u'Responsable'), validator=V.UnicodeString(), attrs=dict(size='8'))
130         miembros = AjaxMultiSelect(label=_(u'Miembros'), validator=V.Int(), on_add="alumnos_agregar_a_la_lista")
131         tutores = W.MultipleSelectField(label=_(u'Tutores'), validator=V.Int())
132
133     fields = Fields()
134     javascript = [W.JSSource("MochiKit.DOM.focusOnLoad('form_nombre');"), W.JSSource(ajax)]
135     form_attrs = dict(onsubmit='return doSubmit()')
136
137 form = GrupoForm()
138
139 def get_gruposA(cursoID):
140     return [(0, u'---')] + [(g.id, g.shortrepr()) for g in Grupo.select(Grupo.q.cursoID==cursoID)]
141
142 def get_gruposB(cursoID):
143     return [(0, u'Nuevo Grupo')] + [(g.id, g.shortrepr()) for g in Grupo.select(Grupo.q.cursoID==cursoID)]
144
145 ajaxadmin = u"""
146     function alumnos_agregar_a_la_lista(texto, lista)
147     {
148         t = MochiKit.DOM.getElement(texto);
149
150         url = "/alumno/get_alumno?padron="+t.value;
151         t.value = "";
152         return url;
153     }
154
155     function err (err)
156     {
157         alert("The metadata for MochiKit.Async could not be fetched :(");
158     }
159
160     function procesar(result)
161     {
162         l = MochiKit.DOM.getElement('form_responsable_info');
163         if (result.error)
164             l.innerHTML = result.msg;
165         else
166             l.innerHTML = result.msg.value;
167     }
168
169     function doSubmit()
170     {
171         /* TODO : Validar datos y evitar el submit si no esta completo */
172
173         /* Selecciono todos los miembros si no, no llegan al controllere*/
174         l = MochiKit.DOM.getElement('form_grupos_to');
175         for (i=0; i<l.options.length; i++) {
176             l.options[i].selected = true;
177         }
178         /* Selecciono todos los miembros si no, no llegan al controllere*/
179         l = MochiKit.DOM.getElement('form_grupos_from');
180         for (i=0; i<l.options.length; i++) {
181             l.options[i].selected = true;
182         }
183
184         return true; // Dejo hacer el submit
185     }
186
187     function initWidgets(disabled) {
188         if ( disabled ) {
189             MochiKit.DOM.getElement('form_listaGrupoA').selectedIndex = 0;
190         }
191         MochiKit.DOM.getElement('form_listaGrupoB').selectedIndex = 0;
192         MochiKit.DOM.getElement('form_grupos_to').options.length = 0;
193         MochiKit.DOM.getElement('form_grupos_from').options.length = 0;
194         MochiKit.DOM.getElement('form_listaGrupoB').disabled = disabled;
195         MochiKit.DOM.getElement('form_grupos_to').disabled = disabled;
196         MochiKit.DOM.getElement('form_grupos_from').disabled = disabled;
197     }
198
199     function onListaAChange() {
200         lista = MochiKit.DOM.getElement('form_listaGrupoA');
201         if ( lista.selectedIndex != '0' ) {
202             initWidgets(false);
203         } else {
204             initWidgets(true);
205             return;
206         }
207         // carga el grupo en el multiple select
208         grupoA = MochiKit.DOM.getElement('form_grupos_from');
209         id = lista.options[lista.selectedIndex].value
210         cargarGrupo(id, grupoA);
211         //carga la lista para seleccionar un responsable
212         responsableA = MochiKit.DOM.getElement('form_responsableA');
213         responsableA.options.length = 0;
214         MochiKit.DOM.appendChildNodes(responsableA, OPTION({"value":0}, "---"));
215         cargarGrupo(id, responsableA);
216     }
217
218     function onListaBChange() {
219         lista = MochiKit.DOM.getElement('form_listaGrupoB');
220         listaA =  MochiKit.DOM.getElement('form_listaGrupoA');
221         MochiKit.DOM.getElement('form_grupos_to').options.length = 0;
222         if ( lista.selectedIndex == 0 ) {
223             return;
224         }
225         if ( lista.selectedIndex != '0' ) {
226             if ( lista.selectedIndex == listaA.selectedIndex ) {
227                 window.alert('Debe seleccionar 2 grupos distintos');
228                 MochiKit.DOM.getElement('form_grupos_to').options.length = 0;
229                 return;
230             }
231             grupoB = MochiKit.DOM.getElement('form_grupos_to');
232             id = lista.options[lista.selectedIndex].value
233             cargarGrupo(id, grupoB);
234
235             //carga la lista para seleccionar un responsable
236             responsableB = MochiKit.DOM.getElement('form_responsableB');
237             responsableB.options.length = 0;
238             MochiKit.DOM.appendChildNodes(responsableB, OPTION({"value":0}, "---"));
239             cargarGrupo(id, responsableB);
240         }
241     }
242
243     function cargarGrupo(grupoid, lista) {
244         //url = "/grupo/get_inscripto?cursoid="+cursoid+'&padron='+padron
245         var result = loadJSONDoc('/curso/grupo/get_alumnos?grupoid='+id);
246         result.addCallbacks(partial(cargarLista, lista), err)
247     }
248
249     function err (err)
250     {
251         alert("The metadata for MochiKit.Async could not be fetched :(");
252     }
253
254     function cargarLista(lista, result) {
255         var alumnos = result.msg;
256         if (result.error) {
257             window.alert(result.msg);
258             return;
259         }
260         for (i in alumnos) {
261             id = alumnos[i].id;
262             label = alumnos[i].label;
263             MochiKit.DOM.appendChildNodes(lista, OPTION({"value":id}, label))
264         }
265     }
266
267 """
268
269 class GrupoAdminForm(W.TableForm):
270     class Fields(W.WidgetsList):
271         cursoID = W.HiddenField()
272         listaGrupoA = W.SingleSelectField(label=_(u'Grupo A'), attrs = dict(onChange='onListaAChange()'), validator = V.Int(not_empty=True))
273         listaGrupoB = W.SingleSelectField(label=_(u'Grupo B'), attrs = dict(onChange='onListaBChange()'), validator = V.Int(not_empty=True))
274         grupos = AjaxDosListasSelect(label=_(u'Grupos'),title_from=u"Grupo A", size=8, title_to=u"Grupo B", validator=V.Int(not_empty=True))
275         responsableA = W.SingleSelectField(label=_(u'Responsable A'), validator = V.Int())
276         responsableB = W.SingleSelectField(label=_(u'Responsable B'), validator = V.Int())
277         tutoresA = W.MultipleSelectField(label=_(u'Tutores A'), validator = V.Int(not_empty=True))
278         tutoresB = W.MultipleSelectField(label=_(u'Tutores B'), validator = V.Int(not_empty=True))
279
280     fields = Fields()
281     javascript = [W.JSSource("MochiKit.DOM.focusOnLoad('listaGrupoA');"), W.JSSource(ajaxadmin)]
282     form_attrs = dict(onsubmit='return doSubmit();')
283
284 formadmin = GrupoAdminForm()
285
286 #}}}
287
288 #{{{ Controlador
289 class GrupoController(controllers.Controller, identity.SecureResource):
290     """Basic model admin interface"""
291     require = identity.has_permission('admin')
292
293     @expose()
294     def default(self, tg_errors=None):
295         """handle non exist urls"""
296         raise redirect(tg.url('/curso/list'))
297
298     @expose()
299     def index(self):
300         raise redirect(tg.url('/curso/list'))
301
302     @expose(template='kid:%s.templates.list' % __name__)
303     @paginate('records')
304     def list(self, cursoID):
305         """List records in model"""
306         r = cls.select(cls.q.cursoID == cursoID)
307         return dict(records=r, name=name, namepl=namepl, cursoID=int(cursoID))
308
309     @expose(template='kid:%s.templates.new' % __name__)
310     def new(self, cursoID, **kw):
311         """Create new records in model"""
312         form.fields[0].attrs['value'] = cursoID
313         options = dict(tutores=get_docentes_inscriptos(cursoID))
314         return dict(name=name, namepl=namepl, cursoID=int(cursoID), form=form, options=options, values=kw)
315
316     @validate(form=form)
317     @error_handler(new)
318     @expose()
319     def create(self, **kw):
320         """Save or create record to model"""
321         resp = kw['responsable']
322         try:
323             # Busco el alumno inscripto
324             resp = AlumnoInscripto.selectBy(cursoID=kw['cursoID'],
325                 alumno=Alumno.byPadron(kw['responsable'])).getOne()
326         except SQLObjectNotFound:
327             resp = None
328         kw['responsable'] = resp
329
330         r = validate_new(kw)
331         flash(_(u'Se creó un nuevo %s.') % name)
332         raise redirect('list/%d' % int(kw['cursoID']))
333
334     @expose(template='kid:%s.templates.edit' % __name__)
335     def edit(self, id, **kw):
336         """Edit record in model"""
337         r = validate_get(id)
338         # TODO : No encontre mejor forma de pasar cosas al form
339         # de manera comoda y facil de formatear segun lo que espera la UI (que
340         # en este caso es super particular). Ese EmptyClass no se si hay algo estandar
341         # en python que usar, puse {} y [] pero cuando quiero hacer values.id = XX explota.
342         options = dict(tutores=get_docentes_inscriptos(r.curso.id))
343         class EmptyClass:
344             pass
345         values = EmptyClass()
346         values.id = r.id
347         values.cursoID = r.cursoID
348         values.nombre = r.nombre
349         # TODO : Ver como llenar la lista primero :S
350         if r.responsable:
351             values.responsable = r.responsable.alumno.padron
352         values.miembros = [{"id":i.alumno.id, "label":i.alumno.alumno.nombre} for i in filter(lambda x: x.baja is None, r.miembros)]
353         values.tutores = [a.docenteID for a in r.tutores]
354         return dict(name=name, namepl=namepl, record=values, options=options, form=form)
355
356     @validate(form=form)
357     @error_handler(edit)
358     @expose()
359     def update(self, id, **kw):
360         """Save or create record to model"""
361         responsable = kw['responsable']
362         curso = kw['cursoID']
363         resp = kw['responsable']
364         try:
365             # Busco el alumno inscripto
366             resp = AlumnoInscripto.selectBy(cursoID=kw['cursoID'],
367                 alumno=Alumno.byPadron(kw['responsable'])).getOne()
368         except SQLObjectNotFound:
369             resp = None
370         kw['responsable'] = resp
371         r = validate_set(id, kw)
372         flash(_(u'El %s fue actualizado.') % name)
373         raise redirect('../list/%d' % r.curso.id)
374
375     @expose(template='kid:%s.templates.show' % __name__)
376     def show(self,id, **kw):
377         """Show record in model"""
378         r = validate_get(id)
379         return dict(name=name, namepl=namepl, record=r)
380
381     @expose()
382     def delete(self, cursoID, id):
383         """Destroy record in model"""
384         validate_del(id)
385         flash(_(u'El %s fue eliminado permanentemente.') % name)
386         raise redirect('../../list/%d' % int(cursoID))
387
388     @expose('json')
389     def get_inscripto(self, cursoid, padron):
390         msg = u''
391         error=False
392         try:
393             # Busco el alumno inscripto
394             alumno = AlumnoInscripto.selectBy(curso=cursoid, alumno=Alumno.byUsuario(padron)).getOne()
395             msg = {}
396             msg['id'] = alumno.id
397             msg['value'] = alumno.alumno.nombre
398         except SQLObjectNotFound:
399             msg = 'No existe el alumno %s en el curso seleccionado.' % padron
400             error=True
401         except Exception, (inst):
402             msg = u"""Se ha producido un error inesperado al buscar el registro:\n      %s""" % str(inst)
403             error = True
404         return dict(msg=msg, error=error)
405
406     @expose('json')
407     def get_alumnos(self, grupoid):
408         msg = u''
409         error=False
410         try:
411             # Busco los alumnos del grupo
412             grupo = Grupo.get(int(grupoid))
413             miembros = Miembro.selectBy(baja=None, grupo=grupo)
414             print miembros
415             integrantes = []
416             for m in miembros:
417                 msg = {}
418                 alumnoInscripto = AlumnoInscripto.get(m.alumno.id)
419                 msg['id'] = alumnoInscripto.id
420                 msg['label'] = alumnoInscripto.shortrepr()
421                 integrantes.append(msg)
422         except Exception, (inst):
423             msg = u"""Se ha producido un error inesperado al buscar el registro:\n      %s""" % str(inst)
424             error = True
425             integrantes = []
426             integrantes.append(msg)
427         return dict(msg=integrantes, error=error)
428
429     @expose(template='kid:%s.templates.admin' % __name__)
430     def admin(self, cursoID, **kw):
431         """Create new records in model"""
432         options = dict(
433             listaGrupoA=get_gruposA(cursoID),
434             listaGrupoB=get_gruposB(cursoID),
435             tutoresA=get_docentes_inscriptos(cursoID),
436             tutoresB=get_docentes_inscriptos(cursoID),
437         )
438         kw['cursoID'] = cursoID
439         return dict(name=name, namepl=namepl, options=options, form=formadmin, values=kw, cursoID=int(cursoID))
440
441     @validate(form=formadmin)
442     @error_handler(admin)
443     @expose()
444     def adminupdate(self, **kw):
445         """Save or create record to model"""
446         cursoID = int(kw['cursoID'])
447         log.debug(kw)
448         grupoAId = kw['listaGrupoA']
449         grupoBId = kw['listaGrupoB']
450         miembrosA = kw.get('grupos_from', [])
451         miembrosB = kw.get('grupos_to', [])
452         responsableA = kw['responsableA']
453         responsableB = kw['responsableB']
454         tutoresA = kw.get('tutoresA', [])
455         tutoresB = kw.get('tutoresB', [])
456
457         # por las dudas de que no sea una lista
458         if not isinstance(miembrosA, list):
459             miembrosA = [miembrosA]
460         if not isinstance(miembrosB, list):
461             miembrosB = [miembrosB]
462         if not isinstance(tutoresA, list):
463             tutoresA = [tutoresA]
464         if not isinstance(tutoresB, list):
465             tutoresB = [tutoresB]
466
467
468         """ levanto los grupos originales """
469         grupoAorig = validate_get(int(grupoAId))
470         log.debug(miembrosA)
471         log.debug(Miembro.selectBy(grupo=grupoAorig, baja=None))
472         """ Si el grupo A quedo vacio deberia eliminarlo (primero
473             genero los otros para que no elimine los alumnos)"""
474         for mA in Miembro.selectBy(grupo=grupoAorig, baja=None):
475             if str(mA.alumno.id) not in miembrosA:
476                 grupoAorig.remove_miembro(mA.alumno.id)
477
478         try:
479             grupoA = validate_get(grupoAId)
480             for a in miembrosA:
481                 try:
482                     grupoA.add_miembro(a, baja=None)
483                 except DuplicateEntryError:
484                     continue
485         except Exception, e:
486             log.debug(e)
487             flash(_(u'Error A %s.' % e))
488             raise redirect(url('/curso/grupo/list' % int(cursoID)))
489         # seteo el reponsable del grupo
490         if int(responsableA) != 0:
491             grupoA.responsable = AlumnoInscripto.get(int(responsableA))
492
493         for t in tutoresA:
494             try:
495                 grupoA.add_tutor(int(t))
496             except:
497                 #TODO ver por que no anda el duplicate error, por ahora cacheo silencioso
498                 pass
499
500
501         #Elimino el grupo si quedo vacio
502         if len(miembrosA) == 0:
503             try:
504                 validate_del(grupoAId)
505             except:
506                 pass
507
508         # si se selecciono un grupo nuevo
509         if int(grupoBId) == 0:
510             # creo un grupo nuevo
511             nuevosMiembros = []
512             for m in miembrosB:
513                 nuevosMiembros.append(AlumnoInscripto.get(int(m)))
514             nuevosTutores = []
515             for t in tutoresB:
516                 nuevosTutores.append(Docente.get(t))
517             #Creo el nuevo grupo
518             Grupo(miembros = nuevosMiembros, tutores = nuevosTutores, cursoID=cursoID, nombre='NuevoGrupo'+str(cursoID))
519         else:
520             grupoBorig = validate_get(int(grupoBId))
521             log.debug(miembrosB)
522             b = list(Miembro.selectBy(grupo=grupoBorig, baja=None))
523             log.debug(b)
524             #borro todos y los vuelvo a agregar
525             for mB in Miembro.selectBy(grupo=grupoBorig, baja=None):
526                 if str(mB.alumno.id) not in miembrosB:
527                     grupoBorig.remove_miembro(mB.alumno.id)
528             try:
529                 grupoB = validate_get(grupoBId)
530                 for b in miembrosB:
531                     try:
532                         grupoB.add_miembro(b, baja=None)
533                     except DuplicateEntryError:
534                         continue
535             except Exception, e:
536                 log.debug(e)
537                 flash(_(u'Error B %s.' % e))
538                 raise redirect(url('/curso/grupo/list/%d' % int(cursoID)))
539             # seteo el reponsable del grupo
540             if int(responsableB) != 0:
541                 grupoB.responsable = AlumnoInscripto.get(int(responsableB))
542
543             #Elimino el grupo si quedo vacio
544             if len(miembrosB) == 0:
545                 try:
546                     validate_del(grupoBId)
547                 except:
548                     pass
549
550             for t in tutoresB:
551                 try:
552                     grupoB.add_tutor(int(t))
553                 except:
554                     #TODO ver por que no anda el duplicate error, por ahora cahceo silencioso
555                     pass
556         flash(_(u'Los grupos fueron actualizado.'))
557         raise redirect(url('/curso/grupo/list/%d' % int(cursoID)))
558 #}}}
559