1 # vim: set et sw=4 sts=4 encoding=utf-8 foldmethod=marker :
5 from turbogears import controllers, expose, redirect, url
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
11 from docutils.core import publish_parts
12 from sercom.subcontrollers import validate as val
13 from sercom.model import ComandoEjecutado, ComandoPruebaEjecutado, Entrega, Correccion, Curso, Ejercicio, InstanciaDeEntrega, Grupo, Miembro, AlumnoInscripto
14 from sqlobject import *
15 from zipfile import ZipFile, BadZipfile
16 from cStringIO import StringIO
28 return val.validate_get(cls, name, id)
30 def validate_set(id, data):
31 return val.validate_set(cls, name, id, data)
33 def validate_new(data):
34 return val.validate_new(cls, name, data)
37 def get_ejercicios_activos():
38 # TODO : Mostrar solo los ejercicios con instancias de entrega activos
39 return [(0, _(u'--'))] + [(a.id, a.shortrepr()) for a in (Ejercicio.select(
40 AND(Ejercicio.q.id==InstanciaDeEntrega.q.ejercicioID, InstanciaDeEntrega.q.inicio <= DateTimeCol.now(),
41 InstanciaDeEntrega.q.fin >= DateTimeCol.now())))]
44 function clearInstancias ()
46 l = MochiKit.DOM.getElement('form_instancia');
51 function mostrarInstancias(res)
54 for(i=0; i < res.instancias.length; i++) {
55 id = res.instancias[i].id;
56 label = res.instancias[i].numero;
57 MochiKit.DOM.appendChildNodes("form_instancia", OPTION({"value":id}, label))
59 if (l.options.length > 0)
65 alert("The metadata for MochiKit.Async could not be fetched :(");
68 function actualizar_instancias ()
70 l = MochiKit.DOM.getElement('form_ejercicio');
71 id = l.options[l.selectedIndex].value;
77 url = "/mis_entregas/instancias?ejercicio_id="+id;
78 var d = loadJSONDoc(url);
79 d.addCallbacks(mostrarInstancias, err);
84 connect('form_ejercicio', 'onchange', actualizar_instancias);
88 MochiKit.DOM.addLoadEvent(prepare)
91 class EntregaForm(W.TableForm):
92 class Fields(W.WidgetsList):
93 ejercicio = W.SingleSelectField(label=_(u'Ejercicio'),
94 options=get_ejercicios_activos, validator=V.Int(not_empty=True))
95 instancia = W.SingleSelectField(label=_(u'Instancia de Entrega'), validator=V.Int(not_empty=True))
96 archivo = W.FileField(label=_(u'Archivo'), help_text=_(u'Archivo en formaro ZIP con tu entrega'))
98 javascript = [W.JSSource("MochiKit.DOM.focusOnLoad('form_ejercicio');"), W.JSSource(ajax)]
105 class MisEntregasController(controllers.Controller, identity.SecureResource):
106 """Basic model admin interface"""
107 require = identity.has_permission('entregar')
112 def default(self, tg_errors=None):
113 """handle non exist urls"""
114 raise redirect('list')
118 raise redirect('list')
120 @expose(template='kid:%s.templates.list' % __name__)
123 """List records in model"""
124 # Un admin no tiene sentido en este area y por las dudas
126 if 'admin' in identity.current.permissions:
127 raise redirect(url("/dashboard"))
129 # Grupos en los que el usuario formo parte
130 m = [i.grupo.id for i in Grupo.selectByAlumno(identity.current.user)]
132 entregador = AlumnoInscripto.selectByAlumno(identity.current.user)
133 m.append(entregador.id)
136 r = cls.select(IN(cls.q.entregadorID, m))
137 return dict(records=r, name=name, namepl=namepl)
139 @expose(template='kid:%s.templates.new' % __name__)
141 """Create new records in model"""
142 return dict(name=name, namepl=namepl, form=form, values=kw)
147 def create(self, archivo, ejercicio, **kw):
148 """Save or create record to model"""
149 archivo = archivo.file.read()
151 zfile = ZipFile(StringIO(archivo), 'r')
153 flash(_(u'El archivo ZIP no es válido'))
154 raise redirect('list')
155 if zfile.testzip() is not None:
156 flash(_(u'El archivo ZIP tiene errores de CRC'))
157 raise redirect('list')
159 # por defecto el entregador es el user loggeado
160 entregador = AlumnoInscripto.selectByAlumno(identity.current.user)
162 ejercicio = Ejercicio.get(int(ejercicio))
164 # Como es grupal, tengo que hacer que la entrega la haga
165 # mi grupo y no yo personalmente. Busco el grupo
168 # Con esto obtengo todos los grupos a los que pertenece el Alumno
169 # y que estan activos
171 # TODO : Falta filtrar por curso!!
174 Miembro.q.alumnoID == AlumnoInscripto.q.id,
175 AlumnoInscripto.q.alumnoID == identity.current.user.id,
176 Miembro.q.baja == None
180 flash(_(u'No puedes realizar la entrega ya que el ejercicio es Grupal y no perteneces a ningún grupo.'))
181 raise redirect('list')
184 kw['archivos'] = archivo
185 kw['entregador'] = entregador
187 flash(_(u'Se creó una nueva %s.') % name)
188 raise redirect('list')
190 @expose(template='kid:%s.templates.corrida' % __name__)
191 def corrida(self, entregaid):
192 e = validate_get(entregaid)
193 return dict(entrega=e)
196 def get_archivo(self, entregaid):
197 from cherrypy import request, response
198 r = validate_get(entregaid)
199 response.headers["Content-Type"] = "application/zip"
200 response.headers["Content-disposition"] = "attachment;filename=Ej_%s-Entrega_%s-%s.zip" % (r.instancia.ejercicio.numero, r.instancia.numero, r.entregador.nombre)
205 from cherrypy import request, response
206 r = ComandoEjecutado.get(id)
207 response.headers["Content-Type"] = "application/zip"
208 response.headers["Content-disposition"] = "attachment;filename=comando_ejecutado_%d.zip" % (r.id)
213 from cherrypy import request, response
214 r = ComandoEjecutado.get(id)
215 response.headers["Content-Type"] = "application/zip"
216 response.headers["Content-disposition"] = "attachment;filename=diferencias_%d.zip" % (r.id)
219 @expose(template='kid:%s.templates.diff' % __name__)
220 def verdiff(self, id):
221 r = ComandoEjecutado.get(id)
222 zip = ZipFile(StringIO(r.diferencias), 'r')
226 def instancias(self, ejercicio_id):
227 instancias = InstanciaDeEntrega.select(AND(
228 InstanciaDeEntrega.q.ejercicioID == ejercicio_id,
229 InstanciaDeEntrega.q.activo == True,
230 InstanciaDeEntrega.q.inicio <= DateTimeCol.now(),
231 InstanciaDeEntrega.q.fin >= DateTimeCol.now()))
232 return dict(instancias=instancias)