From b8a9d1d649b76d4c45d168ed4fe9856320fc9b6a Mon Sep 17 00:00:00 2001 From: Damien Date: Mon, 29 Jun 2026 10:48:15 +0200 Subject: [PATCH 1/2] =?UTF-8?q?=E2=9C=A8=20EDFLEX1-15025:=20Add=20backup/r?= =?UTF-8?q?estore,=20view=20capability=20and=20viewed=20event?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses the Moodle Marketplace review blockers (MMRT-99) before resubmission: - implement the Backup/Restore moodle2 API for the edflex activity - gate view.php behind a new mod/edflex:view capability - emit the standard course_module_viewed event --- .../backup_edflex_activity_task.class.php | 75 +++++++++++++++ backup/moodle2/backup_edflex_stepslib.php | 52 +++++++++++ .../restore_edflex_activity_task.class.php | 91 +++++++++++++++++++ backup/moodle2/restore_edflex_stepslib.php | 74 +++++++++++++++ classes/event/course_module_viewed.php | 57 ++++++++++++ db/access.php | 11 +++ lang/en/edflex.php | 1 + lib.php | 11 ++- version.php | 4 +- view.php | 18 ++++ 10 files changed, 391 insertions(+), 3 deletions(-) create mode 100644 backup/moodle2/backup_edflex_activity_task.class.php create mode 100644 backup/moodle2/backup_edflex_stepslib.php create mode 100644 backup/moodle2/restore_edflex_activity_task.class.php create mode 100644 backup/moodle2/restore_edflex_stepslib.php create mode 100644 classes/event/course_module_viewed.php diff --git a/backup/moodle2/backup_edflex_activity_task.class.php b/backup/moodle2/backup_edflex_activity_task.class.php new file mode 100644 index 0000000..b24ba42 --- /dev/null +++ b/backup/moodle2/backup_edflex_activity_task.class.php @@ -0,0 +1,75 @@ +. + +/** + * Backup task for mod_edflex. + * + * @package mod_edflex + * @copyright 2025 Edflex + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->dirroot . '/mod/edflex/backup/moodle2/backup_edflex_stepslib.php'); + +/** + * Provides the steps to perform one complete backup of the edflex instance. + * + * @package mod_edflex + * @copyright 2025 Edflex + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class backup_edflex_activity_task extends backup_activity_task { + + /** + * Defines particular settings for this activity task. None required. + * + * @return void + */ + protected function define_my_settings() { + } + + /** + * Defines particular steps for this activity backup. + * + * @return void + */ + protected function define_my_steps() { + $this->add_step(new backup_edflex_activity_structure_step('edflex_structure', 'edflex.xml')); + } + + /** + * Encodes URLs to the view and index scripts so they can be decoded on restore. + * + * @param string $content The content to encode. + * + * @return string The content with encoded links. + */ + public static function encode_content_links($content) { + global $CFG; + + $base = preg_quote($CFG->wwwroot, '/'); + + $search = '/(' . $base . '\/mod\/edflex\/view\.php\?id\=)([0-9]+)/'; + $content = preg_replace($search, '$@EDFLEXVIEWBYID*$2@$', $content); + + $search = '/(' . $base . '\/mod\/edflex\/index\.php\?id\=)([0-9]+)/'; + $content = preg_replace($search, '$@EDFLEXINDEX*$2@$', $content); + + return $content; + } +} diff --git a/backup/moodle2/backup_edflex_stepslib.php b/backup/moodle2/backup_edflex_stepslib.php new file mode 100644 index 0000000..d9dec4b --- /dev/null +++ b/backup/moodle2/backup_edflex_stepslib.php @@ -0,0 +1,52 @@ +. + +/** + * Backup steps for mod_edflex. + * + * @package mod_edflex + * @copyright 2025 Edflex + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * Defines the complete edflex structure for backup, with file annotations. + * + * @package mod_edflex + * @copyright 2025 Edflex + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class backup_edflex_activity_structure_step extends backup_activity_structure_step { + + /** + * Defines the backup structure of the edflex activity. + * + * @return backup_nested_element The prepared activity structure to back up. + */ + protected function define_structure() { + $edflex = new backup_nested_element('edflex', ['id'], [ + 'name', 'intro', 'introformat', 'timemodified', + ]); + + $edflex->set_source_table('edflex', ['id' => backup::VAR_ACTIVITYID]); + + $edflex->annotate_files('mod_edflex', 'intro', null); + + return $this->prepare_activity_structure($edflex); + } +} diff --git a/backup/moodle2/restore_edflex_activity_task.class.php b/backup/moodle2/restore_edflex_activity_task.class.php new file mode 100644 index 0000000..cd65177 --- /dev/null +++ b/backup/moodle2/restore_edflex_activity_task.class.php @@ -0,0 +1,91 @@ +. + +/** + * Restore task for mod_edflex. + * + * @package mod_edflex + * @copyright 2025 Edflex + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->dirroot . '/mod/edflex/backup/moodle2/restore_edflex_stepslib.php'); + +/** + * Restore task for the edflex activity module. + * + * @package mod_edflex + * @copyright 2025 Edflex + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class restore_edflex_activity_task extends restore_activity_task { + + /** + * Defines particular settings for this activity task. None required. + * + * @return void + */ + protected function define_my_settings() { + } + + /** + * Defines particular steps for this activity restore. + * + * @return void + */ + protected function define_my_steps() { + $this->add_step(new restore_edflex_activity_structure_step('edflex_structure', 'edflex.xml')); + } + + /** + * Defines the contents in the activity that must be processed by the link decoder. + * + * @return array The decode contents. + */ + public static function define_decode_contents() { + $contents = []; + $contents[] = new restore_decode_content('edflex', ['intro'], 'edflex'); + + return $contents; + } + + /** + * Defines the decoding rules for links belonging to the activity to be executed by the link decoder. + * + * @return array The decode rules. + */ + public static function define_decode_rules() { + $rules = []; + $rules[] = new restore_decode_rule('EDFLEXVIEWBYID', '/mod/edflex/view.php?id=$1', 'course_module'); + $rules[] = new restore_decode_rule('EDFLEXINDEX', '/mod/edflex/index.php?id=$1', 'course'); + + return $rules; + } + + /** + * Defines the restore log rules that will be applied for the activity logs. + * + * @return array The restore log rules. + */ + public static function define_restore_log_rules() { + $rules = []; + $rules[] = new restore_log_rule('edflex', 'view', 'view.php?id={course_module}', '{edflex}'); + + return $rules; + } +} diff --git a/backup/moodle2/restore_edflex_stepslib.php b/backup/moodle2/restore_edflex_stepslib.php new file mode 100644 index 0000000..4b4a8fd --- /dev/null +++ b/backup/moodle2/restore_edflex_stepslib.php @@ -0,0 +1,74 @@ +. + +/** + * Restore steps for mod_edflex. + * + * @package mod_edflex + * @copyright 2025 Edflex + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +/** + * Defines the structure step to restore one edflex activity. + * + * @package mod_edflex + * @copyright 2025 Edflex + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class restore_edflex_activity_structure_step extends restore_activity_structure_step { + + /** + * Defines the structure to be restored for the edflex activity. + * + * @return mixed The prepared activity structure. + */ + protected function define_structure() { + $paths = []; + $paths[] = new restore_path_element('edflex', '/activity/edflex'); + + return $this->prepare_activity_structure($paths); + } + + /** + * Restores one edflex instance from the backup data. + * + * @param array $data The edflex record to restore. + * + * @return void + */ + protected function process_edflex($data) { + global $DB; + + $data = (object) $data; + $data->course = $this->get_courseid(); + $data->timemodified = $this->apply_date_offset($data->timemodified); + + $newitemid = $DB->insert_record('edflex', $data); + $this->apply_activity_instance($newitemid); + } + + /** + * Re-adds the files belonging to the restored instance once execution completes. + * + * @return void + */ + protected function after_execute() { + $this->add_related_files('mod_edflex', 'intro', null); + } +} diff --git a/classes/event/course_module_viewed.php b/classes/event/course_module_viewed.php new file mode 100644 index 0000000..ad9fe18 --- /dev/null +++ b/classes/event/course_module_viewed.php @@ -0,0 +1,57 @@ +. + +/** + * The mod_edflex course module viewed event. + * + * @package mod_edflex + * @copyright 2025 Edflex + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_edflex\event; + +defined('MOODLE_INTERNAL') || die(); + +/** + * The mod_edflex course module viewed event class. + * + * @package mod_edflex + * @copyright 2025 Edflex + * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class course_module_viewed extends \core\event\course_module_viewed { + + /** + * Init method. + * + * @return void + */ + protected function init() { + $this->data['crud'] = 'r'; + $this->data['edulevel'] = self::LEVEL_PARTICIPATING; + $this->data['objecttable'] = 'edflex'; + } + + /** + * Returns the mapping used by restore to remap the objectid. + * + * @return array The objectid mapping. + */ + public static function get_objectid_mapping() { + return ['db' => 'edflex', 'restore' => 'edflex']; + } +} diff --git a/db/access.php b/db/access.php index d4d67f3..d8f32eb 100755 --- a/db/access.php +++ b/db/access.php @@ -31,4 +31,15 @@ 'contextlevel' => CONTEXT_COURSE, 'archetypes' => ['editingteacher' => CAP_ALLOW, 'manager' => CAP_ALLOW], ], + 'mod/edflex:view' => [ + 'captype' => 'read', + 'contextlevel' => CONTEXT_MODULE, + 'archetypes' => [ + 'guest' => CAP_ALLOW, + 'student' => CAP_ALLOW, + 'teacher' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW, + ], + ], ]; diff --git a/lang/en/edflex.php b/lang/en/edflex.php index c360c68..95723ff 100755 --- a/lang/en/edflex.php +++ b/lang/en/edflex.php @@ -60,6 +60,7 @@ $string['downloadscormzipmissing'] = 'Scorm download URL is missing'; $string['duration'] = 'Duration'; $string['edflex:addinstance'] = 'Add a new Edflex activity'; +$string['edflex:view'] = 'View Edflex activity'; $string['edflexbrowserloading'] = 'Loading...'; $string['edflexbrowsertitle'] = 'Browse Edflex Contents'; $string['edflexcontentidinvalid'] = 'Edflex content ID invalid'; diff --git a/lib.php b/lib.php index e75e225..9504889 100755 --- a/lib.php +++ b/lib.php @@ -36,7 +36,14 @@ * @return mixed True if module supports feature, null if doesn't know */ function edflex_supports($feature) { - return null; + switch ($feature) { + case FEATURE_MOD_INTRO: + case FEATURE_SHOW_DESCRIPTION: + case FEATURE_BACKUP_MOODLE2: + return true; + default: + return null; + } } /** @@ -48,6 +55,8 @@ function edflex_supports($feature) { * @return bool */ function edflex_add_instance($moduleinstance, $mform = null) { + // mod_edflex is a launcher only: the form spawns SCORM modules via the + // Edflex browser, so no standalone edflex instance is ever persisted. return false; } diff --git a/version.php b/version.php index a646671..61ef6f7 100755 --- a/version.php +++ b/version.php @@ -25,8 +25,8 @@ defined('MOODLE_INTERNAL') || die(); $plugin->component = 'mod_edflex'; -$plugin->release = 'v1.0.1'; -$plugin->version = 2026062400; +$plugin->release = 'v1.0.2'; +$plugin->version = 2026062900; $plugin->requires = 2022041900; $plugin->maturity = MATURITY_STABLE; $plugin->dependencies = [ diff --git a/view.php b/view.php index 96c0b07..067b397 100755 --- a/view.php +++ b/view.php @@ -26,9 +26,27 @@ $id = required_param('id', PARAM_INT); $cm = get_coursemodule_from_id('edflex', $id, 0, false, MUST_EXIST); $course = $DB->get_record('course', ['id' => $cm->course], '*', MUST_EXIST); +$moduleinstance = $DB->get_record('edflex', ['id' => $cm->instance], '*', MUST_EXIST); require_login($course, true, $cm); +$context = context_module::instance($cm->id); +require_capability('mod/edflex:view', $context); + +$PAGE->set_url('/mod/edflex/view.php', ['id' => $cm->id]); +$PAGE->set_title(format_string($moduleinstance->name)); +$PAGE->set_heading(format_string($course->fullname)); +$PAGE->set_context($context); + +$event = \mod_edflex\event\course_module_viewed::create([ + 'objectid' => $moduleinstance->id, + 'context' => $context, +]); +$event->add_record_snapshot('course', $course); +$event->add_record_snapshot('course_modules', $cm); +$event->add_record_snapshot('edflex', $moduleinstance); +$event->trigger(); + echo $OUTPUT->header(); echo $OUTPUT->heading(get_string('outputheading', 'mod_edflex')); echo $OUTPUT->footer(); From 44c2038cf2a1c22e054a07bc91f0eb216aae5b12 Mon Sep 17 00:00:00 2001 From: Damien Date: Mon, 29 Jun 2026 11:14:27 +0200 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=8E=A8=20EDFLEX1-15025:=20Fix=20PHPCS?= =?UTF-8?q?=20violations=20in=20backup/restore=20and=20event?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - drop the blank line after each class opening brace (PSR12) - remove the unneeded MOODLE_INTERNAL guard from class-only files - capitalise the launcher inline comment in lib.php --- backup/moodle2/backup_edflex_activity_task.class.php | 1 - backup/moodle2/backup_edflex_stepslib.php | 3 --- backup/moodle2/restore_edflex_activity_task.class.php | 1 - backup/moodle2/restore_edflex_stepslib.php | 3 --- classes/event/course_module_viewed.php | 3 --- lib.php | 2 +- 6 files changed, 1 insertion(+), 12 deletions(-) diff --git a/backup/moodle2/backup_edflex_activity_task.class.php b/backup/moodle2/backup_edflex_activity_task.class.php index b24ba42..d725560 100644 --- a/backup/moodle2/backup_edflex_activity_task.class.php +++ b/backup/moodle2/backup_edflex_activity_task.class.php @@ -34,7 +34,6 @@ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class backup_edflex_activity_task extends backup_activity_task { - /** * Defines particular settings for this activity task. None required. * diff --git a/backup/moodle2/backup_edflex_stepslib.php b/backup/moodle2/backup_edflex_stepslib.php index d9dec4b..283c57c 100644 --- a/backup/moodle2/backup_edflex_stepslib.php +++ b/backup/moodle2/backup_edflex_stepslib.php @@ -22,8 +22,6 @@ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -defined('MOODLE_INTERNAL') || die(); - /** * Defines the complete edflex structure for backup, with file annotations. * @@ -32,7 +30,6 @@ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class backup_edflex_activity_structure_step extends backup_activity_structure_step { - /** * Defines the backup structure of the edflex activity. * diff --git a/backup/moodle2/restore_edflex_activity_task.class.php b/backup/moodle2/restore_edflex_activity_task.class.php index cd65177..87a07f9 100644 --- a/backup/moodle2/restore_edflex_activity_task.class.php +++ b/backup/moodle2/restore_edflex_activity_task.class.php @@ -34,7 +34,6 @@ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class restore_edflex_activity_task extends restore_activity_task { - /** * Defines particular settings for this activity task. None required. * diff --git a/backup/moodle2/restore_edflex_stepslib.php b/backup/moodle2/restore_edflex_stepslib.php index 4b4a8fd..64be4e0 100644 --- a/backup/moodle2/restore_edflex_stepslib.php +++ b/backup/moodle2/restore_edflex_stepslib.php @@ -22,8 +22,6 @@ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -defined('MOODLE_INTERNAL') || die(); - /** * Defines the structure step to restore one edflex activity. * @@ -32,7 +30,6 @@ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class restore_edflex_activity_structure_step extends restore_activity_structure_step { - /** * Defines the structure to be restored for the edflex activity. * diff --git a/classes/event/course_module_viewed.php b/classes/event/course_module_viewed.php index ad9fe18..5db228d 100644 --- a/classes/event/course_module_viewed.php +++ b/classes/event/course_module_viewed.php @@ -24,8 +24,6 @@ namespace mod_edflex\event; -defined('MOODLE_INTERNAL') || die(); - /** * The mod_edflex course module viewed event class. * @@ -34,7 +32,6 @@ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class course_module_viewed extends \core\event\course_module_viewed { - /** * Init method. * diff --git a/lib.php b/lib.php index 9504889..cc3191a 100755 --- a/lib.php +++ b/lib.php @@ -55,7 +55,7 @@ function edflex_supports($feature) { * @return bool */ function edflex_add_instance($moduleinstance, $mform = null) { - // mod_edflex is a launcher only: the form spawns SCORM modules via the + // The mod_edflex form is a launcher: it spawns SCORM modules via the // Edflex browser, so no standalone edflex instance is ever persisted. return false; }