]> git.llucax.com Git - software/sercom.git/blob - sercom/subcontrollers/misentregas/__init__.py
Bugfix: faltó el validator :S
[software/sercom.git] / sercom / subcontrollers / misentregas / __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, 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
17
18 #}}}
19
20 #{{{ Configuración
21 cls = Entrega
22 name = 'entrega'
23 namepl = name + 's'
24 #}}}
25
26 #{{{ Validación
27 def validate_get(id):
28     return val.validate_get(cls, name, id)
29
30 def validate_set(id, data):
31     return val.validate_set(cls, name, id, data)
32
33 def validate_new(data):
34     return val.validate_new(cls, name, data)
35 #}}}
36
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())))]
42
43 ajax = """
44     function clearInstancias ()
45     {
46         l = MochiKit.DOM.getElement('form_instancia');
47         l.options.length = 0;
48         l.disabled = true;
49     }
50
51     function mostrarInstancias(res)
52     {
53         clearInstancias();
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))
58         }
59         if (l.options.length > 0)
60             l.disabled = false;
61     }
62
63     function err (err)
64     {
65         alert("The metadata for MochiKit.Async could not be fetched :(");
66     }
67
68     function actualizar_instancias ()
69     {
70         l = MochiKit.DOM.getElement('form_ejercicio');
71         id = l.options[l.selectedIndex].value;
72         if (id == 0) {
73             clearInstancias();
74             return;
75         }
76
77         url = "/mis_entregas/instancias?ejercicio_id="+id;
78         var d = loadJSONDoc(url);
79         d.addCallbacks(mostrarInstancias, err);
80     }
81
82     function prepare()
83     {
84         connect('form_ejercicio', 'onchange', actualizar_instancias);
85         clearInstancias();
86     }
87
88     MochiKit.DOM.addLoadEvent(prepare)
89 """
90 #{{{ Formulario
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'))
97     fields = Fields()
98     javascript = [W.JSSource("MochiKit.DOM.focusOnLoad('form_ejercicio');"), W.JSSource(ajax)]
99
100 form = EntregaForm()
101
102 #}}}
103
104 #{{{ Controlador
105 class MisEntregasController(controllers.Controller, identity.SecureResource):
106     """Basic model admin interface"""
107     require = identity.has_permission('entregar')
108
109     hide_to_admin = 1
110
111     @expose()
112     def default(self, tg_errors=None):
113         """handle non exist urls"""
114         raise redirect('list')
115
116     @expose()
117     def index(self):
118         raise redirect('list')
119
120     @expose(template='kid:%s.templates.list' % __name__)
121     @paginate('records')
122     def list(self):
123         """List records in model"""
124         # Un admin no tiene sentido en este area y por las dudas
125         # lo mando al home.
126         if 'admin' in identity.current.permissions:
127             raise redirect(url("/dashboard"))
128
129         # Grupos en los que el usuario formo parte
130         m = [i.grupo.id for i in Grupo.selectByAlumno(identity.current.user)]
131         try:
132             entregador = AlumnoInscripto.selectByAlumno(identity.current.user)
133             m.append(entregador.id)
134         except:
135             pass
136         r = cls.select(IN(cls.q.entregadorID, m))
137         return dict(records=r, name=name, namepl=namepl)
138
139     @expose(template='kid:%s.templates.new' % __name__)
140     def new(self, **kw):
141         """Create new records in model"""
142         return dict(name=name, namepl=namepl, form=form, values=kw)
143
144     @validate(form=form)
145     @error_handler(new)
146     @expose()
147     def create(self, archivo, ejercicio, **kw):
148         """Save or create record to model"""
149         archivo = archivo.file.read()
150         try:
151             zfile = ZipFile(StringIO(archivo), 'r')
152         except BadZipfile:
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')
158
159         # por defecto el entregador es el user loggeado
160         entregador = AlumnoInscripto.selectByAlumno(identity.current.user)
161
162         ejercicio = Ejercicio.get(int(ejercicio))
163         if ejercicio.grupal:
164             # Como es grupal, tengo que hacer que la entrega la haga
165             # mi grupo y no yo personalmente. Busco el grupo
166             # activo.
167
168             # Con esto obtengo todos los grupos a los que pertenece el Alumno
169             # y que estan activos
170             try:
171                 # TODO : Falta filtrar por curso!!
172                 m = Miembro.select(
173                     AND(
174                         Miembro.q.alumnoID == AlumnoInscripto.q.id,
175                         AlumnoInscripto.q.alumnoID == identity.current.user.id,
176                         Miembro.q.baja == None
177                     )
178                 ).getOne()
179             except:
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')
182
183             entregador = m.grupo
184         kw['archivos'] = archivo
185         kw['entregador'] = entregador
186         validate_new(kw)
187         flash(_(u'Se creó una nueva %s.') % name)
188         raise redirect('list')
189
190     @expose(template='kid:%s.templates.corrida' % __name__)
191     def corrida(self, entregaid):
192         e = validate_get(entregaid)
193         return dict(entrega=e)
194
195     @expose()
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)
201         return r.archivos
202
203     @expose()
204     def file(self, id):
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)
209         return r.archivos
210
211     @expose()
212     def diff(self, 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)
217         return r.diferencias
218
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')
223         return dict(zip=zip)
224
225     @expose('json')
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)
233 #}}}
234