Files
formations-app/ops/provision-sync-role.php
2026-06-10 22:57:49 +02:00

126 lines
4.7 KiB
PHP

<?php
// Idempotent provisioning of the privileged sync web-service user (wssync)
// used by the app to mirror chapter progression into Moodle completion.
// Run: docker cp ops/provision-sync-role.php moodle:/tmp/ &&
// docker exec -e WSSYNC_PASSWORD=... moodle php /tmp/provision-sync-role.php
define('CLI_SCRIPT', true);
require('/var/www/html/config.php');
require_once($CFG->dirroot.'/user/lib.php');
require_once($CFG->libdir.'/accesslib.php');
$systemcontext = context_system::instance();
// 1) Role `wssync` at system context with the exact caps the sync needs.
$capabilities = [
'moodle/user:create',
'moodle/user:viewdetails',
// Required so core_user_get_users_by_field returns the username/email
// fields it was queried by (user_get_user_details strips them otherwise
// and the WS silently returns []).
'moodle/user:viewalldetails',
// Required so lookups by field=email get the email field back:
// outside a course user_get_user_details() only exposes email through
// the site identity fields ($CFG->showuseridentity includes email),
// gated by this cap — Task 4 ensureMoodleUser depends on it.
'moodle/site:viewuseridentity',
'moodle/user:update',
'enrol/manual:enrol',
'moodle/course:overridecompletion',
'moodle/course:viewparticipants',
'webservice/rest:use',
// login/token.php for a non-mobile service requires createtoken (the
// mobile service only needs createmobiletoken, allowed by default).
'moodle/webservice:createtoken',
];
$role = $DB->get_record('role', ['shortname' => 'wssync']);
if (!$role) {
$roleid = create_role('WS Sync', 'wssync',
'Privileged web-service role for formations-app progression sync', '');
$role = $DB->get_record('role', ['id' => $roleid], '*', MUST_EXIST);
echo "role created: {$role->id}\n";
} else {
echo "role exists: {$role->id}\n";
}
set_role_contextlevels($role->id, [CONTEXT_SYSTEM]);
foreach ($capabilities as $cap) {
assign_capability($cap, CAP_ALLOW, $role->id, $systemcontext->id, true);
echo "cap allowed: {$cap}\n";
}
$systemcontext->mark_dirty();
// 2) Service user `wssync`
$username = 'wssync';
$password = getenv('WSSYNC_PASSWORD');
if (!$password) { fwrite(STDERR, "WSSYNC_PASSWORD required\n"); exit(1); }
$user = core_user::get_user_by_username($username);
if (!$user) {
$u = new stdClass();
$u->username = $username;
$u->password = $password;
$u->firstname = 'WS';
$u->lastname = 'Sync';
$u->email = 'wssync@saillant.cc';
$u->confirmed = 1;
$u->mnethostid = $CFG->mnet_localhost_id;
$uid = user_create_user($u, true, false);
$user = core_user::get_user($uid);
echo "user created: {$user->id}\n";
} else {
echo "user exists: {$user->id}\n";
}
// 3) Assign the role at system context (idempotent: role_assign checks dups).
role_assign($role->id, $user->id, $systemcontext->id);
echo "role assigned at system context\n";
// 4) Dedicated external service. The stock moodle_mobile_app service does
// NOT expose core_completion_override_activity_completion_status, so the
// sync token must be issued against this service instead
// (login/token.php?service=formations_sync).
require_once($CFG->dirroot.'/webservice/lib.php');
$wsmanager = new webservice();
$servicefunctions = [
'core_user_get_users_by_field',
'core_user_create_users',
'core_user_update_users',
'enrol_manual_enrol_users',
'core_course_get_contents',
'core_completion_override_activity_completion_status',
];
$service = $DB->get_record('external_services', ['shortname' => 'formations_sync']);
if (!$service) {
$serviceid = $wsmanager->add_external_service((object)[
'name' => 'Formations Sync',
'shortname' => 'formations_sync',
'enabled' => 1,
'restrictedusers' => 1,
'downloadfiles' => 0,
'uploadfiles' => 0,
]);
$service = $DB->get_record('external_services', ['id' => $serviceid], '*', MUST_EXIST);
echo "service created: {$service->id}\n";
} else {
echo "service exists: {$service->id}\n";
}
foreach ($servicefunctions as $fn) {
if (!$DB->record_exists('external_services_functions',
['externalserviceid' => $service->id, 'functionname' => $fn])) {
$wsmanager->add_external_function_to_service($fn, $service->id);
echo "service fn added: {$fn}\n";
} else {
echo "service fn exists: {$fn}\n";
}
}
if (!$DB->record_exists('external_services_users',
['externalserviceid' => $service->id, 'userid' => $user->id])) {
$wsmanager->add_ws_authorised_user((object)[
'externalserviceid' => $service->id,
'userid' => $user->id,
]);
echo "user authorised on service\n";
} else {
echo "user already authorised on service\n";
}
echo "OK\n";