91334a46b5
Co-authored-by: Cursor <cursoragent@cursor.com>
585 lines
20 KiB
PHP
585 lines
20 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/>.
|
|
|
|
/**
|
|
* Library functions for MeetLet Adobe Connect Bridge.
|
|
*
|
|
* @package mod_meetletacbfree
|
|
* @copyright 2026 MeetLet
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
*/
|
|
|
|
defined('MOODLE_INTERNAL') || die();
|
|
|
|
use mod_meetletacbfree\api\service;
|
|
use mod_meetletacbfree\local\config;
|
|
use mod_meetletacbfree\local\roles;
|
|
|
|
/**
|
|
* Feature support.
|
|
*
|
|
* @param string $feature
|
|
* @return mixed
|
|
*/
|
|
function meetletacbfree_supports($feature) {
|
|
switch ($feature) {
|
|
case FEATURE_GROUPS:
|
|
return true;
|
|
case FEATURE_GROUPINGS:
|
|
return true;
|
|
case FEATURE_MOD_INTRO:
|
|
return true;
|
|
case FEATURE_COMPLETION_TRACKS_VIEWS:
|
|
return true;
|
|
case FEATURE_GRADE_HAS_GRADE:
|
|
return true;
|
|
case FEATURE_GRADE_OUTCOMES:
|
|
return false;
|
|
case FEATURE_BACKUP_MOODLE2:
|
|
return true;
|
|
case FEATURE_SHOW_DESCRIPTION:
|
|
return true;
|
|
case FEATURE_MOD_PURPOSE:
|
|
return MOD_PURPOSE_COMMUNICATION;
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Declare branded monologo so Moodle does not recolor it (orange communication filter).
|
|
*
|
|
* @return bool
|
|
*/
|
|
function meetletacbfree_is_branded(): bool {
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Control activity chooser visibility until online registration is complete.
|
|
*
|
|
* @param \core_course\local\entity\content_item $contentitem
|
|
* @param \stdClass $user
|
|
* @param \stdClass $course
|
|
* @return array
|
|
*/
|
|
function mod_meetletacbfree_get_course_content_items(
|
|
\core_course\local\entity\content_item $contentitem,
|
|
\stdClass $user,
|
|
\stdClass $course
|
|
): array {
|
|
if (!\mod_meetletacbfree\registration\manager::is_registered()) {
|
|
return [];
|
|
}
|
|
return [$contentitem];
|
|
}
|
|
|
|
/**
|
|
* Add instance.
|
|
*
|
|
* @param stdClass $data
|
|
* @param mod_meetletacbfree_mod_form|null $mform
|
|
* @return int
|
|
*/
|
|
function meetletacbfree_add_instance($data, $mform = null) {
|
|
global $DB, $USER;
|
|
|
|
\mod_meetletacbfree\registration\manager::require_registered();
|
|
|
|
$data->timecreated = time();
|
|
$data->timemodified = $data->timecreated;
|
|
$data->userid = $USER->id;
|
|
if (empty($data->endtimeenable)) {
|
|
$data->endtime = 0;
|
|
}
|
|
$coursecontext = context_course::instance($data->course);
|
|
$data->participantsmode = empty($data->participantsmode) ? 0 : 1;
|
|
if (empty($data->participantsmode)) {
|
|
$data->participants = '';
|
|
} else if (empty($data->participants)) {
|
|
$data->participants = json_encode(roles::get_participant_list_default($coursecontext, $USER->id));
|
|
}
|
|
$togglefields = meetletacbfree_activity_override_fields();
|
|
$data->settingoverrides = config::setting_overrides_json(meetletacbfree_collect_setting_override_states($data, $togglefields));
|
|
$data->autooffline = meetletacbfree_legacy_setting_value($data, 'autooffline');
|
|
$data->meetingpublic = empty($data->meetingpublic) ? 0 : 1;
|
|
$data->showzip = meetletacbfree_legacy_setting_value($data, 'showzip');
|
|
$data->showofflineplayer = empty($data->showofflineplayer) ? 0 : 1;
|
|
$data->showrecordingstab = meetletacbfree_legacy_setting_value($data, 'showrecordingstab');
|
|
$data->showcontenttab = meetletacbfree_legacy_setting_value($data, 'showcontenttab');
|
|
$data->showmp4 = meetletacbfree_legacy_setting_value($data, 'showmp4');
|
|
$data->showmakeoffline = meetletacbfree_legacy_setting_value($data, 'showmakeoffline');
|
|
$data->linkmode = empty($data->linkmode) ? 0 : 1;
|
|
$data->existingscoid = (int)($data->existingscoid ?? 0);
|
|
$data->waitforhost = meetletacbfree_legacy_setting_value($data, 'waitforhost');
|
|
$data->meetinglang = clean_param($data->meetinglang ?? '', PARAM_ALPHANUMEXT);
|
|
if ($data->linkmode) {
|
|
$data->templatescoid = 0;
|
|
$data->meeturl = '';
|
|
}
|
|
$data->meeturl = meetletacbfree_clean_meet_url($data->meeturl ?? '');
|
|
if (empty($data->featureaccess_override)) {
|
|
$data->featureaccess = '';
|
|
} else {
|
|
$matrix = optional_param_array('featureaccess_matrix', [], PARAM_RAW);
|
|
$data->featureaccess = \mod_meetletacbfree\local\featureaccess::matrix_from_post($matrix);
|
|
}
|
|
unset($data->featureaccess_override, $data->featureaccess_matrix);
|
|
meetletacbfree_clear_override_form_fields($data, $togglefields);
|
|
|
|
$id = $DB->insert_record('meetletacbfree', $data);
|
|
$data->id = $id;
|
|
|
|
meetletacbfree_create_remote_meetings($data);
|
|
meetletacbfree_grade_item_update($data);
|
|
meetletacbfree_update_calendar($data);
|
|
|
|
return $id;
|
|
}
|
|
|
|
/**
|
|
* Update instance.
|
|
*
|
|
* @param stdClass $data
|
|
* @param mod_meetletacbfree_mod_form|null $mform
|
|
* @return bool
|
|
*/
|
|
function meetletacbfree_update_instance($data, $mform = null) {
|
|
global $DB, $USER;
|
|
|
|
\mod_meetletacbfree\registration\manager::require_registered();
|
|
|
|
$data->timemodified = time();
|
|
$data->id = $data->instance;
|
|
if (empty($data->endtimeenable)) {
|
|
$data->endtime = 0;
|
|
}
|
|
$coursecontext = context_course::instance($data->course);
|
|
$data->participantsmode = empty($data->participantsmode) ? 0 : 1;
|
|
if (empty($data->participantsmode)) {
|
|
$data->participants = '';
|
|
} else if (empty($data->participants)) {
|
|
$data->participants = json_encode(roles::get_participant_list_default($coursecontext, $USER->id ?? 0));
|
|
}
|
|
$togglefields = meetletacbfree_activity_override_fields();
|
|
$data->settingoverrides = config::setting_overrides_json(meetletacbfree_collect_setting_override_states($data, $togglefields));
|
|
$data->autooffline = meetletacbfree_legacy_setting_value($data, 'autooffline');
|
|
$data->meetingpublic = empty($data->meetingpublic) ? 0 : 1;
|
|
$data->showzip = meetletacbfree_legacy_setting_value($data, 'showzip');
|
|
$data->showofflineplayer = empty($data->showofflineplayer) ? 0 : 1;
|
|
$data->showrecordingstab = meetletacbfree_legacy_setting_value($data, 'showrecordingstab');
|
|
$data->showcontenttab = meetletacbfree_legacy_setting_value($data, 'showcontenttab');
|
|
$data->showmp4 = meetletacbfree_legacy_setting_value($data, 'showmp4');
|
|
$data->showmakeoffline = meetletacbfree_legacy_setting_value($data, 'showmakeoffline');
|
|
$data->waitforhost = meetletacbfree_legacy_setting_value($data, 'waitforhost');
|
|
$data->meetinglang = clean_param($data->meetinglang ?? '', PARAM_ALPHANUMEXT);
|
|
// linkmode / existingscoid are immutable after create.
|
|
unset($data->linkmode, $data->existingscoid);
|
|
if (empty($data->featureaccess_override)) {
|
|
$data->featureaccess = '';
|
|
} else {
|
|
$matrix = optional_param_array('featureaccess_matrix', [], PARAM_RAW);
|
|
$data->featureaccess = \mod_meetletacbfree\local\featureaccess::matrix_from_post($matrix);
|
|
}
|
|
unset($data->featureaccess_override, $data->featureaccess_matrix);
|
|
meetletacbfree_clear_override_form_fields($data, $togglefields);
|
|
|
|
$DB->update_record('meetletacbfree', $data);
|
|
|
|
if (config::is_configured()) {
|
|
$service = new service();
|
|
$service->login_admin();
|
|
$maps = $DB->get_records('meetletacbfree_meetings', ['instanceid' => $data->id]);
|
|
foreach ($maps as $map) {
|
|
$payload = clone $data;
|
|
if (!empty($map->groupid)) {
|
|
$group = groups_get_group($map->groupid);
|
|
if ($group) {
|
|
$payload->name = $data->name . '_' . $group->name;
|
|
}
|
|
}
|
|
// Create or linked: push name/times/options to Adobe.
|
|
$service->update_meeting((int)$map->meetingscoid, $payload);
|
|
$service->set_meeting_public((int)$map->meetingscoid, !empty($data->meetingpublic));
|
|
}
|
|
$service->logout();
|
|
}
|
|
|
|
meetletacbfree_grade_item_update($data);
|
|
meetletacbfree_update_calendar($data);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Delete instance.
|
|
*
|
|
* @param int $id
|
|
* @return bool
|
|
*/
|
|
function meetletacbfree_delete_instance($id) {
|
|
global $DB;
|
|
|
|
\mod_meetletacbfree\registration\manager::require_registered();
|
|
|
|
if (!$record = $DB->get_record('meetletacbfree', ['id' => $id])) {
|
|
return false;
|
|
}
|
|
|
|
if (config::is_configured()) {
|
|
try {
|
|
$service = new service();
|
|
$service->login_admin();
|
|
$maps = $DB->get_records('meetletacbfree_meetings', ['instanceid' => $id]);
|
|
$deleteremote = empty($record->linkmode);
|
|
foreach ($maps as $map) {
|
|
if ($deleteremote) {
|
|
$service->delete_sco((int)$map->meetingscoid);
|
|
}
|
|
}
|
|
$service->logout();
|
|
} catch (Throwable $e) {
|
|
debugging('MeetLet delete remote meeting failed: ' . $e->getMessage(), DEBUG_DEVELOPER);
|
|
}
|
|
}
|
|
|
|
$DB->delete_records('meetletacbfree_recordings', ['instanceid' => $id]);
|
|
$DB->delete_records('meetletacbfree_meetings', ['instanceid' => $id]);
|
|
$DB->delete_records('meetletacbfree', ['id' => $id]);
|
|
|
|
meetletacbfree_grade_item_delete($record);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Create Adobe meetings for activity (and groups).
|
|
*
|
|
* @param stdClass $data
|
|
*/
|
|
function meetletacbfree_create_remote_meetings(stdClass $data): void {
|
|
global $DB, $COURSE, $USER;
|
|
|
|
if (!config::is_configured()) {
|
|
return;
|
|
}
|
|
|
|
$service = new service();
|
|
$service->login_admin();
|
|
$coursecontext = context_course::instance((int)$data->course);
|
|
$creatorrole = roles::resolve_adobe_role($data, $coursecontext, (int)($USER->id ?? 0));
|
|
if ($creatorrole === null) {
|
|
$creatorrole = service::ROLE_HOST;
|
|
}
|
|
$provisionscoids = [];
|
|
|
|
// Link an existing Adobe meeting instead of creating one.
|
|
if (!empty($data->linkmode) && !empty($data->existingscoid)) {
|
|
$scoid = (int)$data->existingscoid;
|
|
$info = $service->meeting_info($scoid);
|
|
if (!$info) {
|
|
$service->logout();
|
|
throw new moodle_exception('errorexistingsco', 'meetletacbfree');
|
|
}
|
|
$service->set_meeting_public($scoid, !empty($data->meetingpublic));
|
|
// Push Moodle form values (name/times/options) onto the existing Adobe meeting.
|
|
$service->update_meeting($scoid, $data);
|
|
$map = (object)[
|
|
'instanceid' => $data->id,
|
|
'meetingscoid' => $scoid,
|
|
'groupid' => 0,
|
|
'urlpath' => $info->url ?? '',
|
|
];
|
|
$DB->insert_record('meetletacbfree_meetings', $map);
|
|
$provisionscoids[] = $scoid;
|
|
if (!empty($info->url)) {
|
|
$DB->set_field('meetletacbfree', 'meeturl', trim($info->url, '/'), ['id' => $data->id]);
|
|
}
|
|
meetletacbfree_provision_creator_on_meetings($service, $data, $provisionscoids, $creatorrole);
|
|
$service->logout();
|
|
return;
|
|
}
|
|
|
|
$folder = $service->get_folder_scoid('meetings');
|
|
if (!$folder) {
|
|
$service->logout();
|
|
throw new moodle_exception('errornofolder', 'meetletacbfree');
|
|
}
|
|
|
|
// During add_instance, course_modules.instance is not linked yet — use form data.
|
|
$groupmode = (int)($data->groupmode ?? 0);
|
|
|
|
if ($groupmode) {
|
|
$groups = groups_get_all_groups($data->course);
|
|
foreach ($groups as $group) {
|
|
$payload = clone $data;
|
|
$payload->name = $data->name . '_' . $group->name;
|
|
if (!empty($data->meeturl)) {
|
|
$payload->meeturl = meetletacbfree_clean_meet_url($data->meeturl . '_' . $group->name);
|
|
}
|
|
$scoid = $service->create_meeting($payload, $folder);
|
|
$service->set_meeting_public($scoid, !empty($data->meetingpublic));
|
|
$info = $service->meeting_info($scoid);
|
|
$map = (object)[
|
|
'instanceid' => $data->id,
|
|
'meetingscoid' => $scoid,
|
|
'groupid' => $group->id,
|
|
'urlpath' => $info->url ?? '',
|
|
];
|
|
$DB->insert_record('meetletacbfree_meetings', $map);
|
|
$provisionscoids[] = $scoid;
|
|
}
|
|
} else {
|
|
$scoid = $service->create_meeting($data, $folder);
|
|
$service->set_meeting_public($scoid, !empty($data->meetingpublic));
|
|
$info = $service->meeting_info($scoid);
|
|
$map = (object)[
|
|
'instanceid' => $data->id,
|
|
'meetingscoid' => $scoid,
|
|
'groupid' => 0,
|
|
'urlpath' => $info->url ?? '',
|
|
];
|
|
$DB->insert_record('meetletacbfree_meetings', $map);
|
|
$provisionscoids[] = $scoid;
|
|
if (empty($data->meeturl) && !empty($info->url)) {
|
|
$DB->set_field('meetletacbfree', 'meeturl', trim($info->url, '/'), ['id' => $data->id]);
|
|
}
|
|
}
|
|
|
|
meetletacbfree_provision_creator_on_meetings($service, $data, $provisionscoids, $creatorrole);
|
|
$service->logout();
|
|
}
|
|
|
|
/**
|
|
* Provision the activity creator on newly created Adobe meetings (admin API).
|
|
*
|
|
* @param int[] $scoids
|
|
*/
|
|
function meetletacbfree_provision_creator_on_meetings(service $service, stdClass $data, array $scoids, string $permission): void {
|
|
global $USER;
|
|
if (empty($scoids) || empty($USER->id)) {
|
|
return;
|
|
}
|
|
try {
|
|
foreach (array_unique(array_map('intval', $scoids)) as $scoid) {
|
|
if ($scoid > 0) {
|
|
$service->provision_user_on_meeting($USER, $scoid, $permission);
|
|
}
|
|
}
|
|
} catch (Throwable $e) {
|
|
debugging('MeetLet provision creator on meeting failed: ' . $e->getMessage(), DEBUG_DEVELOPER);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clean custom meeting URL path.
|
|
*/
|
|
function meetletacbfree_clean_meet_url(string $url): string {
|
|
$url = trim($url);
|
|
$url = trim($url, '/');
|
|
$url = preg_replace('/[^a-zA-Z0-9\-]/', '', $url);
|
|
return substr((string)$url, 0, 60);
|
|
}
|
|
|
|
/**
|
|
* Grade item update.
|
|
*/
|
|
function meetletacbfree_grade_item_update($meetlet, $grades = null) {
|
|
global $CFG;
|
|
require_once($CFG->libdir . '/gradelib.php');
|
|
|
|
$params = [
|
|
'itemname' => $meetlet->name,
|
|
'idnumber' => $meetlet->cmidnumber ?? '',
|
|
];
|
|
|
|
if (isset($meetlet->grade) && $meetlet->grade > 0) {
|
|
$params['gradetype'] = GRADE_TYPE_VALUE;
|
|
$params['grademax'] = $meetlet->grade;
|
|
$params['grademin'] = 0;
|
|
} else if (isset($meetlet->grade) && $meetlet->grade < 0) {
|
|
$params['gradetype'] = GRADE_TYPE_SCALE;
|
|
$params['scaleid'] = -$meetlet->grade;
|
|
} else {
|
|
$params['gradetype'] = GRADE_TYPE_NONE;
|
|
}
|
|
|
|
if ($grades === 'reset') {
|
|
$params['reset'] = true;
|
|
$grades = null;
|
|
}
|
|
|
|
return grade_update('mod/meetletacbfree', $meetlet->course, 'mod', 'meetletacbfree', $meetlet->id, 0, $grades, $params);
|
|
}
|
|
|
|
/**
|
|
* Delete grade item.
|
|
*/
|
|
function meetletacbfree_grade_item_delete($meetlet) {
|
|
global $CFG;
|
|
require_once($CFG->libdir . '/gradelib.php');
|
|
return grade_update('mod/meetletacbfree', $meetlet->course, 'mod', 'meetletacbfree', $meetlet->id, 0, null, ['deleted' => 1]);
|
|
}
|
|
|
|
/**
|
|
* Update calendar event.
|
|
*/
|
|
function meetletacbfree_update_calendar($meetlet): void {
|
|
global $DB, $CFG;
|
|
require_once($CFG->dirroot . '/calendar/lib.php');
|
|
|
|
$event = $DB->get_record('event', [
|
|
'modulename' => 'meetletacbfree',
|
|
'instance' => $meetlet->id,
|
|
]);
|
|
if (!$event) {
|
|
// Pre-rename calendar rows.
|
|
$event = $DB->get_record('event', [
|
|
'modulename' => 'meetlet',
|
|
'instance' => $meetlet->id,
|
|
]);
|
|
}
|
|
|
|
if (empty($meetlet->starttime)) {
|
|
if ($event) {
|
|
$calendarevent = calendar_event::load($event->id);
|
|
$calendarevent->delete();
|
|
}
|
|
return;
|
|
}
|
|
|
|
$eventdata = new stdClass();
|
|
$eventdata->name = $meetlet->name;
|
|
$eventdata->description = format_module_intro('meetletacbfree', $meetlet, $meetlet->coursemodule ?? 0, false);
|
|
$eventdata->format = FORMAT_HTML;
|
|
$eventdata->courseid = $meetlet->course;
|
|
$eventdata->groupid = 0;
|
|
$eventdata->userid = 0;
|
|
$eventdata->modulename = 'meetletacbfree';
|
|
$eventdata->instance = $meetlet->id;
|
|
$eventdata->eventtype = 'course';
|
|
$eventdata->timestart = $meetlet->starttime;
|
|
$eventdata->timeduration = !empty($meetlet->endtime) ? max(0, $meetlet->endtime - $meetlet->starttime) : 0;
|
|
$eventdata->visible = 1;
|
|
|
|
if ($event) {
|
|
$calendarevent = calendar_event::load($event->id);
|
|
$calendarevent->update($eventdata);
|
|
} else {
|
|
calendar_event::create($eventdata);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Extend settings navigation (optional).
|
|
*/
|
|
function meetletacbfree_extend_settings_navigation(settings_navigation $settingsnav, navigation_node $meetletnode) {
|
|
// Intentionally minimal ? roles are configured in activity settings.
|
|
}
|
|
|
|
/**
|
|
* Course module info for course page.
|
|
*/
|
|
function meetletacbfree_get_coursemodule_info($coursemodule) {
|
|
global $DB;
|
|
if (!$record = $DB->get_record('meetletacbfree', ['id' => $coursemodule->instance], 'id, name, intro, introformat, starttime, endtime')) {
|
|
return false;
|
|
}
|
|
$info = new cached_cm_info();
|
|
$info->name = $record->name;
|
|
if ($coursemodule->showdescription) {
|
|
$info->content = format_module_intro('meetletacbfree', $record, $coursemodule->id, false);
|
|
}
|
|
// Branded monologo: skip Moodle purpose colour filter (orange on course page).
|
|
$info->customdata['filtericon'] = false;
|
|
return $info;
|
|
}
|
|
|
|
/**
|
|
* Apply plugin cron interval to the Moodle scheduled task row.
|
|
*/
|
|
function meetletacbfree_update_cron_interval() {
|
|
\mod_meetletacbfree\local\config::apply_cron_interval();
|
|
}
|
|
|
|
/**
|
|
* Activity boolean settings managed by the inherit/override model.
|
|
*
|
|
* @return string[]
|
|
*/
|
|
function meetletacbfree_activity_override_fields(): array {
|
|
return ['waitforhost', 'autooffline', 'showzip', 'showrecordingstab', 'showcontenttab', 'showmp4', 'showmakeoffline'];
|
|
}
|
|
|
|
/**
|
|
* Collect posted three-state values for activity settings.
|
|
*
|
|
* @param stdClass $data
|
|
* @param string[] $fields
|
|
* @return array<string,int>
|
|
*/
|
|
function meetletacbfree_collect_setting_override_states(stdClass $data, array $fields): array {
|
|
$states = [];
|
|
foreach ($fields as $field) {
|
|
$statefield = $field . '_state';
|
|
$states[$field] = $data->{$statefield} ?? \mod_meetletacbfree\local\config::OVERRIDE_INHERIT;
|
|
}
|
|
return $states;
|
|
}
|
|
|
|
/**
|
|
* Keep legacy columns in sync for older code, reports and backups.
|
|
*/
|
|
function meetletacbfree_legacy_setting_value(stdClass $data, string $field): int {
|
|
$statefield = $field . '_state';
|
|
$state = \mod_meetletacbfree\local\config::normalize_override_state($data->{$statefield} ?? null);
|
|
if ($state === \mod_meetletacbfree\local\config::OVERRIDE_ON) {
|
|
return 1;
|
|
}
|
|
if ($state === \mod_meetletacbfree\local\config::OVERRIDE_OFF) {
|
|
return 0;
|
|
}
|
|
switch ($field) {
|
|
case 'waitforhost':
|
|
return \mod_meetletacbfree\local\config::default_wait_for_host() ? 1 : 0;
|
|
case 'autooffline':
|
|
return \mod_meetletacbfree\local\config::auto_offline_default() ? 1 : 0;
|
|
case 'showzip':
|
|
return \mod_meetletacbfree\local\config::feature_enabled('zip') ? 1 : 0;
|
|
case 'showrecordingstab':
|
|
return \mod_meetletacbfree\local\config::feature_enabled('recordingstab') ? 1 : 0;
|
|
case 'showcontenttab':
|
|
return \mod_meetletacbfree\local\config::feature_enabled('contenttab') ? 1 : 0;
|
|
case 'showmp4':
|
|
return \mod_meetletacbfree\local\config::feature_enabled('mp4') ? 1 : 0;
|
|
case 'showmakeoffline':
|
|
return \mod_meetletacbfree\local\config::feature_enabled('makeoffline') ? 1 : 0;
|
|
default:
|
|
return empty($data->{$field}) ? 0 : 1;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove transient form-only fields before DB write.
|
|
*
|
|
* @param stdClass $data
|
|
* @param string[] $fields
|
|
*/
|
|
function meetletacbfree_clear_override_form_fields(stdClass $data, array $fields): void {
|
|
foreach ($fields as $field) {
|
|
$statefield = $field . '_state';
|
|
unset($data->{$statefield});
|
|
}
|
|
}
|