From 848995e1c405d217566d9edb3bc14b1be37ef7cb Mon Sep 17 00:00:00 2001 From: Michael Milette Date: Tue, 17 Mar 2026 09:27:21 -0400 Subject: [PATCH] Fix: accept both 'course' and 'cm' keys in __construct() for backwards compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 69e5c26 updated save() to output 'course' but did not update __construct() which still read 'cm', causing a coding_exception on every load after save. The constructor now accepts 'course' (post-69e5c26 DB data) and falls back to 'cm' (pre-69e5c26 DB data). No database migration required — data self-heals on next save. Fixes #38 --- classes/condition.php | 10 ++++++---- tests/condition_test.php | 11 +++++------ .../moodle-availability_othercompleted-form-debug.js | 8 ++++---- .../moodle-availability_othercompleted-form-min.js | 2 +- .../moodle-availability_othercompleted-form.js | 8 ++++---- yui/src/form/js/form.js | 8 ++++---- 6 files changed, 24 insertions(+), 23 deletions(-) diff --git a/classes/condition.php b/classes/condition.php index 473a67f..5ff8a14 100644 --- a/classes/condition.php +++ b/classes/condition.php @@ -44,11 +44,13 @@ class condition extends \core_availability\condition { * @throws \coding_exception If invalid data structure. */ public function __construct($structure) { - // Get courseid. - if (isset($structure->cm) && is_number($structure->cm)) { - $this->courseid = (int)$structure->cm; + // Get courseid. Accept 'course' (post-69e5c26) and 'cm' (pre-69e5c26) for backwards compatibility. + if (isset($structure->course) && is_number($structure->course)) { + $this->courseid = (int)$structure->course; + } else if (isset($structure->cm) && is_number($structure->cm)) { + $this->courseid = (int)$structure->cm; // Backwards compat for pre-69e5c26 data. } else { - throw new \coding_exception('Missing or invalid ->cm for completion condition'); + throw new \coding_exception('Missing or invalid ->course for completion condition'); } // Get expected completion. diff --git a/tests/condition_test.php b/tests/condition_test.php index 29c1b81..67f1c52 100644 --- a/tests/condition_test.php +++ b/tests/condition_test.php @@ -96,7 +96,7 @@ public function test_constructor() { $cond = new condition($structure); $this->fail(); } catch (coding_exception $e) { - $this->assertContains('Missing or invalid ->cm', $e->getMessage()); + $this->assertContains('Missing or invalid ->course', $e->getMessage()); } // Invalid $cm. @@ -105,7 +105,7 @@ public function test_constructor() { $cond = new condition($structure); $this->fail(); } catch (coding_exception $e) { - $this->assertContains('Missing or invalid ->cm', $e->getMessage()); + $this->assertContains('Missing or invalid ->course', $e->getMessage()); } // Missing $e. @@ -136,9 +136,8 @@ public function test_constructor() { * Tests the save() function. */ public function test_save() { - $structure = (object)array('cm' => 42, 'e' => COMPLETION_COMPLETE); - $cond = new condition($structure); - $structure->type = 'othercompleted'; + $structure = (object)array('type' => 'othercompleted', 'course' => 42, 'e' => COMPLETION_COMPLETE); + $cond = new condition((object)array('course' => 42, 'e' => COMPLETION_COMPLETE)); $this->assertEquals($structure, $cond->save()); } @@ -257,6 +256,6 @@ public function test_update_dependency_id() { $this->assertFalse($cond->update_dependency_id('course_modules', 12, 34)); $this->assertTrue($cond->update_dependency_id('course_modules', 123, 456)); $after = $cond->save(); - $this->assertEquals(456, $after->cm); + $this->assertEquals(456, $after->course); } } diff --git a/yui/build/moodle-availability_othercompleted-form/moodle-availability_othercompleted-form-debug.js b/yui/build/moodle-availability_othercompleted-form/moodle-availability_othercompleted-form-debug.js index 0bb0863..b475e86 100644 --- a/yui/build/moodle-availability_othercompleted-form/moodle-availability_othercompleted-form-debug.js +++ b/yui/build/moodle-availability_othercompleted-form/moodle-availability_othercompleted-form-debug.js @@ -44,9 +44,9 @@ YUI.add('moodle-availability_othercompleted-form', function (Y, NAME) { var node = Y.Node.create('' + html + ''); // Set initial values. - if (json.cm !== undefined && - node.one('select[name=cm] > option[value=' + json.cm + ']')) { - node.one('select[name=cm]').set('value', '' + json.cm); + if (json.course !== undefined && + node.one('select[name=cm] > option[value=' + json.course + ']')) { + node.one('select[name=cm]').set('value', '' + json.course); } if (json.e !== undefined) { node.one('select[name=e]').set('value', '' + json.e); @@ -66,7 +66,7 @@ YUI.add('moodle-availability_othercompleted-form', function (Y, NAME) { }; M.availability_othercompleted.form.fillValue = function(value, node) { - value.cm = parseInt(node.one('select[name=cm]').get('value'), 10); + value.course = parseInt(node.one('select[name=cm]').get('value'), 10); value.e = parseInt(node.one('select[name=e]').get('value'), 10); }; diff --git a/yui/build/moodle-availability_othercompleted-form/moodle-availability_othercompleted-form-min.js b/yui/build/moodle-availability_othercompleted-form/moodle-availability_othercompleted-form-min.js index a7dc61b..a9e844d 100644 --- a/yui/build/moodle-availability_othercompleted-form/moodle-availability_othercompleted-form-min.js +++ b/yui/build/moodle-availability_othercompleted-form/moodle-availability_othercompleted-form-min.js @@ -1 +1 @@ -YUI.add("moodle-availability_othercompleted-form",function(e,t){M.availability_othercompleted=M.availability_othercompleted||{},M.availability_othercompleted.form=e.Object(M.core_availability.plugin),M.availability_othercompleted.form.initInner=function(e){this.datcms=e},M.availability_othercompleted.form.getNode=function(t){var n=' '+M.util.get_string("title","availability_othercompleted")+""+' ";var s=e.Node.create(''+n+"");t.cm!==undefined&&s.one("select[name=cm] > option[value="+t.cm+"]")&&s.one("select[name=cm]").set("value",""+t.cm),t.e!==undefined&&s.one("select[name=e]").set("value",""+t.e);if(!M.availability_othercompleted.form.addedEvents){M.availability_othercompleted.form.addedEvents=!0;var o=e.one(".availability-field");o.delegate("change",function(){M.core_availability.form.update()},".availability_othercompleted select")}return s},M.availability_othercompleted.form.fillValue=function(e,t){e.cm=parseInt(t.one("select[name=cm]").get("value"),10),e.e=parseInt(t.one("select[name=e]").get("value"),10)},M.availability_othercompleted.form.fillErrors=function(e,t){var n=parseInt(t.one("select[name=cm]").get("value"),10);n===0&&e.push("availability_othercompleted:error_selectcmid");var r=parseInt(t.one("select[name=e]").get("value"),10);(r===2||r===3)&&this.datcms.forEach(function(t){t.id===n&&t.completiongradeitemnumber===null&&e.push("availability_othercompleted:error_selectcmidpassfail")})}},"@VERSION@",{requires:["base","node","event","moodle-core_availability-form"]}); +YUI.add("moodle-availability_othercompleted-form",function(e,t){M.availability_othercompleted=M.availability_othercompleted||{},M.availability_othercompleted.form=e.Object(M.core_availability.plugin),M.availability_othercompleted.form.initInner=function(e){this.datcms=e},M.availability_othercompleted.form.getNode=function(t){var n=' '+M.util.get_string("title","availability_othercompleted")+""+' ";var s=e.Node.create(''+n+"");t.course!==undefined&&s.one("select[name=cm] > option[value="+t.course+"]")&&s.one("select[name=cm]").set("value",""+t.course),t.e!==undefined&&s.one("select[name=e]").set("value",""+t.e);if(!M.availability_othercompleted.form.addedEvents){M.availability_othercompleted.form.addedEvents=!0;var o=e.one(".availability-field");o.delegate("change",function(){M.core_availability.form.update()},".availability_othercompleted select")}return s},M.availability_othercompleted.form.fillValue=function(e,t){e.course=parseInt(t.one("select[name=cm]").get("value"),10),e.e=parseInt(t.one("select[name=e]").get("value"),10)},M.availability_othercompleted.form.fillErrors=function(e,t){var n=parseInt(t.one("select[name=cm]").get("value"),10);n===0&&e.push("availability_othercompleted:error_selectcmid");var r=parseInt(t.one("select[name=e]").get("value"),10);(r===2||r===3)&&this.datcms.forEach(function(t){t.id===n&&t.completiongradeitemnumber===null&&e.push("availability_othercompleted:error_selectcmidpassfail")})}},"@VERSION@",{requires:["base","node","event","moodle-core_availability-form"]}); diff --git a/yui/build/moodle-availability_othercompleted-form/moodle-availability_othercompleted-form.js b/yui/build/moodle-availability_othercompleted-form/moodle-availability_othercompleted-form.js index dc2179d..c5e1578 100644 --- a/yui/build/moodle-availability_othercompleted-form/moodle-availability_othercompleted-form.js +++ b/yui/build/moodle-availability_othercompleted-form/moodle-availability_othercompleted-form.js @@ -43,9 +43,9 @@ M.availability_othercompleted.form.getNode = function(json) { var node = Y.Node.create('' + html + ''); // Set initial values. - if (json.cm !== undefined && - node.one('select[name=cm] > option[value=' + json.cm + ']')) { - node.one('select[name=cm]').set('value', '' + json.cm); + if (json.course !== undefined && + node.one('select[name=cm] > option[value=' + json.course + ']')) { + node.one('select[name=cm]').set('value', '' + json.course); } if (json.e !== undefined) { node.one('select[name=e]').set('value', '' + json.e); @@ -65,7 +65,7 @@ M.availability_othercompleted.form.getNode = function(json) { }; M.availability_othercompleted.form.fillValue = function(value, node) { - value.cm = parseInt(node.one('select[name=cm]').get('value'), 10); + value.course = parseInt(node.one('select[name=cm]').get('value'), 10); value.e = parseInt(node.one('select[name=e]').get('value'), 10); }; diff --git a/yui/src/form/js/form.js b/yui/src/form/js/form.js index 1448809..0cafe2b 100644 --- a/yui/src/form/js/form.js +++ b/yui/src/form/js/form.js @@ -43,9 +43,9 @@ M.availability_othercompleted.form.getNode = function(json) { var node = Y.Node.create('' + html + ''); // Set initial values. - if (json.cm !== undefined && - node.one('select[name=cm] > option[value=' + json.cm + ']')) { - node.one('select[name=cm]').set('value', '' + json.cm); + if (json.course !== undefined && + node.one('select[name=cm] > option[value=' + json.course + ']')) { + node.one('select[name=cm]').set('value', '' + json.course); } if (json.e !== undefined) { node.one('select[name=e]').set('value', '' + json.e); @@ -65,7 +65,7 @@ M.availability_othercompleted.form.getNode = function(json) { }; M.availability_othercompleted.form.fillValue = function(value, node) { - value.cm = parseInt(node.one('select[name=cm]').get('value'), 10); + value.course = parseInt(node.one('select[name=cm]').get('value'), 10); value.e = parseInt(node.one('select[name=e]').get('value'), 10); };