Ir al contenido

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 ​

  1. Entrar y encontrar el grupo (GET /turmas).
  2. Armar el CSV con los alumnos de su sistema.
  3. Simular (modo: "simular"): no se graba nada; el informe dice qué pasaría.
  4. Revisar el informe y aplicar (modo: "aplicar").
  5. 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 ​

csv
nome,email
Ana Ejemplo,ana@exemplo.org
Bruno Ejemplo,bruno@exemplo.org
  • Columnas obligatorias: nome y email. Los nombres de columna aceptan alias en portugués, español e inglés (por ejemplo name, 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:

bash
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"}')"
js
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()
python
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):

json
{
  "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ónSignificado
VALIDA(solo en simular) se crearía o vincularía.
CRIADACuenta nueva creada y matriculada; la persona recibe una invitación por correo.
VINCULADAEl correo ya tenía cuenta en la plataforma; la persona fue matriculada en este grupo.
REATIVADALa matrícula estaba inactiva y volvió.
JA_EXISTEYa estaba matriculada: nada que hacer. Repetir la importación no duplica ni reenvía invitación.
ERROLa 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: aplicar con 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:

  1. simular con parcial: true: la respuesta trae hashConteudo (SHA-256 del contenido) y contagens (importadas, ignoradas).
  2. aplicar con parcial: true y el mismo hashConteudo, con el mismo archivo. Si el archivo cambió, la respuesta es 409 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:

bash
# 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) ​

js
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:

ColumnaObligatoriaValores
nome, emailsíComo arriba.
papelsíALUNO, PROFESSOR, COORDENADOR, AUXILIAR, PRECEPTOR, CURADOR.
disciplinasegún el rolLa sigla de la asignatura.
turmasegún el rolEl nombre del grupo (dentro de la asignatura).
avalia, cadastranosim/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.

contato@presente.app.br