Skip to content

Commit

Permalink
Siempre pedir legajo y confirmar si la entrega es grupal (#54)
Browse files Browse the repository at this point in the history
  • Loading branch information
dato committed Sep 30, 2020
2 parents f89a1e5 + f0ba530 commit 729b452
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 74 deletions.
48 changes: 34 additions & 14 deletions algorw/planilla.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,29 +41,49 @@ def parse_sheets(self, sheet_dict):
# son siempre *listas* de objetos Alumne.
self._alulist_by_id = self._parse_notas(sheet_dict[Hojas.Notas])

# correctores es un diccionario que mapea:
# correctores es un diccionario que se envía a index.html, y mapea
# legajos a un arreglo con:
#
# • legajo ("98765") a corrector individual
# • identificador de grupo ("G07") a corrector grupal
# • 'g' + legajo (p.ej. "g98765") a su corrector grupal correspondiente
# • corrector individual
# • corrector grupal
# • identificador de grupo (normalmente uno, o cero si es un grupo de
# una sola persona; podría haber más de uno si hubo rearme de grupos).
#
# Esto último se usa en las validaciones Javascript en el navegador.
por_grupo = {alu.grupo: alu.ayudante_grupal for alu in self._alulist}
por_legajo = {alu.legajo: alu.ayudante_indiv for alu in self._alulist}
por_grupal = {f"g{alu.legajo}": alu.ayudante_grupal for alu in self._alulist}
self._correctores = {**por_grupo, **por_legajo, **por_grupal}
# Por ejemplo:
#
# correctores = {"98765": ["Docente 1", "Docente 2", "G17"],
# "54321": ["Docente 3"],
# "12345": ["Docente 1", "Docente 3"],
# }
self._correctores = {alu.legajo: [] for alu in self._alulist}

for alu in self._alulist:
for docente in (alu.ayudante_indiv, alu.ayudante_grupal):
if docente:
self._correctores[alu.legajo].append(docente.nombre)
else:
break
else:
if alu.grupo:
# TODO: extraer de la hoja Repos los casos con más de un grupo.
self._correctores[alu.legajo].append(alu.grupo)

@property
def correctores(self) -> Dict[str, str]:
# Compatibilidad con la antigua planilla. (Se incluye solo el nombre del
# ayudante, y se filtran asignaciones nulas.)
return {k: v.nombre for k, v in self._correctores.items() if v is not None}
def correctores(self) -> Dict[str, List[str]]:
return self._correctores.copy()

def get_alu(self, legajo: str) -> Alumne:
"""Lookup de alumne por legajo.
Se lanza KeyError si no el legajo no está presente.
"""
return self._alulist[legajo]

def get_alulist(self, identificador: str) -> List[Alumne]:
"""Devuelve les alumnes para un identificador (grupo o legajo).
Si el identificador es un legajo, devuelve una lista de un solo
elemento. Se lanza KeyError si noexiste el identificador.
elemento. Se lanza KeyError si no existe el identificador.
"""
return self._alulist_by_id[identificador]

Expand Down
28 changes: 20 additions & 8 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,21 +150,26 @@ def post():
files = get_files()
body = request.form["body"] or ""
tipo = request.form["tipo"]
identificador = request.form["identificador"]
legajo = request.form["legajo"]
modalidad = Modalidad(request.form.get("modalidad", "i"))
except KeyError as ex:
raise InvalidForm(f"Formulario inválido sin campo {ex.args[0]!r}") from ex
except ValueError as ex:
raise InvalidForm(f"Formulario con campo inválido: {ex.args[0]}") from ex

# Obtener alumnes que realizan la entrega.
planilla = fetch_planilla()
try:
alulist = planilla.get_alulist(identificador)
alumne = planilla.get_alu(legajo)
except KeyError as ex:
raise InvalidForm(f"No se encuentra grupo o legajo {identificador!r}") from ex
raise InvalidForm(f"No se encuentra el legajo {legajo!r}") from ex

# Validar varios aspectos de la entrega.
if tp not in cfg.entregas:
raise InvalidForm(f"La entrega {tp!r} es inválida")
elif len(alulist) > 1 and cfg.entregas[tp] != Modalidad.GRUPAL:
elif (modalidad == Modalidad.GRUPAL and cfg.entregas[tp] != Modalidad.GRUPAL) or (
modalidad != Modalidad.GRUPAL and cfg.entregas[tp] == Modalidad.GRUPAL
):
raise ValueError(f"La entrega {tp} debe ser individual")
elif tipo == "entrega" and not files:
raise InvalidForm("No se ha adjuntado ningún archivo con extensión válida.")
Expand All @@ -173,15 +178,22 @@ def post():

# Encontrar a le docente correspondiente.
if cfg.entregas[tp] == Modalidad.INDIVIDUAL:
docente = alulist[0].ayudante_indiv
docente = alumne.ayudante_indiv
elif cfg.entregas[tp] == Modalidad.GRUPAL:
docente = alulist[0].ayudante_grupal
docente = alumne.ayudante_grupal
else:
docente = None

if not docente and cfg.entregas[tp] != Modalidad.PARCIALITO:
legajos = ", ".join(x.legajo for x in alulist)
raise FailedDependency(f"No hay corrector para la entrega {tp} de {legajos}")
raise FailedDependency(f"No hay corrector para la entrega {tp} de {legajo}")

# Encontrar la lista de alumnes a quienes pertenece la entrega.
alulist = [alumne]
if modalidad == "grupal" and alumne.group:
try:
alulist = planilla.get_alulist(alumne.group)
except KeyError:
logging.warn(f"KeyError in get_alulist({alumne.group})")

email = make_email(tp.upper(), alulist, docente, body)
legajos = utils.sorted_strnum([x.legajo for x in alulist])
Expand Down
113 changes: 61 additions & 52 deletions templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@
<form class="form-horizontal" role="form" method="post" enctype="multipart/form-data">
{% if alert %}<div class="alert alert-danger">{{ alert }}</div>{% endif %}

<div class="form-group" id="fg_legajo">
<label for="legajo" class="col-xs-2 control-label">Legajo:</label>
<div class="col-xs-4">
<div class="input-group">
<input type="text" class="form-control" name="legajo" id="legajo" value="" placeholder="Legajo o padrón">
<span class="input-group-addon"></span>
</div>
<p class="help-block">
</p>
</div>
</div>
<div class="form-group" id="fg_tp">
<label for="tp" class="col-xs-2 control-label">Trabajo:</label>
<div class="col-xs-4">
Expand All @@ -25,15 +36,22 @@
</select>
</div>
</div>
<div class="form-group" id="fg_identificador">
<label for="identificador" class="col-xs-2 control-label">Identificador:</label>
<div class="form-group" id="fg_modalidad">
<label for="modalidad" class="col-xs-2 control-label">Modalidad:</label>
<div class="col-xs-4">
<div class="input-group">
<input type="text" class="form-control" name="identificador" id="identificador" value="" placeholder="Identificador">
<span class="input-group-addon"></span>
<div class="radio">
<label><input type="radio" name="modalidad" value="i">Entrega individual</label>
</div>
<div class="radio">
<label><input type="radio" name="modalidad" value="g">Entrega para el grupo:
<select class="form-inline" placeholder="Grupo" name="grupo" id="grupo">
<!-- De momento este select es informacional, y main.py nunca lo lee. -->
<option value="" disabled selected>--</option>
</select>
<label for="grupo" class="sr-only">Grupo</label></label>
</div>
</div>
<p class="help-block">
</p>
</div>
</div>
<div class="form-group" id="fg_tipo">
Expand Down Expand Up @@ -90,7 +108,7 @@
<script>
document.addEventListener("DOMContentLoaded", function() {
$('#tp').on('input', validate);
$('#identificador').on('input', validate);
$('#legajo').on('input', validate);
$('input[name=tipo]:radio', '#fg_tipo').change(validate);
$('#file').change(function() {
$('#filename').val(this.files[0].name);
Expand All @@ -104,10 +122,31 @@

function validate() {
var tp = validateTP();
var padronValid = validatePadron(tp);
var legajo = validateLegajo();
var filesValid = validateFiles();
var ausenciaValid = validateAusencia();
var valid = !!tp && padronValid && (filesValid || ausenciaValid);
var valid = !!tp && !!legajo && (filesValid || ausenciaValid);
var grupo = "--";

if (tp && legajo && correctores[legajo]) {
// Mostrar nombre de docente y, si aplica, número de grupo.
let data = correctores[legajo];
var corrector = null;

if (entregas[tp] === 'i' && data[0]) {
corrector = data[0];
} else if (entregas[tp] === 'g' && data[1]) {
grupo = data[2];
corrector = data[1];
}

if (corrector) {
let input = $('#legajo');
input.parent().find('span').html('<b>Corrector:</b> ' + corrector);
}
}

$('#grupo option:selected').text(grupo);
$('#submit').prop('disabled', !valid);
}

Expand All @@ -126,57 +165,27 @@
$('#tp').parent().toggleClass('has-success', valid);

if (!valid) {
return tp;
return null;
}

if (entregas[tp] === 'i') { // individual
$('#fg_identificador label').html('Padrón:');
$('#fg_identificador .help-block').html('Número de padrón');
$('#identificador').attr('placeholder', 'Padrón');
} else { // grupal
$('#fg_identificador label').html('Padrón o grupo:');
$('#fg_identificador .help-block').html('Número de padrón o identificador del grupo (ejemplo: "G04")');
$('#identificador').attr('placeholder', 'Padrón o número de grupo');
}
let es_grupal = entregas[tp] === 'g';

$('[name="modalidad"]').prop('disabled', !es_grupal);
$('[name="modalidad"]').val([es_grupal ? 'g' : 'i']);

return tp;
}

function validatePadron(tp) {
var input = $('#identificador');
var padron = validateAlNum(input);
function validateLegajo() {
let input = $('#legajo');
let legajo = validateAlNum(input);
let is_valid = legajo && legajo in correctores;
let message = is_valid ? '<b>Padrón válido</b>' : '';

if(!padron) {
input.parent().find('span').html('');
input.parent().toggleClass('has-success', false);
return false;
}
input.parent().find('span').html(message);
input.parent().toggleClass('has-success', is_valid);

var valid = false;
var corrector = null;

// Si la entrega es grupal, pero el identificador no es un grupo, el alumno entrega solo.
// Se corrige el padron para incluir 'g', y que el corrector que se muestre sea el correcto.
if (entregas[tp] === 'g' && !(padron.includes('G')) ){
padron = 'g' + padron
}

if (padron in correctores && correctores[padron]) {
corrector = correctores[padron];
valid = true;
}

input.parent().find('span').html(corrector ? '<b>Corrector:</b> ' + corrector : '');
input.parent().toggleClass('has-success', !!corrector);

if(!valid && padron in correctores) {
// Aún no tiene un corrector asignado.
input.parent().find('span').html('<b>Identificador válido</b>');
input.parent().toggleClass('has-success', true);
valid = true;
}

return valid;
return is_valid ? legajo : null;
}

function validateFiles() {
Expand Down

0 comments on commit 729b452

Please sign in to comment.