Sincronizar alumnos
Objetivo: mantener los alumnos de un grupo de Presente iguales a los de su sistema académico. La forma recomendada es la importación CSV, que es idempotente y valida antes de grabar.
Necesita: una cuenta con CADASTRAR en el grupo (por ejemplo, COORDENADOR de la asignatura; vea Permisos) y el identificador (id) del grupo.
Visión general
- Entrar y encontrar el grupo (
GET /turmas). - Armar el CSV con los alumnos de su sistema.
- Simular (
modo: "simular"): no se graba nada; el informe dice qué pasaría. - Revisar el informe y aplicar (
modo: "aplicar"). - Desactivar a quien salió del grupo en su sistema (la importación nunca elimina a nadie).
1. Encontrar el grupo
GET /turmas lista los grupos que la cuenta ve (cada elemento tiene id, nome, disciplinaId, instituicaoId). Para una asignatura específica: GET /disciplinas/{disciplinaId}/turmas. Guarde el id del grupo junto al identificador que tiene en su sistema.
2. El CSV
nome,email
Ana Ejemplo,ana@exemplo.org
Bruno Ejemplo,bruno@exemplo.org- Columnas obligatorias:
nomeyemail. Los nombres de columna aceptan alias en portugués, español e inglés (por ejemploname,nombre,correo), sin distinguir mayúsculas ni tildes. - Separador: coma, punto y coma o tabulación (se detecta por el encabezado). Comillas dobles para valores con separador;
""para comillas dentro del valor. Acepta CRLF o LF y BOM de Excel. - Límites: 500 líneas y 90 000 caracteres por archivo. Por encima, divida en varios archivos y envíe uno por vez.
- El mismo correo dos veces en el archivo: la segunda aparición es error (
duplicate).
3. Simular
POST /turmas/{turmaId}/importacoes/alunos, con el CSV como texto en el cuerpo JSON:
curl -X POST "$API/turmas/$TURMA/importacoes/alunos" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d "$(jq -n --rawfile csv alunos.csv '{csv: $csv, modo: "simular"}')"import { readFileSync } from "node:fs"
const csv = readFileSync("alunos.csv", "utf8")
const r = await fetch(`${API}/turmas/${TURMA}/importacoes/alunos`, {
method: "POST",
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
body: JSON.stringify({ csv, modo: "simular" }),
})
const informe = await r.json()csv = open("alunos.csv", encoding="utf-8").read()
r = requests.post(f"{API}/turmas/{TURMA}/importacoes/alunos",
headers={"Authorization": f"Bearer {token}"},
json={"csv": csv, "modo": "simular"})
informe = r.json()La respuesta es 200 (incluso cuando hay líneas con error: el error de línea es contenido del informe, no de la llamada):
{
"tipo": "alunos",
"modo": "simular",
"aplicado": false,
"erroArquivo": null,
"colunaAusente": null,
"resumo": { "VALIDA": 1, "JA_EXISTE": 1 },
"linhas": [
{ "linha": 2, "situacao": "VALIDA", "rotulo": "ana@exemplo.org" },
{ "linha": 3, "situacao": "JA_EXISTE", "rotulo": "bruno@exemplo.org" }
],
"convites": null
}Situaciones de cada línea:
| Situación | Significado |
|---|---|
VALIDA | (solo en simular) se crearía o vincularía. |
CRIADA | Cuenta nueva creada y matriculada; la persona recibe una invitación por correo. |
VINCULADA | El correo ya tenía cuenta en la plataforma; la persona fue matriculada en este grupo. |
REATIVADA | La matrícula estaba inactiva y volvió. |
JA_EXISTE | Ya estaba matriculada: nada que hacer. Repetir la importación no duplica ni reenvía invitación. |
ERRO | La línea impide la importación; campo y codigo indican el motivo. |
codigo puede ser required, invalid, too_long, out_of_range, duplicate o not_found. erroArquivo indica un problema del archivo completo: empty, too_many_lines, unterminated_quote, too_large o missing_column (con colunaAusente).
Simular no revela si un correo ya tiene cuenta en la plataforma (por privacidad); por eso convites viene null y las líneas nuevas aparecen como VALIDA.
4. Aplicar
Repita la llamada con "modo": "aplicar". Por defecto es todo o nada: si alguna línea tiene ERRO, aplicado viene false y no se graba nada. Corrija el archivo y envíe de nuevo. Con éxito, aplicado es true y convites indica cuántos correos de invitación salieron.
Atención:
aplicarcon correos reales envía invitaciones reales. Pruebe su código en la demostración, con datos ficticios, antes de apuntar a producción.
Modo parcial
Para importar solo las líneas válidas y dejar las otras para después, use "parcial": true con un candado de contenido:
simularconparcial: true: la respuesta traehashConteudo(SHA-256 del contenido) ycontagens(importadas,ignoradas).aplicarconparcial: truey el mismohashConteudo, con el mismo archivo. Si el archivo cambió, la respuesta es409 CONFLICT.
La respuesta del aplicar parcial trae ignoradas: las líneas que quedaron fuera. Existen solo en esa respuesta (no se guardan), así que regístrelas de su lado.
5. Quién salió del grupo
La importación solo agrega o reactiva. Para reflejar salidas, lea las matrículas y desactive a quien ya no está en su sistema:
# todas las matrículas, incluso inactivas (paginar: vea "Paginación y límites")
curl "$API/turmas/$TURMA/matriculas?limite=200&inativos=true" -H "Authorization: Bearer $TOKEN"
# desactivar una matrícula
curl -X PATCH "$API/turmas/$TURMA/matriculas/$MATRICULA" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"ativo": false}'Cada elemento de la lista de matrículas tiene id (la matrícula), usuarioId, nome, email, ativo y el status de la cuenta (CONVIDADO, ATIVO o SUSPENSO). Compare por email con la lista de su sistema. Desactivar una matrícula conserva el historial de asistencia del alumno; para volver, importe de nuevo (REATIVADA) o envíe {"ativo": true}.
Ejemplo completo (JavaScript)
const auth = { Authorization: `Bearer ${token}` }
const json = { ...auth, "Content-Type": "application/json" }
async function importa(csv, modo, extra = {}) {
const r = await fetch(`${API}/turmas/${TURMA}/importacoes/alunos`, { method: "POST", headers: json, body: JSON.stringify({ csv, modo, ...extra }) })
if (!r.ok) throw new Error(`HTTP ${r.status} ${(await r.json()).code}`)
return r.json()
}
const simulacion = await importa(csv, "simular")
const errores = simulacion.linhas.filter((l) => l.situacao === "ERRO")
if (simulacion.erroArquivo || errores.length) {
console.error("Corrija el archivo:", simulacion.erroArquivo ?? errores)
} else {
const aplicado = await importa(csv, "aplicar")
console.info(aplicado.resumo, `invitaciones: ${aplicado.convites}`)
}Personas con rol (equipo)
Para crear profesores, coordinadores, preceptores y auxiliares en lote, y también alumnos de varios grupos a la vez, use POST /instituicoes/{instituicaoId}/importacoes/pessoas. Exige ADMINISTRAR en la institución (CURADOR). El funcionamiento es el mismo; las columnas son:
| Columna | Obligatoria | Valores |
|---|---|---|
nome, email | sí | Como arriba. |
papel | sí | ALUNO, PROFESSOR, COORDENADOR, AUXILIAR, PRECEPTOR, CURADOR. |
disciplina | según el rol | La sigla de la asignatura. |
turma | según el rol | El nombre del grupo (dentro de la asignatura). |
avalia, cadastra | no | sim/não (acepta s, n, yes, si, true, 1...): marcas podeAvaliar y podeCadastrar. |
Ámbito exigido por rol: ALUNO y PROFESSOR piden asignatura y grupo; COORDENADOR pide asignatura; AUXILIAR pide asignatura (y puede tener grupo); CURADOR y PRECEPTOR no llevan asignatura ni grupo. Una asignatura o un grupo que no existen se vuelven ERRO con not_found.