Saltar al contenido principal

Consumo del contexto de actividades — get_activity_context

Estado: En desarrollo

En el ambiente de Pruebas el plugin local_pccntr8203403_iacontext está instalado y la función forma parte del servicio "Componente IA Externo", así que es alcanzable por REST con el token del servicio. El endpoint es aditivo: no altera ninguna de las funciones que el agente ya consume.

Pendiente para darlo por operativo: la cuenta de servicio no administradora descrita en puesta en servicio. Mientras el token sea de un administrador, las comprobaciones de permisos no se ejercitan.

Contrato de integración para el desarrollador del servicio de IA externo. La función local_pccntr8203403_iacontext_get_activity_context devuelve, en una sola llamada, una fila plana por actividad con su nombre, su sección, su tipo, su enlace, su estado de completitud, su nota y su fecha límite, ya unidos por cmid.

Hoy esa unión no existe en ninguna función core: hay que cruzar core_course_get_contents (nombre y sección), core_completion_get_activities_completion_status (estado) y gradereport_user_get_grade_items (nota) por cmid en tiempo de inferencia. Ninguna de las tres trae por sí sola las cuatro cosas, y la de completitud ni siquiera devuelve el nombre de la actividad.

Qué aporta frente al cruce de funciones core​

Medido sobre un curso de 50 módulos, con el mismo estudiante y curso por ambas vías:

Cruce de 3 funciones coreget_activity_context
Caracteres de la respuesta73 5228 585
Rutas de campo distintas13427
Caracteres por actividad1 470277
Llamadas3, más la unión por cmid1
Estructura3 árboles anidados distintos1 array plano
Campos con datos personalesnombre completo y cédula del estudianteninguno con la configuración por defecto

Además excluye la decoración del curso (etiquetas y demás módulos sin página de vista), que en ese curso son 17 de 50 filas sin nota y con un nombre generado a partir de su propio HTML. Una etiqueta puede, sin embargo, tener seguimiento de completitud: ver el ajuste "Excluir módulos sin página de vista".

Requisitos de acceso​

RequisitoDetalle
TokenDel servicio "Componente IA Externo" — ver Web Services IA
Capacidadlocal/pccntr8203403_iacontext:viewcontext en el contexto de cada curso
Capacidadmoodle/course:view, porque la cuenta de servicio no está matriculada en ningún curso
Matrícula del estudianteEl userid consultado sí debe tener matrícula activa en el courseid

La capacidad viewcontext se define sin arquetipos: no la hereda ningún rol estándar y hay que asignarla explícitamente al rol de la cuenta de servicio. Es de tipo lectura y riesgo RISK_PERSONAL.

Cómo pedir los datos​

curl -X POST "https://<host-del-campus>/webservice/rest/server.php" \
-d "wstoken=<TOKEN>" \
-d "wsfunction=local_pccntr8203403_iacontext_get_activity_context" \
-d "moodlewsrestformat=json" \
-d "userid=<ID_ESTUDIANTE>" \
-d "courseid=<ID_CURSO>"
ParámetroValor
useridObligatorio. Id Moodle del estudiante — el mismo moodle_user_id que llega en el payload del tutor (/webhook/v1/campus/tutor)
courseidOpcional. Id del curso. Con 0 (u omitido) responde todos los cursos con matrícula activa del estudiante

Ambos son ids internos numéricos de Moodle (mdl_user.id y mdl_course.id). La función no acepta ni devuelve idnumber, username, cédula ni correo, y no resuelve identificadores: si el consumidor tuviera otro identificador, la resolución se hace aparte con core_user_get_users_by_field.

Desde PowerShell​

Hay que invocar curl.exe con la extensión: curl a secas es un alias de Invoke-WebRequest y no entiende -d ni -s. El acento grave es el carácter de continuación de línea.

