. /** * Ajax: build SSO join URL. * * @package mod_meetletacbmarketplace * @copyright 2026 MeetLet * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace mod_meetletacbmarketplace\external; use core_external\external_api; use core_external\external_function_parameters; use core_external\external_single_structure; use core_external\external_value; use mod_meetletacbmarketplace\api\service; use mod_meetletacbmarketplace\local\config; use mod_meetletacbmarketplace\local\instance; use mod_meetletacbmarketplace\local\roles; use mod_meetletacbmarketplace\local\sso; use mod_meetletacbmarketplace\local\usererror; use moodle_exception; defined('MOODLE_INTERNAL') || die(); /** * Prepare Adobe Connect join URL for current user. */ class get_join_url extends external_api { public static function execute_parameters(): external_function_parameters { return new external_function_parameters([ 'cmid' => new external_value(PARAM_INT, 'Course module id'), 'groupid' => new external_value(PARAM_INT, 'Group id', VALUE_DEFAULT, 0), ]); } public static function execute(int $cmid, int $groupid = 0): array { global $USER; $params = self::validate_parameters(self::execute_parameters(), [ 'cmid' => $cmid, 'groupid' => $groupid, ]); \mod_meetletacbmarketplace\registration\manager::require_registered(); $inst = instance::get_from_cmid($params['cmid'], $params['groupid']); self::validate_context($inst->context); require_capability('mod/meetletacbmarketplace:view', $inst->context); if (!\mod_meetletacbmarketplace\local\featureaccess::allowed( \mod_meetletacbmarketplace\local\featureaccess::JOIN, $inst->context, $inst->record )) { throw new moodle_exception('notparticipant', 'meetletacbmarketplace'); } if ($inst->cm->groupmode != NOGROUPS) { $usrgroups = groups_get_user_groups($inst->course->id, $USER->id); $usrgroups = $usrgroups[0] ?? []; $aag = has_capability('moodle/site:accessallgroups', $inst->context); if (!$aag && $params['groupid'] && !in_array($params['groupid'], $usrgroups, false)) { throw new moodle_exception('usergrouprequired', 'meetletacbmarketplace'); } } $adoberole = roles::resolve_adobe_role($inst->record, $inst->context, $USER->id); if ($adoberole === null) { throw new moodle_exception('notparticipant', 'meetletacbmarketplace'); } try { // Gate join before any Adobe user provisioning / SSO. $lifecycle = \mod_meetletacbmarketplace\local\meetingstatus::resolve($inst, (int)$USER->id, true); if (empty($lifecycle['joinable'])) { $code = !empty($lifecycle['errorcode']) ? $lifecycle['errorcode'] : 'meetingended'; throw new moodle_exception($code, 'meetletacbmarketplace'); } $scoid = $inst->require_meeting(); $service = new service(); $service->login_admin(); $info = $service->meeting_info($scoid); $service->logout(); if (!$info) { throw new moodle_exception('nomeeting', 'meetletacbmarketplace'); } $auth = sso::provision_and_login($USER, $scoid, $adoberole); $url = config::with_html_client(config::public_url($info->url, $auth['cookie'])); $event = \mod_meetletacbmarketplace\event\meeting_joined::create([ 'context' => $inst->context, 'objectid' => $inst->record->id, 'relateduserid' => $USER->id, ]); $event->trigger(); return usererror::ws_ok($url); } catch (\Throwable $e) { if ($e instanceof moodle_exception && in_array($e->errorcode, ['nopermissions', 'requirelogin', 'invalidparameter'], true)) { throw $e; } return usererror::ws_fail($e, $inst->context); } } public static function execute_returns(): external_single_structure { return new external_single_structure(usererror::ws_url_returns()); } }