Files
meetletacbfree/db/upgrade.php
T

1064 lines
44 KiB
PHP

<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* Upgrade steps for mod_meetletacbfree.
*
* @package mod_meetletacbfree
* @copyright 2026 MeetLet <info@meetlet.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* xmldb upgrade.
*
* @param int $oldversion
* @return bool
*/
function xmldb_meetletacbfree_upgrade($oldversion) {
global $DB;
$dbman = $DB->get_manager();
// Plugin table is 10 chars; never alter core {modules}/{event} (CHAR(20) is enough).
xmldb_meetletacbfree_rename_legacy_main_table($dbman);
if ($oldversion < 2026080906) {
foreach (['meetlet_meetings', 'meetlet_recordings'] as $tname) {
if (!$dbman->table_exists($tname)) {
continue;
}
$table = new xmldb_table($tname);
$key = new xmldb_key('fk_instance', XMLDB_KEY_FOREIGN, ['instanceid'], 'meetlet', ['id']);
if ($dbman->find_key_name($table, $key)) {
$dbman->drop_key($table, $key);
}
}
$map = [
'meetlet' => 'meetletacbmarket',
'meetlet_meetings' => 'meetlet_marketplace_meetings',
'meetlet_recordings' => 'meetlet_marketplace_recordings',
];
foreach ($map as $from => $to) {
$table = new xmldb_table($from);
if ($dbman->table_exists($from) && !$dbman->table_exists($to)) {
$dbman->rename_table($table, $to);
}
}
foreach (['meetlet_marketplace_meetings', 'meetlet_marketplace_recordings'] as $tname) {
if ($dbman->table_exists($tname) && $dbman->table_exists('meetletacbmarket')) {
$table = new xmldb_table($tname);
$key = new xmldb_key('fk_instance', XMLDB_KEY_FOREIGN, ['instanceid'],
'meetletacbmarket', ['id']);
if (!$dbman->find_key_name($table, $key)) {
$dbman->add_key($table, $key);
}
}
}
foreach (['meetlet', 'meetletacbmarket'] as $oldmodname) {
if ($mod = $DB->get_record('modules', ['name' => $oldmodname])) {
$mod->name = 'meetletacbmarket';
$DB->update_record('modules', $mod);
}
$DB->set_field('event', 'modulename', 'meetletacbmarket', ['modulename' => $oldmodname]);
if ($dbman->table_exists('grade_items')) {
$DB->set_field('grade_items', 'itemmodule', 'meetletacbmarket', ['itemmodule' => $oldmodname]);
}
}
upgrade_mod_savepoint(true, 2026080906, 'meetletacbmarket');
}
if ($oldversion < 2026080908) {
$table = new xmldb_table('meetletacbmarket');
$fields = [
new xmldb_field('showzip', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'autooffline'),
new xmldb_field('showofflineplayer', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'showzip'),
new xmldb_field('showrecordingstab', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'showofflineplayer'),
new xmldb_field('showcontenttab', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'showrecordingstab'),
];
foreach ($fields as $field) {
if ($dbman->table_exists($table) && !$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
}
upgrade_mod_savepoint(true, 2026080908, 'meetletacbmarket');
}
if ($oldversion < 2026080909) {
$table = new xmldb_table('meetlet_adobe_connect_bridge');
if ($dbman->table_exists('meetlet_adobe_connect_bridge') && !$dbman->table_exists('meetletacbmarket')) {
$dbman->rename_table($table, 'meetletacbmarket');
}
// Re-point FKs on related tables if needed - drop old FK and add new
foreach (['meetlet_marketplace_meetings', 'meetlet_marketplace_recordings'] as $tname) {
if ($dbman->table_exists($tname) && $dbman->table_exists('meetletacbmarket')) {
$t = new xmldb_table($tname);
$oldkey = new xmldb_key('fk_instance', XMLDB_KEY_FOREIGN, ['instanceid'], 'meetlet_adobe_connect_bridge', ['id']);
if ($dbman->find_key_name($t, $oldkey)) {
$dbman->drop_key($t, $oldkey);
}
$newkey = new xmldb_key('fk_instance', XMLDB_KEY_FOREIGN, ['instanceid'], 'meetletacbmarket', ['id']);
if (!$dbman->find_key_name($t, $newkey)) {
$dbman->add_key($t, $newkey);
}
}
}
upgrade_mod_savepoint(true, 2026080909, 'meetletacbmarket');
}
if ($oldversion < 2026080910) {
$table = new xmldb_table('meetletacbmarket');
$field = new xmldb_field('showmp4', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'showcontenttab');
if ($dbman->table_exists($table) && !$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
// Migrate legacy allow_manual_offline into enable_mp4 when unset.
$enablemp4 = get_config('meetletacbmarket', 'enable_mp4');
if ($enablemp4 === false) {
$legacy = get_config('meetletacbmarket', 'allow_manual_offline');
set_config('enable_mp4', ($legacy === false || (bool)$legacy) ? 1 : 0, 'meetletacbmarket');
}
if (get_config('meetletacbmarket', 'allow_override_mp4') === false) {
set_config('allow_override_mp4', 1, 'meetletacbmarket');
}
upgrade_mod_savepoint(true, 2026080910, 'meetletacbmarket');
}
if ($oldversion < 2026080911) {
// ZIP download is opt-in from this release.
set_config('enable_zip', 0, 'meetletacbmarket');
upgrade_mod_savepoint(true, 2026080911, 'meetletacbmarket');
}
if ($oldversion < 2026080912) {
// Remove Adobe offline player (pbMode) from product settings.
set_config('enable_offlineplayer', 0, 'meetletacbmarket');
set_config('allow_override_offlineplayer', 0, 'meetletacbmarket');
upgrade_mod_savepoint(true, 2026080912, 'meetletacbmarket');
}
if ($oldversion < 2026080913) {
$table = new xmldb_table('meetletacbmarket');
$fields = [
new xmldb_field('linkmode', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'showmp4'),
new xmldb_field('existingscoid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'linkmode'),
new xmldb_field('meetinglang', XMLDB_TYPE_CHAR, '20', null, null, null, null, 'existingscoid'),
new xmldb_field('waitforhost', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'meetinglang'),
];
foreach ($fields as $field) {
if ($dbman->table_exists($table) && !$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
}
upgrade_mod_savepoint(true, 2026080913, 'meetletacbmarket');
}
if ($oldversion < 2026080914) {
$table = new xmldb_table('meetletacbmarket');
$field = new xmldb_field('featureaccess', XMLDB_TYPE_TEXT, null, null, null, null, null, 'waitforhost');
if ($dbman->table_exists($table) && !$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
if (get_config('meetletacbmarket', 'featureaccess') === false) {
set_config(
'featureaccess',
json_encode(\mod_meetletacbfree\local\featureaccess::builtin_defaults(), JSON_UNESCAPED_UNICODE),
'meetletacbmarket'
);
}
upgrade_mod_savepoint(true, 2026080914, 'meetletacbmarket');
}
if ($oldversion < 2026080915) {
if (get_config('meetletacbmarket', 'activity_featureaccess') === false) {
set_config('activity_featureaccess', 1, 'meetletacbmarket');
}
// Ensure adobeeditor key exists in stored site matrix.
$raw = get_config('meetletacbmarket', 'featureaccess');
if ($raw !== false && $raw !== '') {
$decoded = json_decode($raw, true);
if (is_array($decoded)) {
$normalized = \mod_meetletacbfree\local\featureaccess::normalize($decoded);
set_config(
'featureaccess',
json_encode($normalized, JSON_UNESCAPED_UNICODE),
'meetletacbmarket'
);
}
}
upgrade_mod_savepoint(true, 2026080915, 'meetletacbmarket');
}
if ($oldversion < 2026080916) {
$raw = get_config('meetletacbmarket', 'featureaccess');
if ($raw !== false && $raw !== '') {
$decoded = json_decode($raw, true);
if (is_array($decoded)) {
set_config(
'featureaccess',
json_encode(
\mod_meetletacbfree\local\featureaccess::normalize($decoded),
JSON_UNESCAPED_UNICODE
),
'meetletacbmarket'
);
}
}
upgrade_mod_savepoint(true, 2026080916, 'meetletacbmarket');
}
if ($oldversion < 2026080917) {
upgrade_mod_savepoint(true, 2026080917, 'meetletacbmarket');
}
if ($oldversion < 2026080918) {
upgrade_mod_savepoint(true, 2026080918, 'meetletacbmarket');
}
if ($oldversion < 2026080919) {
upgrade_mod_savepoint(true, 2026080919, 'meetletacbmarket');
}
if ($oldversion < 2026080920) {
upgrade_mod_savepoint(true, 2026080920, 'meetletacbmarket');
}
if ($oldversion < 2026080921) {
// Expand stored matrix to include every Moodle role.
$raw = get_config('meetletacbmarket', 'featureaccess');
if ($raw !== false && $raw !== null && $raw !== '') {
$decoded = json_decode((string)$raw, true);
if (is_array($decoded)) {
set_config(
'featureaccess',
json_encode(
\mod_meetletacbfree\local\featureaccess::normalize($decoded),
JSON_UNESCAPED_UNICODE
),
'meetletacbmarket'
);
}
} else {
set_config(
'featureaccess',
json_encode(
\mod_meetletacbfree\local\featureaccess::builtin_defaults(),
JSON_UNESCAPED_UNICODE
),
'meetletacbmarket'
);
}
upgrade_mod_savepoint(true, 2026080921, 'meetletacbmarket');
}
if ($oldversion < 2026080922) {
// Apply sensible defaults to blank role rows (e.g. newly listed custom roles).
$raw = get_config('meetletacbmarket', 'featureaccess');
$decoded = [];
if ($raw !== false && $raw !== null && $raw !== '') {
$tmp = json_decode((string)$raw, true);
if (is_array($tmp)) {
$decoded = $tmp;
}
}
set_config(
'featureaccess',
json_encode(
\mod_meetletacbfree\local\featureaccess::normalize_fill_blank_roles($decoded),
JSON_UNESCAPED_UNICODE
),
'meetletacbmarket'
);
upgrade_mod_savepoint(true, 2026080922, 'meetletacbmarket');
}
if ($oldversion < 2026080923) {
upgrade_mod_savepoint(true, 2026080923, 'meetletacbmarket');
}
if ($oldversion < 2026080924) {
upgrade_mod_savepoint(true, 2026080924, 'meetletacbmarket');
}
if ($oldversion < 2026080925) {
// Site ZIP was enabled while activities kept showzip=0 (form default), which hid links.
if ((bool)get_config('meetletacbmarket', 'enable_zip')) {
$DB->set_field('meetletacbmarket', 'showzip', 1);
}
upgrade_mod_savepoint(true, 2026080925, 'meetletacbmarket');
}
if ($oldversion < 2026080926) {
upgrade_mod_savepoint(true, 2026080926, 'meetletacbmarket');
}
if ($oldversion < 2026081110) {
$table = new xmldb_table('meetlet_marketplace_license');
if (!$dbman->table_exists($table)) {
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
$table->add_field('installation_id', XMLDB_TYPE_CHAR, '128', null, XMLDB_NOTNULL);
$table->add_field('private_key_pem', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL);
$table->add_field('public_key_pem', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL);
$table->add_field('auth_json', XMLDB_TYPE_TEXT, null, null, null);
$table->add_field('license_uuid', XMLDB_TYPE_CHAR, '64', null, null);
$table->add_field('status', XMLDB_TYPE_CHAR, '32', null, XMLDB_NOTNULL, null, 'inactive');
$table->add_field('last_error', XMLDB_TYPE_TEXT, null, null, null);
$table->add_field('last_validated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
$table->add_index('installation_uniq', XMLDB_INDEX_UNIQUE, ['installation_id']);
$dbman->create_table($table);
}
upgrade_mod_savepoint(true, 2026081110, 'meetletacbmarket');
}
if ($oldversion < 2026081120) {
$table = new xmldb_table('meetlet_marketplace_recordings');
$field = new xmldb_field('agentjobid', XMLDB_TYPE_CHAR, '64', null, null, null, null, 'jobstatus');
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
upgrade_mod_savepoint(true, 2026081120, 'meetletacbmarket');
}
if ($oldversion < 2026081305) {
// Offline MP4 / Render Agent is opt-in. Preserve existing agent_url sites.
$enabled = get_config('meetletacbmarket', 'offline_render_enabled');
if ($enabled === false) {
$agenturl = trim((string)get_config('meetletacbmarket', 'agent_url'));
set_config(
'offline_render_enabled',
$agenturl !== '' ? 1 : 0,
'meetletacbmarket'
);
}
upgrade_mod_savepoint(true, 2026081305, 'meetletacbmarket');
}
if ($oldversion < 2026081401) {
unset_config('offline_render_enabled', 'meetletacbmarket');
upgrade_mod_savepoint(true, 2026081401, 'meetletacbmarket');
}
if ($oldversion < 2026081402) {
upgrade_mod_savepoint(true, 2026081402, 'meetletacbmarket');
}
if ($oldversion < 2026081410) {
$table = new xmldb_table('meetletacbmarket');
$field = new xmldb_field('showmakeoffline', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '1', 'showmp4');
if ($dbman->table_exists($table) && !$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
if (get_config('meetletacbmarket', 'enable_makeoffline') === false) {
set_config('enable_makeoffline', 1, 'meetletacbmarket');
}
if (get_config('meetletacbmarket', 'allow_override_makeoffline') === false) {
set_config('allow_override_makeoffline', 1, 'meetletacbmarket');
}
$raw = get_config('meetletacbmarket', 'featureaccess');
$decoded = [];
if ($raw !== false && $raw !== null && $raw !== '') {
$tmp = json_decode((string)$raw, true);
if (is_array($tmp)) {
$decoded = $tmp;
}
}
set_config(
'featureaccess',
json_encode(
\mod_meetletacbfree\local\featureaccess::copy_missing_feature_from(
$decoded,
'mp4',
'makeoffline'
),
JSON_UNESCAPED_UNICODE
),
'meetletacbmarket'
);
$activities = $dbman->table_exists('meetletacbmarket')
? $DB->get_records_select('meetletacbmarket', 'featureaccess IS NOT NULL AND featureaccess <> \'\'')
: [];
foreach ($activities as $activity) {
$matrix = json_decode((string)$activity->featureaccess, true);
if (!is_array($matrix)) {
continue;
}
$updated = \mod_meetletacbfree\local\featureaccess::copy_missing_feature_from(
$matrix,
'mp4',
'makeoffline'
);
$DB->set_field(
'meetletacbmarket',
'featureaccess',
json_encode($updated, JSON_UNESCAPED_UNICODE),
['id' => $activity->id]
);
}
upgrade_mod_savepoint(true, 2026081410, 'meetletacbmarket');
}
if ($oldversion < 2026081411) {
xmldb_meetletacbfree_rename_legacy_main_table($dbman);
foreach (['meetletadobeconnectbridge', 'meetlet_adobe_connect_bridge', 'meetlet'] as $oldmodname) {
if ($mod = $DB->get_record('modules', ['name' => $oldmodname])) {
$mod->name = 'meetletacbmarket';
$DB->update_record('modules', $mod);
}
if ($dbman->table_exists('event')) {
$DB->set_field('event', 'modulename', 'meetletacbmarket', ['modulename' => $oldmodname]);
}
if ($dbman->table_exists('grade_items')) {
$DB->set_field('grade_items', 'itemmodule', 'meetletacbmarket', ['itemmodule' => $oldmodname]);
}
}
upgrade_mod_savepoint(true, 2026081411, 'meetletacbmarket');
}
if ($oldversion < 2026081702) {
upgrade_mod_savepoint(true, 2026081702, 'meetletacbmarket');
}
if ($oldversion < 2026081703) {
upgrade_mod_savepoint(true, 2026081703, 'meetletacbmarket');
}
if ($oldversion < 2026081704) {
upgrade_mod_savepoint(true, 2026081704, 'meetletacbmarket');
}
if ($oldversion < 2026081800) {
$table = new xmldb_table('meetlet_marketplace_meetings');
$fields = [
new xmldb_field('islive', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'urlpath'),
new xmldb_field('liveat', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'islive'),
new xmldb_field('closedat', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'liveat'),
new xmldb_field('sweepuntil', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'closedat'),
new xmldb_field('sweptat', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'sweepuntil'),
];
foreach ($fields as $field) {
if ($dbman->table_exists($table) && !$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
}
if (get_config('meetletacbmarket', 'cron_interval') === false) {
set_config('cron_interval', 5, 'meetletacbmarket');
}
\mod_meetletacbfree\local\config::apply_cron_interval();
upgrade_mod_savepoint(true, 2026081800, 'meetletacbmarket');
}
if ($oldversion < 2026081901) {
$table = new xmldb_table('meetlet_marketplace_recordings');
$field = new xmldb_field('jobmessage', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'jobstatus');
if ($dbman->table_exists($table) && !$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
upgrade_mod_savepoint(true, 2026081901, 'meetletacbmarket');
}
if ($oldversion < 2026081902) {
upgrade_mod_savepoint(true, 2026081902, 'meetletacbmarket');
}
if ($oldversion < 2026081903) {
$table = new xmldb_table('meetlet_marketplace_jobqueue');
if (!$dbman->table_exists($table)) {
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
$table->add_field('instanceid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('recordingscoid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('groupid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('status', XMLDB_TYPE_CHAR, '20', null, XMLDB_NOTNULL, null, 'pending');
$table->add_field('attempts', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('lasterror', XMLDB_TYPE_CHAR, '255', null, null, null, null);
$table->add_field('timesent', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
$table->add_index('instance_sco', XMLDB_INDEX_UNIQUE, ['instanceid', 'recordingscoid']);
$table->add_index('status_idx', XMLDB_INDEX_NOTUNIQUE, ['status']);
$dbman->create_table($table);
}
if (get_config('meetletacbmarket', 'agent_dispatch') === false) {
set_config('agent_dispatch', 'immediate', 'meetletacbmarket');
}
if (get_config('meetletacbmarket', 'agent_dispatch_hours') === false) {
set_config('agent_dispatch_hours', '22,23,0,1,2,3,4,5', 'meetletacbmarket');
}
upgrade_mod_savepoint(true, 2026081903, 'meetletacbmarket');
}
if ($oldversion < 2026081904) {
upgrade_mod_savepoint(true, 2026081904, 'meetletacbmarket');
}
if ($oldversion < 2026081905) {
upgrade_mod_savepoint(true, 2026081905, 'meetletacbmarket');
}
if ($oldversion < 2026081906) {
upgrade_mod_savepoint(true, 2026081906, 'meetletacbmarket');
}
if ($oldversion < 2026081912) {
$table = new xmldb_table('meetletacbmarket');
$fields = [
new xmldb_field('settingoverrides', XMLDB_TYPE_TEXT, null, null, null, null, null, 'featureaccess'),
new xmldb_field('participantsmode', XMLDB_TYPE_INTEGER, '1', null, XMLDB_NOTNULL, null, '0', 'settingoverrides'),
];
foreach ($fields as $field) {
if ($dbman->table_exists($table) && !$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
}
if ($dbman->table_exists($table)) {
$activities = $DB->get_records('meetletacbmarket');
foreach ($activities as $activity) {
$overrides = [];
foreach ([
'waitforhost',
'autooffline',
'showzip',
'showrecordingstab',
'showcontenttab',
'showmp4',
'showmakeoffline',
] as $field) {
$overrides[$field] = !empty($activity->{$field})
? \mod_meetletacbfree\local\config::OVERRIDE_ON
: \mod_meetletacbfree\local\config::OVERRIDE_OFF;
}
$update = (object)[
'id' => $activity->id,
'settingoverrides' => \mod_meetletacbfree\local\config::setting_overrides_json($overrides),
'participantsmode' => 1,
];
$DB->update_record('meetletacbmarket', $update);
}
}
upgrade_mod_savepoint(true, 2026081912, 'meetletacbmarket');
}
// 1.5.45 — MP4 import download_one fix + agent-gone reconciliation (no schema).
if ($oldversion < 2026082127) {
upgrade_mod_savepoint(true, 2026082127, 'meetletacbmarket');
}
// 1.5.50 — Agent download without forced Import + Delete from Moodle (no schema).
if ($oldversion < 2026082132) {
upgrade_mod_savepoint(true, 2026082132, 'meetletacbmarket');
}
// 1.5.51 — Dual Moodle/Agent MP4 download buttons + source tooltips (no schema).
if ($oldversion < 2026082133) {
upgrade_mod_savepoint(true, 2026082133, 'meetletacbmarket');
}
// 1.5.54 — Agent MP4 proxy: send_temp_file path fix + stored ftyp validation (no schema).
if ($oldversion < 2026082236) {
upgrade_mod_savepoint(true, 2026082236, 'meetletacbmarket');
}
// 1.5.63 — Content download via Moodle SSO proxy + content view launch URL (no schema).
if ($oldversion < 2026082245) {
upgrade_mod_savepoint(true, 2026082245, 'meetletacbmarket');
}
// 1.5.66 — Content download button loading state (no schema).
if ($oldversion < 2026082248) {
upgrade_mod_savepoint(true, 2026082248, 'meetletacbmarket');
}
// 1.5.68 — Free license: recordings view/edit; MP4 Premium-only (no schema).
if ($oldversion < 2026082250) {
upgrade_mod_savepoint(true, 2026082250, 'meetletacbmarket');
}
// 1.0.1-marketplace — rename component from mod_meetletacbmdlrules.
if ($oldversion < 2026090122) {
xmldb_meetletacbfree_migrate_from_mdlrules($dbman);
upgrade_mod_savepoint(true, 2026090122, 'meetletacbmarket');
}
// 1.0.1-marketplace — UI cleanup, role defaults, lang prune.
if ($oldversion < 2026090123) {
upgrade_mod_savepoint(true, 2026090123, 'meetletacbmarket');
}
// 1.0.1-marketplace — plugin display titles (fa/en).
if ($oldversion < 2026090124) {
upgrade_mod_savepoint(true, 2026090124, 'meetletacbmarket');
}
// 1.0.1-marketplace — dedupe modules row after component rename.
if ($oldversion < 2026090125) {
$marketmods = $DB->get_records('modules', ['name' => 'meetletacbmarket'], 'id ASC');
if (count($marketmods) > 1) {
array_shift($marketmods);
foreach ($marketmods as $dup) {
$DB->delete_records('modules', ['id' => $dup->id]);
}
}
upgrade_mod_savepoint(true, 2026090125, 'meetletacbmarket');
}
// 1.0.1-marketplace — MeetLet logo + visit website button on About tab (no schema).
if ($oldversion < 2026090127) {
upgrade_mod_savepoint(true, 2026090127, 'meetletacbmarket');
}
// 1.0.2-marketplace — optional transparent site registration tab + daily heartbeat.
if ($oldversion < 2026090128) {
$table = new xmldb_table('meetlet_marketplace_license');
if (!$dbman->table_exists($table)) {
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE);
$table->add_field('installation_id', XMLDB_TYPE_CHAR, '128', null, XMLDB_NOTNULL);
$table->add_field('private_key_pem', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL);
$table->add_field('public_key_pem', XMLDB_TYPE_TEXT, null, null, XMLDB_NOTNULL);
$table->add_field('auth_json', XMLDB_TYPE_TEXT, null, null, null);
$table->add_field('license_uuid', XMLDB_TYPE_CHAR, '64', null, null);
$table->add_field('status', XMLDB_TYPE_CHAR, '32', null, XMLDB_NOTNULL, null, 'inactive');
$table->add_field('last_error', XMLDB_TYPE_TEXT, null, null, null);
$table->add_field('last_validated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']);
$table->add_index('installation_uniq', XMLDB_INDEX_UNIQUE, ['installation_id']);
$dbman->create_table($table);
}
upgrade_mod_savepoint(true, 2026090128, 'meetletacbmarket');
}
if ($oldversion < 2026090129) {
upgrade_mod_savepoint(true, 2026090129, 'meetletacbmarket');
}
if ($oldversion < 2026090130) {
upgrade_mod_savepoint(true, 2026090130, 'meetletacbmarket');
}
if ($oldversion < 2026090131) {
upgrade_mod_savepoint(true, 2026090131, 'meetletacbmarket');
}
// 1.0.3-marketplace — optional registration: remove feature gating (no schema).
if ($oldversion < 2026090132) {
upgrade_mod_savepoint(true, 2026090132, 'meetletacbmarket');
}
// 1.0.3-marketplace — hide locked settings tabs until online activation (no schema).
if ($oldversion < 2026090134) {
upgrade_mod_savepoint(true, 2026090134, 'meetletacbmarket');
}
// 1.0.4-marketplace — activity icon badge to distinguish from commercial meetletacb (no schema).
if ($oldversion < 2026090135) {
upgrade_mod_savepoint(true, 2026090135, 'meetletacbmarket');
}
// 1.0.4-marketplace — in-plugin Privacy admin tab; remove external policy link (no schema).
if ($oldversion < 2026090136) {
upgrade_mod_savepoint(true, 2026090136, 'meetletacbmarket');
}
// 1.0.4-marketplace — Privacy tab visible before online activation (no schema).
if ($oldversion < 2026090137) {
upgrade_mod_savepoint(true, 2026090137, 'meetletacbmarket');
}
// 1.0.4-marketplace — fix privacy tab deep-link; enlarge activity icon M badge (no schema).
if ($oldversion < 2026090138) {
upgrade_mod_savepoint(true, 2026090138, 'meetletacbmarket');
}
// 1.0.4-marketplace — privacy tab copy fixes (no schema).
if ($oldversion < 2026090139) {
upgrade_mod_savepoint(true, 2026090139, 'meetletacbmarket');
}
// 1.0.4-marketplace — remove vague local-data privacy paragraph (no schema).
if ($oldversion < 2026090140) {
upgrade_mod_savepoint(true, 2026090140, 'meetletacbmarket');
}
// 1.0.4-marketplace — privacy tab deep-link uses hash anchor (no schema).
if ($oldversion < 2026090141) {
upgrade_mod_savepoint(true, 2026090141, 'meetletacbmarket');
}
// 1.0.5-marketplace — hide activity chooser until online registration (no schema).
if ($oldversion < 2026090143) {
upgrade_mod_savepoint(true, 2026090143, 'meetletacbmarket');
}
// 1.0.6-marketplace — registration confirm modal UI (no schema).
if ($oldversion < 2026090145) {
upgrade_mod_savepoint(true, 2026090145, 'meetletacbmarket');
}
// 1.0.6-marketplace — plugin activation terminology (no schema).
if ($oldversion < 2026090146) {
upgrade_mod_savepoint(true, 2026090146, 'meetletacbmarket');
}
// 1.0.6-marketplace — server guide: no live credentials in admin UI (no schema).
if ($oldversion < 2026090147) {
upgrade_mod_savepoint(true, 2026090147, 'meetletacbmarket');
}
if ($oldversion < 2026090148) {
upgrade_mod_savepoint(true, 2026090148, 'meetletacbmarket');
}
// 1.0.8-marketplace — CI: prefix auxiliary tables with meetletacbmarket_.
if ($oldversion < 2026090149) {
$renames = [
'meetlet_marketplace_meetings' => 'meetletacbmarket_meetings',
'meetlet_marketplace_recordings' => 'meetletacbmarket_recordings',
'meetlet_marketplace_license' => 'meetletacbmarket_license',
'meetlet_marketplace_jobqueue' => 'meetletacbmarket_jobqueue',
];
$fktables = [
'meetlet_marketplace_meetings' => 'meetletacbmarket_meetings',
'meetlet_marketplace_recordings' => 'meetletacbmarket_recordings',
];
foreach ($fktables as $from => $to) {
if (!$dbman->table_exists($from)) {
continue;
}
$t = new xmldb_table($from);
$oldkey = new xmldb_key('fk_instance', XMLDB_KEY_FOREIGN, ['instanceid'], 'meetletacbmarket', ['id']);
if ($dbman->find_key_name($t, $oldkey)) {
$dbman->drop_key($t, $oldkey);
}
}
foreach ($renames as $from => $to) {
if ($dbman->table_exists($from) && !$dbman->table_exists($to)) {
$dbman->rename_table(new xmldb_table($from), $to);
}
}
if ($dbman->table_exists('meetletacbmarket')) {
foreach (['meetletacbmarket_meetings', 'meetletacbmarket_recordings'] as $tname) {
if (!$dbman->table_exists($tname)) {
continue;
}
$t = new xmldb_table($tname);
$newkey = new xmldb_key('fk_instance', XMLDB_KEY_FOREIGN, ['instanceid'], 'meetletacbmarket', ['id']);
if (!$dbman->find_key_name($t, $newkey)) {
$dbman->add_key($t, $newkey);
}
}
}
upgrade_mod_savepoint(true, 2026090149, 'meetletacbmarket');
}
// 1.0.9-marketplace — rename component mod_meetletacbmarket → mod_meetletacbfree (fits mdl_modules.name).
if ($oldversion < 2026090150) {
xmldb_meetletacbfree_migrate_from_market($dbman);
upgrade_mod_savepoint(true, 2026090150, 'meetletacbfree');
}
if ($oldversion < 2026090151) {
// 10.1.0 marketplace release � version bump only.
upgrade_mod_savepoint(true, 2026090151, 'meetletacbfree');
}
if ($oldversion < 2026090152) {
// 1.1.2 marketplace release � version bump only.
upgrade_mod_savepoint(true, 2026090152, 'meetletacbfree');
}
if ($oldversion < 2026090153) {
upgrade_mod_savepoint(true, 2026090153, 'meetletacbfree');
}
return true;
}
/**
* Migrate legacy meetletacbmdlrules / meetlet_mdlrules_* tables and config.
*
* @param \database_manager $dbman
* @return void
*/
function xmldb_meetletacbfree_migrate_from_mdlrules($dbman): void {
global $DB;
$legacymain = new xmldb_table('meetletacbmdlrules');
$newmain = new xmldb_table('meetletacbmarket');
if ($dbman->table_exists($legacymain)) {
if ($dbman->table_exists($newmain)) {
$dbman->drop_table($newmain);
}
$dbman->rename_table($legacymain, 'meetletacbmarket');
}
$tablemap = [
'meetlet_mdlrules_meetings' => 'meetlet_marketplace_meetings',
'meetlet_mdlrules_recordings' => 'meetlet_marketplace_recordings',
];
foreach ($tablemap as $from => $to) {
$fromtable = new xmldb_table($from);
$totable = new xmldb_table($to);
if ($dbman->table_exists($fromtable)) {
if ($dbman->table_exists($totable)) {
$dbman->drop_table($totable);
}
$dbman->rename_table($fromtable, $to);
}
}
if ($dbman->table_exists('meetletacbmarket')) {
foreach (['meetlet_marketplace_meetings', 'meetlet_marketplace_recordings'] as $tname) {
if (!$dbman->table_exists($tname)) {
continue;
}
$t = new xmldb_table($tname);
$oldkeys = [
new xmldb_key('fk_instance', XMLDB_KEY_FOREIGN, ['instanceid'], 'meetletacbmdlrules', ['id']),
new xmldb_key('fk_instance', XMLDB_KEY_FOREIGN, ['instanceid'], 'meetletadobeconnectbridge', ['id']),
];
foreach ($oldkeys as $oldkey) {
if ($dbman->find_key_name($t, $oldkey)) {
$dbman->drop_key($t, $oldkey);
}
}
$newkey = new xmldb_key('fk_instance', XMLDB_KEY_FOREIGN, ['instanceid'], 'meetletacbmarket', ['id']);
if (!$dbman->find_key_name($t, $newkey)) {
$dbman->add_key($t, $newkey);
}
}
}
if ($mod = $DB->get_record('modules', ['name' => 'meetletacbmdlrules'])) {
$mod->name = 'meetletacbmarket';
$DB->update_record('modules', $mod);
}
$marketmods = $DB->get_records('modules', ['name' => 'meetletacbmarket'], 'id ASC');
if (count($marketmods) > 1) {
$keep = array_shift($marketmods);
foreach ($marketmods as $dup) {
$DB->delete_records('modules', ['id' => $dup->id]);
}
} else if (empty($marketmods) && !$DB->record_exists('modules', ['name' => 'meetletacbmarket'])) {
$mod = (object)['name' => 'meetletacbmarket', 'cron' => 0, 'visible' => 1];
$DB->insert_record('modules', $mod);
}
foreach (['meetletacbmdlrules', 'meetletadobeconnectbridge', 'meetlet'] as $oldmodname) {
if ($dbman->table_exists('event')) {
$DB->set_field('event', 'modulename', 'meetletacbmarket', ['modulename' => $oldmodname]);
}
if ($dbman->table_exists('grade_items')) {
$DB->set_field('grade_items', 'itemmodule', 'meetletacbmarket', ['itemmodule' => $oldmodname]);
}
if ($dbman->table_exists('course_modules')) {
$DB->execute(
"UPDATE {course_modules} SET module = (
SELECT id FROM {modules} WHERE name = 'meetletacbmarket'
) WHERE module = (
SELECT id FROM {modules} WHERE name = ?
)",
[$oldmodname]
);
}
}
$configs = $DB->get_records('config_plugins', ['plugin' => 'meetletacbmdlrules']);
foreach ($configs as $cfg) {
if ($DB->record_exists('config_plugins', ['plugin' => 'meetletacbmarket', 'name' => $cfg->name])) {
continue;
}
$cfg->plugin = 'meetletacbmarket';
$DB->insert_record('config_plugins', $cfg);
}
$DB->delete_records('config_plugins', ['plugin' => 'meetletacbmdlrules']);
}
/**
* Rename pre-Marketplace main table via XMLDB (MySQL and PostgreSQL).
*
* @param \database_manager $dbman
* @return void
*/
function xmldb_meetletacbfree_rename_legacy_main_table($dbman): void {
foreach (['meetlet_marketplace_meetings', 'meetlet_marketplace_recordings'] as $tname) {
if (!$dbman->table_exists($tname)) {
continue;
}
$t = new xmldb_table($tname);
$oldkey = new xmldb_key('fk_instance', XMLDB_KEY_FOREIGN, ['instanceid'],
'meetletadobeconnectbridge', ['id']);
if ($dbman->find_key_name($t, $oldkey)) {
$dbman->drop_key($t, $oldkey);
}
}
$oldtable = new xmldb_table('meetletadobeconnectbridge');
if ($dbman->table_exists('meetletadobeconnectbridge') && !$dbman->table_exists('meetletacbmarket')) {
$dbman->rename_table($oldtable, 'meetletacbmarket');
}
foreach (['meetlet_marketplace_meetings', 'meetlet_marketplace_recordings'] as $tname) {
if (!$dbman->table_exists($tname) || !$dbman->table_exists('meetletacbmarket')) {
continue;
}
$t = new xmldb_table($tname);
$newkey = new xmldb_key('fk_instance', XMLDB_KEY_FOREIGN, ['instanceid'], 'meetletacbmarket', ['id']);
if (!$dbman->find_key_name($t, $newkey)) {
$dbman->add_key($t, $newkey);
}
}
}
/**
* Rename mod_meetletacbmarket tables/config to mod_meetletacbfree.
*
* Handles meetletacbmarket*, meetlet_marketplace_* legacy names, and modules row.
*
* @param \database_manager $dbman
* @return void
*/
function xmldb_meetletacbfree_migrate_from_market($dbman): void {
global $DB;
// Ensure legacy meetlet_marketplace_* tables use meetletacbmarket_* prefix first.
$legacyrenames = [
'meetlet_marketplace_meetings' => 'meetletacbmarket_meetings',
'meetlet_marketplace_recordings' => 'meetletacbmarket_recordings',
'meetlet_marketplace_license' => 'meetletacbmarket_license',
'meetlet_marketplace_jobqueue' => 'meetletacbmarket_jobqueue',
];
foreach ($legacyrenames as $from => $to) {
if ($dbman->table_exists($from) && !$dbman->table_exists($to)) {
$dbman->rename_table(new xmldb_table($from), $to);
}
}
// Drop FKs on auxiliary tables before main-table rename.
$fksources = ['meetletacbmarket_meetings', 'meetletacbfree_meetings'];
foreach ($fksources as $tname) {
if (!$dbman->table_exists($tname)) {
continue;
}
$t = new xmldb_table($tname);
foreach (['meetletacbmarket', 'meetletacbfree'] as $reftable) {
$oldkey = new xmldb_key('fk_instance', XMLDB_KEY_FOREIGN, ['instanceid'], $reftable, ['id']);
if ($dbman->find_key_name($t, $oldkey)) {
$dbman->drop_key($t, $oldkey);
}
}
}
$tablerenames = [
'meetletacbmarket' => 'meetletacbfree',
'meetletacbmarket_meetings' => 'meetletacbfree_meetings',
'meetletacbmarket_recordings' => 'meetletacbfree_recordings',
'meetletacbmarket_license' => 'meetletacbfree_license',
'meetletacbmarket_jobqueue' => 'meetletacbfree_jobqueue',
];
foreach ($tablerenames as $from => $to) {
if ($dbman->table_exists($from) && !$dbman->table_exists($to)) {
$dbman->rename_table(new xmldb_table($from), $to);
}
}
if ($dbman->table_exists('meetletacbfree')) {
foreach (['meetletacbfree_meetings', 'meetletacbfree_recordings'] as $tname) {
if (!$dbman->table_exists($tname)) {
continue;
}
$t = new xmldb_table($tname);
$newkey = new xmldb_key('fk_instance', XMLDB_KEY_FOREIGN, ['instanceid'], 'meetletacbfree', ['id']);
if (!$dbman->find_key_name($t, $newkey)) {
$dbman->add_key($t, $newkey);
}
}
}
foreach (['meetletacbmarket', 'meetletacbmarketplace', 'meetletacbmdlrules'] as $oldmodname) {
if ($mod = $DB->get_record('modules', ['name' => $oldmodname])) {
if ($existing = $DB->get_record('modules', ['name' => 'meetletacbfree'])) {
if ($dbman->table_exists('course_modules')) {
$DB->execute(
"UPDATE {course_modules} SET module = ? WHERE module = ?",
[$existing->id, $mod->id]
);
}
$DB->delete_records('modules', ['id' => $mod->id]);
} else {
$mod->name = 'meetletacbfree';
$DB->update_record('modules', $mod);
}
}
if ($dbman->table_exists('event')) {
$DB->set_field('event', 'modulename', 'meetletacbfree', ['modulename' => $oldmodname]);
}
if ($dbman->table_exists('grade_items')) {
$DB->set_field('grade_items', 'itemmodule', 'meetletacbfree', ['itemmodule' => $oldmodname]);
}
if ($dbman->table_exists('course_modules') && $DB->record_exists('modules', ['name' => 'meetletacbfree'])) {
$DB->execute(
"UPDATE {course_modules} SET module = (
SELECT id FROM {modules} WHERE name = 'meetletacbfree'
) WHERE module = (
SELECT id FROM {modules} WHERE name = ?
)",
[$oldmodname]
);
}
}
if (!$DB->record_exists('modules', ['name' => 'meetletacbfree'])) {
$mod = (object)['name' => 'meetletacbfree', 'cron' => 0, 'visible' => 1];
$DB->insert_record('modules', $mod);
}
$freeids = $DB->get_records('modules', ['name' => 'meetletacbfree'], 'id ASC');
if (count($freeids) > 1) {
$keep = array_shift($freeids);
foreach ($freeids as $dup) {
$DB->delete_records('modules', ['id' => $dup->id]);
}
}
foreach (['meetletacbmarket', 'meetletacbmarketplace', 'meetletacbmdlrules'] as $oldplugin) {
$configs = $DB->get_records('config_plugins', ['plugin' => $oldplugin]);
foreach ($configs as $cfg) {
if ($DB->record_exists('config_plugins', ['plugin' => 'meetletacbfree', 'name' => $cfg->name])) {
continue;
}
$cfg->plugin = 'meetletacbfree';
$DB->insert_record('config_plugins', $cfg);
}
$DB->delete_records('config_plugins', ['plugin' => $oldplugin]);
}
}