curl.exe -s "https://<host-del-campus>/webservice/rest/server.php" `
-d "wstoken=<TOKEN>" `
-d "wsfunction=local_pccntr8203403_iacontext_get_activity_context" `
-d "moodlewsrestformat=json" `
-d "userid=<ID_ESTUDIANTE>" `
-d "courseid=<ID_CURSO>"

O con el cliente nativo, que devuelve el objeto ya deserializado:

$body = @{
wstoken = '<TOKEN>'
wsfunction = 'local_pccntr8203403_iacontext_get_activity_context'
moodlewsrestformat = 'json'
userid = <ID_ESTUDIANTE>
courseid = <ID_CURSO>
}
$r = Invoke-RestMethod -Uri 'https://<host-del-campus>/webservice/rest/server.php' -Method Post -Body $body
$r.courses[0].activities | Format-Table cmid, name, section, state, grade, grademax, duedate -AutoSize
Contra el ambiente local

Con el certificado mkcert de https://localhost:8443, curl.exe falla con exit 35 porque Schannel intenta comprobar la revocación del certificado y no encuentra dónde consultarla. Añadir --ssl-no-revoke, que mantiene la validación y sólo salta esa comprobación. Invoke-RestMethod no lo necesita.

Respuesta (abreviada)​

{
"schemaversion": 2,
"userid": 918,
"student": {
"lastaccess": 1786463897 // el nombre solo aparece si administración lo activa
},
"courses": [
{
"courseid": 5,
"coursename": "Puesta en marcha de la biblioteca escolar",
"truncated": false, // true si se aplicó la cota de actividades por curso
"completion": { // ausente si el curso no tiene seguimiento de completitud
"completed": false,
"criteriacompleted": 0,
"criteriatotal": 0,
"timecompleted": null
},
"activities": [
{
"cmid": 122,
"name": "Tema 1. Actividad complementaria 1",
"section": "Modulo 1",
"sectionid": 21,
"sectionnum": 1,
"instance": 26,
"type": "assign",
"url": "https://<host-del-campus>/mod/assign/view.php?id=122",
"visible": true,
"state": 0,
"grade": null,
"grademax": 100,
"duedate": 0
}
]
}
]
}

schemaversion vale 2 desde que la respuesta incorpora las claves de sección, instance, el bloque completion por curso, el bloque student y warnings.

Diccionario rápido​

CampoTipoSignificado
cmidintId del módulo de curso. Siempre presente: es la llave para volver a Moodle por más detalle
namestringNombre de la actividad tal como lo ve el estudiante
sectionstringNombre de la sección que contiene la actividad. Nunca el nombre del curso
sectionidintId de esa sección. Estable aunque se reordene el curso, a diferencia de sectionnum
sectionnumintPosición de la sección dentro del curso
sectionvisibleboolSi el estudiante puede ver la sección. Desactivado por defecto: con la configuración por defecto llega true en todas las filas
instanceintId de la actividad en la tabla de su propio módulo (mdl_assign.id y equivalentes). Es lo que las funciones mod_* piden como instance. No es intercambiable con cmid
typestringTipo genérico: assign, quiz, scorm, forum, h5pactivity...
urlstring | nullEnlace accionable a la actividad
visibleboolSi el estudiante puede verla
stateint | null0 incompleta, 1 completa, 2 completa con aprobado, 3 completa con suspenso. null = la actividad no tiene seguimiento de completitud, que no es lo mismo que 0
gradefloat | nullNota final. null = sin calificar aún, u oculta para quien consulta
grademaxfloat | nullNota máxima, para contextualizar ("8 sobre 10"). null = la actividad no es calificable
duedateint | nullFecha límite en epoch, con la extensión individual del estudiante ya aplicada. 0 = sin fecha límite configurada; null = ese tipo de actividad no tiene concepto de fecha límite

Las distinciones entre null y 0 de state y duedate son deliberadas y el consumidor debe respetarlas: colapsarlas hace que el tutor reporte como pendiente lo que nunca se rastreó, o que invente fechas límite donde no las hay.

Los campos del sobre (schemaversion, userid, courseid, coursename, truncated) siempre viajan. Los catorce campos de actividad son configurables desde administración, salvo cmid.

Bloque student​

Datos del estudiante sobre el que se informa. Se omite entero si administración no activa ninguno de sus campos.

CampoTipoSignificado
firstnamestringNombre de pila. Dato personal: desactivado por defecto
fullnamestringNombre completo. Dato personal: desactivado por defecto
lastaccessintÚltimo acceso al sitio en epoch, no a un curso concreto. 0 = nunca ha entrado

Bloque completion (por curso)​

Completitud a nivel de curso, el agregado que core_completion_get_course_completion_status entrega en una llamada aparte.

CampoTipoSignificado
completedboolEl estudiante completó el curso
criteriacompletedintCriterios de completitud que ha cumplido
criteriatotalintCriterios que define el curso. 0 significa que hay seguimiento pero nadie configuró criterios
timecompletedint | nullCuándo completó el curso, en epoch. null = no lo ha completado

El bloque se omite cuando el curso no tiene seguimiento de completitud, o cuando el estudiante no está incluido en los informes de completitud. Ausencia del bloque y criteriatotal: 0 son cosas distintas: la primera es "la pregunta no aplica", la segunda es "aplica y vale cero".

Configuración desde administración​

En Administración del sitio > Plugins > Plugins locales > Contexto IA:

AjustePor defectoEfecto
Campos de actividad13 de 14 activosDesmarcar un campo lo elimina de la respuesta. cmid se envía siempre. sectionvisible es el único que nace desmarcado
Campos del estudiantesolo lastaccessfirstname y fullname son datos personales y nacen desmarcados. Desmarcar los tres elimina el bloque student de la respuesta
Bloque de completitud del cursoactivadoAñade completion a cada curso
Incluir actividades ocultasdesactivadoCon el valor por defecto, las actividades que el estudiante no ve no se devuelven
Excluir módulos sin página de vistaactivadoDeja fuera la decoración del curso (etiquetas), que no es una actividad que el estudiante pueda abrir. Excluye también las etiquetas que tienen seguimiento de completitud, que sí cuentan para el avance del curso: con el ajuste activado, el número de actividades con state no nulo puede ser menor que el que reporta core_completion_get_activities_completion_status para el mismo estudiante
Máximo de actividades por curso500Cota dura. Al aplicarse, ese curso se marca con truncated: true
Vigencia de la caché60 sAntigüedad máxima de las filas construidas, por estudiante y curso. 0 desactiva la caché

Ajustar el conjunto de campos es un cambio de configuración: no requiere desplegar el plugin ni una ventana de mantenimiento. La capacidad y la matrícula se comprueban siempre, nunca se sirven desde la caché.

Notas y errores comunes​

El consumidor debe ramificar sobre errorcode, nunca sobre message: el identificador es estable entre idiomas, el texto no.

errorcodeCausaQué hacer
usernotenrolledEl par (userid, courseid) no corresponde a una matrícula activa: sin matrícula, suspendida, caducada, o con la instancia de matriculación deshabilitadaInvalidar el par guardado y volver a resolverlo. No reintentar igual
invalidcourseidEl courseid no existeCorregir el id del curso
invalidparameterFalta un parámetro, es de otro tipo, o se pidió la portada del sitioCorregir la petición
nopermissionsAl rol de la cuenta de servicio le falta viewcontext en ese cursoRevisar la asignación del rol. Es un problema de configuración, no del estudiante
userdeleted, suspended, guestsarenotallowed, invaliduserEl userid no es una cuenta activaRefrescar el id del estudiante

La autorización del llamante se resuelve antes que cualquier dato del estudiante: quien no puede reportar sobre un curso recibe nopermissions, y no puede deducir por la diferencia entre errores si un estudiante está o no matriculado en él.

warnings: cuándo el informe está incompleto​

Solo el modo descubrimiento produce warnings. Con un courseid explícito las mismas condiciones lanzan excepción, y eso no cambia.

warningcodeSignificado
nocapabilitySe omitieron cursos porque a la cuenta de servicio le falta viewcontext en ellos
contextnotvalidSe omitieron cursos porque la cuenta de servicio no puede acceder a su contexto

El aviso dice cuántos cursos se omitieron, nunca cuáles. Los ids se retienen a propósito: en modo descubrimiento la lista de cursos sale de las matrículas activas del estudiante, así que nombrar un curso omitido le revelaría a un llamante sin permiso sobre ese curso que el estudiante está matriculado en él. Esa inferencia es justo la que el orden de comprobaciones del endpoint existe para impedir.

Lo que el consumidor necesita saber es que el informe es parcial, para no razonar sobre un conjunto incompleto; eso es lo que el conteo le da. warnings no sustituye a errorcode: un aviso señala un problema de configuración de la cuenta de servicio, no algo que le ocurra al estudiante.

Los dos modos de uso​

ModoCuándoComportamiento
Aserción (courseid explícito)Turno conversacional, donde el par acaba de ser validado por el propio campusEl consumidor afirma que el par es válido. Si no lo es, recibe usernotenrolled
Descubrimiento (courseid = 0)Consulta periódicaEl consumidor guarda sólo el userid y deja que Moodle recalcule los cursos en cada llamada. Es auto-sanante: una baja o una suspensión hacen desaparecer el curso de la respuesta, sin error

Para el sondeo periódico se recomienda el modo descubrimiento: elimina de raíz el problema del par guardado que caduca entre turnos.

Distinguir "no hay nada" de "el par caducó"​

SeñalSignificado
200 con activities: []Curso real, matrícula viva, sin actividades visibles
200 con courses: [] (modo descubrimiento)El estudiante no tiene ninguna matrícula activa
usernotenrolledEl par guardado caducó
nopermissionsProblema de la cuenta de servicio, no del estudiante

Puesta en servicio​

Tres pasos de administración. En Pruebas el primero está hecho; los otros dos siguen pendientes.

  1. Añadir local_pccntr8203403_iacontext_get_activity_context al servicio "Componente IA Externo", en Administración del sitio > Servidor > Servicios web > Servicios externos.
  2. Asignar local/pccntr8203403_iacontext:viewcontext y moodle/course:view al rol de la cuenta de servicio, en contexto de sistema.
  3. Emitir el token con una cuenta no administradora. Una cuenta con privilegios de administrador salta toda verificación de capacidades, de modo que el endpoint respondería aunque los permisos estuvieran mal configurados, y la prueba no demostraría nada.