UNIMOODLE / moodle-local_coursetransfer

Lote P3.2 - Restauración de cursos entre plataformas
2 stars 2 forks source link

22011: cannotviewcategory -> No teniu permís per veure aquesta llista de cursos. #27

Closed tmas0 closed 1 week ago

tmas0 commented 3 months ago

Buenas,

Estamos probando la restauración entre dos sites diferentes. Los tests de conexión dan OK. Entonces, siendo ADMINISTRADOR en ambos sites, al ir a restaurar un cursos, en el step 2, dónde muestra el listado de cursos, nos sale este error: 22011: No teniu permís per veure aquesta llista de cursos.

Necesitamos ayuda ya que esto nos tiene bloqueados.

Un saludo

tmas0 commented 1 month ago

Buenas,

Aporto mas información sobre este problema. Resulta que tenemos un usuario como administrador en dos plataformas diferentes, dónde coinciden username. Al ir a ver los cursos nos está saltando la excepción cannotviewcategory. Cuando este privilegio, al ser administrador, no debería afectar, aun así nos hemos asegurado de que lo tiene.

¿Nos podéis ayudar?

xpazv commented 1 month ago

¿Nos puedes confirmar, por favor, la versión de Moodle y PHP usadas en las pruebas?

gerarddoncel commented 1 month ago

Buenas,

No he podido replicar el error usando Moodle 4.1 y PHP 7.4. El error se produce al obtener el listado de cursos de origen en la funcion _origin_getcourses.

https://github.com/UNIMOODLE/moodle-local_coursetransfer/blob/main/classes/external/backend/origin_course_external.php#L91

Al ser usuarios administradores, si tenéis todas las capabilities el listado debería de aparecer correctamente.

Quedo a la espera de que indiquéis las versiones que utilizáis para poder hacer mas pruebas a ver si conseguimos replicar el error.

tmas0 commented 4 weeks ago

Buenas,

Aporto más información de lo que a nuestro entender es un bug.

Escenario:

  1. Hemos creado un nuevo rol a partir del de editingteacher. A este nuevo rol, lo único que cambiamos es que la capacidad moodle/category:viewhiddencategories está prohibida.
  2. Generamos un curso dentro de Miscelánea (id=1). Lo dejamos visible.
  3. Ocultamos la categoría Miscelánea).
  4. Generamos un usuario y en el curso generado le damos el rol generado en el punto 1.
  5. Convertimos a este usuario en administrador del sitio.
  6. Configuramos el coursetransfer para que origin como target sea este mismo site.
  7. Iniciamos el proceso de restauración.

En este punto nos salta el error: "22011: No tienes permiso para ver esta lista de cursos.", que corresponde con la moodle_exception cannotviewcategory.

Analizando el código librado vemos que el fallo se produce en classes/external/backend/origin_course_external.php

Concretamente en:

        try {
            $authres = coursetransfer::auth_user($field, $value);
            if ($authres['success']) {
                $user = $authres['data'];
                $courses = coursetransfer::get_courses_user($user, $page, $perpage, $search);
                $totalcourses = $courses['total'];
                foreach ($courses['courses'] as $course) {
                    $url = new moodle_url('/course/view.php', ['id' => $course->id]);
                    $item = new stdClass();
                    $item->id = $course->id;
                    $item->url = $url->out(false);
                    $item->fullname = $course->fullname;
                    $item->shortname = $course->shortname;
                    $item->idnumber = $course->idnumber;
                    $item->categoryid = $course->category;
                    $item->backupsizeestimated = coursetransfer::get_backup_size_estimated($course->id);
                    $category = core_course_category::get($item->categoryid);
                    $item->categoryname = $category->name;
                    $data[] = $item;
                }
                $paging['totalcount'] = $totalcourses;
                $paging['page'] = $page;
                $paging['perpage'] = ($perpage !== 0 && $perpage < $totalcourses) ? $perpage : $totalcourses;
            } else {
                $success = false;
                $errors[] = $authres['error'];
            }
        } catch (moodle_exception $e) {
            $success = false;
            $errors[] =
                [
                    'code' => '22011',
                    'msg' => $e->getMessage(),
                ];
        }

Al ejecutar la función $courses = coursetransfer::get_courses_user($user, $page, $perpage, $search); se obtienen todos los cursos de la plataforma, ya que en nuestro caso, estamos como administradores. Luego, al entrar al foreach, la función $category = core_course_category::get($item->categoryid); es la que da la excepción. Intento exponer los motivos:

  1. Tenemos un curso dentro de Miscelánea, que está oculta.
  2. Al revisar si el usuario puede ver o no dicha categoría $coursecat->is_uservisible($user)
  3. Se revisa si ese usuario, para el contexto de la categoría, tiene la capacidad.
        $context = context_coursecat::instance($category->id);
        if (!$category->visible && !has_capability('moodle/category:viewhiddencategories', $context, $user)) {
            return false;
        }

    Al devolver false por falta de esa capacidad, pues devuelve esa excepción, impidiendo poder leer la ristra de cursos del entorno.

Entendemos que obligar a disponer de esta capacidad según el contexto no es adecuado.

Una posible solución es controlar cuando ese usuario sea administrador del sitio, es pasar el parámetro $alwaysreturnhidden a true.

Por tanto,

$alwaysreturnhidden = (is_siteadmin($user)) ? true : false;
$category = core_course_category::get($item->categoryid, MUST_EXISTS, $alwaysreturnhidden);

Un saludo

mapemo4 commented 1 week ago

related #7

tmas0 commented 1 week ago

Solucionado.

Un saludo