diff --git a/.upgradenotes/MDL-87350-2026020304090981.yml b/.upgradenotes/MDL-87350-2026020304090981.yml new file mode 100644 index 00000000000..442f64de040 --- /dev/null +++ b/.upgradenotes/MDL-87350-2026020304090981.yml @@ -0,0 +1,10 @@ +issueNumber: MDL-87350 +notes: + core: + - message: >- + MoodleNet outbound sharing functionality has been removed. All classes, + functions, web services, and entry files related to outbound sharing + have been removed. The OAuth2 service type 'moodlenet' has also been + removed. There is no replacement for this functionality as MoodleNet + outbound sharing was an experimental feature that is being discontinued. + type: removed diff --git a/.upgradenotes/MDL-87350-2026021203494446.yml b/.upgradenotes/MDL-87350-2026021203494446.yml new file mode 100644 index 00000000000..a8780fa0242 --- /dev/null +++ b/.upgradenotes/MDL-87350-2026021203494446.yml @@ -0,0 +1,8 @@ +issueNumber: MDL-87350 +notes: + core: + - message: >- + The get_moodlenet_info() method has been deprecated and will be removed + in a future release (See MDL-87934 for the final deprecation). There is + no replacement for this method. + type: deprecated diff --git a/.upgradenotes/MDL-87351-2026021202531710.yml b/.upgradenotes/MDL-87351-2026021202531710.yml new file mode 100644 index 00000000000..616cededa95 --- /dev/null +++ b/.upgradenotes/MDL-87351-2026021202531710.yml @@ -0,0 +1,9 @@ +issueNumber: MDL-87351 +notes: + core: + - message: >- + The MoodleNet integration plugin (tool_moodlenet) has been removed from + Moodle core. The public MoodleNet service (moodle.net) is being retired + in April 2026. Sites using self-hosted MoodleNet instances can install + the plugin from the Moodle HQ GitHub repository. + type: removed diff --git a/.upgradenotes/MDL-87361-2026021206052287.yml b/.upgradenotes/MDL-87361-2026021206052287.yml new file mode 100644 index 00000000000..0616128b8c5 --- /dev/null +++ b/.upgradenotes/MDL-87361-2026021206052287.yml @@ -0,0 +1,9 @@ +issueNumber: MDL-87361 +notes: + core_user: + - message: >- + The MoodleNet profile field has been migrated from a core user table + field to a custom profile field. Any existing moodlenetprofile data will + be automatically migrated to a custom profile field during upgrade. The + core moodlenetprofile column will be removed from the user table. + type: deprecated diff --git a/lib/plugins.json b/lib/plugins.json index 48930a24ab7..fef1bdb7f62 100644 --- a/lib/plugins.json +++ b/lib/plugins.json @@ -497,7 +497,6 @@ "mfa", "mobile", "monitor", - "moodlenet", "multilangupgrade", "oauth2", "phpunit", @@ -702,6 +701,7 @@ "bloglevelupgrade", "health", "innodb", + "moodlenet", "qeupgradehelper", "timezoneimport" ], diff --git a/public/admin/moodlenet_oauth2_callback.php b/public/admin/moodlenet_oauth2_callback.php deleted file mode 100644 index 7be1a4d0d43..00000000000 --- a/public/admin/moodlenet_oauth2_callback.php +++ /dev/null @@ -1,57 +0,0 @@ -. - -/** - * MoodleNet callback. - * - * @package core - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -use core\moodlenet\moodlenet_client; -use core\oauth2\api; - -require_once(__DIR__ . '/../config.php'); -require_login(); - -// Parameters. -$issuerid = required_param('issuerid', PARAM_INT); -$error = optional_param('error', '', PARAM_RAW); -$message = optional_param('error_description', null, PARAM_RAW); - -// Headers to make it not cacheable. -header('Cache-Control: no-cache, must-revalidate'); -header('Expires: Sat, 26 Jul 1997 05:00:00 GMT'); - -$PAGE->set_context(context_system::instance()); -$PAGE->set_url('/admin/moodlenet_oauth2_callback.php'); -$PAGE->set_pagelayout('popup'); - -// Wait as long as it takes for this script to finish. -core_php_time_limit::raise(); - -$issuer = api::get_issuer($issuerid); -$returnurl = new moodle_url('/admin/moodlenet_oauth2_callback.php'); -$returnurl->param('issuerid', $issuerid); -$returnurl->param('callback', 'yes'); -$returnurl->param('sesskey', sesskey()); -$oauthclient = api::get_user_oauth_client($issuer, $returnurl, moodlenet_client::API_SCOPE_CREATE_RESOURCE, true); -$oauthclient->is_logged_in(); // Will upgrade the auth code to a token. - -echo $OUTPUT->header(); -$PAGE->requires->js_call_amd('core/moodlenet/oauth2callback', 'init', [$error, $message]); -echo $OUTPUT->footer(); diff --git a/public/admin/settings/development.php b/public/admin/settings/development.php index c1597cf6507..a20fb0cb940 100644 --- a/public/admin/settings/development.php +++ b/public/admin/settings/development.php @@ -33,11 +33,6 @@ if ($hassiteconfig) { // Speedup for non-admins, add all caps used on this page. new lang_string('enablecourserelativedates', 'core_admin'), new lang_string('enablecourserelativedates_desc', 'core_admin'), 0)); - // Sharing to MoodleNet setting. - $temp->add(new admin_setting_configcheckbox('enablesharingtomoodlenet', - new lang_string('enablesharingtomoodlenet', 'core_admin'), - new lang_string('enablesharingtomoodlenet_desc', 'core_admin'), 0)); - // New communication subsystem setting. $temp->add(new admin_setting_configcheckbox('enablecommunicationsubsystem', new lang_string('enablecommunicationsubsystem', 'core_admin'), diff --git a/public/admin/settings/moodlenet.php b/public/admin/settings/moodlenet.php deleted file mode 100644 index 22a69a4f6f6..00000000000 --- a/public/admin/settings/moodlenet.php +++ /dev/null @@ -1,55 +0,0 @@ -. - -/** - * This file gives information about MoodleNet. - * - * @package core - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die; - -if ($hassiteconfig) { - if (!empty($CFG->enablesharingtomoodlenet)) { - if (!$ADMIN->locate('moodlenet')) { - $ADMIN->add('root', new admin_category('moodlenet', get_string('pluginname', 'tool_moodlenet'))); - } - - // Outbound settings page. - $settings = new admin_settingpage('moodlenetoutbound', new lang_string('moodlenet:outboundsettings', 'moodle')); - $ADMIN->add('moodlenet', $settings); - - // Get all the issuers. - $issuers = \core\oauth2\api::get_all_issuers(); - $oauth2services = [ - '' => new lang_string('none', 'admin'), - ]; - foreach ($issuers as $issuer) { - // Get the enabled issuer with the service type is MoodleNet only. - if ($issuer->get('servicetype') == 'moodlenet' && $issuer->get('enabled')) { - $oauth2services[$issuer->get('id')] = s($issuer->get('name')); - } - } - - $url = new \moodle_url('/admin/tool/oauth2/issuers.php'); - - $settings->add(new admin_setting_configselect('moodlenet/oauthservice', new lang_string('issuer', 'auth_oauth2'), - new lang_string('moodlenet:configoauthservice', 'moodle', $url->out()), '', $oauth2services)); - - } -} diff --git a/public/admin/settings/users.php b/public/admin/settings/users.php index aac58f93fab..33cf3cd8b49 100644 --- a/public/admin/settings/users.php +++ b/public/admin/settings/users.php @@ -212,7 +212,6 @@ if ($hassiteconfig || has_any_capability($capabilities, $systemcontext)) { // Sp 'email' => new lang_string('email'), 'city' => new lang_string('city'), 'country' => new lang_string('country'), - 'moodlenetprofile' => new lang_string('moodlenetprofile', 'user'), 'timezone' => new lang_string('timezone'), 'firstaccess' => new lang_string('firstaccess'), 'lastaccess' => new lang_string('lastaccess'), diff --git a/public/admin/tests/behat/moodlenet_outbound.feature b/public/admin/tests/behat/moodlenet_outbound.feature deleted file mode 100644 index a88581ef5ba..00000000000 --- a/public/admin/tests/behat/moodlenet_outbound.feature +++ /dev/null @@ -1,52 +0,0 @@ -@core @core_admin -Feature: MoodleNet outbound configuration - In order to send activity/resource to MoodleNet - As a Moodle administrator - I need to set outbound configuration - - Background: - Given I log in as "admin" - - Scenario: Share to MoodleNet experimental flag - Given I navigate to "Development > Experimental" in site administration - Then "Enable sharing to MoodleNet" "field" should exist - And the field "Enable sharing to MoodleNet" matches value "0" - - Scenario: Outbound configuration without experimental flag enable yet - Given I navigate to "MoodleNet" in site administration - Then I should not see "MoodleNet outbound settings" - - Scenario: Outbound configuration without OAuth 2 service setup yet - Given the following config values are set as admin: - | enablesharingtomoodlenet | 1 | - When I navigate to "MoodleNet" in site administration - Then I should see "MoodleNet outbound settings" - And I click on "MoodleNet outbound settings" "link" - And the field "OAuth 2 service" matches value "None" - And I should see "Select a MoodleNet OAuth 2 service to enable sharing to that MoodleNet site. If the service doesn't exist yet, you will need to create it." - And I click on "create" "link" - And I should see "OAuth 2 services" - - Scenario: Outbound configuration with OAuth 2 service setup - Given a MoodleNet mock server is configured - And the following config values are set as admin: - | enablesharingtomoodlenet | 1 | - And I navigate to "Server > OAuth 2 services" in site administration - And I press "Custom" - And I should see "Create new service: Custom" - And I set the following fields to these values: - | Name | Testing custom service | - | Client ID | thisistheclientid | - | Client secret | supersecret | - And I press "Save changes" - When I navigate to "MoodleNet > MoodleNet outbound settings" in site administration - Then the field "OAuth 2 service" matches value "None" - And I navigate to "Server > OAuth 2 services" in site administration - And I press "MoodleNet" - And I should see "Create new service: MoodleNet" - And I change the MoodleNet field "Service base URL" to mock server - And I press "Save changes" - And I navigate to "MoodleNet > MoodleNet outbound settings" in site administration - And the "OAuth 2 service" "field" should be enabled - And I should see "MoodleNet" in the "OAuth 2 service" "select" - And I should not see "Testing custom service" in the "OAuth 2 service" "select" diff --git a/public/admin/tool/lp/classes/output/manage_competency_frameworks_page.php b/public/admin/tool/lp/classes/output/manage_competency_frameworks_page.php index e72e08c16b9..d0795f88f4e 100644 --- a/public/admin/tool/lp/classes/output/manage_competency_frameworks_page.php +++ b/public/admin/tool/lp/classes/output/manage_competency_frameworks_page.php @@ -78,15 +78,6 @@ class manage_competency_frameworks_page implements renderable, templatable { 'get' ); $this->navigation[] = $addpage; - - $icon = $OUTPUT->pix_icon('i/externallink', get_string('opensinnewwindow'), 'moodle', ['class' => 'ms-1']); - $competenciesrepository = new action_link( - new moodle_url('https://moodle.net/search', ['q' => 'competency frameworks']), - get_string('competencyframeworksrepository', 'tool_lp') . $icon, - null, - ['target' => '_blank', 'class' => button::SECONDARY->classes() . ' ms-sm-2'], - ); - $this->navigation[] = $competenciesrepository; } $this->competencyframeworks = api::list_frameworks('shortname', 'ASC', 0, 0, $this->pagecontext); diff --git a/public/admin/tool/lp/lang/en/tool_lp.php b/public/admin/tool/lp/lang/en/tool_lp.php index 77edf1aaf8a..52d69e4c9e2 100644 --- a/public/admin/tool/lp/lang/en/tool_lp.php +++ b/public/admin/tool/lp/lang/en/tool_lp.php @@ -61,7 +61,6 @@ $string['competencyframeworkcreated'] = 'Competency framework created.'; $string['competencyframeworkname'] = 'Name'; $string['competencyframeworkroot'] = 'No parent (top-level competency)'; $string['competencyframeworks'] = 'Competency frameworks'; -$string['competencyframeworksrepository'] = 'Competency frameworks repository'; $string['competencyframeworkupdated'] = 'Competency framework updated.'; $string['competencyoutcome_complete'] = 'Mark as complete'; $string['competencyoutcome_evidence'] = 'Attach an evidence'; diff --git a/public/admin/tool/moodlenet/amd/build/instance_form.min.js b/public/admin/tool/moodlenet/amd/build/instance_form.min.js deleted file mode 100644 index 878e87cd1a0..00000000000 --- a/public/admin/tool/moodlenet/amd/build/instance_form.min.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Our basic form manager for when a user either enters - * their profile url or just wants to browse. - * - * This file is a mishmash of JS functions we need for both the standalone (M3.7, M3.8) - * plugin & Moodle 3.9 functions. The 3.9 Functions have a base understanding that certain - * things exist i.e. directory structures for templates. When this feature goes 3.9+ only - * The goal is that we can quickly gut all AMD modules into bare JS files and use ES6 guidelines. - * Till then this will have to do. - * - * @module tool_moodlenet/instance_form - * @copyright 2020 Mathew May - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -define("tool_moodlenet/instance_form",["tool_moodlenet/validator","tool_moodlenet/selectors","core/loadingicon","core/templates","core/notification","jquery","theme_boost/bootstrap/carousel","core/normalise"],(function(Validator,Selectors,LoadingIcon,Templates,Notification,$,Carousel,Normalise){var chooserNavigateToMnet=function(showMoodleNet,footerData,carousel){showMoodleNet.innerHTML="";var page,spinnerPromise=LoadingIcon.addIconToContainer(showMoodleNet),transitionPromiseResolver=null,transitionPromise=new Promise((resolve=>{transitionPromiseResolver=resolve}));$.when(spinnerPromise,transitionPromise).then((function(){Templates.replaceNodeContents(showMoodleNet,footerData.customcarouseltemplate,"")})).catch(Notification.exception),(page=showMoodleNet).addEventListener("click",(function(e){if(e.target.matches(Selectors.action.submit)){var input=page.querySelector('[data-var="mnet-link"]'),overlay=page.querySelector(Selectors.region.spinner),validationArea=document.querySelector(Selectors.region.validationArea);overlay.classList.remove("d-none");var spinner=LoadingIcon.addIconToContainerWithPromise(overlay);Validator.validation(input).then((function(result){spinner.resolve(),overlay.classList.add("d-none"),result.result?(input.classList.remove("is-invalid"),input.classList.add("is-valid"),validationArea.innerText=result.message,validationArea.classList.remove("text-danger"),validationArea.classList.add("text-success"),setTimeout((function(){window.location=result.domain}),1e3)):(input.classList.add("is-invalid"),validationArea.innerText=result.message,validationArea.classList.add("text-danger"))})).catch(Notification.exception)}})),carousel.addEventListener("slid.bs.carousel",(function(){transitionPromiseResolver()}),{once:!0}),Carousel.getInstance(carousel).to(2)};return{footerClickListener:function(e,footerData,modal){const modalBody=Normalise.getFirst(modal.getBody());if(e.target.matches(Selectors.action.showMoodleNet)||e.target.closest(Selectors.action.showMoodleNet)){e.preventDefault();const carousel=modalBody.querySelector(Selectors.region.carousel),showMoodleNet=carousel.querySelector(Selectors.region.moodleNet);chooserNavigateToMnet(showMoodleNet,footerData,carousel)}if(e.target.matches(Selectors.action.closeOption)){!function(carousel,modal,footerData){Carousel.getInstance(carousel).to(0),modal.setFooter(footerData.customfootertemplate)}(modalBody.querySelector(Selectors.region.carousel),modal,footerData)}}}})); - -//# sourceMappingURL=instance_form.min.js.map \ No newline at end of file diff --git a/public/admin/tool/moodlenet/amd/build/instance_form.min.js.map b/public/admin/tool/moodlenet/amd/build/instance_form.min.js.map deleted file mode 100644 index 54c22d57953..00000000000 --- a/public/admin/tool/moodlenet/amd/build/instance_form.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"instance_form.min.js","sources":["../src/instance_form.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Our basic form manager for when a user either enters\n * their profile url or just wants to browse.\n *\n * This file is a mishmash of JS functions we need for both the standalone (M3.7, M3.8)\n * plugin & Moodle 3.9 functions. The 3.9 Functions have a base understanding that certain\n * things exist i.e. directory structures for templates. When this feature goes 3.9+ only\n * The goal is that we can quickly gut all AMD modules into bare JS files and use ES6 guidelines.\n * Till then this will have to do.\n *\n * @module tool_moodlenet/instance_form\n * @copyright 2020 Mathew May \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(['tool_moodlenet/validator',\n 'tool_moodlenet/selectors',\n 'core/loadingicon',\n 'core/templates',\n 'core/notification',\n 'jquery',\n 'theme_boost/bootstrap/carousel',\n 'core/normalise'],\n function(Validator,\n Selectors,\n LoadingIcon,\n Templates,\n Notification,\n $,\n Carousel,\n Normalise) {\n\n /**\n * Add the event listeners to our form.\n *\n * @method registerListenerEvents\n * @param {HTMLElement} page The whole page element for our form area\n */\n var registerListenerEvents = function registerListenerEvents(page) {\n page.addEventListener('click', function(e) {\n\n // Our fake submit button / browse button.\n if (e.target.matches(Selectors.action.submit)) {\n var input = page.querySelector('[data-var=\"mnet-link\"]');\n var overlay = page.querySelector(Selectors.region.spinner);\n var validationArea = document.querySelector(Selectors.region.validationArea);\n\n overlay.classList.remove('d-none');\n var spinner = LoadingIcon.addIconToContainerWithPromise(overlay);\n Validator.validation(input)\n .then(function(result) {\n spinner.resolve();\n overlay.classList.add('d-none');\n if (result.result) {\n input.classList.remove('is-invalid'); // Just in case the class has been applied already.\n input.classList.add('is-valid');\n validationArea.innerText = result.message;\n validationArea.classList.remove('text-danger');\n validationArea.classList.add('text-success');\n // Give the user some time to see their input is valid.\n setTimeout(function() {\n window.location = result.domain;\n }, 1000);\n } else {\n input.classList.add('is-invalid');\n validationArea.innerText = result.message;\n validationArea.classList.add('text-danger');\n }\n return;\n }).catch(Notification.exception);\n }\n });\n };\n\n /**\n * Given a user wishes to see the MoodleNet profile url form transition them there.\n *\n * @method chooserNavigateToMnet\n * @param {HTMLElement} showMoodleNet The chooser's area for ment\n * @param {Object} footerData Our footer object to render out\n * @param {Element} carousel Our carousel instance to manage\n */\n var chooserNavigateToMnet = function(showMoodleNet, footerData, carousel) {\n showMoodleNet.innerHTML = '';\n\n // Add a spinner.\n var spinnerPromise = LoadingIcon.addIconToContainer(showMoodleNet);\n\n // Used later...\n var transitionPromiseResolver = null;\n var transitionPromise = new Promise(resolve => {\n transitionPromiseResolver = resolve;\n });\n\n $.when(\n spinnerPromise,\n transitionPromise\n ).then(function() {\n Templates.replaceNodeContents(showMoodleNet, footerData.customcarouseltemplate, '');\n return;\n }).catch(Notification.exception);\n\n // We apply our handlers in here to minimise plugin dependency in the Chooser.\n registerListenerEvents(showMoodleNet);\n\n // Move to the next slide, and resolve the transition promise when it's done.\n carousel.addEventListener('slid.bs.carousel', function() {\n transitionPromiseResolver();\n }, {once: true});\n // Trigger the transition between 'pages'.\n Carousel.getInstance(carousel).to(2);\n };\n\n /**\n * Given a user no longer wishes to see the MoodleNet profile url form transition them from there.\n *\n * @method chooserNavigateFromMnet\n * @param {Element} carousel Our carousel instance to manage\n * @param {jQuery} modal Our modal instance to manage\n * @param {Object} footerData Our footer object to render out\n */\n var chooserNavigateFromMnet = function(carousel, modal, footerData) {\n // Trigger the transition between 'pages'.\n Carousel.getInstance(carousel).to(0);\n modal.setFooter(footerData.customfootertemplate);\n };\n\n /**\n * Create the custom listener that would handle anything in the footer.\n *\n * @param {Event} e The event being triggered.\n * @param {Object} footerData The data generated from the exporter.\n * @param {Object} modal The chooser modal.\n */\n var footerClickListener = function(e, footerData, modal) {\n const modalBody = Normalise.getFirst(modal.getBody());\n if (e.target.matches(Selectors.action.showMoodleNet) || e.target.closest(Selectors.action.showMoodleNet)) {\n e.preventDefault();\n const carousel = modalBody.querySelector(Selectors.region.carousel);\n const showMoodleNet = carousel.querySelector(Selectors.region.moodleNet);\n\n chooserNavigateToMnet(showMoodleNet, footerData, carousel, modal);\n }\n // From the help screen go back to the module overview.\n if (e.target.matches(Selectors.action.closeOption)) {\n const carousel = modalBody.querySelector(Selectors.region.carousel);\n\n chooserNavigateFromMnet(carousel, modal, footerData);\n }\n };\n\n return {\n footerClickListener: footerClickListener\n };\n});\n"],"names":["define","Validator","Selectors","LoadingIcon","Templates","Notification","$","Carousel","Normalise","chooserNavigateToMnet","showMoodleNet","footerData","carousel","innerHTML","page","spinnerPromise","addIconToContainer","transitionPromiseResolver","transitionPromise","Promise","resolve","when","then","replaceNodeContents","customcarouseltemplate","catch","exception","addEventListener","e","target","matches","action","submit","input","querySelector","overlay","region","spinner","validationArea","document","classList","remove","addIconToContainerWithPromise","validation","result","add","innerText","message","setTimeout","window","location","domain","once","getInstance","to","footerClickListener","modal","modalBody","getFirst","getBody","closest","preventDefault","moodleNet","closeOption","setFooter","customfootertemplate","chooserNavigateFromMnet"],"mappings":";;;;;;;;;;;;;;AA8BAA,sCAAO,CAAC,2BACA,2BACA,mBACA,iBACA,oBACA,SACA,iCACA,mBACJ,SAASC,UACAC,UACAC,YACAC,UACAC,aACAC,EACAC,SACAC,eAoDLC,sBAAwB,SAASC,cAAeC,WAAYC,UAC5DF,cAAcG,UAAY,OA7C+BC,KAgDrDC,eAAiBZ,YAAYa,mBAAmBN,eAGhDO,0BAA4B,KAC5BC,kBAAoB,IAAIC,SAAQC,UAChCH,0BAA4BG,WAGhCd,EAAEe,KACEN,eACAG,mBACFI,MAAK,WACClB,UAAUmB,oBAAoBb,cAAeC,WAAWa,uBAAwB,OAErFC,MAAMpB,aAAaqB,YA9DmCZ,KAiElCJ,eAhElBiB,iBAAiB,SAAS,SAASC,MAGhCA,EAAEC,OAAOC,QAAQ5B,UAAU6B,OAAOC,QAAS,KACvCC,MAAQnB,KAAKoB,cAAc,0BAC3BC,QAAUrB,KAAKoB,cAAchC,UAAUkC,OAAOC,SAC9CC,eAAiBC,SAASL,cAAchC,UAAUkC,OAAOE,gBAE7DH,QAAQK,UAAUC,OAAO,cACrBJ,QAAUlC,YAAYuC,8BAA8BP,SACxDlC,UAAU0C,WAAWV,OAChBX,MAAK,SAASsB,QACXP,QAAQjB,UACRe,QAAQK,UAAUK,IAAI,UAClBD,OAAOA,QACPX,MAAMO,UAAUC,OAAO,cACvBR,MAAMO,UAAUK,IAAI,YACpBP,eAAeQ,UAAYF,OAAOG,QAClCT,eAAeE,UAAUC,OAAO,eAChCH,eAAeE,UAAUK,IAAI,gBAE7BG,YAAW,WACPC,OAAOC,SAAWN,OAAOO,SAC1B,OAEHlB,MAAMO,UAAUK,IAAI,cACpBP,eAAeQ,UAAYF,OAAOG,QAClCT,eAAeE,UAAUK,IAAI,mBAGtCpB,MAAMpB,aAAaqB,eAqC9Bd,SAASe,iBAAiB,oBAAoB,WAC1CV,8BACD,CAACmC,MAAM,IAEV7C,SAAS8C,YAAYzC,UAAU0C,GAAG,UAyC/B,CACHC,oBAlBsB,SAAS3B,EAAGjB,WAAY6C,aACxCC,UAAYjD,UAAUkD,SAASF,MAAMG,cACvC/B,EAAEC,OAAOC,QAAQ5B,UAAU6B,OAAOrB,gBAAkBkB,EAAEC,OAAO+B,QAAQ1D,UAAU6B,OAAOrB,eAAgB,CACtGkB,EAAEiC,uBACIjD,SAAW6C,UAAUvB,cAAchC,UAAUkC,OAAOxB,UACpDF,cAAgBE,SAASsB,cAAchC,UAAUkC,OAAO0B,WAE9DrD,sBAAsBC,cAAeC,WAAYC,aAGjDgB,EAAEC,OAAOC,QAAQ5B,UAAU6B,OAAOgC,aAAc,EAvB1B,SAASnD,SAAU4C,MAAO7C,YAEpDJ,SAAS8C,YAAYzC,UAAU0C,GAAG,GAClCE,MAAMQ,UAAUrD,WAAWsD,sBAuBvBC,CAFiBT,UAAUvB,cAAchC,UAAUkC,OAAOxB,UAExB4C,MAAO7C"} \ No newline at end of file diff --git a/public/admin/tool/moodlenet/amd/build/select_page.min.js b/public/admin/tool/moodlenet/amd/build/select_page.min.js deleted file mode 100644 index a74d396a408..00000000000 --- a/public/admin/tool/moodlenet/amd/build/select_page.min.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * When returning to Moodle let the user select which course to add the resource to. - * - * @module tool_moodlenet/select_page - * @copyright 2020 Mathew May - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -define("tool_moodlenet/select_page",["core/ajax","core/templates","tool_moodlenet/selectors","core/notification"],(function(Ajax,Templates,Selectors,Notification){var importId,searchCourses=function(inputValue,page,areaReplace){var searchIcon=page.querySelector(Selectors.region.searchIcon),clearIcon=page.querySelector(Selectors.region.clearIcon);""!==inputValue?(searchIcon.classList.add("d-none"),clearIcon.parentElement.classList.remove("d-none")):(searchIcon.classList.remove("d-none"),clearIcon.parentElement.classList.add("d-none"));var args={searchvalue:inputValue};Ajax.call([{methodname:"tool_moodlenet_search_courses",args:args}])[0].then((function(result){return 0===result.courses.length?function(areaReplace){return Templates.renderPix("courses","tool_moodlenet").then((function(img){return img})).then((function(img){var temp=document.createElement("div");return temp.innerHTML=img.trim(),Templates.render("core_course/no-courses",{nocoursesimg:temp.firstChild.src})})).then((function(html,js){Templates.replaceNodeContents(areaReplace,html,js),areaReplace.classList.add("mx-auto"),areaReplace.classList.add("w-25")}))}(areaReplace):(result.courses.forEach((function(course){course.viewurl+="&id="+importId})),function(areaReplace,courses){return Templates.render("tool_moodlenet/view-cards",{courses:courses}).then((function(html,js){Templates.replaceNodeContents(areaReplace,html,js),areaReplace.classList.remove("mx-auto"),areaReplace.classList.remove("w-25")}))}(areaReplace,result.courses))})).catch(Notification.exception)},registerListenerEvents=function(page){var input=page.querySelector(Selectors.region.searchInput),courseArea=page.querySelector(Selectors.region.courses);page.querySelector(Selectors.region.clearIcon).addEventListener("click",(function(){input.value="",searchCourses("",page,courseArea)})),input.addEventListener("input",debounce((function(){searchCourses(input.value,page,courseArea)}),300))},addCourses=function(page){var courseArea=page.querySelector(Selectors.region.courses);searchCourses("",page,courseArea)},debounce=function(func,wait,immediate){var timeout;return function(){var context=this,args=arguments,later=function(){timeout=null,immediate||func.apply(context,args)},callNow=immediate&&!timeout;clearTimeout(timeout),timeout=setTimeout(later,wait),callNow&&func.apply(context,args)}};return{init:function(importIdString){importId=importIdString;var page=document.querySelector(Selectors.region.selectPage);registerListenerEvents(page),addCourses(page)}}})); - -//# sourceMappingURL=select_page.min.js.map \ No newline at end of file diff --git a/public/admin/tool/moodlenet/amd/build/select_page.min.js.map b/public/admin/tool/moodlenet/amd/build/select_page.min.js.map deleted file mode 100644 index bc80e534253..00000000000 --- a/public/admin/tool/moodlenet/amd/build/select_page.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"select_page.min.js","sources":["../src/select_page.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * When returning to Moodle let the user select which course to add the resource to.\n *\n * @module tool_moodlenet/select_page\n * @copyright 2020 Mathew May \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine([\n 'core/ajax',\n 'core/templates',\n 'tool_moodlenet/selectors',\n 'core/notification'\n], function(\n Ajax,\n Templates,\n Selectors,\n Notification\n) {\n /**\n * @var {string} The id corresponding to the import.\n */\n var importId;\n\n /**\n * Set up the page.\n *\n * @method init\n * @param {string} importIdString the string ID of the import.\n */\n var init = function(importIdString) {\n importId = importIdString;\n var page = document.querySelector(Selectors.region.selectPage);\n registerListenerEvents(page);\n addCourses(page);\n };\n\n /**\n * Renders the 'no-courses' template.\n *\n * @param {HTMLElement} areaReplace the DOM node to replace.\n * @returns {Promise}\n */\n var renderNoCourses = function(areaReplace) {\n return Templates.renderPix('courses', 'tool_moodlenet').then(function(img) {\n return img;\n }).then(function(img) {\n var temp = document.createElement('div');\n temp.innerHTML = img.trim();\n return Templates.render('core_course/no-courses', {\n nocoursesimg: temp.firstChild.src\n });\n }).then(function(html, js) {\n Templates.replaceNodeContents(areaReplace, html, js);\n areaReplace.classList.add('mx-auto');\n areaReplace.classList.add('w-25');\n return;\n });\n };\n\n /**\n * Render the course cards for those supplied courses.\n *\n * @param {HTMLElement} areaReplace the DOM node to replace.\n * @param {Array} courses the courses to render.\n * @returns {Promise}\n */\n var renderCourses = function(areaReplace, courses) {\n return Templates.render('tool_moodlenet/view-cards', {\n courses: courses\n }).then(function(html, js) {\n Templates.replaceNodeContents(areaReplace, html, js);\n areaReplace.classList.remove('mx-auto');\n areaReplace.classList.remove('w-25');\n return;\n });\n };\n\n /**\n * For a given input, the page & what to replace fetch courses and manage icons too.\n *\n * @method searchCourses\n * @param {string} inputValue What to search for\n * @param {HTMLElement} page The whole page element for our page\n * @param {HTMLElement} areaReplace The Element to replace the contents of\n */\n var searchCourses = function(inputValue, page, areaReplace) {\n var searchIcon = page.querySelector(Selectors.region.searchIcon);\n var clearIcon = page.querySelector(Selectors.region.clearIcon);\n\n if (inputValue !== '') {\n searchIcon.classList.add('d-none');\n clearIcon.parentElement.classList.remove('d-none');\n } else {\n searchIcon.classList.remove('d-none');\n clearIcon.parentElement.classList.add('d-none');\n }\n var args = {\n searchvalue: inputValue,\n };\n Ajax.call([{\n methodname: 'tool_moodlenet_search_courses',\n args: args\n }])[0].then(function(result) {\n if (result.courses.length === 0) {\n return renderNoCourses(areaReplace);\n } else {\n // Add the importId to the course link\n result.courses.forEach(function(course) {\n course.viewurl += '&id=' + importId;\n });\n return renderCourses(areaReplace, result.courses);\n }\n }).catch(Notification.exception);\n };\n\n /**\n * Add the event listeners to our page.\n *\n * @method registerListenerEvents\n * @param {HTMLElement} page The whole page element for our page\n */\n var registerListenerEvents = function(page) {\n var input = page.querySelector(Selectors.region.searchInput);\n var courseArea = page.querySelector(Selectors.region.courses);\n var clearIcon = page.querySelector(Selectors.region.clearIcon);\n clearIcon.addEventListener('click', function() {\n input.value = '';\n searchCourses('', page, courseArea);\n });\n\n input.addEventListener('input', debounce(function() {\n searchCourses(input.value, page, courseArea);\n }, 300));\n };\n\n /**\n * Fetch the courses to show the user. We use the same WS structure & template as the search for consistency.\n *\n * @method addCourses\n * @param {HTMLElement} page The whole page element for our course page\n */\n var addCourses = function(page) {\n var courseArea = page.querySelector(Selectors.region.courses);\n searchCourses('', page, courseArea);\n };\n\n /**\n * Define our own debounce function as Moodle 3.7 does not have it.\n *\n * @method debounce\n * @from underscore.js\n * @copyright 2009-2020 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n * @licence MIT\n * @param {function} func The function we want to keep calling\n * @param {number} wait Our timeout\n * @param {boolean} immediate Do we want to apply the function immediately\n * @return {function}\n */\n var debounce = function(func, wait, immediate) {\n var timeout;\n return function() {\n var context = this;\n var args = arguments;\n var later = function() {\n timeout = null;\n if (!immediate) {\n func.apply(context, args);\n }\n };\n var callNow = immediate && !timeout;\n clearTimeout(timeout);\n timeout = setTimeout(later, wait);\n if (callNow) {\n func.apply(context, args);\n }\n };\n };\n return {\n init: init,\n };\n});\n"],"names":["define","Ajax","Templates","Selectors","Notification","importId","searchCourses","inputValue","page","areaReplace","searchIcon","querySelector","region","clearIcon","classList","add","parentElement","remove","args","searchvalue","call","methodname","then","result","courses","length","renderPix","img","temp","document","createElement","innerHTML","trim","render","nocoursesimg","firstChild","src","html","js","replaceNodeContents","renderNoCourses","forEach","course","viewurl","renderCourses","catch","exception","registerListenerEvents","input","searchInput","courseArea","addEventListener","value","debounce","addCourses","func","wait","immediate","timeout","context","this","arguments","later","apply","callNow","clearTimeout","setTimeout","init","importIdString","selectPage"],"mappings":";;;;;;;AAuBAA,oCAAO,CACH,YACA,iBACA,2BACA,sBACD,SACCC,KACAC,UACAC,UACAC,kBAKIC,SAgEAC,cAAgB,SAASC,WAAYC,KAAMC,iBACvCC,WAAaF,KAAKG,cAAcR,UAAUS,OAAOF,YACjDG,UAAYL,KAAKG,cAAcR,UAAUS,OAAOC,WAEjC,KAAfN,YACAG,WAAWI,UAAUC,IAAI,UACzBF,UAAUG,cAAcF,UAAUG,OAAO,YAEzCP,WAAWI,UAAUG,OAAO,UAC5BJ,UAAUG,cAAcF,UAAUC,IAAI,eAEtCG,KAAO,CACPC,YAAaZ,YAEjBN,KAAKmB,KAAK,CAAC,CACPC,WAAY,gCACZH,KAAMA,QACN,GAAGI,MAAK,SAASC,eACa,IAA1BA,OAAOC,QAAQC,OA7DL,SAAShB,oBACpBP,UAAUwB,UAAU,UAAW,kBAAkBJ,MAAK,SAASK,YAC3DA,OACRL,MAAK,SAASK,SACTC,KAAOC,SAASC,cAAc,cAClCF,KAAKG,UAAYJ,IAAIK,OACd9B,UAAU+B,OAAO,yBAA0B,CAC9CC,aAAcN,KAAKO,WAAWC,SAEnCd,MAAK,SAASe,KAAMC,IACnBpC,UAAUqC,oBAAoB9B,YAAa4B,KAAMC,IACjD7B,YAAYK,UAAUC,IAAI,WAC1BN,YAAYK,UAAUC,IAAI,WAkDfyB,CAAgB/B,cAGvBc,OAAOC,QAAQiB,SAAQ,SAASC,QAC5BA,OAAOC,SAAW,OAAStC,YA1CvB,SAASI,YAAae,gBAC/BtB,UAAU+B,OAAO,4BAA6B,CACjDT,QAASA,UACVF,MAAK,SAASe,KAAMC,IACnBpC,UAAUqC,oBAAoB9B,YAAa4B,KAAMC,IACjD7B,YAAYK,UAAUG,OAAO,WAC7BR,YAAYK,UAAUG,OAAO,WAsClB2B,CAAcnC,YAAac,OAAOC,aAE9CqB,MAAMzC,aAAa0C,YAStBC,uBAAyB,SAASvC,UAC9BwC,MAAQxC,KAAKG,cAAcR,UAAUS,OAAOqC,aAC5CC,WAAa1C,KAAKG,cAAcR,UAAUS,OAAOY,SACrChB,KAAKG,cAAcR,UAAUS,OAAOC,WAC1CsC,iBAAiB,SAAS,WAChCH,MAAMI,MAAQ,GACd9C,cAAc,GAAIE,KAAM0C,eAG5BF,MAAMG,iBAAiB,QAASE,UAAS,WACrC/C,cAAc0C,MAAMI,MAAO5C,KAAM0C,cAClC,OASHI,WAAa,SAAS9C,UAClB0C,WAAa1C,KAAKG,cAAcR,UAAUS,OAAOY,SACrDlB,cAAc,GAAIE,KAAM0C,aAexBG,SAAW,SAASE,KAAMC,KAAMC,eAC5BC,eACG,eACCC,QAAUC,KACV1C,KAAO2C,UACPC,MAAQ,WACRJ,QAAU,KACLD,WACDF,KAAKQ,MAAMJ,QAASzC,OAGxB8C,QAAUP,YAAcC,QAC5BO,aAAaP,SACbA,QAAUQ,WAAWJ,MAAON,MACxBQ,SACAT,KAAKQ,MAAMJ,QAASzC,cAIzB,CACHiD,KArJO,SAASC,gBAChB/D,SAAW+D,mBACP5D,KAAOqB,SAASlB,cAAcR,UAAUS,OAAOyD,YACnDtB,uBAAuBvC,MACvB8C,WAAW9C"} \ No newline at end of file diff --git a/public/admin/tool/moodlenet/amd/build/selectors.min.js b/public/admin/tool/moodlenet/amd/build/selectors.min.js deleted file mode 100644 index 75de02c08db..00000000000 --- a/public/admin/tool/moodlenet/amd/build/selectors.min.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Define all of the selectors we will be using within MoodleNet plugin. - * - * @module tool_moodlenet/selectors - * @copyright 2020 Mathew May - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -define("tool_moodlenet/selectors",[],(function(){return{action:{browse:'[data-action="browse"]',submit:'[data-action="submit"]',showMoodleNet:'[data-action="show-moodlenet"]',closeOption:'[data-action="close-chooser-option-summary"]'},region:{clearIcon:'[data-region="clear-icon"]',courses:'[data-region="mnet-courses"]',instancePage:'[data-region="moodle-net"]',searchInput:'[data-region="search-input"]',searchIcon:'[data-region="search-icon"]',selectPage:'[data-region="moodle-net-select"]',spinner:'[data-region="spinner"]',validationArea:'[data-region="validation-area"]',carousel:'[data-region="carousel"]',moodleNet:'[data-region="pluginCarousel"]'}}})); - -//# sourceMappingURL=selectors.min.js.map \ No newline at end of file diff --git a/public/admin/tool/moodlenet/amd/build/selectors.min.js.map b/public/admin/tool/moodlenet/amd/build/selectors.min.js.map deleted file mode 100644 index 4adbf8d872f..00000000000 --- a/public/admin/tool/moodlenet/amd/build/selectors.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"selectors.min.js","sources":["../src/selectors.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Define all of the selectors we will be using within MoodleNet plugin.\n *\n * @module tool_moodlenet/selectors\n * @copyright 2020 Mathew May \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine([], function() {\n return {\n action: {\n browse: '[data-action=\"browse\"]',\n submit: '[data-action=\"submit\"]',\n showMoodleNet: '[data-action=\"show-moodlenet\"]',\n closeOption: '[data-action=\"close-chooser-option-summary\"]',\n },\n region: {\n clearIcon: '[data-region=\"clear-icon\"]',\n courses: '[data-region=\"mnet-courses\"]',\n instancePage: '[data-region=\"moodle-net\"]',\n searchInput: '[data-region=\"search-input\"]',\n searchIcon: '[data-region=\"search-icon\"]',\n selectPage: '[data-region=\"moodle-net-select\"]',\n spinner: '[data-region=\"spinner\"]',\n validationArea: '[data-region=\"validation-area\"]',\n carousel: '[data-region=\"carousel\"]',\n moodleNet: '[data-region=\"pluginCarousel\"]',\n },\n };\n});\n"],"names":["define","action","browse","submit","showMoodleNet","closeOption","region","clearIcon","courses","instancePage","searchInput","searchIcon","selectPage","spinner","validationArea","carousel","moodleNet"],"mappings":";;;;;;;AAsBAA,kCAAO,IAAI,iBACA,CACHC,OAAQ,CACJC,OAAQ,yBACRC,OAAQ,yBACRC,cAAe,iCACfC,YAAa,gDAEjBC,OAAQ,CACJC,UAAW,6BACXC,QAAS,+BACTC,aAAc,6BACdC,YAAa,+BACbC,WAAY,8BACZC,WAAY,oCACZC,QAAS,0BACTC,eAAgB,kCAChBC,SAAU,2BACVC,UAAW"} \ No newline at end of file diff --git a/public/admin/tool/moodlenet/amd/build/validator.min.js b/public/admin/tool/moodlenet/amd/build/validator.min.js deleted file mode 100644 index b5685ff2297..00000000000 --- a/public/admin/tool/moodlenet/amd/build/validator.min.js +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Our validator that splits the user's input then fires off to a webservice - * - * @module tool_moodlenet/validator - * @copyright 2020 Mathew May - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -define("tool_moodlenet/validator",["jquery","core/ajax","core/str","core/notification"],(function($,Ajax,Str,Notification){return{validation:function(inputElement){var inputValue=inputElement.value;return""!==inputValue&&inputValue.includes("@")||$.when(Str.get_string("profilevalidationerror","tool_moodlenet")).then((function(strings){return Promise.reject().catch((function(){return{result:!1,message:strings[0]}}))})).fail(Notification.exception),Ajax.call([{methodname:"tool_moodlenet_verify_webfinger",args:{profileurl:inputValue,course:inputElement.dataset.courseid,section:inputElement.dataset.sectionnum}}])[0].then((function(result){return result})).catch()}}})); - -//# sourceMappingURL=validator.min.js.map \ No newline at end of file diff --git a/public/admin/tool/moodlenet/amd/build/validator.min.js.map b/public/admin/tool/moodlenet/amd/build/validator.min.js.map deleted file mode 100644 index c34f262a291..00000000000 --- a/public/admin/tool/moodlenet/amd/build/validator.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"validator.min.js","sources":["../src/validator.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Our validator that splits the user's input then fires off to a webservice\n *\n * @module tool_moodlenet/validator\n * @copyright 2020 Mathew May \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\ndefine(['jquery', 'core/ajax', 'core/str', 'core/notification'], function($, Ajax, Str, Notification) {\n /**\n * Handle form validation\n *\n * @method validation\n * @param {HTMLElement} inputElement The element the user entered text into.\n * @return {Promise} Was the users' entry a valid profile URL?\n */\n var validation = function validation(inputElement) {\n var inputValue = inputElement.value;\n\n // They didn't submit anything or they gave us a simple string that we can't do anything with.\n if (inputValue === \"\" || !inputValue.includes(\"@\")) {\n // Create a promise and immediately reject it.\n $.when(Str.get_string('profilevalidationerror', 'tool_moodlenet')).then(function(strings) {\n return Promise.reject().catch(function() {\n return {result: false, message: strings[0]};\n });\n }).fail(Notification.exception);\n }\n\n return Ajax.call([{\n methodname: 'tool_moodlenet_verify_webfinger',\n args: {\n profileurl: inputValue,\n course: inputElement.dataset.courseid,\n section: inputElement.dataset.sectionnum\n }\n }])[0].then(function(result) {\n return result;\n }).catch();\n };\n return {\n validation: validation,\n };\n});\n"],"names":["define","$","Ajax","Str","Notification","validation","inputElement","inputValue","value","includes","when","get_string","then","strings","Promise","reject","catch","result","message","fail","exception","call","methodname","args","profileurl","course","dataset","courseid","section","sectionnum"],"mappings":";;;;;;;AAsBAA,kCAAO,CAAC,SAAU,YAAa,WAAY,sBAAsB,SAASC,EAAGC,KAAMC,IAAKC,oBAgC7E,CACHC,WAzBa,SAAoBC,kBAC7BC,WAAaD,aAAaE,YAGX,KAAfD,YAAsBA,WAAWE,SAAS,MAE1CR,EAAES,KAAKP,IAAIQ,WAAW,yBAA0B,mBAAmBC,MAAK,SAASC,gBACtEC,QAAQC,SAASC,OAAM,iBACnB,CAACC,QAAQ,EAAOC,QAASL,QAAQ,UAE7CM,KAAKf,aAAagB,WAGlBlB,KAAKmB,KAAK,CAAC,CACdC,WAAY,kCACZC,KAAM,CACFC,WAAYjB,WACZkB,OAAQnB,aAAaoB,QAAQC,SAC7BC,QAAStB,aAAaoB,QAAQG,eAElC,GAAGjB,MAAK,SAASK,eACVA,UACRD"} \ No newline at end of file diff --git a/public/admin/tool/moodlenet/amd/src/instance_form.js b/public/admin/tool/moodlenet/amd/src/instance_form.js deleted file mode 100644 index 768501a05d4..00000000000 --- a/public/admin/tool/moodlenet/amd/src/instance_form.js +++ /dev/null @@ -1,170 +0,0 @@ -// 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 . - -/** - * Our basic form manager for when a user either enters - * their profile url or just wants to browse. - * - * This file is a mishmash of JS functions we need for both the standalone (M3.7, M3.8) - * plugin & Moodle 3.9 functions. The 3.9 Functions have a base understanding that certain - * things exist i.e. directory structures for templates. When this feature goes 3.9+ only - * The goal is that we can quickly gut all AMD modules into bare JS files and use ES6 guidelines. - * Till then this will have to do. - * - * @module tool_moodlenet/instance_form - * @copyright 2020 Mathew May - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -define(['tool_moodlenet/validator', - 'tool_moodlenet/selectors', - 'core/loadingicon', - 'core/templates', - 'core/notification', - 'jquery', - 'theme_boost/bootstrap/carousel', - 'core/normalise'], - function(Validator, - Selectors, - LoadingIcon, - Templates, - Notification, - $, - Carousel, - Normalise) { - - /** - * Add the event listeners to our form. - * - * @method registerListenerEvents - * @param {HTMLElement} page The whole page element for our form area - */ - var registerListenerEvents = function registerListenerEvents(page) { - page.addEventListener('click', function(e) { - - // Our fake submit button / browse button. - if (e.target.matches(Selectors.action.submit)) { - var input = page.querySelector('[data-var="mnet-link"]'); - var overlay = page.querySelector(Selectors.region.spinner); - var validationArea = document.querySelector(Selectors.region.validationArea); - - overlay.classList.remove('d-none'); - var spinner = LoadingIcon.addIconToContainerWithPromise(overlay); - Validator.validation(input) - .then(function(result) { - spinner.resolve(); - overlay.classList.add('d-none'); - if (result.result) { - input.classList.remove('is-invalid'); // Just in case the class has been applied already. - input.classList.add('is-valid'); - validationArea.innerText = result.message; - validationArea.classList.remove('text-danger'); - validationArea.classList.add('text-success'); - // Give the user some time to see their input is valid. - setTimeout(function() { - window.location = result.domain; - }, 1000); - } else { - input.classList.add('is-invalid'); - validationArea.innerText = result.message; - validationArea.classList.add('text-danger'); - } - return; - }).catch(Notification.exception); - } - }); - }; - - /** - * Given a user wishes to see the MoodleNet profile url form transition them there. - * - * @method chooserNavigateToMnet - * @param {HTMLElement} showMoodleNet The chooser's area for ment - * @param {Object} footerData Our footer object to render out - * @param {Element} carousel Our carousel instance to manage - */ - var chooserNavigateToMnet = function(showMoodleNet, footerData, carousel) { - showMoodleNet.innerHTML = ''; - - // Add a spinner. - var spinnerPromise = LoadingIcon.addIconToContainer(showMoodleNet); - - // Used later... - var transitionPromiseResolver = null; - var transitionPromise = new Promise(resolve => { - transitionPromiseResolver = resolve; - }); - - $.when( - spinnerPromise, - transitionPromise - ).then(function() { - Templates.replaceNodeContents(showMoodleNet, footerData.customcarouseltemplate, ''); - return; - }).catch(Notification.exception); - - // We apply our handlers in here to minimise plugin dependency in the Chooser. - registerListenerEvents(showMoodleNet); - - // Move to the next slide, and resolve the transition promise when it's done. - carousel.addEventListener('slid.bs.carousel', function() { - transitionPromiseResolver(); - }, {once: true}); - // Trigger the transition between 'pages'. - Carousel.getInstance(carousel).to(2); - }; - - /** - * Given a user no longer wishes to see the MoodleNet profile url form transition them from there. - * - * @method chooserNavigateFromMnet - * @param {Element} carousel Our carousel instance to manage - * @param {jQuery} modal Our modal instance to manage - * @param {Object} footerData Our footer object to render out - */ - var chooserNavigateFromMnet = function(carousel, modal, footerData) { - // Trigger the transition between 'pages'. - Carousel.getInstance(carousel).to(0); - modal.setFooter(footerData.customfootertemplate); - }; - - /** - * Create the custom listener that would handle anything in the footer. - * - * @param {Event} e The event being triggered. - * @param {Object} footerData The data generated from the exporter. - * @param {Object} modal The chooser modal. - */ - var footerClickListener = function(e, footerData, modal) { - const modalBody = Normalise.getFirst(modal.getBody()); - if (e.target.matches(Selectors.action.showMoodleNet) || e.target.closest(Selectors.action.showMoodleNet)) { - e.preventDefault(); - const carousel = modalBody.querySelector(Selectors.region.carousel); - const showMoodleNet = carousel.querySelector(Selectors.region.moodleNet); - - chooserNavigateToMnet(showMoodleNet, footerData, carousel, modal); - } - // From the help screen go back to the module overview. - if (e.target.matches(Selectors.action.closeOption)) { - const carousel = modalBody.querySelector(Selectors.region.carousel); - - chooserNavigateFromMnet(carousel, modal, footerData); - } - }; - - return { - footerClickListener: footerClickListener - }; -}); diff --git a/public/admin/tool/moodlenet/amd/src/select_page.js b/public/admin/tool/moodlenet/amd/src/select_page.js deleted file mode 100644 index 92fafd80ead..00000000000 --- a/public/admin/tool/moodlenet/amd/src/select_page.js +++ /dev/null @@ -1,197 +0,0 @@ -// 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 . - -/** - * When returning to Moodle let the user select which course to add the resource to. - * - * @module tool_moodlenet/select_page - * @copyright 2020 Mathew May - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -define([ - 'core/ajax', - 'core/templates', - 'tool_moodlenet/selectors', - 'core/notification' -], function( - Ajax, - Templates, - Selectors, - Notification -) { - /** - * @var {string} The id corresponding to the import. - */ - var importId; - - /** - * Set up the page. - * - * @method init - * @param {string} importIdString the string ID of the import. - */ - var init = function(importIdString) { - importId = importIdString; - var page = document.querySelector(Selectors.region.selectPage); - registerListenerEvents(page); - addCourses(page); - }; - - /** - * Renders the 'no-courses' template. - * - * @param {HTMLElement} areaReplace the DOM node to replace. - * @returns {Promise} - */ - var renderNoCourses = function(areaReplace) { - return Templates.renderPix('courses', 'tool_moodlenet').then(function(img) { - return img; - }).then(function(img) { - var temp = document.createElement('div'); - temp.innerHTML = img.trim(); - return Templates.render('core_course/no-courses', { - nocoursesimg: temp.firstChild.src - }); - }).then(function(html, js) { - Templates.replaceNodeContents(areaReplace, html, js); - areaReplace.classList.add('mx-auto'); - areaReplace.classList.add('w-25'); - return; - }); - }; - - /** - * Render the course cards for those supplied courses. - * - * @param {HTMLElement} areaReplace the DOM node to replace. - * @param {Array} courses the courses to render. - * @returns {Promise} - */ - var renderCourses = function(areaReplace, courses) { - return Templates.render('tool_moodlenet/view-cards', { - courses: courses - }).then(function(html, js) { - Templates.replaceNodeContents(areaReplace, html, js); - areaReplace.classList.remove('mx-auto'); - areaReplace.classList.remove('w-25'); - return; - }); - }; - - /** - * For a given input, the page & what to replace fetch courses and manage icons too. - * - * @method searchCourses - * @param {string} inputValue What to search for - * @param {HTMLElement} page The whole page element for our page - * @param {HTMLElement} areaReplace The Element to replace the contents of - */ - var searchCourses = function(inputValue, page, areaReplace) { - var searchIcon = page.querySelector(Selectors.region.searchIcon); - var clearIcon = page.querySelector(Selectors.region.clearIcon); - - if (inputValue !== '') { - searchIcon.classList.add('d-none'); - clearIcon.parentElement.classList.remove('d-none'); - } else { - searchIcon.classList.remove('d-none'); - clearIcon.parentElement.classList.add('d-none'); - } - var args = { - searchvalue: inputValue, - }; - Ajax.call([{ - methodname: 'tool_moodlenet_search_courses', - args: args - }])[0].then(function(result) { - if (result.courses.length === 0) { - return renderNoCourses(areaReplace); - } else { - // Add the importId to the course link - result.courses.forEach(function(course) { - course.viewurl += '&id=' + importId; - }); - return renderCourses(areaReplace, result.courses); - } - }).catch(Notification.exception); - }; - - /** - * Add the event listeners to our page. - * - * @method registerListenerEvents - * @param {HTMLElement} page The whole page element for our page - */ - var registerListenerEvents = function(page) { - var input = page.querySelector(Selectors.region.searchInput); - var courseArea = page.querySelector(Selectors.region.courses); - var clearIcon = page.querySelector(Selectors.region.clearIcon); - clearIcon.addEventListener('click', function() { - input.value = ''; - searchCourses('', page, courseArea); - }); - - input.addEventListener('input', debounce(function() { - searchCourses(input.value, page, courseArea); - }, 300)); - }; - - /** - * Fetch the courses to show the user. We use the same WS structure & template as the search for consistency. - * - * @method addCourses - * @param {HTMLElement} page The whole page element for our course page - */ - var addCourses = function(page) { - var courseArea = page.querySelector(Selectors.region.courses); - searchCourses('', page, courseArea); - }; - - /** - * Define our own debounce function as Moodle 3.7 does not have it. - * - * @method debounce - * @from underscore.js - * @copyright 2009-2020 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors - * @licence MIT - * @param {function} func The function we want to keep calling - * @param {number} wait Our timeout - * @param {boolean} immediate Do we want to apply the function immediately - * @return {function} - */ - var debounce = function(func, wait, immediate) { - var timeout; - return function() { - var context = this; - var args = arguments; - var later = function() { - timeout = null; - if (!immediate) { - func.apply(context, args); - } - }; - var callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - if (callNow) { - func.apply(context, args); - } - }; - }; - return { - init: init, - }; -}); diff --git a/public/admin/tool/moodlenet/amd/src/selectors.js b/public/admin/tool/moodlenet/amd/src/selectors.js deleted file mode 100644 index 63e3e9064e1..00000000000 --- a/public/admin/tool/moodlenet/amd/src/selectors.js +++ /dev/null @@ -1,44 +0,0 @@ -// 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 . - -/** - * Define all of the selectors we will be using within MoodleNet plugin. - * - * @module tool_moodlenet/selectors - * @copyright 2020 Mathew May - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -define([], function() { - return { - action: { - browse: '[data-action="browse"]', - submit: '[data-action="submit"]', - showMoodleNet: '[data-action="show-moodlenet"]', - closeOption: '[data-action="close-chooser-option-summary"]', - }, - region: { - clearIcon: '[data-region="clear-icon"]', - courses: '[data-region="mnet-courses"]', - instancePage: '[data-region="moodle-net"]', - searchInput: '[data-region="search-input"]', - searchIcon: '[data-region="search-icon"]', - selectPage: '[data-region="moodle-net-select"]', - spinner: '[data-region="spinner"]', - validationArea: '[data-region="validation-area"]', - carousel: '[data-region="carousel"]', - moodleNet: '[data-region="pluginCarousel"]', - }, - }; -}); diff --git a/public/admin/tool/moodlenet/amd/src/validator.js b/public/admin/tool/moodlenet/amd/src/validator.js deleted file mode 100644 index 91b6b3f6c03..00000000000 --- a/public/admin/tool/moodlenet/amd/src/validator.js +++ /dev/null @@ -1,58 +0,0 @@ -// 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 . - -/** - * Our validator that splits the user's input then fires off to a webservice - * - * @module tool_moodlenet/validator - * @copyright 2020 Mathew May - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -define(['jquery', 'core/ajax', 'core/str', 'core/notification'], function($, Ajax, Str, Notification) { - /** - * Handle form validation - * - * @method validation - * @param {HTMLElement} inputElement The element the user entered text into. - * @return {Promise} Was the users' entry a valid profile URL? - */ - var validation = function validation(inputElement) { - var inputValue = inputElement.value; - - // They didn't submit anything or they gave us a simple string that we can't do anything with. - if (inputValue === "" || !inputValue.includes("@")) { - // Create a promise and immediately reject it. - $.when(Str.get_string('profilevalidationerror', 'tool_moodlenet')).then(function(strings) { - return Promise.reject().catch(function() { - return {result: false, message: strings[0]}; - }); - }).fail(Notification.exception); - } - - return Ajax.call([{ - methodname: 'tool_moodlenet_verify_webfinger', - args: { - profileurl: inputValue, - course: inputElement.dataset.courseid, - section: inputElement.dataset.sectionnum - } - }])[0].then(function(result) { - return result; - }).catch(); - }; - return { - validation: validation, - }; -}); diff --git a/public/admin/tool/moodlenet/classes/external.php b/public/admin/tool/moodlenet/classes/external.php deleted file mode 100644 index 9d413ca8c82..00000000000 --- a/public/admin/tool/moodlenet/classes/external.php +++ /dev/null @@ -1,189 +0,0 @@ -. - -/** - * This is the external API for this component. - * - * @package tool_moodlenet - * @copyright 2020 Mathew May {@link https://mathew.solutions} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace tool_moodlenet; - -defined('MOODLE_INTERNAL') || die(); - -require_once($CFG->libdir . '/filelib.php'); -require_once(__DIR__ . '/../lib.php'); - -use core_course\external\course_summary_exporter; -use core_external\external_api; -use core_external\external_function_parameters; -use core_external\external_multiple_structure; -use core_external\external_single_structure; -use core_external\external_value; - -/** - * This is the external API for this component. - * - * @copyright 2020 Mathew May {@link https://mathew.solutions} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class external extends external_api { - - /** - * verify_webfinger parameters - * - * @return external_function_parameters - */ - public static function verify_webfinger_parameters() { - return new external_function_parameters( - array( - 'profileurl' => new external_value(PARAM_NOTAGS, 'The profile url that the user has given us', VALUE_REQUIRED), - 'course' => new external_value(PARAM_INT, 'The course we are adding to', VALUE_REQUIRED), - 'section' => new external_value(PARAM_INT, 'The section within the course we are adding to', VALUE_REQUIRED), - ) - ); - } - - /** - * Figure out if the passed content resolves with a WebFinger account. - * - * @param string $profileurl The profile url that the user states exists - * @param int $course The course we are adding to - * @param int $section The section within the course we are adding to - * @return array Contains the result and domain if any - * @throws \invalid_parameter_exception - */ - public static function verify_webfinger(string $profileurl, int $course, int $section) { - global $USER; - - $params = self::validate_parameters(self::verify_webfinger_parameters(), [ - 'profileurl' => $profileurl, - 'section' => $section, - 'course' => $course - ] - ); - try { - $mnetprofile = new moodlenet_user_profile($params['profileurl'], $USER->id); - } catch (\Exception $e) { - return [ - 'result' => false, - 'message' => get_string('profilevalidationfail', 'tool_moodlenet'), - ]; - } - - $userlink = profile_manager::get_moodlenet_profile_link($mnetprofile); - - // There were no problems verifying the account so lets store it. - if ($userlink['result'] === true) { - profile_manager::save_moodlenet_user_profile($mnetprofile); - $userlink['domain'] = generate_mnet_endpoint($mnetprofile->get_profile_name(), $course, $section); - } - - return $userlink; - } - - /** - * verify_webfinger return. - * - * @return external_description - */ - public static function verify_webfinger_returns() { - return new external_single_structure([ - 'result' => new external_value(PARAM_BOOL, 'Was the passed content a valid WebFinger?'), - 'message' => new external_value(PARAM_TEXT, 'Our message for the user'), - 'domain' => new external_value(PARAM_RAW, 'Domain to redirect the user to', VALUE_OPTIONAL), - ]); - } - - /** - * search_courses_parameters - * - * @return external_function_parameters - */ - public static function search_courses_parameters() { - return new external_function_parameters( - array( - 'searchvalue' => new external_value(PARAM_RAW, 'search value'), - ) - ); - } - - /** - * For some given input find and return any course that matches it. - * - * @param string $searchvalue The profile url that the user states exists - * @return array Contains the result set of courses for the value - */ - public static function search_courses(string $searchvalue) { - global $OUTPUT; - - $params = self::validate_parameters( - self::search_courses_parameters(), - ['searchvalue' => $searchvalue] - ); - self::validate_context(\context_system::instance()); - - $courses = array(); - - if ($arrcourses = \core_course_category::search_courses(array('search' => $params['searchvalue']))) { - foreach ($arrcourses as $course) { - if (has_capability('moodle/course:manageactivities', \context_course::instance($course->id))) { - $data = new \stdClass(); - $data->id = $course->id; - $data->fullname = $course->fullname; - $data->hidden = $course->visible; - $options = [ - 'course' => $course->id, - ]; - $viewurl = new \moodle_url('/admin/tool/moodlenet/options.php', $options); - $data->viewurl = $viewurl->out(false); - $category = \core_course_category::get($course->category); - $data->coursecategory = $category->name; - $courseimage = course_summary_exporter::get_course_image($data); - if (!$courseimage) { - $courseimage = $OUTPUT->get_generated_image_for_id($data->id); - } - $data->courseimage = $courseimage; - $courses[] = $data; - } - } - } - return array( - 'courses' => $courses - ); - } - - /** - * search_courses_returns. - * - * @return external_description - */ - public static function search_courses_returns() { - return new external_single_structure([ - 'courses' => new external_multiple_structure( - new external_single_structure([ - 'id' => new external_value(PARAM_INT, 'course id'), - 'fullname' => new external_value(PARAM_TEXT, 'course full name'), - 'hidden' => new external_value(PARAM_INT, 'is the course visible'), - 'viewurl' => new external_value(PARAM_URL, 'Next step of import'), - 'coursecategory' => new external_value(PARAM_TEXT, 'Category name'), - 'courseimage' => new external_value(PARAM_RAW, 'course image'), - ])) - ]); - } -} diff --git a/public/admin/tool/moodlenet/classes/local/import_backup_helper.php b/public/admin/tool/moodlenet/classes/local/import_backup_helper.php deleted file mode 100644 index a53398dfb5f..00000000000 --- a/public/admin/tool/moodlenet/classes/local/import_backup_helper.php +++ /dev/null @@ -1,194 +0,0 @@ -. -/** - * Contains the import_backup_helper class. - * - * @package tool_moodlenet - * @copyright 2020 Adrian Greeve - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -namespace tool_moodlenet\local; - -/** - * The import_backup_helper class. - * - * The import_backup_helper objects provide a means to prepare a backup for for restoration of a course or activity backup file. - * - * @copyright 2020 Adrian Greeve - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class import_backup_helper { - - /** @var remote_resource $remoteresource A file resource to be restored. */ - protected $remoteresource; - - /** @var user $user The user trying to restore a file. */ - protected $user; - - /** @var context $context The context we are trying to restore this file into. */ - protected $context; - - /** @var int $useruploadlimit The size limit that this user can upload in this context. */ - protected $useruploadlimit; - - /** - * Constructor for the import backup helper. - * - * @param remote_resource $remoteresource A remote file resource - * @param \stdClass $user The user importing a file. - * @param \context $context Context to restore into. - */ - public function __construct(remote_resource $remoteresource, \stdClass $user, \context $context) { - $this->remoteresource = $remoteresource; - $this->user = $user; - $this->context = $context; - - $maxbytes = 0; - if ($this->context->contextlevel == CONTEXT_COURSE) { - $course = get_course($this->context->instanceid); - $maxbytes = $course->maxbytes; - } - $this->useruploadlimit = get_user_max_upload_file_size($this->context, get_config('core', 'maxbytes'), - $maxbytes, 0, $this->user); - } - - /** - * Return a stored user draft file for processing. - * - * @return \stored_file The imported file to ultimately be restored. - */ - public function get_stored_file(): \stored_file { - - // Check if the user can upload a backup to this context. - require_capability('moodle/restore:uploadfile', $this->context, $this->user->id); - - // Before starting a potentially lengthy download, try to ensure the file size does not exceed the upload size restrictions - // for the user. This is a time saving measure. - // This is a naive check, that serves only to catch files if they provide the content length header. - // Because of potential content encoding (compression), the stored file will be checked again after download as well. - $size = $this->remoteresource->get_download_size() ?? -1; - if ($this->size_exceeds_upload_limit($size)) { - throw new \moodle_exception('uploadlimitexceeded', 'tool_moodlenet', '', ['filesize' => $size, - 'uploadlimit' => $this->useruploadlimit]); - } - - [$filepath, $filename] = $this->remoteresource->download_to_requestdir(); - \core\antivirus\manager::scan_file($filepath . DIRECTORY_SEPARATOR . $filename, $filename, true); - - // Check the final size of file against the user upload limits. - $localsize = filesize(sprintf('%s/%s', $filepath, $filename)); - if ($this->size_exceeds_upload_limit($localsize)) { - throw new \moodle_exception('uploadlimitexceeded', 'tool_moodlenet', '', ['filesize' => $localsize, - 'uploadlimit' => $this->useruploadlimit]); - } - - return $this->create_user_draft_stored_file($filename, $filepath); - } - - /** - * Does the size exceed the upload limit for the current import, taking into account user and core settings. - * - * @param int $sizeinbytes - * @return bool true if exceeded, false otherwise. - */ - protected function size_exceeds_upload_limit(int $sizeinbytes): bool { - $maxbytes = 0; - if ($this->context->contextlevel == CONTEXT_COURSE) { - $course = get_course($this->context->instanceid); - $maxbytes = $course->maxbytes; - } - $maxbytes = get_user_max_upload_file_size($this->context, get_config('core', 'maxbytes'), $maxbytes, 0, - $this->user); - if ($maxbytes != USER_CAN_IGNORE_FILE_SIZE_LIMITS && $sizeinbytes > $maxbytes) { - return true; - } - return false; - } - - /** - * Create a file in the user drafts ready for use by plugins implementing dndupload_handle(). - * - * @param string $filename the name of the file on disk - * @param string $path the path where the file is stored on disk - * @return \stored_file - */ - protected function create_user_draft_stored_file(string $filename, string $path): \stored_file { - global $CFG; - - $record = new \stdClass(); - $record->filearea = 'draft'; - $record->component = 'user'; - $record->filepath = '/'; - $record->itemid = file_get_unused_draft_itemid(); - $record->license = $CFG->sitedefaultlicense; - $record->author = ''; - $record->filename = clean_param($filename, PARAM_FILE); - $record->contextid = \context_user::instance($this->user->id)->id; - $record->userid = $this->user->id; - - $fullpathwithname = sprintf('%s/%s', $path, $filename); - - $fs = get_file_storage(); - - return $fs->create_file_from_pathname($record, $fullpathwithname); - } - - /** - * Looks for a context that this user has permission to upload backup files to. - * This gets a list of roles that the user has, checks for the restore:uploadfile capability and then sends back a context - * that has this permission if available. - * - * This starts with the highest context level and moves down i.e. system -> category -> course. - * - * @param int $userid The user ID that we are looking for a working context for. - * @return \context A context that allows the upload of backup files. - */ - public static function get_context_for_user(int $userid): ?\context { - global $DB; - - if (is_siteadmin()) { - return \context_system::instance(); - } - - $sql = "SELECT ctx.id, ctx.contextlevel, ctx.instanceid, ctx.path, ctx.depth, ctx.locked - FROM {context} ctx - JOIN {role_assignments} r ON ctx.id = r.contextid - WHERE r.userid = :userid AND ctx.contextlevel IN (:contextsystem, :contextcategory, :contextcourse) - ORDER BY ctx.contextlevel ASC"; - - $params = [ - 'userid' => $userid, - 'contextsystem' => CONTEXT_SYSTEM, - 'contextcategory' => CONTEXT_COURSECAT, - 'contextcourse' => CONTEXT_COURSE - ]; - $records = $DB->get_records_sql($sql, $params); - foreach ($records as $record) { - \context_helper::preload_from_record($record); - if ($record->contextlevel == CONTEXT_COURSECAT) { - $context = \context_coursecat::instance($record->instanceid); - } else if ($record->contextlevel == CONTEXT_COURSE) { - $context = \context_course::instance($record->instanceid); - } else { - $context = \context_system::instance(); - } - if (has_capability('moodle/restore:uploadfile', $context, $userid)) { - return $context; - } - } - return null; - } -} diff --git a/public/admin/tool/moodlenet/classes/local/import_handler_info.php b/public/admin/tool/moodlenet/classes/local/import_handler_info.php deleted file mode 100644 index 8517f376c25..00000000000 --- a/public/admin/tool/moodlenet/classes/local/import_handler_info.php +++ /dev/null @@ -1,91 +0,0 @@ -. -/** - * Contains the import_handler_info class. - * - * @package tool_moodlenet - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace tool_moodlenet\local; - -/** - * The import_handler_info class. - * - * An import_handler_info object represent an resource import handler for a particular module. - * - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class import_handler_info { - - /** @var string $modulename the name of the module. */ - protected $modulename; - - /** @var string $description the description. */ - protected $description; - - /** @var import_strategy $importstrategy the strategy which will be used to import resources handled by this handler */ - protected $importstrategy; - - /** - * The import_handler_info constructor. - * - * @param string $modulename the name of the module handling the file extension. E.g. 'label'. - * @param string $description A description of how the module handles files of this extension type. - * @param import_strategy $strategy the strategy which will be used to import the resource. - * @throws \coding_exception - */ - public function __construct(string $modulename, string $description, import_strategy $strategy) { - if (empty($modulename)) { - throw new \coding_exception("Module name cannot be empty."); - } - if (empty($description)) { - throw new \coding_exception("Description cannot be empty."); - } - $this->modulename = $modulename; - $this->description = $description; - $this->importstrategy = $strategy; - } - - /** - * Get the name of the module. - * - * @return string the module name, e.g. 'label'. - */ - public function get_module_name(): string { - return $this->modulename; - } - - /** - * Get a human readable, localised description of how the file is handled by the module. - * - * @return string the localised description. - */ - public function get_description(): string { - return $this->description; - } - - /** - * Get the import strategy used by this handler. - * - * @return import_strategy the import strategy object. - */ - public function get_strategy(): import_strategy { - return $this->importstrategy; - } -} diff --git a/public/admin/tool/moodlenet/classes/local/import_handler_registry.php b/public/admin/tool/moodlenet/classes/local/import_handler_registry.php deleted file mode 100644 index c0e766aacc5..00000000000 --- a/public/admin/tool/moodlenet/classes/local/import_handler_registry.php +++ /dev/null @@ -1,187 +0,0 @@ -. -/** - * Contains the import_handler_registry class. - * - * @package tool_moodlenet - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -namespace tool_moodlenet\local; - -use core_course\dndupload_handler; - -/** - * The import_handler_registry class. - * - * The import_handler_registry objects represent a register of modules handling various file extensions for a given course and user. - * Only modules which are available to the user in the course are included in the register for that user. - * - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class import_handler_registry { - - /** - * @var array array containing the names and messages of all modules handling import of resources as a 'file' type. - */ - protected $filehandlers = []; - - /** - * @var array $typehandlers the array of modules registering as handlers of other, non-file types, indexed by typename. - */ - protected $typehandlers = []; - - /** - * @var array $registry the aggregate of all registrations made by plugins, indexed by 'file' and 'type'. - */ - protected $registry = []; - - /** - * @var \context_course the course context object. - */ - protected $context; - - /** - * @var \stdClass a course object. - */ - protected $course; - - /** - * @var \stdClass a user object. - */ - protected $user; - - /** - * The import_handler_registry constructor. - * - * @param \stdClass $course the course, which impacts available handlers. - * @param \stdClass $user the user, which impacts available handlers. - */ - public function __construct(\stdClass $course, \stdClass $user) { - $this->course = $course; - $this->user = $user; - $this->context = \context_course::instance($course->id); - - // Generate the full list of handlers for all extensions for this user and course. - $this->populate_handlers(); - } - - /** - * Get all handlers for the remote resource, depending on the strategy being used to import the resource. - * - * @param remote_resource $resource the remote resource. - * @param import_strategy $strategy an import_strategy instance. - * @return import_handler_info[] the array of import_handler_info handlers. - */ - public function get_resource_handlers_for_strategy(remote_resource $resource, import_strategy $strategy): array { - return $strategy->get_handlers($this->registry, $resource); - } - - /** - * Get a specific handler for the resource, belonging to a specific module and for a specific strategy. - * - * @param remote_resource $resource the remote resource. - * @param string $modname the name of the module, e.g. 'label'. - * @param import_strategy $strategy a string representing how to treat the resource. e.g. 'file', 'link'. - * @return import_handler_info|null the import_handler_info object, if found, otherwise null. - */ - public function get_resource_handler_for_mod_and_strategy(remote_resource $resource, string $modname, - import_strategy $strategy): ?import_handler_info { - foreach ($strategy->get_handlers($this->registry, $resource) as $handler) { - if ($handler->get_module_name() === $modname) { - return $handler; - } - } - return null; - } - - /** - * Build up a list of extension handlers by leveraging the dndupload_register callbacks. - */ - protected function populate_handlers() { - // Generate a dndupload_handler object, just so we can call ->is_known_type() on the types being registered by plugins. - // We must vet each type which is reported to be handled against the list of known, supported types. - $dndhandlers = new dndupload_handler($this->course); - - // Get the list of mods enabled at site level first. We need to cross check this. - $pluginman = \core_plugin_manager::instance(); - $sitemods = $pluginman->get_plugins_of_type('mod'); - $sitedisabledmods = array_filter($sitemods, function(\core\plugininfo\mod $modplugininfo){ - return !$modplugininfo->is_enabled(); - }); - $sitedisabledmods = array_map(function($modplugininfo) { - return $modplugininfo->name; - }, $sitedisabledmods); - - // Loop through all modules to find the registered handlers. - $mods = get_plugin_list_with_function('mod', 'dndupload_register'); - foreach ($mods as $component => $funcname) { - list($modtype, $modname) = \core_component::normalize_component($component); - if (!empty($sitedisabledmods) && array_key_exists($modname, $sitedisabledmods)) { - continue; // Module is disabled at the site level. - } - if (!course_allowed_module($this->course, $modname, $this->user)) { - continue; // User does not have permission to add this module to the course. - } - - if (!$resp = component_callback($component, 'dndupload_register')) { - continue; - }; - - if (isset($resp['files'])) { - foreach ($resp['files'] as $file) { - $this->register_file_handler($file['extension'], $modname, $file['message']); - } - } - if (isset($resp['types'])) { - foreach ($resp['types'] as $type) { - if (!$dndhandlers->is_known_type($type['identifier'])) { - throw new \coding_exception("Trying to add handler for unknown type $type"); - } - $this->register_type_handler($type['identifier'], $modname, $type['message']); - } - } - } - $this->registry = [ - 'files' => $this->filehandlers, - 'types' => $this->typehandlers - ]; - } - - /** - * Adds a type handler to the list. - * - * @param string $identifier the name of the type. - * @param string $module the name of the module, e.g. 'label'. - * @param string $message the message describing how the module handles the type. - */ - protected function register_type_handler(string $identifier, string $module, string $message) { - $this->typehandlers[$identifier][] = ['module' => $module, 'message' => $message]; - } - - /** - * Adds a file extension handler to the list. - * - * @param string $extension the extension, e.g. 'png'. - * @param string $module the name of the module handling this extension - * @param string $message the message describing how the module handles the extension. - */ - protected function register_file_handler(string $extension, string $module, string $message) { - $extension = strtolower($extension); - $this->filehandlers[$extension][] = ['module' => $module, 'message' => $message]; - } -} diff --git a/public/admin/tool/moodlenet/classes/local/import_info.php b/public/admin/tool/moodlenet/classes/local/import_info.php deleted file mode 100644 index 818f4c551e2..00000000000 --- a/public/admin/tool/moodlenet/classes/local/import_info.php +++ /dev/null @@ -1,126 +0,0 @@ -. -/** - * Contains the import_info class. - * - * @package tool_moodlenet - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -namespace tool_moodlenet\local; - -/** - * Class import_info, describing objects which represent a resource being imported by a user. - * - * Objects of this class encapsulate both: - * - information about the resource (remote_resource). - * - config data pertaining to the import process, such as the destination course and section - * and how the resource should be treated (i.e. the type and the name of the module selected as the import handler) - * - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class import_info { - - /** @var int $userid the user conducting this import. */ - protected $userid; - - /** @var remote_resource $resource the resource being imported. */ - protected $resource; - - /** @var \stdClass $config config data pertaining to the import process, e.g. course, section, type. */ - protected $config; - - /** @var string $id string identifier for this object. */ - protected $id; - - /** - * The import_controller constructor. - * - * @param int $userid the id of the user performing the import. - * @param remote_resource $resource the resource being imported. - * @param \stdClass $config import config like 'course', 'section', 'type'. - */ - public function __construct(int $userid, remote_resource $resource, \stdClass $config) { - $this->userid = $userid; - $this->resource = $resource; - $this->config = $config; - $this->id = md5($resource->get_url()->get_value()); - } - - /** - * Get the id of this object. - */ - public function get_id() { - return $this->id; - } - - /** - * Get the remote resource being imported. - * - * @return remote_resource the remote resource being imported. - */ - public function get_resource(): remote_resource { - return $this->resource; - } - - /** - * Get the configuration data pertaining to the import. - * - * @return \stdClass the import configuration data. - */ - public function get_config(): \stdClass { - return $this->config; - } - - /** - * Set the configuration data pertaining to the import. - * - * @param \stdClass $config the configuration data to set. - */ - public function set_config(\stdClass $config): void { - $this->config = $config; - } - - /** - * Get an import_info object by id. - * - * @param string $id the id of the import_info object to load. - * @return mixed an import_info object if found, otherwise null. - */ - public static function load(string $id): ?import_info { - // This currently lives in the session, so we don't need userid. - // It might be useful if we ever move to another storage mechanism however, where we would need it. - global $SESSION; - return isset($SESSION->moodlenetimports[$id]) ? unserialize($SESSION->moodlenetimports[$id]) : null; - } - - /** - * Save this object to a store which is accessible across requests. - */ - public function save(): void { - global $SESSION; - $SESSION->moodlenetimports[$this->id] = serialize($this); - } - - /** - * Remove all information about an import from the store. - */ - public function purge(): void { - global $SESSION; - unset($SESSION->moodlenetimports[$this->id]); - } -} diff --git a/public/admin/tool/moodlenet/classes/local/import_processor.php b/public/admin/tool/moodlenet/classes/local/import_processor.php deleted file mode 100644 index 4a17253ab86..00000000000 --- a/public/admin/tool/moodlenet/classes/local/import_processor.php +++ /dev/null @@ -1,206 +0,0 @@ -. -/** - * Contains the import_processor class. - * - * @package tool_moodlenet - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -namespace tool_moodlenet\local; - -/** - * The import_processor class. - * - * The import_processor objects provide a means to import a remote resource into a course section, delegating the handling of - * content to the relevant module, via its dndupload_handler callback. - * - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class import_processor { - - /** @var object The course that we are uploading to */ - protected $course = null; - - /** @var int The section number we are uploading to */ - protected $section = null; - - /** @var import_handler_registry $handlerregistry registry object to use for cross checking the supplied handler.*/ - protected $handlerregistry; - - /** @var import_handler_info $handlerinfo information about the module handling the import.*/ - protected $handlerinfo; - - /** @var \stdClass $user the user conducting the import.*/ - protected $user; - - /** @var remote_resource $remoteresource the remote resource being imported.*/ - protected $remoteresource; - - /** @var string[] $descriptionoverrides list of modules which support having their descriptions updated, post-import. */ - protected $descriptionoverrides = ['folder', 'page', 'resource', 'scorm', 'url']; - - /** - * The import_processor constructor. - * - * @param \stdClass $course the course object. - * @param int $section the section number in the course, starting at 0. - * @param remote_resource $remoteresource the remote resource to import. - * @param import_handler_info $handlerinfo information about which module is handling the import. - * @param import_handler_registry $handlerregistry A registry of import handlers, to use for validation. - * @throws \coding_exception If any of the params are invalid. - */ - public function __construct(\stdClass $course, int $section, remote_resource $remoteresource, import_handler_info $handlerinfo, - import_handler_registry $handlerregistry) { - - global $DB, $USER; - - if ($section < 0) { - throw new \coding_exception("Invalid section number $section. Must be > 0."); - } - if (!$DB->record_exists('modules', array('name' => $handlerinfo->get_module_name()))) { - throw new \coding_exception("Module {$handlerinfo->get_module_name()} does not exist"); - } - - $this->course = $course; - $this->section = $section; - $this->handlerregistry = $handlerregistry; - $this->user = $USER; - $this->remoteresource = $remoteresource; - $this->handlerinfo = $handlerinfo; - - // ALL handlers must have a strategy and ANY strategy can process ANY resource. - // It is therefore NOT POSSIBLE to have a resource that CANNOT be processed by a handler. - // So, there's no need to verify that the remote_resource CAN be handled by the handler. It always can. - } - - /** - * Run the import process, including file download, module creation and cleanup (cache purge, etc). - */ - public function process(): void { - // Allow the strategy to do setup for this file import. - $moduledata = $this->handlerinfo->get_strategy()->import($this->remoteresource, $this->user, $this->course, $this->section); - - // Create the course module, and add that information to the data to be sent to the plugin handling the resource. - $cmdata = $this->create_course_module($this->course, $this->section, $this->handlerinfo->get_module_name()); - $moduledata->coursemodule = $cmdata->id; - - // Now, send the data to the handling plugin to let it set up. - $instanceid = plugin_callback('mod', $this->handlerinfo->get_module_name(), 'dndupload', 'handle', [$moduledata], - 'invalidfunction'); - if ($instanceid == 'invalidfunction') { - $name = $this->handlerinfo->get_module_name(); - throw new \coding_exception("$name does not support drag and drop upload (missing {$name}_dndupload_handle function)"); - } - - // Now, update the module description if the module supports it and only if it's not currently set. - $this->update_module_description($instanceid); - - // Finish setting up the course module. - $this->finish_setup_course_module($instanceid, $cmdata->id); - } - - /** - * Update the module's description (intro), if that feature is supported. - * - * @param int $instanceid the instance id of the module to update. - */ - protected function update_module_description(int $instanceid): void { - global $DB, $CFG; - require_once($CFG->libdir . '/moodlelib.php'); - - if (plugin_supports('mod', $this->handlerinfo->get_module_name(), FEATURE_MOD_INTRO, true)) { - require_once($CFG->libdir . '/editorlib.php'); - require_once($CFG->libdir . '/modinfolib.php'); - - $rec = $DB->get_record($this->handlerinfo->get_module_name(), ['id' => $instanceid]); - - if (empty($rec->intro) || in_array($this->handlerinfo->get_module_name(), $this->descriptionoverrides)) { - $updatedata = (object)[ - 'id' => $instanceid, - 'intro' => clean_param($this->remoteresource->get_description(), PARAM_TEXT), - 'introformat' => editors_get_preferred_format() - ]; - - $DB->update_record($this->handlerinfo->get_module_name(), $updatedata); - - rebuild_course_cache($this->course->id, true); - } - } - } - - /** - * Create the course module to hold the file/content that has been uploaded. - * @param \stdClass $course the course object. - * @param int $section the section. - * @param string $modname the name of the module, e.g. 'label'. - * @return \stdClass the course module data. - */ - protected function create_course_module(\stdClass $course, int $section, string $modname): \stdClass { - global $CFG; - require_once($CFG->dirroot . '/course/modlib.php'); - list($module, $context, $cw, $cm, $data) = prepare_new_moduleinfo_data($course, $modname, $section); - $data->visible = false; // The module is created in a hidden state. - $data->coursemodule = $data->id = add_course_module($data); - return $data; - } - - /** - * Finish off any course module setup, such as adding to the course section and firing events. - * - * @param int $instanceid id returned by the mod when it was created. - * @param int $cmid the course module record id, for removal if something went wrong. - */ - protected function finish_setup_course_module($instanceid, int $cmid): void { - global $DB; - - if (!$instanceid) { - // Something has gone wrong - undo everything we can. - $coursecontext = \context_module::instance($cmid)->get_course_context(); - \core_courseformat\formatactions::cm($coursecontext->instanceid)->delete($cmid); - throw new \moodle_exception('errorcreatingactivity', 'moodle', '', $this->handlerinfo->get_module_name()); - } - - // Note the section visibility. - $visible = get_fast_modinfo($this->course)->get_section_info($this->section)->visible; - - $DB->set_field('course_modules', 'instance', $instanceid, array('id' => $cmid)); - - // Rebuild the course cache after update action. - rebuild_course_cache($this->course->id, true); - - course_add_cm_to_section($this->course, $cmid, $this->section, modname: $this->handlerinfo->get_module_name()); - - set_coursemodule_visible($cmid, $visible); - if (!$visible) { - $DB->set_field('course_modules', 'visibleold', 1, array('id' => $cmid)); - } - - // Retrieve the final info about this module. - $info = get_fast_modinfo($this->course, $this->user->id); - if (!isset($info->cms[$cmid])) { - // The course module has not been properly created in the course - undo everything. - \core_courseformat\formatactions::cm($this->course->id)->delete($cmid); - throw new \moodle_exception('errorcreatingactivity', 'moodle', '', $this->handlerinfo->get_module_name()); - } - $mod = $info->get_cm($cmid); - - // Trigger course module created event. - $event = \core\event\course_module_created::create_from_cm($mod); - $event->trigger(); - } -} diff --git a/public/admin/tool/moodlenet/classes/local/import_strategy.php b/public/admin/tool/moodlenet/classes/local/import_strategy.php deleted file mode 100644 index d647e26b63c..00000000000 --- a/public/admin/tool/moodlenet/classes/local/import_strategy.php +++ /dev/null @@ -1,69 +0,0 @@ -. -/** - * Contains the import_strategy interface. - * - * @package tool_moodlenet - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -namespace tool_moodlenet\local; - -/** - * The import_strategy interface. - * - * This provides a contract allowing different import strategies to be implemented. - * - * An import_strategy encapsulates the logic used to prepare a remote_resource for import into Moodle in some way and is used by the - * import_processor (to perform aforementioned preparations) before it hands control of the import over to a course module plugin. - * - * We may wish to have many strategies because the preparation steps may vary depending on how the resource is to be treated. - * E.g. We may wish to import as a file in which case download steps will be required, or we may simply wish to import the remote - * resource as a link, in which cases setup steps will not require any file download. - * - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -interface import_strategy { - - /** - * Get an array of import_handler_info objects supported by this import strategy, based on the registrydata and resource. - * - * Implementations should check the registry data for any entries which align with their import strategy and should create - * import_handler_info objects to represent each relevant entry. If an entry represents a module, or handling type which does - * not align with the strategy, that item should simply be skipped. - * - * E.g. If one strategy aims to import all remote resources as files (e.g. import_strategy_file), it would only generate a list - * of import_handler_info objects created from those registry entries of type 'file', as those entries represent the modules - * which have said they can handle resources as files. - * - * @param array $registrydata The fully populated handler registry. - * @param remote_resource $resource the remote resource. - * @return import_handler_info[] the array of import_handler_info objects, or an empty array if none were matched. - */ - public function get_handlers(array $registrydata, remote_resource $resource): array; - - /** - * Called during import to perform required import setup steps. - * - * @param remote_resource $resource the resource to import. - * @param \stdClass $user the user to import on behalf of. - * @param \stdClass $course the course into which the remote resource is being imported. - * @param int $section the section into which the remote resource is being imported. - * @return \stdClass the module data which will be passed on to the course module plugin. - */ - public function import(remote_resource $resource, \stdClass $user, \stdClass $course, int $section): \stdClass; -} diff --git a/public/admin/tool/moodlenet/classes/local/import_strategy_file.php b/public/admin/tool/moodlenet/classes/local/import_strategy_file.php deleted file mode 100644 index 3a546401c10..00000000000 --- a/public/admin/tool/moodlenet/classes/local/import_strategy_file.php +++ /dev/null @@ -1,170 +0,0 @@ -. -/** - * Contains the import_strategy_file class. - * - * @package tool_moodlenet - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -namespace tool_moodlenet\local; - -use core\antivirus\manager as avmanager; - -/** - * The import_strategy_file class. - * - * The import_strategy_file objects contains the setup steps needed to prepare a resource for import as a file into Moodle. This - * ensures the remote_resource is first downloaded and put in a draft file area, ready for use as a file by the handling module. - * - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class import_strategy_file implements import_strategy { - - /** - * Get an array of import_handler_info objects representing modules supporting import of this file type. - * - * @param array $registrydata the fully populated registry. - * @param remote_resource $resource the remote resource. - * @return import_handler_info[] the array of import_handler_info objects. - */ - public function get_handlers(array $registrydata, remote_resource $resource): array { - $handlers = []; - foreach ($registrydata['files'] as $index => $items) { - foreach ($items as $item) { - if ($index === $resource->get_extension() || $index === '*') { - $handlers[] = new import_handler_info($item['module'], $item['message'], $this); - } - } - } - return $handlers; - } - - /** - * Import the remote resource according to the rules of this strategy. - * - * @param remote_resource $resource the resource to import. - * @param \stdClass $user the user to import on behalf of. - * @param \stdClass $course the course into which the remote_resource is being imported. - * @param int $section the section into which the remote_resource is being imported. - * @return \stdClass the module data. - * @throws \moodle_exception if the file size means the upload limit is exceeded for the user. - */ - public function import(remote_resource $resource, \stdClass $user, \stdClass $course, int $section): \stdClass { - // Before starting a potentially lengthy download, try to ensure the file size does not exceed the upload size restrictions - // for the user. This is a time saving measure. - // This is a naive check, that serves only to catch files if they provide the content length header. - // Because of potential content encoding (compression), the stored file will be checked again after download as well. - $size = $resource->get_download_size() ?? -1; - $useruploadlimit = $this->get_user_upload_limit($user, $course); - if ($this->size_exceeds_upload_limit($size, $useruploadlimit)) { - throw new \moodle_exception('uploadlimitexceeded', 'tool_moodlenet', '', ['filesize' => $size, - 'uploadlimit' => $useruploadlimit]); - } - - // Download the file into a request directory and scan it. - [$filepath, $filename] = $resource->download_to_requestdir(); - avmanager::scan_file($filepath . DIRECTORY_SEPARATOR . $filename, $filename, true); - - // Check the final size of file against the user upload limits. - $localsize = filesize(sprintf('%s/%s', $filepath, $filename)); - if ($this->size_exceeds_upload_limit($localsize, $useruploadlimit)) { - throw new \moodle_exception('uploadlimitexceeded', 'tool_moodlenet', '', ['filesize' => $localsize, - 'uploadlimit' => $useruploadlimit]); - } - - // Store in the user draft file area. - $storedfile = $this->create_user_draft_stored_file($user, $filename, $filepath); - - // Prepare the data to be sent to the modules dndupload_handle hook. - return $this->prepare_module_data($course, $resource, $storedfile->get_itemid()); - } - - - /** - * Creates the data to pass to the dndupload_handle() hooks. - * - * @param \stdClass $course the course record. - * @param remote_resource $resource the resource being imported as a file. - * @param int $draftitemid the itemid of the draft file. - * @return \stdClass the data object. - */ - protected function prepare_module_data(\stdClass $course, remote_resource $resource, int $draftitemid): \stdClass { - $data = new \stdClass(); - $data->type = 'Files'; - $data->course = $course; - $data->draftitemid = $draftitemid; - $data->displayname = $resource->get_name(); - return $data; - } - - /** - * Get the max file size limit for the user in the course. - * - * @param \stdClass $user the user to check. - * @param \stdClass $course the course to check in. - * @return int the file size limit, in bytes. - */ - protected function get_user_upload_limit(\stdClass $user, \stdClass $course): int { - return get_user_max_upload_file_size(\context_course::instance($course->id), get_config('core', 'maxbytes'), - $course->maxbytes, 0, $user); - } - - /** - * Does the size exceed the upload limit for the current import, taking into account user and core settings. - * - * @param int $sizeinbytes the size, in bytes. - * @param int $useruploadlimit the upload limit, in bytes. - * @return bool true if exceeded, false otherwise. - * @throws \dml_exception - */ - protected function size_exceeds_upload_limit(int $sizeinbytes, int $useruploadlimit): bool { - if ($useruploadlimit != USER_CAN_IGNORE_FILE_SIZE_LIMITS && $sizeinbytes > $useruploadlimit) { - return true; - } - return false; - } - - /** - * Create a file in the user drafts ready for use by plugins implementing dndupload_handle(). - * - * @param \stdClass $user the user object. - * @param string $filename the name of the file on disk - * @param string $path the path where the file is stored on disk - * @return \stored_file - */ - protected function create_user_draft_stored_file(\stdClass $user, string $filename, string $path): \stored_file { - global $CFG; - - $record = new \stdClass(); - $record->filearea = 'draft'; - $record->component = 'user'; - $record->filepath = '/'; - $record->itemid = file_get_unused_draft_itemid(); - $record->license = $CFG->sitedefaultlicense; - $record->author = ''; - $record->filename = clean_param($filename, PARAM_FILE); - $record->contextid = \context_user::instance($user->id)->id; - $record->userid = $user->id; - - $fullpathwithname = sprintf('%s/%s', $path, $filename); - - $fs = get_file_storage(); - - return $fs->create_file_from_pathname($record, $fullpathwithname); - } -} diff --git a/public/admin/tool/moodlenet/classes/local/import_strategy_link.php b/public/admin/tool/moodlenet/classes/local/import_strategy_link.php deleted file mode 100644 index ca04f061d88..00000000000 --- a/public/admin/tool/moodlenet/classes/local/import_strategy_link.php +++ /dev/null @@ -1,71 +0,0 @@ -. -/** - * Contains the import_strategy_link class. - * - * @package tool_moodlenet - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -namespace tool_moodlenet\local; - -/** - * The import_strategy_link class. - * - * The import_strategy_link objects contains the setup steps needed to prepare a resource for import as a URL into Moodle. - * - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class import_strategy_link implements import_strategy { - - /** - * Get an array of import_handler_info objects representing modules supporting import of the resource. - * - * @param array $registrydata the fully populated registry. - * @param remote_resource $resource the remote resource. - * @return import_handler_info[] the array of import_handler_info objects. - */ - public function get_handlers(array $registrydata, remote_resource $resource): array { - $handlers = []; - foreach ($registrydata['types'] as $identifier => $items) { - foreach ($items as $item) { - if ($identifier === 'url') { - $handlers[] = new import_handler_info($item['module'], $item['message'], $this); - } - } - } - return $handlers; - } - - /** - * Import the remote resource according to the rules of this strategy. - * - * @param remote_resource $resource the resource to import. - * @param \stdClass $user the user to import on behalf of. - * @param \stdClass $course the course into which the remote_resource is being imported. - * @param int $section the section into which the remote_resource is being imported. - * @return \stdClass the module data. - */ - public function import(remote_resource $resource, \stdClass $user, \stdClass $course, int $section): \stdClass { - $data = new \stdClass(); - $data->type = 'url'; - $data->course = $course; - $data->content = $resource->get_url()->get_value(); - $data->displayname = $resource->get_name(); - return $data; - } -} diff --git a/public/admin/tool/moodlenet/classes/local/remote_resource.php b/public/admin/tool/moodlenet/classes/local/remote_resource.php deleted file mode 100644 index a08a3bb7015..00000000000 --- a/public/admin/tool/moodlenet/classes/local/remote_resource.php +++ /dev/null @@ -1,169 +0,0 @@ -. -/** - * Contains the remote_resource class definition. - * - * @package tool_moodlenet - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -namespace tool_moodlenet\local; - -/** - * The remote_resource class. - * - * Objects of type remote_resource provide a means of interacting with resources over HTTP. - * - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class remote_resource { - - /** @var \curl $curl the curl http helper.*/ - protected $curl; - - /** @var url $url the url to the remote resource.*/ - protected $url; - - /** @var string $filename the name of this remote file.*/ - protected $filename; - - /** @var string $extension the file extension of this remote file.*/ - protected $extension; - - /** @var array $headinfo the array of information for the most recent HEAD request.*/ - protected $headinfo = []; - - /** @var \stdClass $metadata information about the resource. */ - protected $metadata; - - /** - * The remote_resource constructor. - * - * @param \curl $curl a curl object for HTTP requests. - * @param url $url the URL of the remote resource. - * @param \stdClass $metadata resource metadata such as name, summary, license, etc. - */ - public function __construct(\curl $curl, url $url, \stdClass $metadata) { - $this->curl = $curl; - $this->url = $url; - $this->filename = pathinfo($this->url->get_path() ?? '', PATHINFO_FILENAME); - $this->extension = pathinfo($this->url->get_path() ?? '', PATHINFO_EXTENSION); - $this->metadata = $metadata; - } - - /** - * Return the URL for this remote resource. - * - * @return url the url object. - */ - public function get_url(): url { - return $this->url; - } - - /** - * Get the name of the file as taken from the metadata. - */ - public function get_name(): string { - return $this->metadata->name ?? ''; - } - - /** - * Get the resource metadata. - * - * @return \stdClass the metadata. - */ - public function get_metadata(): \stdClass { - return$this->metadata; - } - - /** - * Get the description of the resource as taken from the metadata. - * - * @return string - */ - public function get_description(): string { - return $this->metadata->description ?? ''; - } - - /** - * Return the extension of the file, if found. - * - * @return string the extension of the file, if found. - */ - public function get_extension(): string { - return $this->extension; - } - - /** - * Returns the file size of the remote file, in bytes, or null if it cannot be determined. - * - * @return int|null the content length, if able to be determined, otherwise null. - */ - public function get_download_size(): ?int { - $this->get_resource_info(); - return $this->headinfo['download_content_length'] ?? null; - } - - /** - * Download the remote resource to a local requestdir, returning the path and name of the resulting file. - * - * @return array an array containing filepath adn filename, e.g. [filepath, filename]. - * @throws \moodle_exception if the file cannot be downloaded. - */ - public function download_to_requestdir(): array { - $filename = sprintf('%s.%s', $this->filename, $this->get_extension()); - $path = make_request_directory(); - $fullpathwithname = sprintf('%s/%s', $path, $filename); - - // In future, use a timeout (download and/or connection) controlled by a tool_moodlenet setting. - $downloadtimeout = 30; - - $result = $this->curl->download_one($this->url->get_value(), null, ['filepath' => $fullpathwithname, - 'timeout' => $downloadtimeout]); - if ($result !== true) { - throw new \moodle_exception('errorduringdownload', 'tool_moodlenet', '', $result); - } - - return [$path, $filename]; - } - - /** - * Fetches information about the remote resource via a HEAD request. - * - * @throws \coding_exception if any connection problems occur. - */ - protected function get_resource_info() { - if (!empty($this->headinfo)) { - return; - } - $options['CURLOPT_RETURNTRANSFER'] = 1; - $options['CURLOPT_FOLLOWLOCATION'] = 1; - $options['CURLOPT_MAXREDIRS'] = 5; - $options['CURLOPT_FAILONERROR'] = 1; // We want to consider http error codes as errors to report, not just status codes. - - $this->curl->head($this->url->get_value(), $options); - $errorno = $this->curl->get_errno(); - $this->curl->resetopt(); - - if ($errorno !== 0) { - $message = 'Problem during HEAD request for remote resource \''.$this->url->get_value().'\'. Curl Errno: ' . $errorno; - throw new \coding_exception($message); - } - $this->headinfo = $this->curl->get_info(); - } - -} diff --git a/public/admin/tool/moodlenet/classes/local/url.php b/public/admin/tool/moodlenet/classes/local/url.php deleted file mode 100644 index 233b770f56e..00000000000 --- a/public/admin/tool/moodlenet/classes/local/url.php +++ /dev/null @@ -1,84 +0,0 @@ -. -/** - * Contains the url class, providing a representation of a url and operations on its component parts. - * - * @package tool_moodlenet - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -namespace tool_moodlenet\local; - -/** - * The url class, providing a representation of a url and operations on its component parts. - * - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class url { - - /** @var string $url the full URL string.*/ - protected $url; - - /** @var string|null $path the path component of this URL.*/ - protected $path; - - /** @var host|null $host the host component of this URL.*/ - protected $host; - - /** - * The url constructor. - * - * @param string $url the URL string. - * @throws \coding_exception if the URL does not pass syntax validation. - */ - public function __construct(string $url) { - // This object supports URLs as per the spec, so non-ascii chars must be encoded as per IDNA rules. - if (!filter_var($url, FILTER_VALIDATE_URL)) { - throw new \coding_exception('Malformed URL'); - } - $this->url = $url; - $this->path = parse_url($url, PHP_URL_PATH); - $this->host = parse_url($url, PHP_URL_HOST); - } - - /** - * Get the path component of the URL. - * - * @return string|null the path component of the URL. - */ - public function get_path(): ?string { - return $this->path; - } - - /** - * Return the domain component of the URL. - * - * @return string|null the domain component of the URL. - */ - public function get_host(): ?string { - return $this->host; - } - - /** - * Return the full URL string. - * - * @return string the full URL string. - */ - public function get_value() { - return $this->url; - } -} diff --git a/public/admin/tool/moodlenet/classes/moodlenet_user_profile.php b/public/admin/tool/moodlenet/classes/moodlenet_user_profile.php deleted file mode 100644 index 51e33f96b80..00000000000 --- a/public/admin/tool/moodlenet/classes/moodlenet_user_profile.php +++ /dev/null @@ -1,107 +0,0 @@ -. - -/** - * Moodle net user profile class. - * - * @package tool_moodlenet - * @copyright 2020 Adrian Greeve - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace tool_moodlenet; - -/** - * A class to represent the moodlenet profile. - * - * @package tool_moodlenet - * @copyright 2020 Adrian Greeve - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class moodlenet_user_profile { - - /** @var string $profile The full profile name. */ - protected $profile; - - /** @var int $userid The user ID that this profile belongs to. */ - protected $userid; - - /** @var string $username The username from $userprofile */ - protected $username; - - /** @var string $domain The domain from $domain */ - protected $domain; - - /** - * Constructor method. - * - * @param string $userprofile The moodle net user profile string. - * @param int $userid The user ID that this profile belongs to. - */ - public function __construct(string $userprofile, int $userid) { - $this->profile = $userprofile; - $this->userid = $userid; - - $explodedprofile = explode('@', $this->profile); - if (count($explodedprofile) === 2) { - // It'll either be an email or WebFinger entry. - $this->username = $explodedprofile[0]; - $this->domain = $explodedprofile[1]; - } else if (count($explodedprofile) === 3) { - // We may have a profile link as MoodleNet gives to the user. - $this->username = $explodedprofile[1]; - $this->domain = $explodedprofile[2]; - } else { - throw new \moodle_exception('invalidmoodlenetprofile', 'tool_moodlenet'); - } - } - - /** - * Get the full moodle net profile. - * - * @return string The moodle net profile. - */ - public function get_profile_name(): string { - return $this->profile; - } - - /** - * Get the user ID that this profile belongs to. - * - * @return int The user ID. - */ - public function get_userid(): int { - return $this->userid; - } - - /** - * Get the username for this profile. - * - * @return string The username. - */ - public function get_username(): string { - return $this->username; - } - - /** - * Get the domain for this profile. - * - * @return string The domain. - */ - public function get_domain(): string { - return $this->domain; - } -} diff --git a/public/admin/tool/moodlenet/classes/output/renderer.php b/public/admin/tool/moodlenet/classes/output/renderer.php deleted file mode 100644 index 98de3e4ccbf..00000000000 --- a/public/admin/tool/moodlenet/classes/output/renderer.php +++ /dev/null @@ -1,52 +0,0 @@ -. - -/** - * Renderer. - * - * @package tool_moodlenet - * @copyright 2020 Mathew May {@link https://mathew.solutions} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace tool_moodlenet\output; - -defined('MOODLE_INTERNAL') || die(); - -use plugin_renderer_base; - -/** - * Renderer class. - * - * @package tool_moodlenet - * @copyright 2020 Mathew May {@link https://mathew.solutions} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class renderer extends plugin_renderer_base { - - /** - * Defer to template. - * - * @param select_page $selectpage - * @return string HTML - */ - protected function render_select_page(select_page $selectpage): string { - - $this->page->requires->js_call_amd('tool_moodlenet/select_page', 'init', [$selectpage->get_import_info()->get_id()]); - $data = $selectpage->export_for_template($this); - return parent::render_from_template('tool_moodlenet/select_page', $data); - } -} diff --git a/public/admin/tool/moodlenet/classes/output/select_page.php b/public/admin/tool/moodlenet/classes/output/select_page.php deleted file mode 100644 index 3a7a50013eb..00000000000 --- a/public/admin/tool/moodlenet/classes/output/select_page.php +++ /dev/null @@ -1,76 +0,0 @@ -. - -/** - * Select page renderable. - * - * @package tool_moodlenet - * @copyright 2020 Mathew May {@link https://mathew.solutions} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace tool_moodlenet\output; - -defined('MOODLE_INTERNAL') || die; - -use tool_moodlenet\local\import_info; - -/** - * Select page renderable. - * - * @package tool_moodlenet - * @copyright 2020 Mathew May {@link https://mathew.solutions} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class select_page implements \renderable, \templatable { - - /** @var import_info $importinfo resource and config information pertaining to an import. */ - protected $importinfo; - - /** - * Inits the Select page renderable. - * - * @param import_info $importinfo resource and config information pertaining to an import. - */ - public function __construct(import_info $importinfo) { - $this->importinfo = $importinfo; - } - - /** - * Return the import info. - * - * @return import_info the import information. - */ - public function get_import_info(): import_info { - return $this->importinfo; - } - - /** - * Export the data. - * - * @param \renderer_base $output - * @return \stdClass - */ - public function export_for_template(\renderer_base $output): \stdClass { - - // Prepare the context object. - return (object) [ - 'name' => $this->importinfo->get_resource()->get_name(), - 'type' => $this->importinfo->get_config()->type, - 'cancellink' => new \moodle_url('/'), - ]; - } -} diff --git a/public/admin/tool/moodlenet/classes/privacy/provider.php b/public/admin/tool/moodlenet/classes/privacy/provider.php deleted file mode 100644 index 2822d3e74c0..00000000000 --- a/public/admin/tool/moodlenet/classes/privacy/provider.php +++ /dev/null @@ -1,44 +0,0 @@ -. -/** - * Privacy class for tool_moodlenet. - * - * @package tool_moodlenet - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -namespace tool_moodlenet\privacy; - -defined('MOODLE_INTERNAL') || die(); - -/** - * Privacy class for tool_moodlenet. - * - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class provider implements \core_privacy\local\metadata\null_provider { - - /** - * Get the language string identifier with the component's language - * file to explain why this plugin stores no data. - * - * @return string - */ - public static function get_reason(): string { - return 'privacy:metadata'; - } -} diff --git a/public/admin/tool/moodlenet/classes/profile_manager.php b/public/admin/tool/moodlenet/classes/profile_manager.php deleted file mode 100644 index 94ab64de549..00000000000 --- a/public/admin/tool/moodlenet/classes/profile_manager.php +++ /dev/null @@ -1,349 +0,0 @@ -. - -/** - * Profile manager class - * - * @package tool_moodlenet - * @copyright 2020 Adrian Greeve - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace tool_moodlenet; - -/** - * Class for handling interaction with the moodlenet profile. - * - * @package tool_moodlenet - * @copyright 2020 Adrian Greeve - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class profile_manager { - - /** - * Get the mnet profile for a user. - * - * @param int $userid The ID for the user to get the profile form - * @return moodlenet_user_profile or null. - */ - public static function get_moodlenet_user_profile(int $userid): ?moodlenet_user_profile { - global $CFG; - // Check for official profile. - if (self::official_profile_exists()) { - $user = \core_user::get_user($userid, 'moodlenetprofile'); - try { - $userprofile = $user->moodlenetprofile ? $user->moodlenetprofile : ''; - return (isset($user)) ? new moodlenet_user_profile(s($userprofile), $userid) : null; - } catch (\moodle_exception $e) { - // If an exception is thrown, means there isn't a valid profile set. No need to log exception. - return null; - } - } - // Otherwise get hacked in user profile field. - require_once($CFG->dirroot . '/user/profile/lib.php'); - $profilefields = profile_get_user_fields_with_data($userid); - foreach ($profilefields as $key => $field) { - if ($field->get_category_name() == self::get_category_name() - && $field->inputname == 'profile_field_mnetprofile') { - try { - return new moodlenet_user_profile(s($field->display_data()), $userid); - } catch (\moodle_exception $e) { - // If an exception is thrown, means there isn't a valid profile set. No need to log exception. - return null; - } - } - } - return null; - } - - /** - * Save the moodlenet profile. - * - * @param moodlenet_user_profile $moodlenetprofile The moodlenet profile to save. - */ - public static function save_moodlenet_user_profile(moodlenet_user_profile $moodlenetprofile): void { - global $CFG, $DB; - // Do some cursory checks first to see if saving is possible. - if (self::official_profile_exists()) { - // All good. Let's save. - $user = \core_user::get_user($moodlenetprofile->get_userid()); - $user->moodlenetprofile = $moodlenetprofile->get_profile_name(); - - require_once($CFG->dirroot . '/user/lib.php'); - - \user_update_user($user, false, true); - return; - } - $fielddata = self::get_user_profile_field(); - $fielddata = self::validate_and_fix_missing_profile_items($fielddata); - // Everything should be back to normal. Let's save. - require_once($CFG->dirroot . '/user/profile/lib.php'); - \profile_save_custom_fields($moodlenetprofile->get_userid(), - [$fielddata->shortname => $moodlenetprofile->get_profile_name()]); - } - - /** - * Checks to see if the required user profile fields and categories are in place. If not it regenerates them. - * - * @param stdClass $fielddata The moodlenet profile field. - * @return stdClass The same moodlenet profile field, with any necessary updates made. - */ - private static function validate_and_fix_missing_profile_items(\stdClass $fielddata): \stdClass { - global $DB; - - if (empty((array) $fielddata)) { - // We need to regenerate the category and field to store this data. - if (!self::check_profile_category()) { - $categoryid = self::create_user_profile_category(); - self::create_user_profile_text_field($categoryid); - } else { - // We need the category id. - $category = $DB->get_record('user_info_category', ['name' => self::get_category_name()]); - self::create_user_profile_text_field($category->id); - } - $fielddata = self::get_user_profile_field(); - } else { - if (!self::check_profile_category($fielddata->categoryid)) { - $categoryid = self::create_user_profile_category(); - // Update the field to put it back into this category. - $fielddata->categoryid = $categoryid; - $DB->update_record('user_info_field', $fielddata); - } - } - return $fielddata; - } - - /** - * Returns the user profile field table object. - * - * @return stdClass the moodlenet profile table object. False if no record found. - */ - private static function get_user_profile_field(): \stdClass { - global $DB; - $fieldname = self::get_profile_field_name(); - $record = $DB->get_record('user_info_field', ['shortname' => $fieldname]); - return ($record) ? $record : (object) []; - } - - /** - * This reports back if the category has been deleted or the config value is different. - * - * @param int $categoryid The category id to check against. - * @return bool True is the category checks out, otherwise false. - */ - private static function check_profile_category(?int $categoryid = null): bool { - global $DB; - $categoryname = self::get_category_name(); - $categorydata = $DB->get_record('user_info_category', ['name' => $categoryname]); - if (empty($categorydata)) { - return false; - } - if (isset($categoryid) && $categorydata->id != $categoryid) { - return false; - } - return true; - } - - /** - * Are we using the proper user profile field to hold the mnet profile? - * - * @return bool True if we are using a user table field for the mnet profile. False means we are using costom profile fields. - */ - public static function official_profile_exists(): bool { - global $DB; - - $usertablecolumns = $DB->get_columns('user', false); - if (isset($usertablecolumns['moodlenetprofile'])) { - return true; - } - return false; - } - - /** - * Gets the category name that is set for this site. - * - * @return string The category used to hold the moodle net profile field. - */ - public static function get_category_name(): string { - return get_config('tool_moodlenet', 'profile_category'); - } - - /** - * Sets the a unique category to hold the moodle net user profile. - * - * @param string $categoryname The base category name to use. - * @return string The actual name of the category to use. - */ - private static function set_category_name(string $categoryname): string { - global $DB; - - $attemptname = $categoryname; - - // Check if this category already exists. - $foundcategoryname = false; - $i = 0; - do { - $category = $DB->count_records('user_info_category', ['name' => $attemptname]); - if ($category > 0) { - $i++; - $attemptname = $categoryname . $i; - } else { - set_config('profile_category', $attemptname, 'tool_moodlenet'); - $foundcategoryname = true; - } - } while (!$foundcategoryname); - return $attemptname; - } - - /** - * Create a custom user profile category to hold our custom field. - * - * @return int The id of the created category. - */ - public static function create_user_profile_category(): int { - global $DB; - // No nice API to do this, so direct DB calls it is. - $data = new \stdClass(); - $data->sortorder = $DB->count_records('user_info_category') + 1; - $data->name = self::set_category_name(get_string('pluginname', 'tool_moodlenet')); - $data->id = $DB->insert_record('user_info_category', $data, true); - - $createdcategory = $DB->get_record('user_info_category', array('id' => $data->id)); - \core\event\user_info_category_created::create_from_category($createdcategory)->trigger(); - return $createdcategory->id; - } - - /** - * Sets a unique name to be used for the moodle net profile. - * - * @param string $fieldname The base fieldname to use. - * @return string The actual profile field name. - */ - private static function set_profile_field_name(string $fieldname): string { - global $DB; - - $attemptname = $fieldname; - - // Check if this profilefield already exists. - $foundfieldname = false; - $i = 0; - do { - $profilefield = $DB->count_records('user_info_field', ['shortname' => $attemptname]); - if ($profilefield > 0) { - $i++; - $attemptname = $fieldname . $i; - } else { - set_config('profile_field_name', $attemptname, 'tool_moodlenet'); - $foundfieldname = true; - } - } while (!$foundfieldname); - return $attemptname; - } - - /** - * Gets the unique profile field used to hold the moodle net profile. - * - * @return string The profile field name being used on this site. - */ - public static function get_profile_field_name(): string { - return get_config('tool_moodlenet', 'profile_field_name'); - } - - - /** - * Create a user profile field to hold the moodlenet profile information. - * - * @param int $categoryid The category to put this field into. - */ - public static function create_user_profile_text_field(int $categoryid): void { - global $CFG; - - require_once($CFG->dirroot . '/user/profile/definelib.php'); - require_once($CFG->dirroot . '/user/profile/field/text/define.class.php'); - - // Add our moodlenet profile field. - $profileclass = new \profile_define_text(); - $data = (object) [ - 'shortname' => self::set_profile_field_name('mnetprofile'), - 'name' => get_string('mnetprofile', 'tool_moodlenet'), - 'datatype' => 'text', - 'description' => get_string('mnetprofiledesc', 'tool_moodlenet'), - 'descriptionformat' => 1, - 'categoryid' => $categoryid, - 'signup' => 1, - 'forceunique' => 1, - 'visible' => 2, - 'param1' => 30, - 'param2' => 2048 - ]; - $profileclass->define_save($data); - } - - /** - * Given our $moodlenetprofile let's cURL the domains' WebFinger endpoint - * - * @param moodlenet_user_profile $moodlenetprofile The moodlenet profile to get info from. - * @return array [bool, text, raw] - */ - public static function get_moodlenet_profile_link(moodlenet_user_profile $moodlenetprofile): array { - $domain = $moodlenetprofile->get_domain(); - $username = $moodlenetprofile->get_username(); - - // Assumption: All MoodleNet instance's will contain a WebFinger validation script. - $url = "https://".$domain."/.well-known/webfinger?resource=acct:".$username."@".$domain; - - $curl = new \curl(); - $options = [ - 'CURLOPT_HEADER' => 0, - ]; - $content = $curl->get($url, null, $options); - $info = $curl->get_info(); - - // The base cURL seems fine, let's press on. - if (!$curl->get_errno() && !$curl->error) { - // WebFinger gave us a 404 back so the user has no droids here. - if ($info['http_code'] >= 400) { - if ($info['http_code'] === 404) { - // User not found. - return [ - 'result' => false, - 'message' => get_string('profilevalidationfail', 'tool_moodlenet'), - ]; - } else { - // There was some other error that was not a missing account. - return [ - 'result' => false, - 'message' => get_string('profilevalidationerror', 'tool_moodlenet'), - ]; - } - } - - // We must have a valid link so give it back to the user. - $data = json_decode($content); - return [ - 'result' => true, - 'message' => get_string('profilevalidationpass', 'tool_moodlenet'), - 'domain' => $data->aliases[0] - ]; - } else { - // There was some failure in curl so report it back. - return [ - 'result' => false, - 'message' => get_string('profilevalidationerror', 'tool_moodlenet'), - ]; - } - } -} diff --git a/public/admin/tool/moodlenet/classes/task/post_install.php b/public/admin/tool/moodlenet/classes/task/post_install.php deleted file mode 100644 index 55f2ca13881..00000000000 --- a/public/admin/tool/moodlenet/classes/task/post_install.php +++ /dev/null @@ -1,35 +0,0 @@ -. - -declare(strict_types=1); - -namespace tool_moodlenet\task; - -/** - * Ad-hoc task to perform post install tasks. - * We use this to set the active activity chooser footer plugin to tool_moodlenet. - * We couldn't do this directly in install.php, because there is an admin_apply_default_settings() call after all plugins are - * installed and that would reset whatever value we had set earlier to 'hidden'. - * - * @package tool_moodlenet - * @copyright 2022 Shamim Rezaie - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class post_install extends \core\task\adhoc_task { - public function execute() { - set_config('activitychooseractivefooter', 'tool_moodlenet'); - } -} diff --git a/public/admin/tool/moodlenet/classes/task/send_enable_notification.php b/public/admin/tool/moodlenet/classes/task/send_enable_notification.php deleted file mode 100644 index 97255473b9f..00000000000 --- a/public/admin/tool/moodlenet/classes/task/send_enable_notification.php +++ /dev/null @@ -1,47 +0,0 @@ -. - -declare(strict_types=1); - -namespace tool_moodlenet\task; - -/** - * Ad-hoc task to send the notification to admin stating MoodleNet is automatically enabled after upgrade. - * - * @package tool_moodlenet - * @copyright 2022 Shamim Rezaie - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class send_enable_notification extends \core\task\adhoc_task { - public function execute(): void { - $message = new \core\message\message(); - $message->component = 'moodle'; - $message->name = 'notices'; - $message->userfrom = \core_user::get_noreply_user(); - $message->userto = get_admin(); - $message->notification = 1; - $message->contexturl = (new \moodle_url('/admin/settings.php', - ['section' => 'optionalsubsystems'], 'admin-enablemoodlenet'))->out(false); - $message->contexturlname = get_string('advancedfeatures', 'admin'); - $message->subject = get_string('autoenablenotification_subject', 'tool_moodlenet'); - $message->fullmessageformat = FORMAT_HTML; - $message->fullmessagehtml = get_string('autoenablenotification', 'tool_moodlenet', (object) [ - 'settingslink' => (new \moodle_url('/admin/settings.php', ['section' => 'tool_moodlenet']))->out(false), - ]); - $message->smallmessage = strip_tags($message->fullmessagehtml); - message_send($message); - } -} diff --git a/public/admin/tool/moodlenet/classes/task/send_mnet_profiles_data_removed_notification.php b/public/admin/tool/moodlenet/classes/task/send_mnet_profiles_data_removed_notification.php deleted file mode 100644 index 59554542305..00000000000 --- a/public/admin/tool/moodlenet/classes/task/send_mnet_profiles_data_removed_notification.php +++ /dev/null @@ -1,45 +0,0 @@ -. - -declare(strict_types=1); - -namespace tool_moodlenet\task; - -use core\message\message; - -/** - * Ad-hoc task to send a notification to admin stating that the user data related to the linked MoodleNet profiles has - * been removed. - * - * @package tool_moodlenet - * @copyright 2022 Mihail Geshoski - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class send_mnet_profiles_data_removed_notification extends \core\task\adhoc_task { - public function execute(): void { - $message = new message(); - $message->component = 'moodle'; - $message->name = 'notices'; - $message->userfrom = \core_user::get_noreply_user(); - $message->userto = get_admin(); - $message->notification = 1; - $message->subject = get_string('removedmnetprofilenotification_subject', 'tool_moodlenet'); - $message->fullmessageformat = FORMAT_HTML; - $message->fullmessagehtml = get_string('removedmnetprofilenotification', 'tool_moodlenet'); - $message->smallmessage = strip_tags($message->fullmessagehtml); - message_send($message); - } -} diff --git a/public/admin/tool/moodlenet/db/install.php b/public/admin/tool/moodlenet/db/install.php deleted file mode 100644 index d9c1a0f8669..00000000000 --- a/public/admin/tool/moodlenet/db/install.php +++ /dev/null @@ -1,39 +0,0 @@ -. - -/** - * Install script for tool_moodlenet. - * - * @package tool_moodlenet - * @copyright 2022 Shamim Rezaie - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -declare(strict_types=1); - -/** - * Perform the post-install procedures. - */ -function xmldb_tool_moodlenet_install() { - // Use an ad-hoc task to set the active activity chooser footer plugin to tool_moodlenet. - // We couldn't do this in admin/settings/courses.php for 2 reasons: - // - First, because it would be a breach of component communications principles to do so there. - // - Second, because we can't call get_plugins_with_function() during install and upgrade (or it will return []). - // We couldn't do this directly here either, because there is an admin_apply_default_settings() call after all plugins are - // installed and that would reset whatever value we set here to 'hidden'. - $postinstall = new tool_moodlenet\task\post_install(); - core\task\manager::queue_adhoc_task($postinstall); -} diff --git a/public/admin/tool/moodlenet/db/services.php b/public/admin/tool/moodlenet/db/services.php deleted file mode 100644 index a5b452a0af0..00000000000 --- a/public/admin/tool/moodlenet/db/services.php +++ /dev/null @@ -1,44 +0,0 @@ -. - -/** - * Tool Moodle.Net webservice definitions. - * - * @package tool_moodlenet - * @copyright 2020 Mathew May {@link https://mathew.solutions} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$functions = [ - 'tool_moodlenet_verify_webfinger' => [ - 'classname' => 'tool_moodlenet\external', - 'methodname' => 'verify_webfinger', - 'description' => 'Verify if the passed information resolves into a WebFinger profile URL', - 'type' => 'read', - 'ajax' => true, - 'services' => [MOODLE_OFFICIAL_MOBILE_SERVICE] - ], - 'tool_moodlenet_search_courses' => [ - 'classname' => 'tool_moodlenet\external', - 'methodname' => 'search_courses', - 'description' => 'For some given input search for a course that matches', - 'type' => 'read', - 'ajax' => true, - 'services' => [MOODLE_OFFICIAL_MOBILE_SERVICE] - ], -]; diff --git a/public/admin/tool/moodlenet/db/upgrade.php b/public/admin/tool/moodlenet/db/upgrade.php deleted file mode 100644 index 7fab58ed894..00000000000 --- a/public/admin/tool/moodlenet/db/upgrade.php +++ /dev/null @@ -1,45 +0,0 @@ -. - -/** - * Upgrade script for tool_moodlenet. - * - * @package tool_moodlenet - * @copyright 2020 Adrian Greeve - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -/** - * Upgrade the plugin. - * - * @param int $oldversion - * @return bool always true - */ -function xmldb_tool_moodlenet_upgrade(int $oldversion) { - // Automatically generated Moodle v4.4.0 release upgrade line. - // Put any upgrade step following this. - - // Automatically generated Moodle v4.5.0 release upgrade line. - // Put any upgrade step following this. - - // Automatically generated Moodle v5.0.0 release upgrade line. - // Put any upgrade step following this. - - // Automatically generated Moodle v5.1.0 release upgrade line. - // Put any upgrade step following this. - - return true; -} diff --git a/public/admin/tool/moodlenet/import.php b/public/admin/tool/moodlenet/import.php deleted file mode 100644 index c4a9df2af1f..00000000000 --- a/public/admin/tool/moodlenet/import.php +++ /dev/null @@ -1,85 +0,0 @@ -. - -/** - * This is the main endpoint which MoodleNet instances POST to. - * - * MoodleNet instances send the user agent to this endpoint via a form POST. - * Then: - * 1. The POSTed resource information is put in a session store for cross-request access. - * 2. This page makes a GET request for admin/tool/moodlenet/index.php (the import confirmation page). - * 3. Then, depending on whether the user is authenticated, the user will either: - * - If not authenticated, they will be asked to login, after which they will see the confirmation page (leveraging $wantsurl). - * - If authenticated, they will see the confirmation page immediately. - * - * @package tool_moodlenet - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -use tool_moodlenet\local\import_info; -use tool_moodlenet\local\remote_resource; -use tool_moodlenet\local\url; - -require_once(__DIR__ . '/../../../config.php'); - -// The integration must be enabled for this import endpoint to be active. -if (!get_config('tool_moodlenet', 'enablemoodlenet')) { - throw new \moodle_exception('moodlenetnotenabled', 'tool_moodlenet'); -} - -$resourceurl = required_param('resourceurl', PARAM_URL); -$resourceinfo = required_param('resource_info', PARAM_RAW); -$resourceinfo = json_decode($resourceinfo); -$type = optional_param('type', 'link', PARAM_TEXT); -$course = optional_param('course', 0, PARAM_INT); -$section = optional_param('section', 0, PARAM_INT); -// If course isn't provided, course and section are null. -if (empty($course)) { - $course = null; - $section = null; -} -$name = validate_param($resourceinfo->name, PARAM_TEXT); -$description = validate_param($resourceinfo->summary, PARAM_TEXT); - -// Only accept POSTs. -if (!empty($_POST)) { - // Store information about the import of the resource for the current user. - $importconfig = (object) [ - 'course' => $course, - 'section' => $section, - 'type' => $type, - ]; - $metadata = (object) [ - 'name' => $name, - 'description' => $description ?? '' - ]; - - require_once($CFG->libdir . '/filelib.php'); - $importinfo = new import_info( - $USER->id, - new remote_resource(new \curl(), new url($resourceurl), $metadata), - $importconfig - ); - $importinfo->save(); - - // Redirect to the import confirmation page, detouring via the log in page if required. - redirect(new moodle_url('/admin/tool/moodlenet/index.php', ['id' => $importinfo->get_id()])); - -} - -// Invalid or missing POST data. Show an error to the user. -throw new \moodle_exception('missinginvalidpostdata', 'tool_moodlenet'); diff --git a/public/admin/tool/moodlenet/index.php b/public/admin/tool/moodlenet/index.php deleted file mode 100644 index f32bec9ab02..00000000000 --- a/public/admin/tool/moodlenet/index.php +++ /dev/null @@ -1,136 +0,0 @@ -. - -/** - * Landing page for all imports from MoodleNet. - * - * This page asks the user to confirm the import process, and takes them to the relevant next step. - * - * @package tool_moodlenet - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -use tool_moodlenet\local\import_info; -use tool_moodlenet\local\import_backup_helper; - -require_once(__DIR__ . '/../../../config.php'); -require_once($CFG->dirroot .'/course/lib.php'); - -$cancel = optional_param('cancel', null, PARAM_TEXT); -$continue = optional_param('continue', null, PARAM_TEXT); -$id = required_param('id', PARAM_ALPHANUM); - -if (is_null($importinfo = import_info::load($id))) { - throw new moodle_exception('missinginvalidpostdata', 'tool_moodlenet'); -} - -// Access control. -require_login($importinfo->get_config()->course, false); // Course may be null here - that's ok. -if ($importinfo->get_config()->course) { - require_capability('moodle/course:manageactivities', context_course::instance($importinfo->get_config()->course)); -} -if (!get_config('tool_moodlenet', 'enablemoodlenet')) { - throw new \moodle_exception('moodlenetnotenabled', 'tool_moodlenet'); -} - -// Handle the form submits. -// This page POSTs to self to verify the sesskey for the confirm action. -// The next page will either be: -// - 1. The restore process for a course or module, if the file is an mbz file. -// - 2. The 'select a course' tool page, if course and section are not provided. -// - 3. The 'select what to do with the content' tool page, provided course and section are present. -// - 4. The dashboard, if the user decides to cancel and course or section is not found. -// - 5. The course home, if the user decides to cancel but the course and section are found. -if ($cancel) { - if (!empty($importinfo->get_config()->course)) { - $url = new \moodle_url('/course/view.php', ['id' => $importinfo->get_config()->course]); - } else { - $url = new \moodle_url('/'); - } - redirect($url); -} else if ($continue) { - require_sesskey(); - - // Handle backups. - if (strtolower($importinfo->get_resource()->get_extension()) == 'mbz') { - if (empty($importinfo->get_config()->course)) { - // Find a course that the user has permission to upload a backup file. - // This is likely to be very slow on larger sites. - $context = import_backup_helper::get_context_for_user($USER->id); - - if (is_null($context)) { - throw new \moodle_exception('nopermissions', 'error', '', get_string('restore:uploadfile', 'core_role')); - } - } else { - $context = context_course::instance($importinfo->get_config()->course); - } - - $importbackuphelper = new import_backup_helper($importinfo->get_resource(), $USER, $context); - $storedfile = $importbackuphelper->get_stored_file(); - - $url = new \moodle_url('/backup/restorefile.php', [ - 'component' => $storedfile->get_component(), - 'filearea' => $storedfile->get_filearea(), - 'itemid' => $storedfile->get_itemid(), - 'filepath' => $storedfile->get_filepath(), - 'filename' => $storedfile->get_filename(), - 'filecontextid' => $storedfile->get_contextid(), - 'contextid' => $context->id, - 'action' => 'choosebackupfile' - ]); - redirect($url); - } - - // Handle adding files to a course. - // Course and section data present and confirmed. Redirect to the option select view. - if (!is_null($importinfo->get_config()->course) && !is_null($importinfo->get_config()->section)) { - redirect(new \moodle_url('/admin/tool/moodlenet/options.php', ['id' => $id])); - } - - if (is_null($importinfo->get_config()->course)) { - redirect(new \moodle_url('/admin/tool/moodlenet/select.php', ['id' => $id])); - } -} - -// Display the page. -$PAGE->set_context(context_system::instance()); -$PAGE->set_pagelayout('base'); -$PAGE->set_title(get_string('addingaresource', 'tool_moodlenet')); -$PAGE->set_heading(get_string('addingaresource', 'tool_moodlenet')); -$url = new moodle_url('/admin/tool/moodlenet/index.php'); -$PAGE->set_url($url); -$renderer = $PAGE->get_renderer('core'); - -// Relevant confirmation form. -$context = $context = [ - 'resourceurl' => $importinfo->get_resource()->get_url()->get_value(), - 'resourcename' => $importinfo->get_resource()->get_name(), - 'resourcetype' => $importinfo->get_config()->type, - 'sesskey' => sesskey() -]; -if (!is_null($importinfo->get_config()->course) && !is_null($importinfo->get_config()->section)) { - $course = get_course($importinfo->get_config()->course); - $context = array_merge($context, [ - 'course' => $course->id, - 'coursename' => $course->shortname, - 'section' => $importinfo->get_config()->section - ]); -} - -echo $OUTPUT->header(); -echo $renderer->render_from_template('tool_moodlenet/import_confirmation', $context); -echo $OUTPUT->footer(); diff --git a/public/admin/tool/moodlenet/lang/en/tool_moodlenet.php b/public/admin/tool/moodlenet/lang/en/tool_moodlenet.php deleted file mode 100644 index dcb01c5184a..00000000000 --- a/public/admin/tool/moodlenet/lang/en/tool_moodlenet.php +++ /dev/null @@ -1,74 +0,0 @@ -. - -/** - * Strings for the tool_moodlenet component. - * - * @package tool_moodlenet - * @category string - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$string['addingaresource'] = 'Adding content from MoodleNet'; -$string['aria:enterprofile'] = "Enter your MoodleNet profile ID"; -$string['aria:footermessage'] = "Browse for content on MoodleNet"; -$string['autoenablenotification'] = '

In Moodle 4.0 onwards, the MoodleNet integration is enabled by default in Advanced features. Users with the capability to create and manage activities can browse MoodleNet via the activity chooser and import MoodleNet resources into their courses.

If desired, an alternative MoodleNet instance may be specified in the MoodleNet inbound settings.

'; -$string['autoenablenotification_subject'] = 'Default MoodleNet setting changed.'; -$string['browsecontentmoodlenet'] = "Or browse for content on MoodleNet"; -$string['clearsearch'] = "Clear search"; -$string['connectandbrowse'] = "Connect to and browse:"; -$string['defaultmoodlenet'] = 'MoodleNet URL'; -$string['defaultmoodlenet_desc'] = 'The URL of the MoodleNet instance available via the activity chooser.'; -$string['defaultmoodlenetname'] = "MoodleNet instance name"; -$string['defaultmoodlenetname_desc'] = 'The name of the MoodleNet instance available via the activity chooser.'; -$string['defaultmoodlenetnamevalue'] = 'MoodleNet Central'; -$string['enablemoodlenet'] = 'Enable MoodleNet integration (inbound)'; -$string['enablemoodlenet_desc'] = 'If enabled, a user with the capability to create and manage activities can browse MoodleNet via the activity chooser and import MoodleNet resources into their course. In addition, a user with the capability to restore backups can select a backup file on MoodleNet and restore it into Moodle.'; -$string['errorduringdownload'] = 'An error occurred while downloading the file: {$a}'; -$string['footermessage'] = "Or browse for content on"; -$string['forminfo'] = 'Your MoodleNet profile ID will be automatically saved in your profile on this site.'; -$string['importconfirm'] = 'You are about to import the content "{$a->resourcename} ({$a->resourcetype})" into the course "{$a->coursename}". Are you sure you want to continue?'; -$string['importconfirmnocourse'] = 'You are about to import the content "{$a->resourcename} ({$a->resourcetype})" into your site. Are you sure you want to continue?'; -$string['importformatselectguidingtext'] = 'In which format would you like the content "{$a->name} ({$a->type})" to be added to your course?'; -$string['importformatselectheader'] = 'Choose the content display format'; -$string['inputhelp'] = 'Or if you have a MoodleNet account already, copy the ID from your MoodleNet profile and paste it here:'; -$string['instancedescription'] = "MoodleNet is an open social media platform for educators, with a focus on the collaborative curation of collections of open resources. "; -$string['instanceplaceholder'] = 'a1b2c3d4e5f6-example@moodle.net'; -$string['invalidmoodlenetprofile'] = '$userprofile is not correctly formatted'; -$string['missinginvalidpostdata'] = 'The resource information from MoodleNet is either missing, or is in an incorrect format. -If this happens repeatedly, please contact the site administrator.'; -$string['mnetprofile'] = 'MoodleNet profile'; -$string['mnetprofiledesc'] = '

Enter your MoodleNet profile details here to be redirected to your profile while visiting MoodleNet.

'; -$string['moodlenetnotenabled'] = 'The MoodleNet integration must be enabled in Site administration / MoodleNet before resource imports can be processed.'; -$string['moodlenetsettings'] = 'MoodleNet inbound settings'; -$string['notification'] = 'You are about to import the content "{$a->name} ({$a->type})" into your site. Select the course in which it should be added, or cancel.'; -$string['pluginname'] = 'MoodleNet'; -$string['privacy:metadata'] = "The MoodleNet tool only facilitates communication with MoodleNet. It stores no data."; -$string['profilevalidationerror'] = 'There was a problem trying to validate your MoodleNet profile ID'; -$string['profilevalidationfail'] = 'Please enter a valid MoodleNet profile ID'; -$string['profilevalidationpass'] = 'Looks good!'; -$string['removalwarning_feature'] = 'If you need to continue using MoodleNet, contact your site administrator about setting up a self-hosted MoodleNet instance.'; -$string['removalwarning_service'] = 'After the date, you will no longer be able to browse or add content from MoodleNet Central.'; -$string['removalwarning_title'] = 'The MoodleNet service will be shut down on 20 April 2026.'; -$string['removedmnetprofilenotification'] = 'Due to recent changes on the MoodleNet platform, any users who previously saved their MoodleNet profile ID on the site will need to enter a MoodleNet profile ID in the new format in order to authenticate on the MoodleNet platform.'; -$string['removedmnetprofilenotification_subject'] = 'MoodleNet profile ID format change'; -$string['saveandgo'] = "Save and go"; -$string['searchcourses'] = "Search courses"; -$string['selectpagetitle'] = 'Select page'; -$string['uploadlimitexceeded'] = 'The file size {$a->filesize} exceeds the user upload limit of {$a->uploadlimit} bytes.'; diff --git a/public/admin/tool/moodlenet/lib.php b/public/admin/tool/moodlenet/lib.php deleted file mode 100644 index c2ee2461d2f..00000000000 --- a/public/admin/tool/moodlenet/lib.php +++ /dev/null @@ -1,104 +0,0 @@ -. - -/** - * This page lists public api for tool_moodlenet plugin. - * - * @package tool_moodlenet - * @copyright 2020 Peter Dias - * @license http://www.gnu.org/copyleft/gpl.html GNU - */ - -defined('MOODLE_INTERNAL') || die; - -use \core_course\local\entity\activity_chooser_footer; - -/** - * The default endpoint to MoodleNet. - */ -define('MOODLENET_DEFAULT_ENDPOINT', "lms/moodle/search"); - -/** - * Generate the endpoint url to the user's moodlenet site. - * - * @param string $profileurl The user's moodlenet profile page - * @param int $course The moodle course the mnet resource will be added to - * @param int $section The section of the course will be added to. Defaults to the 0th element. - * @return string the resulting endpoint - * @throws moodle_exception - */ -function generate_mnet_endpoint(string $profileurl, int $course, int $section = 0) { - global $CFG; - $urlportions = explode('@', $profileurl); - $domain = end($urlportions); - $parsedurl = parse_url($domain); - $params = [ - 'site' => $CFG->wwwroot, - 'course' => $course, - 'section' => $section - ]; - $endpoint = new moodle_url(MOODLENET_DEFAULT_ENDPOINT, $params); - return (isset($parsedurl['scheme']) ? $domain : "https://$domain")."/{$endpoint->out(false)}"; -} - -/** - * Hooking function to build up the initial Activity Chooser footer information for MoodleNet - * - * @param int $courseid The course the user is currently in and wants to add resources to - * @param int $sectionid The section the user is currently in and wants to add resources to - * @return activity_chooser_footer - * @throws dml_exception - * @throws moodle_exception - */ -function tool_moodlenet_custom_chooser_footer(int $courseid, int $sectionid): activity_chooser_footer { - global $CFG, $USER, $OUTPUT; - $defaultlink = get_config('tool_moodlenet', 'defaultmoodlenet'); - $enabled = get_config('tool_moodlenet', 'enablemoodlenet'); - - $advanced = false; - // We are in the MoodleNet lib. It is safe assume we have our own functions here. - $mnetprofile = \tool_moodlenet\profile_manager::get_moodlenet_user_profile($USER->id); - if ($mnetprofile !== null) { - $advanced = $mnetprofile->get_domain() ?? false; - } - - $defaultlink = generate_mnet_endpoint($defaultlink, $courseid, $sectionid); - if ($advanced !== false) { - $advanced = generate_mnet_endpoint($advanced, $courseid, $sectionid); - } - - $renderedfooter = $OUTPUT->render_from_template('tool_moodlenet/chooser_footer', (object)[ - 'enabled' => (bool)$enabled, - 'generic' => $defaultlink, - 'advanced' => $advanced, - 'courseID' => $courseid, - 'sectionnum' => $sectionid, - 'img' => $OUTPUT->image_url('MoodleNet', 'tool_moodlenet')->out(false), - ]); - - $renderedcarousel = $OUTPUT->render_from_template('tool_moodlenet/chooser_moodlenet', (object)[ - 'buttonName' => get_config('tool_moodlenet', 'defaultmoodlenetname'), - 'generic' => $defaultlink, - 'courseID' => $courseid, - 'sectionnum' => $sectionid, - 'img' => $OUTPUT->image_url('MoodleNet', 'tool_moodlenet')->out(false), - ]); - return new activity_chooser_footer( - 'tool_moodlenet/instance_form', - $renderedfooter, - $renderedcarousel - ); -} diff --git a/public/admin/tool/moodlenet/options.php b/public/admin/tool/moodlenet/options.php deleted file mode 100644 index 7454f7ed72b..00000000000 --- a/public/admin/tool/moodlenet/options.php +++ /dev/null @@ -1,128 +0,0 @@ -. - -/** - * Page to select WHAT to do with a given resource stored on MoodleNet. - * - * This collates and presents the same options as a user would see for a drag and drop upload. - * That is, it leverages the dndupload_register() hooks and delegates the resource handling to the dndupload_handle hooks. - * - * This page requires a course, section an resourceurl to be provided via import_info. - * - * @package tool_moodlenet - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -use tool_moodlenet\local\import_handler_registry; -use tool_moodlenet\local\import_processor; -use tool_moodlenet\local\import_info; -use tool_moodlenet\local\import_strategy_file; -use tool_moodlenet\local\import_strategy_link; - -require_once(__DIR__ . '/../../../config.php'); -require_once($CFG->dirroot . '/course/lib.php'); - -$module = optional_param('module', null, PARAM_PLUGIN); -$import = optional_param('import', null, PARAM_ALPHA); -$cancel = optional_param('cancel', null, PARAM_ALPHA); -$id = required_param('id', PARAM_ALPHANUM); - -if (is_null($importinfo = import_info::load($id))) { - throw new moodle_exception('missinginvalidpostdata', 'tool_moodlenet'); -} - -// Resolve course and section params. -// If course is not already set in the importinfo, we require it in the URL params. -$config = $importinfo->get_config(); -if (!isset($config->course)) { - $course = required_param('course', PARAM_INT); - $config->course = $course; - $config->section = 0; - $importinfo->set_config($config); - $importinfo->save(); -} - -// Access control. -require_login($config->course, false); -require_capability('moodle/course:manageactivities', context_course::instance($config->course)); -if (!get_config('tool_moodlenet', 'enablemoodlenet')) { - throw new \moodle_exception('moodlenetnotenabled', 'tool_moodlenet'); -} - -// If the user cancelled, break early. -if ($cancel) { - redirect(new moodle_url('/course/view.php', ['id' => $config->course])); -} - -// Set up required objects. -$course = get_course($config->course); -$handlerregistry = new import_handler_registry($course, $USER); -switch ($config->type) { - case 'file': - $strategy = new import_strategy_file(); - break; - case 'link': - default: - $strategy = new import_strategy_link(); - break; -} - -if ($import && $module) { - require_sesskey(); - - $handlerinfo = $handlerregistry->get_resource_handler_for_mod_and_strategy($importinfo->get_resource(), $module, $strategy); - if (is_null($handlerinfo)) { - throw new coding_exception("Invalid handler '$module'. The import handler could not be found."); - } - $importproc = new import_processor($course, $config->section, $importinfo->get_resource(), $handlerinfo, $handlerregistry); - $importproc->process(); - - $importinfo->purge(); // We don't need information about the import any more. - - redirect(new moodle_url('/course/view.php', ['id' => $course->id])); -} - -// Setup the page and display the form. -$PAGE->set_context(context_course::instance($course->id)); -$PAGE->set_pagelayout('base'); -$PAGE->set_title(get_string('coursetitle', 'moodle', array('course' => $course->fullname))); -$PAGE->set_heading($course->fullname); -$PAGE->set_url(new moodle_url('/admin/tool/moodlenet/options.php')); - -// Fetch the handlers supporting this resource. We'll display each of these as an option in the form. -$handlercontext = []; -foreach ($handlerregistry->get_resource_handlers_for_strategy($importinfo->get_resource(), $strategy) as $handler) { - $handlercontext[] = [ - 'module' => $handler->get_module_name(), - 'message' => $handler->get_description(), - ]; -} - -// Template context. -$context = [ - 'resourcename' => $importinfo->get_resource()->get_name(), - 'resourcetype' => $importinfo->get_config()->type, - 'resourceurl' => urlencode($importinfo->get_resource()->get_url()->get_value()), - 'course' => $course->id, - 'section' => $config->section, - 'sesskey' => sesskey(), - 'handlers' => $handlercontext, - 'oneoption' => sizeof($handlercontext) === 1 -]; - -echo $OUTPUT->header(); -echo $PAGE->get_renderer('core')->render_from_template('tool_moodlenet/import_options_select', $context); -echo $OUTPUT->footer(); diff --git a/public/admin/tool/moodlenet/pix/MoodleNet.png b/public/admin/tool/moodlenet/pix/MoodleNet.png deleted file mode 100644 index 872756bda88..00000000000 Binary files a/public/admin/tool/moodlenet/pix/MoodleNet.png and /dev/null differ diff --git a/public/admin/tool/moodlenet/pix/MoodleNet.svg b/public/admin/tool/moodlenet/pix/MoodleNet.svg deleted file mode 100644 index 1fc4f12f585..00000000000 --- a/public/admin/tool/moodlenet/pix/MoodleNet.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/admin/tool/moodlenet/pix/courses.svg b/public/admin/tool/moodlenet/pix/courses.svg deleted file mode 100644 index 75e59fcf04b..00000000000 --- a/public/admin/tool/moodlenet/pix/courses.svg +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/admin/tool/moodlenet/select.php b/public/admin/tool/moodlenet/select.php deleted file mode 100644 index 1a01ec0e245..00000000000 --- a/public/admin/tool/moodlenet/select.php +++ /dev/null @@ -1,53 +0,0 @@ -. - -/** - * Select page. - * - * @package tool_moodlenet - * @copyright 2020 Mathew May {@link https://mathew.solutions} - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -use tool_moodlenet\local\import_info; -use tool_moodlenet\output\select_page; - -require_once(__DIR__ . '/../../../config.php'); - -$id = required_param('id', PARAM_ALPHANUM); - -// Access control. -require_login(); -if (!get_config('tool_moodlenet', 'enablemoodlenet')) { - throw new \moodle_exception('moodlenetnotenabled', 'tool_moodlenet'); -} - -if (is_null($importinfo = import_info::load($id))) { - throw new moodle_exception('missinginvalidpostdata', 'tool_moodlenet'); -} - -$PAGE->set_url('/admin/tool/moodlenet/select.php'); -$PAGE->set_context(context_system::instance()); -$PAGE->set_pagelayout('standard'); -$PAGE->set_title(get_string('selectpagetitle', 'tool_moodlenet')); -$PAGE->set_heading(format_string($SITE->fullname)); - -echo $OUTPUT->header(); - -$renderable = new select_page($importinfo); -$renderer = $PAGE->get_renderer('tool_moodlenet'); -echo $renderer->render($renderable); - -echo $OUTPUT->footer(); diff --git a/public/admin/tool/moodlenet/settings.php b/public/admin/tool/moodlenet/settings.php deleted file mode 100644 index 35d09c77ed9..00000000000 --- a/public/admin/tool/moodlenet/settings.php +++ /dev/null @@ -1,55 +0,0 @@ -. - -/** - * Puts the plugin actions into the admin settings tree. - * - * @package tool_moodlenet - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -if ($hassiteconfig) { - // Add an enable subsystem setting to the "Advanced features" settings page. - $optionalsubsystems = $ADMIN->locate('optionalsubsystems'); - $optionalsubsystems->add(new admin_setting_configcheckbox('tool_moodlenet/enablemoodlenet', - new lang_string('enablemoodlenet', 'tool_moodlenet'), - new lang_string('enablemoodlenet_desc', 'tool_moodlenet'), - 1, 1, 0) - ); - - // Create a MoodleNet category. - if (get_config('tool_moodlenet', 'enablemoodlenet')) { - if (!$ADMIN->locate('moodlenet')) { - $ADMIN->add('root', new admin_category('moodlenet', get_string('pluginname', 'tool_moodlenet'))); - } - // Our settings page. - $settings = new admin_settingpage('tool_moodlenet', get_string('moodlenetsettings', 'tool_moodlenet')); - $ADMIN->add('moodlenet', $settings); - - $temp = new admin_setting_configtext('tool_moodlenet/defaultmoodlenetname', - get_string('defaultmoodlenetname', 'tool_moodlenet'), new lang_string('defaultmoodlenetname_desc', 'tool_moodlenet'), - new lang_string('defaultmoodlenetnamevalue', 'tool_moodlenet')); - $settings->add($temp); - - $temp = new admin_setting_configtext('tool_moodlenet/defaultmoodlenet', get_string('defaultmoodlenet', 'tool_moodlenet'), - new lang_string('defaultmoodlenet_desc', 'tool_moodlenet'), 'https://moodle.net'); - $settings->add($temp); - - } -} diff --git a/public/admin/tool/moodlenet/templates/chooser_footer.mustache b/public/admin/tool/moodlenet/templates/chooser_footer.mustache deleted file mode 100644 index c4f71f13761..00000000000 --- a/public/admin/tool/moodlenet/templates/chooser_footer.mustache +++ /dev/null @@ -1,46 +0,0 @@ -{{! - 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 . -}} -{{! - @template tool_moodlenet/chooser_footer - - Chooser favourite template partial. - - Example context (json): - { - } -}} -{{#enabled}} - -{{/enabled}} diff --git a/public/admin/tool/moodlenet/templates/chooser_footer_close_mnet.mustache b/public/admin/tool/moodlenet/templates/chooser_footer_close_mnet.mustache deleted file mode 100644 index 69b5ba8e100..00000000000 --- a/public/admin/tool/moodlenet/templates/chooser_footer_close_mnet.mustache +++ /dev/null @@ -1,28 +0,0 @@ -{{! - 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 . -}} -{{! - @template tool_moodlenet/chooser_footer_close_mnet - - Chooser favourite template partial. - - Example context (json): - { - } -}} - diff --git a/public/admin/tool/moodlenet/templates/chooser_moodlenet.mustache b/public/admin/tool/moodlenet/templates/chooser_moodlenet.mustache deleted file mode 100644 index a2b37b5cfd5..00000000000 --- a/public/admin/tool/moodlenet/templates/chooser_moodlenet.mustache +++ /dev/null @@ -1,73 +0,0 @@ -{{! - 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 . -}} -{{! - @template tool_moodlenet/chooser_moodlenet - - Chooser favourite template partial. - - Example context (json): - { - } -}} -
-
-
-
- -

{{#str}} instancedescription, tool_moodlenet {{/str}}

- - {{! Removal warning - always visible when MoodleNet integration is enabled }} - - -

{{#str}} connectandbrowse, tool_moodlenet {{/str}}

- - {{{buttonName}}} - -
- -
-

{{#str}}inputhelp, tool_moodlenet{{/str}}

-
- - -
-

-

{{#str}} forminfo, tool_moodlenet {{/str}}

-
-
-
-
-
diff --git a/public/admin/tool/moodlenet/templates/import_confirmation.mustache b/public/admin/tool/moodlenet/templates/import_confirmation.mustache deleted file mode 100644 index f38cc0edf23..00000000000 --- a/public/admin/tool/moodlenet/templates/import_confirmation.mustache +++ /dev/null @@ -1,76 +0,0 @@ -{{! - 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 . -}} -{{! - @template tool_moodlenet/import_confirmation - - MoodleNet import confirmation template. - - The purpose of this template is to present the user with a confirm/cancel dialog-like page. - - Classes required for JS: - * none - - Data attributes required for JS: - * none - - Context variables required for this template: - * resourceurl The URL to the remote resource on MoodleNet. - * resourcename The name of the remote resource on MoodleNet. - * sesskey The CSRF token, as per sesskey() - - Example context (json): - { - "course": 33, - "coursename": "Introduction to quantum physics", - "section": 0, - "resourceurl": "http://example.com/test.png", - "resourcename": "test.png", - "sesskey": "abc123" - } -}} - diff --git a/public/admin/tool/moodlenet/templates/import_options_select.mustache b/public/admin/tool/moodlenet/templates/import_options_select.mustache deleted file mode 100644 index 3f7a865b500..00000000000 --- a/public/admin/tool/moodlenet/templates/import_options_select.mustache +++ /dev/null @@ -1,80 +0,0 @@ -{{! - 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 . -}} -{{! - @template tool_moodlenet/import_options_select - - MoodleNet import options template. - - The purpose of this template is to render an list of import options as radio-button-like controls. - - Classes required for JS: - * none - - Data attributes required for JS: - * none - - Context variables required for this template: - * course The course id. - * section The sectio id. - * resourceurl The URL to the remote resource on MoodleNet. - * resourcename The name of the remote resource on MoodleNet. - * sesskey The CSRF token, as per sesskey() - * handlers The array of handler options to present the user with - - Example context (json): - { - "course": 33, - "coursename": "Introduction to quantum physics", - "section": 0, - "resourceurl": "http://example.com/test.png", - "resourcename": "A test image", - "sesskey": "abc123", - "handlers": [ - { - "module": "label", - "message": "Add media to the course page" - } - ] - } -}} - diff --git a/public/admin/tool/moodlenet/templates/select_page.mustache b/public/admin/tool/moodlenet/templates/select_page.mustache deleted file mode 100644 index fa86834ece7..00000000000 --- a/public/admin/tool/moodlenet/templates/select_page.mustache +++ /dev/null @@ -1,58 +0,0 @@ -{{! - 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 . -}} -{{! - @template tool_moodlenet/select_page - - This template renders the course selection page for the MoodleNet tool. - - Example context (json): - { - "name": "A cat picture", - "cancellink": "https://moodlesite/my" - } -}} -
- -

{{#str}} selectacourse {{/str}}

- -
-
diff --git a/public/admin/tool/moodlenet/templates/view-cards.mustache b/public/admin/tool/moodlenet/templates/view-cards.mustache deleted file mode 100644 index 2c601ee66e1..00000000000 --- a/public/admin/tool/moodlenet/templates/view-cards.mustache +++ /dev/null @@ -1,54 +0,0 @@ -{{! - 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 . -}} -{{! - @template tool_moodlenet/view-cards - - This template renders the cards view for the MoodleNet tool. - - Example context (json): - { - "courses": [ - { - "name": "Assignment due 1", - "viewurl": "https://moodlesite/course/view.php?id=2", - "courseimage": "https://moodlesite/pluginfile/123/course/overviewfiles/123.jpg", - "fullname": "course 3", - "coursecategory": "Category 1", - "visible": true - } - ] - } -}} - -{{< core_course/coursecards }} - {{$coursename}} - - {{#shortentext}}50, {{{fullname}}} {{/shortentext}} - - {{/coursename}} - {{$coursecategory}} - - {{#str}}aria:coursecategory, core_course{{/str}} - - - {{{coursecategory}}} - - {{/coursecategory}} - {{$divider}} -
|
- {{/divider}} -{{/ core_course/coursecards }} diff --git a/public/admin/tool/moodlenet/tests/import_backup_helper_test.php b/public/admin/tool/moodlenet/tests/import_backup_helper_test.php deleted file mode 100644 index 639a494e881..00000000000 --- a/public/admin/tool/moodlenet/tests/import_backup_helper_test.php +++ /dev/null @@ -1,78 +0,0 @@ -. - -namespace tool_moodlenet; - -/** - * Unit tests for the import_backup_helper - * - * @package tool_moodlenet - * @category test - * @copyright 2020 Adrian Greeve - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -final class import_backup_helper_test extends \advanced_testcase { - - /** - * Test that the first available context with the capability to upload backup files is returned. - */ - public function test_get_context_for_user(): void { - global $DB; - - $this->resetAfterTest(); - - $user1 = $this->getDataGenerator()->create_user(); - $user2 = $this->getDataGenerator()->create_user(); - $user3 = $this->getDataGenerator()->create_user(); - $user4 = $this->getDataGenerator()->create_user(); - $user5 = $this->getDataGenerator()->create_user(); - - $course = $this->getDataGenerator()->create_course(); - $coursecontext = \context_course::instance($course->id); - - $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student'); - $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'editingteacher'); - $this->getDataGenerator()->enrol_user($user5->id, $course->id, 'student'); - - $category = $this->getDataGenerator()->create_category(); - $rolerecord = $DB->get_record('role', ['shortname' => 'manager']); - $categorycontext = \context_coursecat::instance($category->id); - $this->getDataGenerator()->role_assign($rolerecord->id, $user3->id, $categorycontext->id); - $this->getDataGenerator()->role_assign($rolerecord->id, $user5->id, $categorycontext->id); - - $roleid = $this->getDataGenerator()->create_role(); - $sitecontext = \context_system::instance(); - assign_capability('moodle/restore:uploadfile', CAP_ALLOW, $roleid, $sitecontext->id, true); - accesslib_clear_all_caches_for_unit_testing(); - $this->getDataGenerator()->role_assign($roleid, $user4->id, $sitecontext->id); - - $result = \tool_moodlenet\local\import_backup_helper::get_context_for_user($user1->id); - $this->assertNull($result); - $result = \tool_moodlenet\local\import_backup_helper::get_context_for_user($user2->id); - $this->assertEquals($result, $coursecontext); - $this->assertEquals(CONTEXT_COURSE, $result->contextlevel); - $result = \tool_moodlenet\local\import_backup_helper::get_context_for_user($user3->id); - $this->assertEquals($result, $categorycontext); - $this->assertEquals(CONTEXT_COURSECAT, $result->contextlevel); - $result = \tool_moodlenet\local\import_backup_helper::get_context_for_user($user4->id); - $this->assertEquals($result, $sitecontext); - $this->assertEquals(CONTEXT_SYSTEM, $result->contextlevel); - $result = \tool_moodlenet\local\import_backup_helper::get_context_for_user($user5->id); - $this->assertEquals($result, $categorycontext); - $this->assertEquals(CONTEXT_COURSECAT, $result->contextlevel); - } - -} diff --git a/public/admin/tool/moodlenet/tests/lib_test.php b/public/admin/tool/moodlenet/tests/lib_test.php deleted file mode 100644 index 7014db9f6b2..00000000000 --- a/public/admin/tool/moodlenet/tests/lib_test.php +++ /dev/null @@ -1,81 +0,0 @@ -. - -/** - * Unit tests for tool_moodlenet lib - * - * @package tool_moodlenet - * @copyright 2020 Peter Dias - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -namespace tool_moodlenet; - -defined('MOODLE_INTERNAL') || die(); - -global $CFG; -require_once($CFG->dirroot . '/admin/tool/moodlenet/lib.php'); - -/** - * Test moodlenet functions - */ -final class lib_test extends \advanced_testcase { - - /** - * Test the generate_mnet_endpoint function - * - * @dataProvider get_endpoints_provider - * @param string $profileurl - * @param int $course - * @param int $section - * @param string $expected - */ - public function test_generate_mnet_endpoint($profileurl, $course, $section, $expected): void { - $endpoint = generate_mnet_endpoint($profileurl, $course, $section); - $this->assertEquals($expected, $endpoint); - } - - /** - * Dataprovider for test_generate_mnet_endpoint - * - * @return array - */ - public static function get_endpoints_provider(): array { - global $CFG; - return [ - [ - '@name@domain.name', - 1, - 2, - 'https://domain.name/' . MOODLENET_DEFAULT_ENDPOINT . '?site=' . urlencode($CFG->wwwroot) - . '&course=1§ion=2' - ], - [ - '@profile@name@domain.name', - 1, - 2, - 'https://domain.name/' . MOODLENET_DEFAULT_ENDPOINT . '?site=' . urlencode($CFG->wwwroot) - . '&course=1§ion=2' - ], - [ - 'https://domain.name', - 1, - 2, - 'https://domain.name/' . MOODLENET_DEFAULT_ENDPOINT . '?site=' . urlencode($CFG->wwwroot) - . '&course=1§ion=2' - ] - ]; - } -} diff --git a/public/admin/tool/moodlenet/tests/local/import_handler_info_test.php b/public/admin/tool/moodlenet/tests/local/import_handler_info_test.php deleted file mode 100644 index ad5f267d617..00000000000 --- a/public/admin/tool/moodlenet/tests/local/import_handler_info_test.php +++ /dev/null @@ -1,70 +0,0 @@ -. - -namespace tool_moodlenet\local; - -use tool_moodlenet\local\import_handler_info; -use tool_moodlenet\local\import_strategy; -use tool_moodlenet\local\import_strategy_file; - -/** - * Class tool_moodlenet_import_handler_info_testcase, providing test cases for the import_handler_info class. - * - * @package tool_moodlenet - * @category test - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -final class import_handler_info_test extends \advanced_testcase { - - /** - * Test init and the getters. - * - * @dataProvider handler_info_data_provider - * @param string $modname the name of the mod. - * @param string $description description of the mod. - * @param bool $expectexception whether we expect an exception during init or not. - */ - public function test_initialisation($modname, $description, $expectexception): void { - $this->resetAfterTest(); - // Skip those cases we cannot init. - if ($expectexception) { - $this->expectException(\coding_exception::class); - $handlerinfo = new import_handler_info($modname, $description, new import_strategy_file()); - } - - $handlerinfo = new import_handler_info($modname, $description, new import_strategy_file()); - - $this->assertEquals($modname, $handlerinfo->get_module_name()); - $this->assertEquals($description, $handlerinfo->get_description()); - $this->assertInstanceOf(import_strategy::class, $handlerinfo->get_strategy()); - } - - - /** - * Data provider for creation of import_handler_info objects. - * - * @return array the data for creation of the info object. - */ - public static function handler_info_data_provider(): array { - return [ - 'All data present' => ['label', 'Add a label to the course', false], - 'Empty module name' => ['', 'Add a file resource to the course', true], - 'Empty description' => ['resource', '', true], - - ]; - } -} diff --git a/public/admin/tool/moodlenet/tests/local/import_handler_registry_test.php b/public/admin/tool/moodlenet/tests/local/import_handler_registry_test.php deleted file mode 100644 index c9631f0e4b5..00000000000 --- a/public/admin/tool/moodlenet/tests/local/import_handler_registry_test.php +++ /dev/null @@ -1,114 +0,0 @@ -. - -namespace tool_moodlenet\local; - -use tool_moodlenet\local\import_handler_registry; -use tool_moodlenet\local\import_handler_info; -use tool_moodlenet\local\import_strategy_file; -use tool_moodlenet\local\import_strategy_link; -use tool_moodlenet\local\remote_resource; -use tool_moodlenet\local\url; - -/** - * Class tool_moodlenet_import_handler_registry_testcase, providing test cases for the import_handler_registry class. - * - * @package tool_moodlenet - * @category test - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -final class import_handler_registry_test extends \advanced_testcase { - - /** - * Test confirming the behaviour of get_resource_handlers_for_strategy with different params. - */ - public function test_get_resource_handlers_for_strategy(): void { - $this->resetAfterTest(); - - $course = $this->getDataGenerator()->create_course(); - $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); - $ihr = new import_handler_registry($course, $teacher); - $resource = new remote_resource( - new \curl(), - new url('http://example.org'), - (object) [ - 'name' => 'Resource name', - 'description' => 'Resource description' - ] - ); - - $handlers = $ihr->get_resource_handlers_for_strategy($resource, new import_strategy_file()); - $this->assertIsArray($handlers); - foreach ($handlers as $handler) { - $this->assertInstanceOf(import_handler_info::class, $handler); - } - } - - /** - * Test confirming that the results are scoped to the provided user. - */ - public function test_get_resource_handlers_for_strategy_user_scoping(): void { - $this->resetAfterTest(); - - $course = $this->getDataGenerator()->create_course(); - $student = $this->getDataGenerator()->create_and_enrol($course, 'student'); - $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); - - $studentihr = new import_handler_registry($course, $student); - $teacherihr = new import_handler_registry($course, $teacher); - $resource = new remote_resource( - new \curl(), - new url('http://example.org'), - (object) [ - 'name' => 'Resource name', - 'description' => 'Resource description' - ] - ); - - $this->assertEmpty($studentihr->get_resource_handlers_for_strategy($resource, new import_strategy_file())); - $this->assertNotEmpty($teacherihr->get_resource_handlers_for_strategy($resource, new import_strategy_file())); - } - - /** - * Test confirming that we can find a unique handler based on the module and strategy name. - */ - public function test_get_resource_handler_for_module_and_strategy(): void { - $this->resetAfterTest(); - - $course = $this->getDataGenerator()->create_course(); - $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); - $ihr = new import_handler_registry($course, $teacher); - $resource = new remote_resource( - new \curl(), - new url('http://example.org'), - (object) [ - 'name' => 'Resource name', - 'description' => 'Resource description' - ] - ); - - // Resource handles every file type, so we'll always be able to find that unique handler when looking. - $handler = $ihr->get_resource_handler_for_mod_and_strategy($resource, 'resource', new import_strategy_file()); - $this->assertInstanceOf(import_handler_info::class, $handler); - - // URL handles every resource, so we'll always be able to find that unique handler when looking with a link strategy. - $handler = $ihr->get_resource_handler_for_mod_and_strategy($resource, 'url', new import_strategy_link()); - $this->assertInstanceOf(import_handler_info::class, $handler); - $this->assertEquals('url', $handler->get_module_name()); - $this->assertInstanceOf(import_strategy_link::class, $handler->get_strategy()); - } -} diff --git a/public/admin/tool/moodlenet/tests/local/import_info_test.php b/public/admin/tool/moodlenet/tests/local/import_info_test.php deleted file mode 100644 index 651b664f0cf..00000000000 --- a/public/admin/tool/moodlenet/tests/local/import_info_test.php +++ /dev/null @@ -1,100 +0,0 @@ -. - -namespace tool_moodlenet\local; - -use tool_moodlenet\local\import_info; -use tool_moodlenet\local\remote_resource; -use tool_moodlenet\local\url; - -/** - * Class tool_moodlenet_import_info_testcase, providing test cases for the import_info class. - * - * @package tool_moodlenet - * @category test - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -final class import_info_test extends \advanced_testcase { - - /** - * Create some test objects. - * - * @return array - */ - protected function create_test_info(): array { - $user = $this->getDataGenerator()->create_user(); - $resource = new remote_resource(new \curl(), - new url('http://example.org'), - (object) [ - 'name' => 'Resource name', - 'description' => 'Resource summary' - ] - ); - $importinfo = new import_info($user->id, $resource, (object)[]); - - return [$user, $resource, $importinfo]; - } - - /** - * Test for creation and getters. - */ - public function test_getters(): void { - $this->resetAfterTest(); - [$user, $resource, $importinfo] = $this->create_test_info(); - - $this->assertEquals($resource, $importinfo->get_resource()); - $this->assertEquals(new \stdClass(), $importinfo->get_config()); - $this->assertNotEmpty($importinfo->get_id()); - } - - /** - * Test for setters. - */ - public function test_set_config(): void { - $this->resetAfterTest(); - [$user, $resource, $importinfo] = $this->create_test_info(); - - $config = $importinfo->get_config(); - $this->assertEquals(new \stdClass(), $config); - $config->course = 3; - $config->section = 1; - $importinfo->set_config($config); - $this->assertEquals((object) ['course' => 3, 'section' => 1], $importinfo->get_config()); - } - - /** - * Verify the object can be stored and loaded. - */ - public function test_persistence(): void { - $this->resetAfterTest(); - [$user, $resource, $importinfo] = $this->create_test_info(); - - // Nothing to load initially since nothing has been saved. - $loadedinfo = import_info::load($importinfo->get_id()); - $this->assertNull($loadedinfo); - - // Now, save and confirm we can load the data into a new object. - $importinfo->save(); - $loadedinfo2 = import_info::load($importinfo->get_id()); - $this->assertEquals($importinfo, $loadedinfo2); - - // Purge and confirm the load returns null now. - $importinfo->purge(); - $loadedinfo3 = import_info::load($importinfo->get_id()); - $this->assertNull($loadedinfo3); - } -} diff --git a/public/admin/tool/moodlenet/tests/local/import_processor_test.php b/public/admin/tool/moodlenet/tests/local/import_processor_test.php deleted file mode 100644 index 603558d6e87..00000000000 --- a/public/admin/tool/moodlenet/tests/local/import_processor_test.php +++ /dev/null @@ -1,151 +0,0 @@ -. - -namespace tool_moodlenet\local; - -use tool_moodlenet\local\import_handler_registry; -use tool_moodlenet\local\import_processor; -use tool_moodlenet\local\import_strategy_file; -use tool_moodlenet\local\import_strategy_link; -use tool_moodlenet\local\remote_resource; -use tool_moodlenet\local\url; - -/** - * Class tool_moodlenet_import_processor_testcase, providing test cases for the import_processor class. - * - * @package tool_moodlenet - * @category test - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -final class import_processor_test extends \advanced_testcase { - - /** - * An integration test, this confirms the ability to construct an import processor and run the import for the current user. - */ - public function test_process_valid_resource(): void { - $this->resetAfterTest(); - - // Set up a user as a teacher in a course. - $course = $this->getDataGenerator()->create_course(); - $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); - $section = 0; - $this->setUser($teacher); - - // Set up the import, using a mod_resource handler for the html extension. - $resourceurl = $this->getExternalTestFileUrl('/test.html'); - $remoteresource = new remote_resource( - new \curl(), - new url($resourceurl), - (object) [ - 'name' => 'Resource name', - 'description' => 'Resource description' - ] - ); - $handlerregistry = new import_handler_registry($course, $teacher); - $handlerinfo = $handlerregistry->get_resource_handler_for_mod_and_strategy($remoteresource, 'resource', - new import_strategy_file()); - $importproc = new import_processor($course, $section, $remoteresource, $handlerinfo, $handlerregistry); - - // Import the file. - $importproc->process(); - - // Verify there is a new mod_resource created with correct name, description and containing the test.html file. - $modinfo = get_fast_modinfo($course, $teacher->id); - $cms = $modinfo->get_instances(); - $this->assertArrayHasKey('resource', $cms); - $cminfo = array_shift($cms['resource']); - $this->assertEquals('Resource name', $cminfo->get_formatted_name()); - $cm = get_coursemodule_from_id('', $cminfo->id, 0, false, MUST_EXIST); - list($cm, $context, $module, $data, $cw) = get_moduleinfo_data($cminfo, $course); - $this->assertEquals($remoteresource->get_description(), $data->intro); - $fs = get_file_storage(); - $files = $fs->get_area_files(\context_module::instance($cminfo->id)->id, 'mod_resource', 'content', false, - 'sortorder DESC, id ASC', false); - $file = reset($files); - $this->assertEquals('test.html', $file->get_filename()); - $this->assertEquals('text/html', $file->get_mimetype()); - } - - /** - * Test confirming that an exception is thrown when trying to process a resource which does not exist. - */ - public function test_process_invalid_resource(): void { - $this->resetAfterTest(); - - // Set up a user as a teacher in a course. - $course = $this->getDataGenerator()->create_course(); - $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); - $section = 0; - $this->setUser($teacher); - - // Set up the import, using a mod_resource handler for the html extension. - $resourceurl = $this->getExternalTestFileUrl('/test.htmlzz'); - $remoteresource = new remote_resource( - new \curl(), - new url($resourceurl), - (object) [ - 'name' => 'Resource name', - 'description' => 'Resource description' - ] - ); - $handlerregistry = new import_handler_registry($course, $teacher); - $handlerinfo = $handlerregistry->get_resource_handler_for_mod_and_strategy($remoteresource, 'resource', - new import_strategy_file()); - $importproc = new import_processor($course, $section, $remoteresource, $handlerinfo, $handlerregistry); - - // Import the file. - $this->expectException(\coding_exception::class); - $importproc->process(); - } - - /** - * Test confirming that imports can be completed using alternative import strategies. - */ - public function test_process_alternative_import_strategies(): void { - $this->resetAfterTest(); - - // Set up a user as a teacher in a course. - $course = $this->getDataGenerator()->create_course(); - $teacher = $this->getDataGenerator()->create_and_enrol($course, 'editingteacher'); - $section = 0; - $this->setUser($teacher); - - // Set up the import, using a mod_url handler and the link import strategy. - $remoteresource = new remote_resource( - new \curl(), - new url('http://example.com/cats.pdf'), - (object) [ - 'name' => 'Resource name', - 'description' => 'Resource description' - ] - ); - $handlerregistry = new import_handler_registry($course, $teacher); - $handlerinfo = $handlerregistry->get_resource_handler_for_mod_and_strategy($remoteresource, 'url', - new import_strategy_link()); - $importproc = new import_processor($course, $section, $remoteresource, $handlerinfo, $handlerregistry); - - // Import the resource as a link. - $importproc->process(); - - // Verify there is a new mod_url created with name 'cats' and containing the URL of the resource. - $modinfo = get_fast_modinfo($course, $teacher->id); - $cms = $modinfo->get_instances(); - $this->assertArrayHasKey('url', $cms); - $cminfo = array_shift($cms['url']); - $this->assertEquals('Resource name', $cminfo->get_formatted_name()); - } -} diff --git a/public/admin/tool/moodlenet/tests/local/remote_resource_test.php b/public/admin/tool/moodlenet/tests/local/remote_resource_test.php deleted file mode 100644 index d4543345844..00000000000 --- a/public/admin/tool/moodlenet/tests/local/remote_resource_test.php +++ /dev/null @@ -1,118 +0,0 @@ -. - -namespace tool_moodlenet\local; - -use tool_moodlenet\local\remote_resource; -use tool_moodlenet\local\url; - -/** - * Class tool_moodlenet_remote_resource_testcase, providing test cases for the remote_resource class. - * - * @package tool_moodlenet - * @category test - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -final class remote_resource_test extends \advanced_testcase { - - /** - * Test getters. - * - * @dataProvider remote_resource_data_provider - * @param string $url the url of the resource. - * @param string $metadata the resource metadata like name, description, etc. - * @param string $expectedextension the extension we expect to find when querying the remote resource. - */ - public function test_getters($url, $metadata, $expectedextension): void { - $this->resetAfterTest(); - - $remoteres = new remote_resource(new \curl(), new url($url), $metadata); - - $this->assertEquals(new url($url), $remoteres->get_url()); - $this->assertEquals($metadata->name, $remoteres->get_name()); - $this->assertEquals($metadata->description, $remoteres->get_description()); - $this->assertEquals($expectedextension, $remoteres->get_extension()); - } - - /** - * Data provider generating remote urls. - * - * @return array - */ - public static function remote_resource_data_provider(): array { - return [ - 'With filename and extension' => [ - self::getExternalTestFileUrl('/test.html'), - (object) [ - 'name' => 'Test html file', - 'description' => 'Full description of the html file' - ], - 'html' - ], - 'With filename only' => [ - 'http://example.com/path/file', - (object) [ - 'name' => 'Test html file', - 'description' => 'Full description of the html file' - ], - '' - ] - ]; - } - - /** - * Test confirming the network based operations of a remote_resource. - */ - public function test_network_features(): void { - $url = self::getExternalTestFileUrl('/test.html'); - $nonexistenturl = self::getExternalTestFileUrl('/test.htmlzz'); - - $remoteres = new remote_resource( - new \curl(), - new url($url), - (object) [ - 'name' => 'Test html file', - 'description' => 'Some description' - ] - ); - $nonexistentremoteres = new remote_resource( - new \curl(), - new url($nonexistenturl), - (object) [ - 'name' => 'Test html file', - 'description' => 'Some description' - ] - ); - - // We need to handle size of -1 (missing "Content-Length" header), or where it is set and greater than zero. - $this->assertThat( - $remoteres->get_download_size(), - $this->logicalOr( - $this->equalTo(-1), - $this->greaterThan(0), - ), - ); - - [$path, $name] = $remoteres->download_to_requestdir(); - $this->assertIsString($path); - $this->assertEquals('test.html', $name); - $this->assertFileExists($path . '/' . $name); - - $this->expectException(\coding_exception::class); - $nonexistentremoteres->get_download_size(); - } -} diff --git a/public/admin/tool/moodlenet/tests/local/url_test.php b/public/admin/tool/moodlenet/tests/local/url_test.php deleted file mode 100644 index 9422b24e6c7..00000000000 --- a/public/admin/tool/moodlenet/tests/local/url_test.php +++ /dev/null @@ -1,98 +0,0 @@ -. - -namespace tool_moodlenet\local; - -use tool_moodlenet\local\url; - -/** - * Class tool_moodlenet_url_testcase, providing test cases for the url class. - * - * @package tool_moodlenet - * @category test - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -final class url_test extends \advanced_testcase { - - /** - * Test the parsing to host + path components. - * - * @dataProvider url_provider - * @param string $url The full URL string - * @param string $host the expected host component of the URL. - * @param string $path the expected path component of the URL. - * @param bool $exception whether or not an exception is expected during construction. - */ - public function test_parsing($urlstring, $host, $path, $exception): void { - if ($exception) { - $this->expectException(\coding_exception::class); - $url = new url($urlstring); - return; - } - - $url = new url($urlstring); - $this->assertEquals($urlstring, $url->get_value()); - $this->assertEquals($host, $url->get_host()); - $this->assertEquals($path, $url->get_path()); - } - - /** - * Data provider. - * - * @return array - */ - public static function url_provider(): array { - return [ - 'No path' => [ - 'urlstring' => 'https://example.moodle.net', - 'host' => 'example.moodle.net', - 'path' => null, - 'exception' => false, - ], - 'Slash path' => [ - 'urlstring' => 'https://example.moodle.net/', - 'host' => 'example.moodle.net', - 'path' => '/', - 'exception' => false, - ], - 'Path includes file and extension' => [ - 'urlstring' => 'https://example.moodle.net/uploads/123456789/pic.png', - 'host' => 'example.moodle.net', - 'path' => '/uploads/123456789/pic.png', - 'exception' => false, - ], - 'Path includes file, extension and params' => [ - 'urlstring' => 'https://example.moodle.net/uploads/123456789/pic.png?option=1&option2=test', - 'host' => 'example.moodle.net', - 'path' => '/uploads/123456789/pic.png', - 'exception' => false, - ], - 'Malformed - invalid' => [ - 'urlstring' => 'invalid', - 'host' => null, - 'path' => null, - 'exception' => true, - ], - 'Direct, non-encoded utf8 - invalid' => [ - 'urlstring' => 'http://москва.рф/services/', - 'host' => 'москва.рф', - 'path' => '/services/', - 'exception' => true, - ], - ]; - } -} diff --git a/public/admin/tool/moodlenet/tests/profile_manager_test.php b/public/admin/tool/moodlenet/tests/profile_manager_test.php deleted file mode 100644 index 1a41a0dc8d6..00000000000 --- a/public/admin/tool/moodlenet/tests/profile_manager_test.php +++ /dev/null @@ -1,136 +0,0 @@ -. - -namespace tool_moodlenet; - -/** - * Unit tests for the profile manager - * - * @package tool_moodlenet - * @category test - * @copyright 2020 Adrian Greeve - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -final class profile_manager_test extends \advanced_testcase { - - /** - * Test that on this site we use the user table to hold moodle net profile information. - */ - public function test_official_profile_exists(): void { - $this->assertTrue(\tool_moodlenet\profile_manager::official_profile_exists()); - } - - /** - * Test a null is returned when the user's mnet profile field is not set. - */ - public function test_get_moodlenet_user_profile_no_profile_set(): void { - $this->resetAfterTest(); - $user = $this->getDataGenerator()->create_user(); - - $result = \tool_moodlenet\profile_manager::get_moodlenet_user_profile($user->id); - $this->assertNull($result); - } - - /** - * Test a null is returned when the user's mnet profile field is not set. - */ - public function test_moodlenet_user_profile_creation_no_profile_set(): void { - $this->resetAfterTest(); - $user = $this->getDataGenerator()->create_user(); - - $this->expectException(\moodle_exception::class); - $this->expectExceptionMessage(get_string('invalidmoodlenetprofile', 'tool_moodlenet')); - $result = new \tool_moodlenet\moodlenet_user_profile("", $user->id); - } - - /** - * Test the return of a moodle net profile. - */ - public function test_get_moodlenet_user_profile(): void { - $this->resetAfterTest(); - $user = $this->getDataGenerator()->create_user(['moodlenetprofile' => '@matt@hq.mnet']); - - $result = \tool_moodlenet\profile_manager::get_moodlenet_user_profile($user->id); - $this->assertEquals($user->moodlenetprofile, $result->get_profile_name()); - } - - /** - * Test the creation of a user profile category. - */ - public function test_create_user_profile_category(): void { - global $DB; - $this->resetAfterTest(); - - $basecategoryname = get_string('pluginname', 'tool_moodlenet'); - - \tool_moodlenet\profile_manager::create_user_profile_category(); - $categoryname = \tool_moodlenet\profile_manager::get_category_name(); - $this->assertEquals($basecategoryname, $categoryname); - \tool_moodlenet\profile_manager::create_user_profile_category(); - - $recordcount = $DB->count_records('user_info_category', ['name' => $basecategoryname]); - $this->assertEquals(1, $recordcount); - - // Test the duplication of categories to ensure a unique name is always used. - $categoryname = \tool_moodlenet\profile_manager::get_category_name(); - $this->assertEquals($basecategoryname . 1, $categoryname); - \tool_moodlenet\profile_manager::create_user_profile_category(); - $categoryname = \tool_moodlenet\profile_manager::get_category_name(); - $this->assertEquals($basecategoryname . 2, $categoryname); - } - - /** - * Test the creating of the custom user profile field to hold the moodle net profile. - */ - public function test_create_user_profile_text_field(): void { - global $DB; - $this->resetAfterTest(); - - $shortname = 'mnetprofile'; - - $categoryid = \tool_moodlenet\profile_manager::create_user_profile_category(); - \tool_moodlenet\profile_manager::create_user_profile_text_field($categoryid); - - $record = $DB->get_record('user_info_field', ['shortname' => $shortname]); - $this->assertEquals($shortname, $record->shortname); - $this->assertEquals($categoryid, $record->categoryid); - - // Test for a unique name if 'mnetprofile' is already in use. - \tool_moodlenet\profile_manager::create_user_profile_text_field($categoryid); - $profilename = \tool_moodlenet\profile_manager::get_profile_field_name(); - $this->assertEquals($shortname . 1, $profilename); - \tool_moodlenet\profile_manager::create_user_profile_text_field($categoryid); - $profilename = \tool_moodlenet\profile_manager::get_profile_field_name(); - $this->assertEquals($shortname . 2, $profilename); - } - - /** - * Test that the user moodlenet profile is saved. - */ - public function test_save_moodlenet_user_profile(): void { - $this->resetAfterTest(); - - $user = $this->getDataGenerator()->create_user(); - $profilename = '@matt@hq.mnet'; - - $moodlenetprofile = new \tool_moodlenet\moodlenet_user_profile($profilename, $user->id); - - \tool_moodlenet\profile_manager::save_moodlenet_user_profile($moodlenetprofile); - - $userdata = \core_user::get_user($user->id); - $this->assertEquals($profilename, $userdata->moodlenetprofile); - } -} diff --git a/public/admin/tool/moodlenet/version.php b/public/admin/tool/moodlenet/version.php deleted file mode 100644 index cb24b13ece6..00000000000 --- a/public/admin/tool/moodlenet/version.php +++ /dev/null @@ -1,30 +0,0 @@ -. - -/** - * Version file for tool_moodlenet - * - * @package tool_moodlenet - * @copyright 2020 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -defined('MOODLE_INTERNAL') || die(); - -$plugin->component = 'tool_moodlenet'; -$plugin->version = 2025100600; -$plugin->requires = 2025092600; -$plugin->maturity = MATURITY_ALPHA; diff --git a/public/admin/tool/oauth2/classes/form/issuer.php b/public/admin/tool/oauth2/classes/form/issuer.php index 1f79e649c33..f766bf76078 100644 --- a/public/admin/tool/oauth2/classes/form/issuer.php +++ b/public/admin/tool/oauth2/classes/form/issuer.php @@ -187,8 +187,7 @@ class issuer extends persistent { $mform->hideIf('acceptrisk', 'requireconfirmation', 'checked'); - if ($this->type == 'imsobv2p1' || $issuer->get('servicetype') == 'imsobv2p1' - || $this->type == 'moodlenet' || $issuer->get('servicetype') == 'moodlenet') { + if ($this->type == 'imsobv2p1' || $issuer->get('servicetype') == 'imsobv2p1') { $mform->addRule('baseurl', null, 'required', null, 'client'); } else { $mform->addRule('clientid', null, 'required', null, 'client'); diff --git a/public/admin/tool/oauth2/issuers.php b/public/admin/tool/oauth2/issuers.php index 35156a77bcc..8cee1fc136b 100644 --- a/public/admin/tool/oauth2/issuers.php +++ b/public/admin/tool/oauth2/issuers.php @@ -222,12 +222,6 @@ if ($mform && $mform->is_cancelled()) { $addurl = new moodle_url('/admin/tool/oauth2/issuers.php', $params); echo $renderer->single_button($addurl, get_string('clever_service', 'tool_oauth2')); - // MoodleNet template. - $docs = 'admin/tool/oauth2/issuers/moodlenet'; - $params = ['action' => 'edittemplate', 'type' => 'moodlenet', 'sesskey' => sesskey(), 'docslink' => $docs]; - $addurl = new moodle_url('/admin/tool/oauth2/issuers.php', $params); - echo $renderer->single_button($addurl, get_string('moodlenet_service', 'tool_oauth2')); - // Generic issuer. $addurl = new moodle_url('/admin/tool/oauth2/issuers.php', ['action' => 'edit']); echo $renderer->single_button($addurl, get_string('custom_service', 'tool_oauth2')); diff --git a/public/admin/tool/oauth2/lang/en/tool_oauth2.php b/public/admin/tool/oauth2/lang/en/tool_oauth2.php index 6a244cf766b..30b380b0fcb 100644 --- a/public/admin/tool/oauth2/lang/en/tool_oauth2.php +++ b/public/admin/tool/oauth2/lang/en/tool_oauth2.php @@ -105,7 +105,6 @@ $string['linkedin_service'] = 'LinkedIn'; $string['logindisplay'] = 'Display on login page as'; $string['loginissuer'] = 'Allow login'; $string['microsoft_service'] = 'Microsoft'; -$string['moodlenet_service'] = 'MoodleNet'; $string['nextcloud_service'] = 'Nextcloud'; $string['notconfigured'] = 'Not configured'; $string['notdiscovered'] = 'Service discovery not successful'; diff --git a/public/admin/tool/usertours/classes/manager.php b/public/admin/tool/usertours/classes/manager.php index ffc0b70a2c5..d11e55bcec1 100644 --- a/public/admin/tool/usertours/classes/manager.php +++ b/public/admin/tool/usertours/classes/manager.php @@ -272,14 +272,6 @@ class manager { 'img' => 'i/tour-import', 'title' => get_string('importtour', 'tool_usertours'), ], - (object) [ - 'link' => new \moodle_url('https://moodle.net/search', ['q' => 'user tours']), - 'linkproperties' => [ - 'target' => '_blank', - ], - 'img' => 'i/tour-shared', - 'title' => get_string('sharedtourslink', 'tool_usertours'), - ], ]; echo \html_writer::start_tag('div', [ diff --git a/public/course/format/classes/output/local/content/bulkedittools.php b/public/course/format/classes/output/local/content/bulkedittools.php index eb1254c3852..2886281e90e 100644 --- a/public/course/format/classes/output/local/content/bulkedittools.php +++ b/public/course/format/classes/output/local/content/bulkedittools.php @@ -16,7 +16,6 @@ namespace core_courseformat\output\local\content; -use core\moodlenet\utilities; use core\output\named_templatable; use core_courseformat\base as course_format; use core_courseformat\output\local\courseformat_named_templatable; @@ -132,18 +131,6 @@ class bulkedittools implements named_templatable, renderable { ]; } - $usercanshare = utilities::can_user_share($context, $user->id, 'course'); - if ($CFG->enablesharingtomoodlenet && $usercanshare) { - $controls['sharetomoodlenet'] = [ - 'id' => 'cmShareToMoodleNet', - 'icon' => 'i/share', - 'action' => 'cmShareToMoodleNet', - 'name' => get_string('moodlenet:sharetomoodlenet'), - 'title' => get_string('moodlenet:sharetomoodlenet'), - 'bulk' => 'cm', - ]; - } - return $controls; } diff --git a/public/course/format/tests/behat/activity_chooser.feature b/public/course/format/tests/behat/activity_chooser.feature index 200175d5704..12786670019 100644 --- a/public/course/format/tests/behat/activity_chooser.feature +++ b/public/course/format/tests/behat/activity_chooser.feature @@ -14,8 +14,6 @@ Feature: Display and choose from the available activities in course And the following "course enrolments" exist: | user | course | role | | teacher | C | editingteacher | - And the following config values are set as admin: - | enablemoodlenet | 0 | tool_moodlenet | And I log in as "teacher" And I am on "Course" course homepage with editing mode on diff --git a/public/lang/en/admin.php b/public/lang/en/admin.php index 92ff41994ce..198c998ee3d 100644 --- a/public/lang/en/admin.php +++ b/public/lang/en/admin.php @@ -624,8 +624,6 @@ $string['enableplugin'] = 'Enable {$a}'; $string['enablerecordcache'] = 'Enable record cache'; $string['enablerssfeeds'] = 'Enable RSS feeds'; $string['enablesearchareas'] = 'Enable search areas'; -$string['enablesharingtomoodlenet'] = 'Enable sharing to MoodleNet (outbound)'; -$string['enablesharingtomoodlenet_desc'] = 'Enable users to share course content to a configured MoodleNet instance if they have the relevant capability.'; $string['enablestats'] = 'Enable statistics'; $string['enabletrusttext'] = 'Enable trusted content'; $string['enableuserfeedback'] = 'Enable feedback about this software'; @@ -987,7 +985,7 @@ $string['maxtimelimit'] = 'Maximum time limit'; $string['maxtimelimit_desc'] = 'To restrict the maximum PHP execution time that Moodle will allow without any output being displayed, enter a value in seconds here. 0 means that Moodle default restrictions are used. If you have a front-end server with its own time limit, set this value lower to receive PHP errors in logs. Does not apply to CLI scripts.'; $string['moodlebrandedapp'] = 'Branded Moodle app'; $string['moodlebrandedappreference'] = 'Alternatively, get a Branded Moodle app with your own custom branding.'; -$string['moodlenetremovalwarning'] = 'The MoodleNet service will be shut down on 20 April 2026. If you wish to continue using MoodleNet on your site, install the MoodleNet plugin from the Moodle plugins directory and connect it to a self-hosted MoodleNet instance. Following this, the MoodleNet profile ID field will be removed; please migrate that data if you are using it for other purposes.'; +$string['moodlenetremovalwarning'] = 'The MoodleNet service will be shut down on 20 April 2026. If you wish to continue using MoodleNet on your site, install the MoodleNet plugin from the Moodle HQ GitHub repository and connect it to a self-hosted MoodleNet instance. Following this, the MoodleNet profile ID field will be removed; please migrate that data if you are using it for other purposes.'; $string['noreplyaddress'] = 'No-reply address'; $string['noreplydomain'] = 'No-reply and domain'; $string['noreplydomaindetail'] = 'Settings for No-reply and configured domains'; diff --git a/public/lang/en/cache.php b/public/lang/en/cache.php index aa2561887e5..be7fa187c97 100644 --- a/public/lang/en/cache.php +++ b/public/lang/en/cache.php @@ -76,7 +76,6 @@ $string['cachedef_langmenu'] = 'List of available languages'; $string['cachedef_license'] = 'List of licences'; $string['cachedef_message_time_last_message_between_users'] = 'Time created for most recent message in a conversation'; $string['cachedef_modelfirstanalyses'] = 'First analysis by model and analysable'; -$string['cachedef_moodlenet_usercanshare'] = 'Users can share resources to MoodleNet'; $string['cachedef_locking'] = 'Locking'; $string['cachedef_message_processors_enabled'] = "Message processors enabled status"; $string['cachedef_contextwithinsights'] = 'Context with insights'; diff --git a/public/lang/en/deprecated.txt b/public/lang/en/deprecated.txt index 2965514902b..1717339d76c 100644 --- a/public/lang/en/deprecated.txt +++ b/public/lang/en/deprecated.txt @@ -96,3 +96,6 @@ sitename,core_hub sitename_help,core_hub defaultissuerpassword_help,core_badges invalidfiletype,core_repository +moodlenetprofile,core_user +moodlenetprofile_help,core_user +privacy:metadata:moodlenetprofile,core_user diff --git a/public/lang/en/error.php b/public/lang/en/error.php index 61887881ded..db7f0f840ab 100644 --- a/public/lang/en/error.php +++ b/public/lang/en/error.php @@ -427,10 +427,6 @@ $string['moduledisable'] = 'This module ({$a}) has been disabled for this partic $string['moduledoesnotexist'] = 'This module does not exist'; $string['moduleinstancedoesnotexist'] = 'The instance of this module does not exist'; $string['modulemissingcode'] = 'Module {$a} is missing the code needed to perform this function'; -$string['moodlenet:invalidshareformat'] = 'Incorrect MoodleNet share format'; -$string['moodlenet:invalidsharestatus'] = 'Incorrect MoodleNet share status'; -$string['moodlenet:invalidsharetype'] = 'Invalid MoodleNet share type'; -$string['moodlenet:usernotconfigured'] = 'You do not have permission to share content to MoodleNet, or your account is incorrectly configured.'; $string['movecatcontentstoroot'] = 'Moving the category content to root is not allowed. You must move the contents to an existing category!'; $string['movecatcontentstoselected'] = 'Some category content cannot be moved into the selected category.'; $string['movecategorynotpossible'] = 'You cannot move category \'{$a}\' into the selected category.'; diff --git a/public/lang/en/moodle.php b/public/lang/en/moodle.php index e0b4312af01..0a1e027ebc4 100644 --- a/public/lang/en/moodle.php +++ b/public/lang/en/moodle.php @@ -1388,38 +1388,6 @@ $string['moodledocslink'] = 'Documentation for this page'; $string['moodleversion'] = 'Moodle version'; $string['moodlerelease'] = 'Moodle release'; $string['moodleservicesandsupport'] = 'Services and support'; -$string['moodlenet:cannotconnecttoserver'] = 'Cannot connect to MoodleNet server'; -$string['moodlenet:columnname'] = 'Name'; -$string['moodlenet:columnsenddate'] = 'Send date'; -$string['moodlenet:columnsendstatus'] = 'Send status'; -$string['moodlenet:columntype'] = 'Type'; -$string['moodlenet:configoauthservice'] = 'Select a MoodleNet OAuth 2 service to enable sharing to that MoodleNet site. If the service doesn\'t exist yet, you will need to create it.'; -$string['moodlenet:deletedactivity'] = 'Deleted activity'; -$string['moodlenet:deletedcourse'] = 'Deleted course'; -$string['moodlenet:eventresourceexported'] = 'Resource exported'; -$string['moodlenet:gotomoodlenet'] = 'Go to MoodleNet drafts'; -$string['moodlenet:issuerisnotauthorized'] = 'MoodleNet issuer is not authorised'; -$string['moodlenet:issuerisnotenabled'] = 'MoodleNet issuer is not enabled'; -$string['moodlenet:issuerisnotset'] = 'MoodleNet issuer is not set at site administration'; -$string['moodlenet:nosharedresources'] = 'There are no shared resources to display at this time.'; -$string['moodlenet:outboundsettings'] = 'MoodleNet outbound settings'; -$string['moodlenet:sharenoticeactivity'] = 'This activity is being shared with MoodleNet as a resource.'; -$string['moodlenet:sharenoticecourse'] = 'This course is being shared with MoodleNet as a resource.'; -$string['moodlenet:sharenoticepartial'] = 'The selected activities are being shared with MoodleNet as a resource.'; -$string['moodlenet:sharenoticepartialactivitynumber'] = '{$a} activities will be included in the course.'; -$string['moodlenet:sharefailtitle'] = 'Something went wrong'; -$string['moodlenet:sharefailtext'] = 'There was an error sharing your content to MoodleNet.
Please try again later.'; -$string['moodlenet:sharefailtextwithsitesupport'] = 'There was an error sharing your content to MoodleNet.
Please try again later or contact site support.'; -$string['moodlenet:sharefilesizelimitexceeded'] = 'The size of the resource being shared ({$a->filesize} bytes) exceeds the limit of {$a->filesizelimit} bytes.'; -$string['moodlenet:shareprogress'] = 'MoodleNet share progress'; -$string['moodlenet:shareprogressinfo'] = 'The list shows courses and activities you have shared to MoodleNet.
Click the resource name to view in MoodleNet.'; -$string['moodlenet:sharesuccesstitle'] = 'Saved to MoodleNet drafts'; -$string['moodlenet:sharesuccesstext'] = "Almost done! Visit your drafts in MoodleNet to finish sharing your content."; -$string['moodlenet:sharetomoodlenet'] = 'Share to MoodleNet'; -$string['moodlenet:sharingstatus'] = 'Sharing to MoodleNet'; -$string['moodlenet:sharinglargefile'] = "Large files can take some time."; -$string['moodlenet:sharingto'] = 'Sharing to: '; -$string['moodlenet:packagingandsending'] = 'Packaging your file and sending to MoodleNet...'; $string['more'] = 'more'; $string['morehelp'] = 'More help'; $string['morehelpaboutmodule'] = 'More help about the {$a} activity'; @@ -1741,14 +1709,6 @@ $string['privacy:metadata:log:module'] = 'module'; $string['privacy:metadata:log:time'] = 'The time when the action took place'; $string['privacy:metadata:log:url'] = 'The URL related to the event'; $string['privacy:metadata:log:userid'] = 'The ID of the user who performed the action'; -$string['privacy:metadata:moodlenet_share_progress'] = 'MoodleNet share progress details'; -$string['privacy:metadata:moodlenet_share_progress:type'] = 'The type of share that was performed'; -$string['privacy:metadata:moodlenet_share_progress:courseid'] = 'The associated course ID'; -$string['privacy:metadata:moodlenet_share_progress:cmid'] = 'The associated course module ID'; -$string['privacy:metadata:moodlenet_share_progress:userid'] = 'The user that performed the share'; -$string['privacy:metadata:moodlenet_share_progress:timecreated'] = 'The time the share was performed'; -$string['privacy:metadata:moodlenet_share_progress:resourceurl'] = 'The returned URL from MoodleNet after a successful share'; -$string['privacy:metadata:moodlenet_share_progress:status'] = 'The resulting status of the share'; $string['privacy:metadata:oauth2_refresh_token'] = 'Refresh token used in OAuth 2.0 communication'; $string['privacy:metadata:oauth2_refresh_token:issuerid'] = 'The ID of the issuer to which the token corresponds'; $string['privacy:metadata:oauth2_refresh_token:scopehash'] = 'The ID of the user to whom the token corresponds'; diff --git a/public/lang/en/role.php b/public/lang/en/role.php index 2107d3c77cf..31e71086db0 100644 --- a/public/lang/en/role.php +++ b/public/lang/en/role.php @@ -324,8 +324,6 @@ $string['manager'] = 'Manager'; $string['managerdescription'] = 'Managers can access courses and modify them, but usually do not participate in them.'; $string['manageroles'] = 'Manage roles'; $string['maybeassignedin'] = 'Context types where this role may be assigned'; -$string['moodlenet:shareactivity'] = 'Share activities to MoodleNet'; -$string['moodlenet:sharecourse'] = 'Share course to MoodleNet'; $string['morethan'] = 'More than {$a}'; $string['multipleroles'] = 'Multiple roles'; $string['my:manageblocks'] = 'Manage Dashboard page blocks'; diff --git a/public/lang/en/user.php b/public/lang/en/user.php index 0bcf46a1392..b8962dcec04 100644 --- a/public/lang/en/user.php +++ b/public/lang/en/user.php @@ -23,8 +23,6 @@ */ $string['countparticipantsfound'] = '{$a} participants found'; -$string['moodlenetprofile'] = 'MoodleNet profile ID'; -$string['moodlenetprofile_help'] = 'Your MoodleNet profile ID links your MoodleNet profile with this site.'; $string['placeholdertype'] = 'Type...'; $string['privacy:courserequestpath'] = 'Requested courses'; $string['privacy:descriptionpath'] = 'Profile description'; @@ -78,7 +76,6 @@ $string['privacy:metadata:maildisplay'] = 'A preference for the user about displ $string['privacy:metadata:middlename'] = 'The middle name of the user'; $string['privacy:metadata:mnethostid'] = 'An identifier for the MNet host if used'; $string['privacy:metadata:model'] = 'The device name, occam or iPhone etc..'; -$string['privacy:metadata:moodlenetprofile'] = 'The MoodleNet profile for the user'; $string['privacy:metadata:msn'] = 'The MSN identifier of the user'; $string['privacy:metadata:my_pages'] = 'User pages - dashboard and profile. This table does not contain personal data and only used to link dashboard blocks to users'; $string['privacy:metadata:my_pages:name'] = 'Page name'; @@ -141,3 +138,8 @@ $string['target:upcomingactivitiesdue_help'] = 'This target generates reminders $string['target:upcomingactivitiesdueinfo'] = 'All upcoming activities due insights are listed here. These students have received these insights directly.'; $string['usergroupselectorcount'] = '{$a->fullname} ({$a->groupcount})'; $string['userprofile'] = 'User profile'; + +// Deprecated since Moodle 5.2. +$string['moodlenetprofile'] = 'MoodleNet profile ID'; +$string['moodlenetprofile_help'] = 'Your MoodleNet profile ID links your MoodleNet profile with this site.'; +$string['privacy:metadata:moodlenetprofile'] = 'The MoodleNet profile for the user'; diff --git a/public/lib/amd/build/moodlenet/authorize.min.js b/public/lib/amd/build/moodlenet/authorize.min.js deleted file mode 100644 index a5ed6b0553f..00000000000 --- a/public/lib/amd/build/moodlenet/authorize.min.js +++ /dev/null @@ -1,11 +0,0 @@ -define("core/moodlenet/authorize",["exports","core/notification","core/moodlenet/service","core/moodlenet/send_resource"],(function(_exports,_notification,MoodleNetService,_send_resource){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.handleAuthorization=void 0,MoodleNetService=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj} -/** - * MoodleNet authorization. - * - * @module core/moodlenet/authorize - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @since 4.3 - */(MoodleNetService);const handleAuthorization=(issuerId,courseId,resourceId,shareFormat)=>MoodleNetService.authorizationCheck(issuerId,courseId).then((async data=>data.status?(0,_send_resource.sendToMoodleNet)(issuerId,resourceId,shareFormat):(window.moodleNetAuthorize=(error,errorDescription)=>{""===error?handleAuthorization(issuerId,courseId,resourceId,shareFormat):"access_denied"!==error&&(0,_notification.alert)("Authorization error","Error: "+error+"

Error description: "+errorDescription,"Cancel")},window.open(data.loginurl,"moodlenet_auth","location=0,status=0,width=".concat(550,",height=").concat(550,",scrollbars=yes"))))).catch(_notification.exception);_exports.handleAuthorization=handleAuthorization})); - -//# sourceMappingURL=authorize.min.js.map \ No newline at end of file diff --git a/public/lib/amd/build/moodlenet/authorize.min.js.map b/public/lib/amd/build/moodlenet/authorize.min.js.map deleted file mode 100644 index ed0c616e449..00000000000 --- a/public/lib/amd/build/moodlenet/authorize.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"authorize.min.js","sources":["../../src/moodlenet/authorize.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * MoodleNet authorization.\n *\n * @module core/moodlenet/authorize\n * @copyright 2023 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 4.3\n */\n\nimport {alert as displayAlert, exception as displayException} from 'core/notification';\nimport * as MoodleNetService from 'core/moodlenet/service';\nimport {sendToMoodleNet} from 'core/moodlenet/send_resource';\n\n/**\n * Handle authorization with MoodleNet server.\n *\n * @param {int} issuerId The OAuth 2 issuer ID.\n * @param {int} courseId Course id.\n * @param {int} resourceId Resource id.\n * @param {int} shareFormat Share format.\n * @return {promise}\n */\nexport const handleAuthorization = (issuerId, courseId, resourceId, shareFormat) => {\n const windowSizeWidth = 550;\n const windowSizeHeight = 550;\n\n // Check if the user is authorized with MoodleNet or not.\n return MoodleNetService.authorizationCheck(issuerId, courseId).then(async(data) => {\n if (!data.status) {\n // Not yet authorized.\n // Declare moodleNetAuthorize variable, so we can call it later in the callback.\n window.moodleNetAuthorize = (error, errorDescription) => {\n // This will be called by the callback after the authorization is successful.\n if (error === '') {\n handleAuthorization(issuerId, courseId, resourceId, shareFormat);\n } else if (error !== 'access_denied') {\n displayAlert(\n 'Authorization error',\n 'Error: ' + error + '

Error description: ' + errorDescription,\n 'Cancel'\n );\n }\n };\n // Open the login url of the OAuth 2 issuer for user to login into MoodleNet and authorize.\n return window.open(data.loginurl, 'moodlenet_auth',\n `location=0,status=0,width=${windowSizeWidth},height=${windowSizeHeight},scrollbars=yes`);\n } else {\n // Already authorized.\n return sendToMoodleNet(issuerId, resourceId, shareFormat);\n }\n }).catch(displayException);\n};\n"],"names":["handleAuthorization","issuerId","courseId","resourceId","shareFormat","MoodleNetService","authorizationCheck","then","async","data","status","window","moodleNetAuthorize","error","errorDescription","open","loginurl","catch","displayException"],"mappings":";;;;;;;;8BAqCaA,oBAAsB,CAACC,SAAUC,SAAUC,WAAYC,cAKzDC,iBAAiBC,mBAAmBL,SAAUC,UAAUK,MAAKC,MAAAA,MAC3DC,KAAKC,QAoBC,kCAAgBT,SAAUE,WAAYC,cAjB7CO,OAAOC,mBAAqB,CAACC,MAAOC,oBAElB,KAAVD,MACAb,oBAAoBC,SAAUC,SAAUC,WAAYC,aACnC,kBAAVS,+BAEH,sBACA,UAAYA,MAAQ,8BAAgCC,iBACpD,WAKLH,OAAOI,KAAKN,KAAKO,SAAU,qDArBlB,uBACC,2BA0BtBC,MAAMC"} \ No newline at end of file diff --git a/public/lib/amd/build/moodlenet/events.min.js b/public/lib/amd/build/moodlenet/events.min.js deleted file mode 100644 index c3dad1edbd2..00000000000 --- a/public/lib/amd/build/moodlenet/events.min.js +++ /dev/null @@ -1,3 +0,0 @@ -define("core/moodlenet/events",["exports"],(function(_exports){Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0;return _exports.default={MOODLENET_SHARE_STARTED:"moodlenet-share-started"},_exports.default})); - -//# sourceMappingURL=events.min.js.map \ No newline at end of file diff --git a/public/lib/amd/build/moodlenet/events.min.js.map b/public/lib/amd/build/moodlenet/events.min.js.map deleted file mode 100644 index 1a3e4e4d96a..00000000000 --- a/public/lib/amd/build/moodlenet/events.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"events.min.js","sources":["../../src/moodlenet/events.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * MoodleNet events.\n *\n * @module core/moodlenet/events\n * @copyright 2023 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 4.3\n */\n\nexport default {\n MOODLENET_SHARE_STARTED: 'moodlenet-share-started',\n};\n"],"names":["MOODLENET_SHARE_STARTED"],"mappings":"uKAwBe,CACXA,wBAAyB"} \ No newline at end of file diff --git a/public/lib/amd/build/moodlenet/mutations.min.js b/public/lib/amd/build/moodlenet/mutations.min.js deleted file mode 100644 index 256cbcd881e..00000000000 --- a/public/lib/amd/build/moodlenet/mutations.min.js +++ /dev/null @@ -1,3 +0,0 @@ -define("core/moodlenet/mutations",["exports","core_courseformat/local/courseeditor/mutations","core_courseformat/courseeditor","core_courseformat/local/content/actions","core/pubsub","core/moodlenet/send_resource","core/moodlenet/events"],(function(_exports,_mutations,_courseeditor,_actions,_pubsub,_send_resource,_events){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_mutations=_interopRequireDefault(_mutations),_actions=_interopRequireDefault(_actions),_events=_interopRequireDefault(_events);class MoodleNetMutations extends _mutations.default{constructor(){var obj,key,value;super(...arguments),value=async function(stateManager,cmIds){0!=cmIds.length&&(this.cmLock(stateManager,cmIds,!0),(0,_send_resource.handleModal)("partial",cmIds),this.cmLock(stateManager,cmIds,!1),(0,_pubsub.subscribe)(_events.default.MOODLENET_SHARE_STARTED,(()=>{this.bulkReset(stateManager)})))},(key="shareToMoodleNet")in(obj=this)?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value}}_exports.init=()=>{(0,_courseeditor.getCurrentCourseEditor)().addMutations(new MoodleNetMutations),_actions.default.addActions({cmShareToMoodleNet:"shareToMoodleNet"})}})); - -//# sourceMappingURL=mutations.min.js.map \ No newline at end of file diff --git a/public/lib/amd/build/moodlenet/mutations.min.js.map b/public/lib/amd/build/moodlenet/mutations.min.js.map deleted file mode 100644 index e6f5b7c9699..00000000000 --- a/public/lib/amd/build/moodlenet/mutations.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"mutations.min.js","sources":["../../src/moodlenet/mutations.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * MoodleNet mutations.\n * An instance of this class will be used to add custom mutations to the course editor.\n *\n * @module core/moodlenet/mutations\n * @copyright 2023 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 4.3\n */\n\nimport DefaultMutations from 'core_courseformat/local/courseeditor/mutations';\nimport {getCurrentCourseEditor} from 'core_courseformat/courseeditor';\nimport CourseActions from 'core_courseformat/local/content/actions';\nimport {subscribe} from 'core/pubsub';\nimport {handleModal} from 'core/moodlenet/send_resource';\nimport MoodleNetEvents from 'core/moodlenet/events';\n\nclass MoodleNetMutations extends DefaultMutations {\n\n /**\n * Share to MoodleNet.\n *\n * @param {StateManager} stateManager the current state manager\n * @param {array} cmIds Course module ids.\n */\n shareToMoodleNet = async function(stateManager, cmIds) {\n if (cmIds.length == 0) {\n return;\n }\n this.cmLock(stateManager, cmIds, true);\n handleModal('partial', cmIds);\n this.cmLock(stateManager, cmIds, false);\n subscribe(MoodleNetEvents.MOODLENET_SHARE_STARTED, () => {\n // Only clear the selection if the user starts the sharing.\n this.bulkReset(stateManager);\n });\n };\n}\n\n/**\n * Initialize.\n */\nexport const init = () => {\n const courseEditor = getCurrentCourseEditor();\n courseEditor.addMutations(new MoodleNetMutations());\n // Add direct mutation content actions.\n CourseActions.addActions({\n cmShareToMoodleNet: 'shareToMoodleNet'\n });\n};\n"],"names":["MoodleNetMutations","DefaultMutations","async","stateManager","cmIds","length","cmLock","MoodleNetEvents","MOODLENET_SHARE_STARTED","bulkReset","addMutations","addActions","cmShareToMoodleNet"],"mappings":"ymBAgCMA,2BAA2BC,6EAQVC,eAAeC,aAAcC,OACxB,GAAhBA,MAAMC,cAGLC,OAAOH,aAAcC,OAAO,kCACrB,UAAWA,YAClBE,OAAOH,aAAcC,OAAO,yBACvBG,gBAAgBC,yBAAyB,UAE1CC,UAAUN,6KAQP,MACK,0CACRO,aAAa,IAAIV,qCAEhBW,WAAW,CACrBC,mBAAoB"} \ No newline at end of file diff --git a/public/lib/amd/build/moodlenet/oauth2callback.min.js b/public/lib/amd/build/moodlenet/oauth2callback.min.js deleted file mode 100644 index 12c3eb6ce11..00000000000 --- a/public/lib/amd/build/moodlenet/oauth2callback.min.js +++ /dev/null @@ -1,11 +0,0 @@ -define("core/moodlenet/oauth2callback",["exports","core/prefetch","core/notification","core/str"],(function(_exports,_prefetch,_notification,_str){var obj; -/** - * A module to handle the OAuth2 callback for MoodleNet. - * - * @module core/moodlenet/oauth2callback - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @since 4.2 - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_prefetch=(obj=_prefetch)&&obj.__esModule?obj:{default:obj};_exports.init=(error,errorDescription)=>{_prefetch.default.prefetchStrings("moodle",["moodlenet:sharefailtitle","error"]),((error,errorDescription)=>{window.opener?(window.opener.moodleNetAuthorize(error,errorDescription),setTimeout((()=>{window.close()}),300)):(0,_notification.alert)((0,_str.getString)("error","moodle"),(0,_str.getString)("moodlenet:sharefailtitle","moodle"))})(error,errorDescription)}})); - -//# sourceMappingURL=oauth2callback.min.js.map \ No newline at end of file diff --git a/public/lib/amd/build/moodlenet/oauth2callback.min.js.map b/public/lib/amd/build/moodlenet/oauth2callback.min.js.map deleted file mode 100644 index 9c09da0bbd2..00000000000 --- a/public/lib/amd/build/moodlenet/oauth2callback.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"oauth2callback.min.js","sources":["../../src/moodlenet/oauth2callback.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * A module to handle the OAuth2 callback for MoodleNet.\n *\n * @module core/moodlenet/oauth2callback\n * @copyright 2023 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 4.2\n */\n\nimport Prefetch from \"core/prefetch\";\nimport {alert} from 'core/notification';\nimport {getString} from 'core/str';\n\n/**\n * Handle the OAuth2 callback for MoodleNet.\n *\n * @param {String} error Error\n * @param {String} errorDescription Error description\n */\nconst handleCallback = (error, errorDescription) => {\n if (window.opener) {\n // Call the MoodleNet Authorization again in the opener window.\n window.opener.moodleNetAuthorize(error, errorDescription);\n // Close the authorization popup.\n // We need to use setTimeout here because the Behat 'I press \"x\" and switch to main window' step expects the popup to still\n // be visible after clicking the button. Otherwise, it will throw a webdriver error.\n setTimeout(() => {\n // Close the authorization popup.\n window.close();\n }, 300);\n } else {\n alert(getString('error', 'moodle'), getString('moodlenet:sharefailtitle', 'moodle'));\n }\n};\n\n/**\n * Initialize.\n *\n * @param {String} error Error\n * @param {String} errorDescription Error description\n */\nexport const init = (error, errorDescription) => {\n Prefetch.prefetchStrings('moodle', ['moodlenet:sharefailtitle', 'error']);\n handleCallback(error, errorDescription);\n};\n"],"names":["error","errorDescription","prefetchStrings","window","opener","moodleNetAuthorize","setTimeout","close","handleCallback"],"mappings":";;;;;;;;4JAwDoB,CAACA,MAAOC,sCACfC,gBAAgB,SAAU,CAAC,2BAA4B,UAvB7C,EAACF,MAAOC,oBACvBE,OAAOC,QAEPD,OAAOC,OAAOC,mBAAmBL,MAAOC,kBAIxCK,YAAW,KAEPH,OAAOI,UACR,+BAEG,kBAAU,QAAS,WAAW,kBAAU,2BAA4B,YAY9EC,CAAeR,MAAOC"} \ No newline at end of file diff --git a/public/lib/amd/build/moodlenet/send_activity_modal.min.js b/public/lib/amd/build/moodlenet/send_activity_modal.min.js deleted file mode 100644 index 148c808b957..00000000000 --- a/public/lib/amd/build/moodlenet/send_activity_modal.min.js +++ /dev/null @@ -1,3 +0,0 @@ -define("core/moodlenet/send_activity_modal",["exports","core/modal"],(function(_exports,_modal){var obj;function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_modal=(obj=_modal)&&obj.__esModule?obj:{default:obj};class SendActivityModal extends _modal.default{registerEventListeners(){super.registerEventListeners(),this.registerCloseOnSave(),this.registerCloseOnCancel()}configure(modalConfig){modalConfig.show=!0,modalConfig.large=!0,super.configure(modalConfig)}}return _exports.default=SendActivityModal,_defineProperty(SendActivityModal,"TYPE","core/moodlenet/send_activity_modal"),_defineProperty(SendActivityModal,"TEMPLATE","core/moodlenet/send_activity_modal_base"),SendActivityModal.registerModalType(),_exports.default})); - -//# sourceMappingURL=send_activity_modal.min.js.map \ No newline at end of file diff --git a/public/lib/amd/build/moodlenet/send_activity_modal.min.js.map b/public/lib/amd/build/moodlenet/send_activity_modal.min.js.map deleted file mode 100644 index 64856deb172..00000000000 --- a/public/lib/amd/build/moodlenet/send_activity_modal.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"send_activity_modal.min.js","sources":["../../src/moodlenet/send_activity_modal.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Send activity modal for MoodleNet.\n *\n * @module core/moodlenet/send_activity_modal\n * @copyright 2023 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 4.2\n */\n\nimport Modal from 'core/modal';\n\nexport default class SendActivityModal extends Modal {\n static TYPE = 'core/moodlenet/send_activity_modal';\n static TEMPLATE = 'core/moodlenet/send_activity_modal_base';\n\n registerEventListeners() {\n // Call the parent registration.\n super.registerEventListeners();\n\n // Register to close on save/cancel.\n this.registerCloseOnSave();\n this.registerCloseOnCancel();\n }\n\n configure(modalConfig) {\n modalConfig.show = true;\n modalConfig.large = true;\n super.configure(modalConfig);\n }\n}\n\nSendActivityModal.registerModalType();\n"],"names":["SendActivityModal","Modal","registerEventListeners","registerCloseOnSave","registerCloseOnCancel","configure","modalConfig","show","large","registerModalType"],"mappings":"wZA0BqBA,0BAA0BC,eAI3CC,+BAEUA,8BAGDC,2BACAC,wBAGTC,UAAUC,aACNA,YAAYC,MAAO,EACnBD,YAAYE,OAAQ,QACdH,UAAUC,wEAhBHN,yBACH,sDADGA,6BAEC,2CAkBtBA,kBAAkBS"} \ No newline at end of file diff --git a/public/lib/amd/build/moodlenet/send_resource.min.js b/public/lib/amd/build/moodlenet/send_resource.min.js deleted file mode 100644 index f1db101faed..00000000000 --- a/public/lib/amd/build/moodlenet/send_resource.min.js +++ /dev/null @@ -1,11 +0,0 @@ -define("core/moodlenet/send_resource",["exports","core/config","core/notification","core/str","core/prefetch","core/templates","core/pubsub","core/moodlenet/service","core/moodlenet/send_activity_modal","core/moodlenet/authorize","core/moodlenet/events"],(function(_exports,_config,_notification,_str,_prefetch,Templates,_pubsub,MoodleNetService,_send_activity_modal,MoodleNetAuthorize,_events){function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireWildcard(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}return newObj.default=obj,cache&&cache.set(obj,newObj),newObj}function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}} -/** - * A module to handle Share operations of the MoodleNet. - * - * @module core/moodlenet/send_resource - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @since 4.2 - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.sendToMoodleNet=_exports.init=_exports.handleModal=void 0,_config=_interopRequireDefault(_config),_prefetch=_interopRequireDefault(_prefetch),Templates=_interopRequireWildcard(Templates),MoodleNetService=_interopRequireWildcard(MoodleNetService),_send_activity_modal=_interopRequireDefault(_send_activity_modal),MoodleNetAuthorize=_interopRequireWildcard(MoodleNetAuthorize),_events=_interopRequireDefault(_events);let currentModal,siteSupportUrl,issuerId,courseId,resourceId,shareFormat,type,selectedCmIds,listenersRegistered=!1;_exports.sendToMoodleNet=(issuerId,resourceId,shareFormat)=>{const modal=currentModal.getModal()[0];let infoPromise;modal.querySelector(".modal-header").classList.remove("no-border"),modal.querySelector(".modal-header").classList.add("no-header-text"),currentModal.setBody(Templates.render("core/moodlenet/send_activity_modal_packaging",{})),currentModal.hideFooter(),"activity"===type?infoPromise=MoodleNetService.sendActivity(issuerId,resourceId,shareFormat):"course"===type?infoPromise=MoodleNetService.sendCourse(issuerId,resourceId,shareFormat):"partial"===type&&(infoPromise=selectedCmIds.length>1?MoodleNetService.sendPartialCourse(issuerId,resourceId,selectedCmIds,shareFormat):MoodleNetService.sendActivity(issuerId,selectedCmIds[0],shareFormat)),infoPromise.then((async data=>{const status=data.status,resourceUrl=data.resourceurl;return responseFromMoodleNet(status,resourceUrl)})).catch(_notification.exception)};const responseFromMoodleNet=function(status){let resourceUrl=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";const $modal=currentModal.getModal(),modal=$modal[0];modal.querySelector(".modal-header").classList.add("no-border"),currentModal.setBody(Templates.render("core/moodlenet/send_activity_modal_done",{success:status,sitesupporturl:siteSupportUrl})),status&&(currentModal.setFooter(Templates.render("core/moodlenet/send_activity_modal_footer_view",{resourceurl:resourceUrl})),currentModal.showFooter())},renderModal=async(data,selectedActivities)=>{if(data.status){siteSupportUrl=data.supportpageurl,issuerId=data.issuerid;let modalConfig={templateContext:{activitytype:data.type,activityname:data.name,server:data.server}};return selectedActivities.length>0&&(selectedCmIds=selectedActivities),selectedActivities.length>1?(modalConfig.templateContext.fullsharing=!1,modalConfig.templateContext.selectedactivitiesnotice=await(0,_str.getString)("moodlenet:sharenoticepartialactivitynumber","moodle",selectedActivities.length),modalConfig.templateContext.sharenotice=await(0,_str.getString)("moodlenet:sharenoticepartial","moodle")):(modalConfig.templateContext.fullsharing=!0,"activity"===type||"partial"===type&&1==selectedActivities.length?modalConfig.templateContext.sharenotice=await(0,_str.getString)("moodlenet:sharenoticeactivity","moodle"):modalConfig.templateContext.sharenotice=await(0,_str.getString)("moodlenet:sharenoticecourse","moodle")),_send_activity_modal.default.create(modalConfig)}return(0,_notification.addNotification)({message:data.warnings[0].message,type:"error"})},handleModal=function(shareActionType){let selectedActivities=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];const resourceId=_config.default.contextInstanceId;type=shareActionType,Promise.resolve(type).then((type=>{if("activity"===type)return MoodleNetService.getActivityInformation(resourceId);if("course"===type)return MoodleNetService.getCourseInformation(resourceId);if("partial"===type)return selectedActivities.length>1?MoodleNetService.getCourseInformation(resourceId):MoodleNetService.getActivityInformation(selectedActivities[0]);throw new Error("Unknown type ".concat(type))})).then((data=>renderModal(data,selectedActivities))).then((modal=>(currentModal=modal,currentModal))).catch(_notification.exception)};_exports.handleModal=handleModal;_exports.init=()=>{listenersRegistered||(_prefetch.default.prefetchTemplates(["core/moodlenet/send_activity_modal_base","core/moodlenet/send_activity_modal_packaging","core/moodlenet/send_activity_modal_done","core/moodlenet/send_activity_modal_footer_view","core/moodlenet/send_activity_modal_footer_share"]),document.addEventListener("click",(e=>{const shareAction=e.target.closest('[data-action="sendtomoodlenet"]'),sendAction=e.target.closest('.moodlenet-action-buttons [data-action="share"]');shareAction&&(e.preventDefault(),type=shareAction.getAttribute("data-type"),handleModal(shareAction.getAttribute("data-type"))),sendAction&&(e.preventDefault(),(0,_pubsub.publish)(_events.default.MOODLENET_SHARE_STARTED,{}),courseId=_config.default.courseId,resourceId=_config.default.contextInstanceId,shareFormat=0,MoodleNetAuthorize.handleAuthorization(issuerId,courseId,resourceId,0))})),listenersRegistered=!0)}})); - -//# sourceMappingURL=send_resource.min.js.map \ No newline at end of file diff --git a/public/lib/amd/build/moodlenet/send_resource.min.js.map b/public/lib/amd/build/moodlenet/send_resource.min.js.map deleted file mode 100644 index 24fc26dd1c8..00000000000 --- a/public/lib/amd/build/moodlenet/send_resource.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"send_resource.min.js","sources":["../../src/moodlenet/send_resource.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * A module to handle Share operations of the MoodleNet.\n *\n * @module core/moodlenet/send_resource\n * @copyright 2023 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 4.2\n */\n\nimport Config from 'core/config';\nimport {addNotification, exception as displayException} from 'core/notification';\nimport {getString} from 'core/str';\nimport Prefetch from \"core/prefetch\";\nimport * as Templates from 'core/templates';\nimport {publish} from 'core/pubsub';\nimport * as MoodleNetService from 'core/moodlenet/service';\nimport SendActivityModal from 'core/moodlenet/send_activity_modal';\nimport * as MoodleNetAuthorize from 'core/moodlenet/authorize';\nimport MoodleNetEvents from 'core/moodlenet/events';\n\nconst TYPE_ACTIVITY = \"activity\";\nconst TYPE_COURSE = \"course\";\nconst TYPE_PARTIAL_COURSE = \"partial\";\n\nlet listenersRegistered = false;\nlet currentModal;\nlet siteSupportUrl;\nlet issuerId;\nlet courseId;\nlet resourceId;\nlet shareFormat;\nlet type;\nlet selectedCmIds;\n\n/**\n * Handle send to MoodleNet.\n *\n * @param {int} issuerId The OAuth 2 issuer ID.\n * @param {int} resourceId The resource ID, it can be a course or an activity.\n * @param {int} shareFormat The share format.\n */\nexport const sendToMoodleNet = (issuerId, resourceId, shareFormat) => {\n const $modal = currentModal.getModal();\n const modal = $modal[0];\n modal.querySelector('.modal-header').classList.remove('no-border');\n modal.querySelector('.modal-header').classList.add('no-header-text');\n\n currentModal.setBody(Templates.render('core/moodlenet/send_activity_modal_packaging', {}));\n currentModal.hideFooter();\n\n let infoPromise;\n if (type === TYPE_ACTIVITY) {\n infoPromise = MoodleNetService.sendActivity(issuerId, resourceId, shareFormat);\n } else if (type === TYPE_COURSE) {\n infoPromise = MoodleNetService.sendCourse(issuerId, resourceId, shareFormat);\n } else if (type === TYPE_PARTIAL_COURSE) {\n if (selectedCmIds.length > 1) {\n infoPromise = MoodleNetService.sendPartialCourse(issuerId, resourceId, selectedCmIds, shareFormat);\n } else {\n infoPromise = MoodleNetService.sendActivity(issuerId, selectedCmIds[0], shareFormat);\n }\n }\n infoPromise.then(async(data) => {\n const status = data.status;\n const resourceUrl = data.resourceurl;\n return responseFromMoodleNet(status, resourceUrl);\n }).catch(displayException);\n};\n\n/**\n * Handle response from MoodleNet.\n *\n * @param {boolean} status Response status. True if successful.\n * @param {String} resourceUrl Resource URL.\n */\nconst responseFromMoodleNet = (status, resourceUrl = '') => {\n const $modal = currentModal.getModal();\n const modal = $modal[0];\n modal.querySelector('.modal-header').classList.add('no-border');\n currentModal.setBody(Templates.render('core/moodlenet/send_activity_modal_done', {\n success: status,\n sitesupporturl: siteSupportUrl,\n }));\n\n if (status) {\n currentModal.setFooter(Templates.render('core/moodlenet/send_activity_modal_footer_view', {\n resourceurl: resourceUrl,\n }));\n currentModal.showFooter();\n }\n};\n\n/**\n * Render the modal to send resource to MoodleNet.\n *\n * @param {object} data The data of the resource to be shared.\n * @param {array} selectedActivities Selected activities.\n */\nconst renderModal = async(data, selectedActivities) => {\n if (data.status) {\n siteSupportUrl = data.supportpageurl;\n issuerId = data.issuerid;\n let modalConfig = {\n templateContext: {\n 'activitytype': data.type,\n 'activityname': data.name,\n 'server': data.server,\n }\n };\n if (selectedActivities.length > 0) {\n selectedCmIds = selectedActivities;\n }\n if (selectedActivities.length > 1) {\n modalConfig.templateContext.fullsharing = false;\n modalConfig.templateContext.selectedactivitiesnotice = await getString('moodlenet:sharenoticepartialactivitynumber',\n 'moodle', selectedActivities.length);\n modalConfig.templateContext.sharenotice = await getString('moodlenet:sharenoticepartial', 'moodle');\n } else {\n modalConfig.templateContext.fullsharing = true;\n if (type === TYPE_ACTIVITY || (type === TYPE_PARTIAL_COURSE && selectedActivities.length == 1)) {\n modalConfig.templateContext.sharenotice = await getString('moodlenet:sharenoticeactivity', 'moodle');\n } else {\n modalConfig.templateContext.sharenotice = await getString('moodlenet:sharenoticecourse', 'moodle');\n }\n }\n\n return SendActivityModal.create(modalConfig);\n } else {\n return addNotification({\n message: data.warnings[0].message,\n type: 'error'\n });\n }\n};\n\n/**\n * Handle modal.\n * @param {string} shareActionType Share action type.\n * @param {array} selectedActivities Selected activities.\n */\nexport const handleModal = (shareActionType, selectedActivities = []) => {\n const resourceId = Config.contextInstanceId;\n type = shareActionType;\n\n Promise.resolve(type)\n .then((type) => {\n if (type === TYPE_ACTIVITY) {\n return MoodleNetService.getActivityInformation(resourceId);\n } else if (type === TYPE_COURSE) {\n return MoodleNetService.getCourseInformation(resourceId);\n } else if (type === TYPE_PARTIAL_COURSE) {\n if (selectedActivities.length > 1) {\n // Selected more than one activity.\n return MoodleNetService.getCourseInformation(resourceId);\n } else {\n // Select only one activity. Switch to activity mode.\n return MoodleNetService.getActivityInformation(selectedActivities[0]);\n }\n }\n throw new Error(`Unknown type ${type}`);\n })\n .then((data) => {\n return renderModal(data, selectedActivities);\n })\n .then((modal) => {\n currentModal = modal;\n return currentModal;\n })\n .catch(displayException);\n};\n\n/**\n * Register events.\n */\nconst registerEventListeners = () => {\n document.addEventListener('click', (e) => {\n const shareAction = e.target.closest('[data-action=\"sendtomoodlenet\"]');\n const sendAction = e.target.closest('.moodlenet-action-buttons [data-action=\"share\"]');\n if (shareAction) {\n e.preventDefault();\n type = shareAction.getAttribute('data-type');\n handleModal(shareAction.getAttribute('data-type'));\n }\n\n if (sendAction) {\n e.preventDefault();\n publish(MoodleNetEvents.MOODLENET_SHARE_STARTED, {});\n courseId = Config.courseId;\n resourceId = Config.contextInstanceId;\n shareFormat = 0;\n MoodleNetAuthorize.handleAuthorization(issuerId, courseId, resourceId, shareFormat);\n }\n });\n};\n\n\n/**\n * Initialize.\n */\nexport const init = () => {\n if (!listenersRegistered) {\n Prefetch.prefetchTemplates([\n 'core/moodlenet/send_activity_modal_base',\n 'core/moodlenet/send_activity_modal_packaging',\n 'core/moodlenet/send_activity_modal_done',\n 'core/moodlenet/send_activity_modal_footer_view',\n 'core/moodlenet/send_activity_modal_footer_share',\n ]);\n registerEventListeners();\n listenersRegistered = true;\n }\n};\n"],"names":["currentModal","siteSupportUrl","issuerId","courseId","resourceId","shareFormat","type","selectedCmIds","listenersRegistered","modal","getModal","infoPromise","querySelector","classList","remove","add","setBody","Templates","render","hideFooter","MoodleNetService","sendActivity","sendCourse","length","sendPartialCourse","then","async","status","data","resourceUrl","resourceurl","responseFromMoodleNet","catch","displayException","$modal","success","sitesupporturl","setFooter","showFooter","renderModal","selectedActivities","supportpageurl","issuerid","modalConfig","templateContext","name","server","fullsharing","selectedactivitiesnotice","sharenotice","SendActivityModal","create","message","warnings","handleModal","shareActionType","Config","contextInstanceId","Promise","resolve","getActivityInformation","getCourseInformation","Error","prefetchTemplates","document","addEventListener","e","shareAction","target","closest","sendAction","preventDefault","getAttribute","MoodleNetEvents","MOODLENET_SHARE_STARTED","MoodleNetAuthorize","handleAuthorization"],"mappings":";;;;;;;;yeAwCIA,aACAC,eACAC,SACAC,SACAC,WACAC,YACAC,KACAC,cARAC,qBAAsB,2BAiBK,CAACN,SAAUE,WAAYC,qBAE5CI,MADST,aAAaU,WACP,OAOjBC,YANJF,MAAMG,cAAc,iBAAiBC,UAAUC,OAAO,aACtDL,MAAMG,cAAc,iBAAiBC,UAAUE,IAAI,kBAEnDf,aAAagB,QAAQC,UAAUC,OAAO,+CAAgD,KACtFlB,aAAamB,aA5BK,aA+Bdb,KACAK,YAAcS,iBAAiBC,aAAanB,SAAUE,WAAYC,aA/BtD,WAgCLC,KACPK,YAAcS,iBAAiBE,WAAWpB,SAAUE,WAAYC,aAhC5C,YAiCbC,OAEHK,YADAJ,cAAcgB,OAAS,EACTH,iBAAiBI,kBAAkBtB,SAAUE,WAAYG,cAAeF,aAExEe,iBAAiBC,aAAanB,SAAUK,cAAc,GAAIF,cAGhFM,YAAYc,MAAKC,MAAAA,aACPC,OAASC,KAAKD,OACdE,YAAcD,KAAKE,mBAClBC,sBAAsBJ,OAAQE,gBACtCG,MAAMC,gCASPF,sBAAwB,SAACJ,YAAQE,mEAAc,SAC3CK,OAASlC,aAAaU,WACtBD,MAAQyB,OAAO,GACrBzB,MAAMG,cAAc,iBAAiBC,UAAUE,IAAI,aACnDf,aAAagB,QAAQC,UAAUC,OAAO,0CAA2C,CAC7EiB,QAASR,OACTS,eAAgBnC,kBAGhB0B,SACA3B,aAAaqC,UAAUpB,UAAUC,OAAO,iDAAkD,CACtFY,YAAaD,eAEjB7B,aAAasC,eAUfC,YAAcb,MAAME,KAAMY,yBACxBZ,KAAKD,OAAQ,CACb1B,eAAiB2B,KAAKa,eACtBvC,SAAW0B,KAAKc,aACZC,YAAc,CACdC,gBAAiB,cACGhB,KAAKtB,kBACLsB,KAAKiB,YACXjB,KAAKkB,gBAGnBN,mBAAmBjB,OAAS,IAC5BhB,cAAgBiC,oBAEhBA,mBAAmBjB,OAAS,GAC5BoB,YAAYC,gBAAgBG,aAAc,EAC1CJ,YAAYC,gBAAgBI,+BAAiC,kBAAU,6CACnE,SAAUR,mBAAmBjB,QACjCoB,YAAYC,gBAAgBK,kBAAoB,kBAAU,+BAAgC,YAE1FN,YAAYC,gBAAgBG,aAAc,EAlGhC,aAmGNzC,MAjGY,YAiGeA,MAA6D,GAA7BkC,mBAAmBjB,OAC9EoB,YAAYC,gBAAgBK,kBAAoB,kBAAU,gCAAiC,UAE3FN,YAAYC,gBAAgBK,kBAAoB,kBAAU,8BAA+B,WAI1FC,6BAAkBC,OAAOR,oBAEzB,iCAAgB,CACnBS,QAASxB,KAAKyB,SAAS,GAAGD,QAC1B9C,KAAM,WAULgD,YAAc,SAACC,qBAAiBf,0EAAqB,SACxDpC,WAAaoD,gBAAOC,kBAC1BnD,KAAOiD,gBAEPG,QAAQC,QAAQrD,MACXmB,MAAMnB,UA7HO,aA8HNA,YACOc,iBAAiBwC,uBAAuBxD,YAC5C,GA/HC,WA+HGE,YACAc,iBAAiByC,qBAAqBzD,YAC1C,GAhIS,YAgILE,YACHkC,mBAAmBjB,OAAS,EAErBH,iBAAiByC,qBAAqBzD,YAGtCgB,iBAAiBwC,uBAAuBpB,mBAAmB,UAGpE,IAAIsB,6BAAsBxD,UAEnCmB,MAAMG,MACIW,YAAYX,KAAMY,sBAE5Bf,MAAMhB,QACHT,aAAeS,MACRT,gBAEVgC,MAAMC,yEA+BK,KACXzB,wCACQuD,kBAAkB,CACvB,0CACA,+CACA,0CACA,iDACA,oDA/BRC,SAASC,iBAAiB,SAAUC,UAC1BC,YAAcD,EAAEE,OAAOC,QAAQ,mCAC/BC,WAAaJ,EAAEE,OAAOC,QAAQ,mDAChCF,cACAD,EAAEK,iBACFjE,KAAO6D,YAAYK,aAAa,aAChClB,YAAYa,YAAYK,aAAa,eAGrCF,aACAJ,EAAEK,qCACME,gBAAgBC,wBAAyB,IACjDvE,SAAWqD,gBAAOrD,SAClBC,WAAaoD,gBAAOC,kBACpBpD,YAAc,EACdsE,mBAAmBC,oBAAoB1E,SAAUC,SAAUC,WAD7C,OAoBlBI,qBAAsB"} \ No newline at end of file diff --git a/public/lib/amd/build/moodlenet/service.min.js b/public/lib/amd/build/moodlenet/service.min.js deleted file mode 100644 index 9de4f89b072..00000000000 --- a/public/lib/amd/build/moodlenet/service.min.js +++ /dev/null @@ -1,11 +0,0 @@ -define("core/moodlenet/service",["exports","core/ajax"],(function(_exports,_ajax){var obj; -/** - * A javascript module to handle MoodleNet ajax actions. - * - * @module core/moodlenet/service - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @since 4.2 - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.sendPartialCourse=_exports.sendCourse=_exports.sendActivity=_exports.getCourseInformation=_exports.getActivityInformation=_exports.authorizationCheck=void 0,_ajax=(obj=_ajax)&&obj.__esModule?obj:{default:obj};_exports.getActivityInformation=cmId=>{const request={methodname:"core_moodlenet_get_share_info_activity",args:{cmid:cmId}};return _ajax.default.call([request])[0]};_exports.getCourseInformation=courseID=>{const request={methodname:"core_moodlenet_get_shared_course_info",args:{courseid:courseID}};return _ajax.default.call([request])[0]};_exports.sendCourse=(issuerId,courseId,shareFormat)=>{const request={methodname:"core_moodlenet_send_course",args:{issuerid:issuerId,courseid:courseId,shareformat:shareFormat}};return _ajax.default.call([request])[0]};_exports.sendActivity=(issuerId,cmId,shareFormat)=>{const request={methodname:"core_moodlenet_send_activity",args:{issuerid:issuerId,cmid:cmId,shareformat:shareFormat}};return _ajax.default.call([request])[0]};_exports.sendPartialCourse=(issuerId,courseId,selectedCmIds,shareFormat)=>{const request={methodname:"core_moodlenet_send_course",args:{issuerid:issuerId,courseid:courseId,shareformat:shareFormat,cmids:selectedCmIds}};return _ajax.default.call([request])[0]};_exports.authorizationCheck=(issuerId,courseId)=>{const request={methodname:"core_moodlenet_auth_check",args:{issuerid:issuerId,courseid:courseId}};return _ajax.default.call([request])[0]}})); - -//# sourceMappingURL=service.min.js.map \ No newline at end of file diff --git a/public/lib/amd/build/moodlenet/service.min.js.map b/public/lib/amd/build/moodlenet/service.min.js.map deleted file mode 100644 index f0fea22d072..00000000000 --- a/public/lib/amd/build/moodlenet/service.min.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"service.min.js","sources":["../../src/moodlenet/service.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * A javascript module to handle MoodleNet ajax actions.\n *\n * @module core/moodlenet/service\n * @copyright 2023 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 4.2\n */\n\nimport Ajax from 'core/ajax';\n\n/**\n * Get the activity information by course module id.\n *\n * @param {Integer} cmId The course module id.\n * @return {promise}\n */\nexport const getActivityInformation = (cmId) => {\n const request = {\n methodname: 'core_moodlenet_get_share_info_activity',\n args: {\n cmid: cmId\n }\n };\n\n return Ajax.call([request])[0];\n};\n\n\n/**\n * Get the course information by course module id.\n *\n * @param {Integer} courseID The course id.\n * @return {promise}\n */\nexport const getCourseInformation = (courseID) => {\n const request = {\n methodname: 'core_moodlenet_get_shared_course_info',\n args: {\n courseid: courseID\n }\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Send the course to MoodleNet.\n *\n * @param {Integer} issuerId The OAuth 2 issuer ID.\n * @param {Integer} courseId The course ID.\n * @param {Integer} shareFormat The share format.\n * @return {promise}\n */\nexport const sendCourse = (issuerId, courseId, shareFormat) => {\n const request = {\n methodname: 'core_moodlenet_send_course',\n args: {\n issuerid: issuerId,\n courseid: courseId,\n shareformat: shareFormat,\n }\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Send the activity to Moodlenet.\n *\n * @param {Integer} issuerId The OAuth 2 issuer ID.\n * @param {Integer} cmId The course module ID.\n * @param {Integer} shareFormat The share format.\n * @return {promise}\n */\nexport const sendActivity = (issuerId, cmId, shareFormat) => {\n const request = {\n methodname: 'core_moodlenet_send_activity',\n args: {\n issuerid: issuerId,\n cmid: cmId,\n shareformat: shareFormat,\n }\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Send the selected activities in a course to MoodleNet.\n *\n * @param {Integer} issuerId The OAuth 2 issuer ID.\n * @param {Integer} courseId The course ID.\n * @param {array} selectedCmIds Course module IDs in the course.\n * @param {Integer} shareFormat The share format.\n * @return {promise}\n */\nexport const sendPartialCourse = (issuerId, courseId, selectedCmIds, shareFormat) => {\n const request = {\n methodname: 'core_moodlenet_send_course',\n args: {\n issuerid: issuerId,\n courseid: courseId,\n shareformat: shareFormat,\n cmids: selectedCmIds,\n }\n };\n\n return Ajax.call([request])[0];\n};\n\n/**\n * Check if the user is already authorized with MoodleNet.\n *\n * @param {Integer} issuerId The OAuth 2 issuer ID.\n * @param {Integer} courseId The course ID.\n * @return {promise}\n */\nexport const authorizationCheck = (issuerId, courseId) => {\n const request = {\n methodname: 'core_moodlenet_auth_check',\n args: {\n issuerid: issuerId,\n courseid: courseId,\n }\n };\n\n return Ajax.call([request])[0];\n};\n"],"names":["cmId","request","methodname","args","cmid","Ajax","call","courseID","courseid","issuerId","courseId","shareFormat","issuerid","shareformat","selectedCmIds","cmids"],"mappings":";;;;;;;;uTAgCuCA,aAC7BC,QAAU,CACZC,WAAY,yCACZC,KAAM,CACFC,KAAMJ,cAIPK,cAAKC,KAAK,CAACL,UAAU,kCAUKM,iBAC3BN,QAAU,CACZC,WAAY,wCACZC,KAAM,CACFK,SAAUD,kBAIXF,cAAKC,KAAK,CAACL,UAAU,wBAWN,CAACQ,SAAUC,SAAUC,qBACrCV,QAAU,CACZC,WAAY,6BACZC,KAAM,CACFS,SAAUH,SACVD,SAAUE,SACVG,YAAaF,qBAIdN,cAAKC,KAAK,CAACL,UAAU,0BAWJ,CAACQ,SAAUT,KAAMW,qBACnCV,QAAU,CACZC,WAAY,+BACZC,KAAM,CACFS,SAAUH,SACVL,KAAMJ,KACNa,YAAaF,qBAIdN,cAAKC,KAAK,CAACL,UAAU,+BAYC,CAACQ,SAAUC,SAAUI,cAAeH,qBAC3DV,QAAU,CACZC,WAAY,6BACZC,KAAM,CACFS,SAAUH,SACVD,SAAUE,SACVG,YAAaF,YACbI,MAAOD,uBAIRT,cAAKC,KAAK,CAACL,UAAU,gCAUE,CAACQ,SAAUC,kBACnCT,QAAU,CACZC,WAAY,4BACZC,KAAM,CACFS,SAAUH,SACVD,SAAUE,kBAIXL,cAAKC,KAAK,CAACL,UAAU"} \ No newline at end of file diff --git a/public/lib/amd/src/moodlenet/authorize.js b/public/lib/amd/src/moodlenet/authorize.js deleted file mode 100644 index d3e29bca02f..00000000000 --- a/public/lib/amd/src/moodlenet/authorize.js +++ /dev/null @@ -1,67 +0,0 @@ -// 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 . - -/** - * MoodleNet authorization. - * - * @module core/moodlenet/authorize - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @since 4.3 - */ - -import {alert as displayAlert, exception as displayException} from 'core/notification'; -import * as MoodleNetService from 'core/moodlenet/service'; -import {sendToMoodleNet} from 'core/moodlenet/send_resource'; - -/** - * Handle authorization with MoodleNet server. - * - * @param {int} issuerId The OAuth 2 issuer ID. - * @param {int} courseId Course id. - * @param {int} resourceId Resource id. - * @param {int} shareFormat Share format. - * @return {promise} - */ -export const handleAuthorization = (issuerId, courseId, resourceId, shareFormat) => { - const windowSizeWidth = 550; - const windowSizeHeight = 550; - - // Check if the user is authorized with MoodleNet or not. - return MoodleNetService.authorizationCheck(issuerId, courseId).then(async(data) => { - if (!data.status) { - // Not yet authorized. - // Declare moodleNetAuthorize variable, so we can call it later in the callback. - window.moodleNetAuthorize = (error, errorDescription) => { - // This will be called by the callback after the authorization is successful. - if (error === '') { - handleAuthorization(issuerId, courseId, resourceId, shareFormat); - } else if (error !== 'access_denied') { - displayAlert( - 'Authorization error', - 'Error: ' + error + '

Error description: ' + errorDescription, - 'Cancel' - ); - } - }; - // Open the login url of the OAuth 2 issuer for user to login into MoodleNet and authorize. - return window.open(data.loginurl, 'moodlenet_auth', - `location=0,status=0,width=${windowSizeWidth},height=${windowSizeHeight},scrollbars=yes`); - } else { - // Already authorized. - return sendToMoodleNet(issuerId, resourceId, shareFormat); - } - }).catch(displayException); -}; diff --git a/public/lib/amd/src/moodlenet/events.js b/public/lib/amd/src/moodlenet/events.js deleted file mode 100644 index 90e008d42f9..00000000000 --- a/public/lib/amd/src/moodlenet/events.js +++ /dev/null @@ -1,27 +0,0 @@ -// 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 . - -/** - * MoodleNet events. - * - * @module core/moodlenet/events - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @since 4.3 - */ - -export default { - MOODLENET_SHARE_STARTED: 'moodlenet-share-started', -}; diff --git a/public/lib/amd/src/moodlenet/mutations.js b/public/lib/amd/src/moodlenet/mutations.js deleted file mode 100644 index 1ae2244c75f..00000000000 --- a/public/lib/amd/src/moodlenet/mutations.js +++ /dev/null @@ -1,65 +0,0 @@ -// 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 . - -/** - * MoodleNet mutations. - * An instance of this class will be used to add custom mutations to the course editor. - * - * @module core/moodlenet/mutations - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @since 4.3 - */ - -import DefaultMutations from 'core_courseformat/local/courseeditor/mutations'; -import {getCurrentCourseEditor} from 'core_courseformat/courseeditor'; -import CourseActions from 'core_courseformat/local/content/actions'; -import {subscribe} from 'core/pubsub'; -import {handleModal} from 'core/moodlenet/send_resource'; -import MoodleNetEvents from 'core/moodlenet/events'; - -class MoodleNetMutations extends DefaultMutations { - - /** - * Share to MoodleNet. - * - * @param {StateManager} stateManager the current state manager - * @param {array} cmIds Course module ids. - */ - shareToMoodleNet = async function(stateManager, cmIds) { - if (cmIds.length == 0) { - return; - } - this.cmLock(stateManager, cmIds, true); - handleModal('partial', cmIds); - this.cmLock(stateManager, cmIds, false); - subscribe(MoodleNetEvents.MOODLENET_SHARE_STARTED, () => { - // Only clear the selection if the user starts the sharing. - this.bulkReset(stateManager); - }); - }; -} - -/** - * Initialize. - */ -export const init = () => { - const courseEditor = getCurrentCourseEditor(); - courseEditor.addMutations(new MoodleNetMutations()); - // Add direct mutation content actions. - CourseActions.addActions({ - cmShareToMoodleNet: 'shareToMoodleNet' - }); -}; diff --git a/public/lib/amd/src/moodlenet/oauth2callback.js b/public/lib/amd/src/moodlenet/oauth2callback.js deleted file mode 100644 index 552fb33d22f..00000000000 --- a/public/lib/amd/src/moodlenet/oauth2callback.js +++ /dev/null @@ -1,60 +0,0 @@ -// 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 . - -/** - * A module to handle the OAuth2 callback for MoodleNet. - * - * @module core/moodlenet/oauth2callback - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @since 4.2 - */ - -import Prefetch from "core/prefetch"; -import {alert} from 'core/notification'; -import {getString} from 'core/str'; - -/** - * Handle the OAuth2 callback for MoodleNet. - * - * @param {String} error Error - * @param {String} errorDescription Error description - */ -const handleCallback = (error, errorDescription) => { - if (window.opener) { - // Call the MoodleNet Authorization again in the opener window. - window.opener.moodleNetAuthorize(error, errorDescription); - // Close the authorization popup. - // We need to use setTimeout here because the Behat 'I press "x" and switch to main window' step expects the popup to still - // be visible after clicking the button. Otherwise, it will throw a webdriver error. - setTimeout(() => { - // Close the authorization popup. - window.close(); - }, 300); - } else { - alert(getString('error', 'moodle'), getString('moodlenet:sharefailtitle', 'moodle')); - } -}; - -/** - * Initialize. - * - * @param {String} error Error - * @param {String} errorDescription Error description - */ -export const init = (error, errorDescription) => { - Prefetch.prefetchStrings('moodle', ['moodlenet:sharefailtitle', 'error']); - handleCallback(error, errorDescription); -}; diff --git a/public/lib/amd/src/moodlenet/send_activity_modal.js b/public/lib/amd/src/moodlenet/send_activity_modal.js deleted file mode 100644 index aed47743083..00000000000 --- a/public/lib/amd/src/moodlenet/send_activity_modal.js +++ /dev/null @@ -1,47 +0,0 @@ -// 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 . - -/** - * Send activity modal for MoodleNet. - * - * @module core/moodlenet/send_activity_modal - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @since 4.2 - */ - -import Modal from 'core/modal'; - -export default class SendActivityModal extends Modal { - static TYPE = 'core/moodlenet/send_activity_modal'; - static TEMPLATE = 'core/moodlenet/send_activity_modal_base'; - - registerEventListeners() { - // Call the parent registration. - super.registerEventListeners(); - - // Register to close on save/cancel. - this.registerCloseOnSave(); - this.registerCloseOnCancel(); - } - - configure(modalConfig) { - modalConfig.show = true; - modalConfig.large = true; - super.configure(modalConfig); - } -} - -SendActivityModal.registerModalType(); diff --git a/public/lib/amd/src/moodlenet/send_resource.js b/public/lib/amd/src/moodlenet/send_resource.js deleted file mode 100644 index c3834c9435e..00000000000 --- a/public/lib/amd/src/moodlenet/send_resource.js +++ /dev/null @@ -1,227 +0,0 @@ -// 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 . - -/** - * A module to handle Share operations of the MoodleNet. - * - * @module core/moodlenet/send_resource - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @since 4.2 - */ - -import Config from 'core/config'; -import {addNotification, exception as displayException} from 'core/notification'; -import {getString} from 'core/str'; -import Prefetch from "core/prefetch"; -import * as Templates from 'core/templates'; -import {publish} from 'core/pubsub'; -import * as MoodleNetService from 'core/moodlenet/service'; -import SendActivityModal from 'core/moodlenet/send_activity_modal'; -import * as MoodleNetAuthorize from 'core/moodlenet/authorize'; -import MoodleNetEvents from 'core/moodlenet/events'; - -const TYPE_ACTIVITY = "activity"; -const TYPE_COURSE = "course"; -const TYPE_PARTIAL_COURSE = "partial"; - -let listenersRegistered = false; -let currentModal; -let siteSupportUrl; -let issuerId; -let courseId; -let resourceId; -let shareFormat; -let type; -let selectedCmIds; - -/** - * Handle send to MoodleNet. - * - * @param {int} issuerId The OAuth 2 issuer ID. - * @param {int} resourceId The resource ID, it can be a course or an activity. - * @param {int} shareFormat The share format. - */ -export const sendToMoodleNet = (issuerId, resourceId, shareFormat) => { - const $modal = currentModal.getModal(); - const modal = $modal[0]; - modal.querySelector('.modal-header').classList.remove('no-border'); - modal.querySelector('.modal-header').classList.add('no-header-text'); - - currentModal.setBody(Templates.render('core/moodlenet/send_activity_modal_packaging', {})); - currentModal.hideFooter(); - - let infoPromise; - if (type === TYPE_ACTIVITY) { - infoPromise = MoodleNetService.sendActivity(issuerId, resourceId, shareFormat); - } else if (type === TYPE_COURSE) { - infoPromise = MoodleNetService.sendCourse(issuerId, resourceId, shareFormat); - } else if (type === TYPE_PARTIAL_COURSE) { - if (selectedCmIds.length > 1) { - infoPromise = MoodleNetService.sendPartialCourse(issuerId, resourceId, selectedCmIds, shareFormat); - } else { - infoPromise = MoodleNetService.sendActivity(issuerId, selectedCmIds[0], shareFormat); - } - } - infoPromise.then(async(data) => { - const status = data.status; - const resourceUrl = data.resourceurl; - return responseFromMoodleNet(status, resourceUrl); - }).catch(displayException); -}; - -/** - * Handle response from MoodleNet. - * - * @param {boolean} status Response status. True if successful. - * @param {String} resourceUrl Resource URL. - */ -const responseFromMoodleNet = (status, resourceUrl = '') => { - const $modal = currentModal.getModal(); - const modal = $modal[0]; - modal.querySelector('.modal-header').classList.add('no-border'); - currentModal.setBody(Templates.render('core/moodlenet/send_activity_modal_done', { - success: status, - sitesupporturl: siteSupportUrl, - })); - - if (status) { - currentModal.setFooter(Templates.render('core/moodlenet/send_activity_modal_footer_view', { - resourceurl: resourceUrl, - })); - currentModal.showFooter(); - } -}; - -/** - * Render the modal to send resource to MoodleNet. - * - * @param {object} data The data of the resource to be shared. - * @param {array} selectedActivities Selected activities. - */ -const renderModal = async(data, selectedActivities) => { - if (data.status) { - siteSupportUrl = data.supportpageurl; - issuerId = data.issuerid; - let modalConfig = { - templateContext: { - 'activitytype': data.type, - 'activityname': data.name, - 'server': data.server, - } - }; - if (selectedActivities.length > 0) { - selectedCmIds = selectedActivities; - } - if (selectedActivities.length > 1) { - modalConfig.templateContext.fullsharing = false; - modalConfig.templateContext.selectedactivitiesnotice = await getString('moodlenet:sharenoticepartialactivitynumber', - 'moodle', selectedActivities.length); - modalConfig.templateContext.sharenotice = await getString('moodlenet:sharenoticepartial', 'moodle'); - } else { - modalConfig.templateContext.fullsharing = true; - if (type === TYPE_ACTIVITY || (type === TYPE_PARTIAL_COURSE && selectedActivities.length == 1)) { - modalConfig.templateContext.sharenotice = await getString('moodlenet:sharenoticeactivity', 'moodle'); - } else { - modalConfig.templateContext.sharenotice = await getString('moodlenet:sharenoticecourse', 'moodle'); - } - } - - return SendActivityModal.create(modalConfig); - } else { - return addNotification({ - message: data.warnings[0].message, - type: 'error' - }); - } -}; - -/** - * Handle modal. - * @param {string} shareActionType Share action type. - * @param {array} selectedActivities Selected activities. - */ -export const handleModal = (shareActionType, selectedActivities = []) => { - const resourceId = Config.contextInstanceId; - type = shareActionType; - - Promise.resolve(type) - .then((type) => { - if (type === TYPE_ACTIVITY) { - return MoodleNetService.getActivityInformation(resourceId); - } else if (type === TYPE_COURSE) { - return MoodleNetService.getCourseInformation(resourceId); - } else if (type === TYPE_PARTIAL_COURSE) { - if (selectedActivities.length > 1) { - // Selected more than one activity. - return MoodleNetService.getCourseInformation(resourceId); - } else { - // Select only one activity. Switch to activity mode. - return MoodleNetService.getActivityInformation(selectedActivities[0]); - } - } - throw new Error(`Unknown type ${type}`); - }) - .then((data) => { - return renderModal(data, selectedActivities); - }) - .then((modal) => { - currentModal = modal; - return currentModal; - }) - .catch(displayException); -}; - -/** - * Register events. - */ -const registerEventListeners = () => { - document.addEventListener('click', (e) => { - const shareAction = e.target.closest('[data-action="sendtomoodlenet"]'); - const sendAction = e.target.closest('.moodlenet-action-buttons [data-action="share"]'); - if (shareAction) { - e.preventDefault(); - type = shareAction.getAttribute('data-type'); - handleModal(shareAction.getAttribute('data-type')); - } - - if (sendAction) { - e.preventDefault(); - publish(MoodleNetEvents.MOODLENET_SHARE_STARTED, {}); - courseId = Config.courseId; - resourceId = Config.contextInstanceId; - shareFormat = 0; - MoodleNetAuthorize.handleAuthorization(issuerId, courseId, resourceId, shareFormat); - } - }); -}; - - -/** - * Initialize. - */ -export const init = () => { - if (!listenersRegistered) { - Prefetch.prefetchTemplates([ - 'core/moodlenet/send_activity_modal_base', - 'core/moodlenet/send_activity_modal_packaging', - 'core/moodlenet/send_activity_modal_done', - 'core/moodlenet/send_activity_modal_footer_view', - 'core/moodlenet/send_activity_modal_footer_share', - ]); - registerEventListeners(); - listenersRegistered = true; - } -}; diff --git a/public/lib/amd/src/moodlenet/service.js b/public/lib/amd/src/moodlenet/service.js deleted file mode 100644 index 11dafb27e7c..00000000000 --- a/public/lib/amd/src/moodlenet/service.js +++ /dev/null @@ -1,144 +0,0 @@ -// 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 . - -/** - * A javascript module to handle MoodleNet ajax actions. - * - * @module core/moodlenet/service - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @since 4.2 - */ - -import Ajax from 'core/ajax'; - -/** - * Get the activity information by course module id. - * - * @param {Integer} cmId The course module id. - * @return {promise} - */ -export const getActivityInformation = (cmId) => { - const request = { - methodname: 'core_moodlenet_get_share_info_activity', - args: { - cmid: cmId - } - }; - - return Ajax.call([request])[0]; -}; - - -/** - * Get the course information by course module id. - * - * @param {Integer} courseID The course id. - * @return {promise} - */ -export const getCourseInformation = (courseID) => { - const request = { - methodname: 'core_moodlenet_get_shared_course_info', - args: { - courseid: courseID - } - }; - - return Ajax.call([request])[0]; -}; - -/** - * Send the course to MoodleNet. - * - * @param {Integer} issuerId The OAuth 2 issuer ID. - * @param {Integer} courseId The course ID. - * @param {Integer} shareFormat The share format. - * @return {promise} - */ -export const sendCourse = (issuerId, courseId, shareFormat) => { - const request = { - methodname: 'core_moodlenet_send_course', - args: { - issuerid: issuerId, - courseid: courseId, - shareformat: shareFormat, - } - }; - - return Ajax.call([request])[0]; -}; - -/** - * Send the activity to Moodlenet. - * - * @param {Integer} issuerId The OAuth 2 issuer ID. - * @param {Integer} cmId The course module ID. - * @param {Integer} shareFormat The share format. - * @return {promise} - */ -export const sendActivity = (issuerId, cmId, shareFormat) => { - const request = { - methodname: 'core_moodlenet_send_activity', - args: { - issuerid: issuerId, - cmid: cmId, - shareformat: shareFormat, - } - }; - - return Ajax.call([request])[0]; -}; - -/** - * Send the selected activities in a course to MoodleNet. - * - * @param {Integer} issuerId The OAuth 2 issuer ID. - * @param {Integer} courseId The course ID. - * @param {array} selectedCmIds Course module IDs in the course. - * @param {Integer} shareFormat The share format. - * @return {promise} - */ -export const sendPartialCourse = (issuerId, courseId, selectedCmIds, shareFormat) => { - const request = { - methodname: 'core_moodlenet_send_course', - args: { - issuerid: issuerId, - courseid: courseId, - shareformat: shareFormat, - cmids: selectedCmIds, - } - }; - - return Ajax.call([request])[0]; -}; - -/** - * Check if the user is already authorized with MoodleNet. - * - * @param {Integer} issuerId The OAuth 2 issuer ID. - * @param {Integer} courseId The course ID. - * @return {promise} - */ -export const authorizationCheck = (issuerId, courseId) => { - const request = { - methodname: 'core_moodlenet_auth_check', - args: { - issuerid: issuerId, - courseid: courseId, - } - }; - - return Ajax.call([request])[0]; -}; diff --git a/public/lib/apis.json b/public/lib/apis.json index a765940c784..6821d49698f 100644 --- a/public/lib/apis.json +++ b/public/lib/apis.json @@ -184,11 +184,6 @@ "allowedlevel2": true, "allowedspread": true }, - "moodlenet": { - "component": "core", - "allowedlevel2": false, - "allowedspread": false - }, "navigation": { "component": "core", "allowedlevel2": true, diff --git a/public/lib/classes/event/moodlenet_resource_exported.php b/public/lib/classes/event/moodlenet_resource_exported.php deleted file mode 100644 index 967dd27d08e..00000000000 --- a/public/lib/classes/event/moodlenet_resource_exported.php +++ /dev/null @@ -1,78 +0,0 @@ -. - -namespace core\event; - -/** - * MoodleNet send attempt event. - * - * @package core - * @copyright 2023 Michael Hawkins - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class moodlenet_resource_exported extends \core\event\base { - - /** - * Set basic properties for the event. - * - * @return void - */ - protected function init(): void { - $this->data['crud'] = 'c'; - - // Used by teachers, but not for direct educational value to their students. - $this->data['edulevel'] = self::LEVEL_OTHER; - } - - /** - * Fetch the localised general event name. - * - * @return string - */ - public static function get_name(): string { - return get_string('moodlenet:eventresourceexported'); - } - - /** - * Fetch the non-localised event description. - * This description format is designed to work for both single activity and course sharing. - * - * @return string - */ - public function get_description() { - $outcome = $this->other['success'] ? 'successfully shared' : 'failed to share'; - - if (!empty($this->other['cmids'])) { - $cmids = implode("', '", $this->other['cmids']); - $description = "The user with id '{$this->userid}' {$outcome} activities to MoodleNet with the " . - "following course module ids, from context with id '{$this->data['contextid']}': '{$cmids}'."; - } else if (!empty($this->other['courseid'])) { - $courseid = implode("', '", $this->other['courseid']); - $description = "The user with id '{$this->userid}' {$outcome} course to MoodleNet with the " . - "following course id, from context with id '{$this->data['contextid']}': '{$courseid}'."; - } - - return rtrim($description, ", '"); - } - - /** - * Returns relevant URL. - * @return \moodle_url - */ - public function get_url() { - return new \moodle_url($this->other['resourceurl']); - } -} diff --git a/public/lib/classes/external/moodlenet_auth_check.php b/public/lib/classes/external/moodlenet_auth_check.php deleted file mode 100644 index 79553c68b6d..00000000000 --- a/public/lib/classes/external/moodlenet_auth_check.php +++ /dev/null @@ -1,148 +0,0 @@ -. - -namespace core\external; - -use context_course; -use core\moodlenet\moodlenet_client; -use core\moodlenet\utilities; -use core\oauth2\api; -use core_external\external_api; -use core_external\external_function_parameters; -use core_external\external_single_structure; -use core_external\external_value; -use core_external\external_warnings; -use moodle_url; - -/** - * The external API to check whether a user has authorized for a given MoodleNet OAuth 2 issuer. - * - * @package core - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class moodlenet_auth_check extends external_api { - - /** - * Returns description of parameters. - * - * @return external_function_parameters - * @since Moodle 4.2 - */ - public static function execute_parameters(): external_function_parameters { - return new external_function_parameters([ - 'issuerid' => new external_value(PARAM_INT, 'OAuth 2 issuer ID', VALUE_REQUIRED), - 'courseid' => new external_value(PARAM_INT, 'Course ID', VALUE_REQUIRED), - ]); - } - - /** - * External function to check if the user is already authorized with MoodleNet. - * - * @param int $issuerid Issuer Id. - * @param int $courseid The course ID that contains the activity which being shared - * @return array - * @since Moodle 4.2 - */ - public static function execute(int $issuerid, int $courseid): array { - global $USER; - [ - 'issuerid' => $issuerid, - 'courseid' => $courseid, - ] = self::validate_parameters(self::execute_parameters(), [ - 'issuerid' => $issuerid, - 'courseid' => $courseid, - ]); - - // Check capability. - $coursecontext = context_course::instance($courseid); - $usercanshareactivity = utilities::can_user_share($coursecontext, $USER->id, 'activity'); - $usercansharecourse = utilities::can_user_share($coursecontext, $USER->id, 'course'); - if (!$usercanshareactivity && !$usercansharecourse) { - return self::return_errors($courseid, 'errorpermission', - get_string('nopermissions', 'error', get_string('moodlenet:sharetomoodlenet', 'moodle'))); - } - - // Get the issuer. - $issuer = api::get_issuer($issuerid); - // Validate the issuer and check if it is enabled or not. - if (!utilities::is_valid_instance($issuer)) { - return self::return_errors($issuerid, 'errorissuernotenabled', get_string('invalidparameter', 'debug')); - } - - $returnurl = new moodle_url('/admin/moodlenet_oauth2_callback.php'); - $returnurl->param('issuerid', $issuerid); - $returnurl->param('callback', 'yes'); - $returnurl->param('sesskey', sesskey()); - - // Get the OAuth Client. - if (!$oauthclient = api::get_user_oauth_client($issuer, $returnurl, moodlenet_client::API_SCOPE_CREATE_RESOURCE, true)) { - return self::return_errors($issuerid, 'erroroauthclient', get_string('invalidparameter', 'debug')); - } - - $status = false; - $warnings = []; - $loginurl = ''; - - if (!$oauthclient->is_logged_in()) { - $loginurl = $oauthclient->get_login_url()->out(false); - } else { - $status = true; - } - - return [ - 'status' => $status, - 'loginurl' => $loginurl, - 'warnings' => $warnings, - ]; - } - - /** - * Describes the data returned from the external function. - * - * @return external_single_structure - * @since Moodle 4.2 - */ - public static function execute_returns(): external_single_structure { - return new external_single_structure([ - 'loginurl' => new external_value(PARAM_RAW, 'Login url'), - 'status' => new external_value(PARAM_BOOL, 'status: true if success'), - 'warnings' => new external_warnings(), - ]); - } - - /** - * Handle return error. - * - * @param int $itemid Item id - * @param string $warningcode Warning code - * @param string $message Message - * @return array - */ - protected static function return_errors(int $itemid, string $warningcode, string $message): array { - $warnings[] = [ - 'item' => $itemid, - 'warningcode' => $warningcode, - 'message' => $message, - ]; - - return [ - 'status' => false, - 'loginurl' => '', - 'warnings' => $warnings, - ]; - } -} diff --git a/public/lib/classes/external/moodlenet_get_share_info_activity.php b/public/lib/classes/external/moodlenet_get_share_info_activity.php deleted file mode 100644 index c649e75d94f..00000000000 --- a/public/lib/classes/external/moodlenet_get_share_info_activity.php +++ /dev/null @@ -1,152 +0,0 @@ -. - -namespace core\external; - -use context_course; -use core\moodlenet\utilities; -use core\oauth2\api; -use core_external\external_api; -use core_external\external_function_parameters; -use core_external\external_single_structure; -use core_external\external_value; -use core_external\external_warnings; - -/** - * The external API to het the activity information for MoodleNet sharing. - * - * @package core - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class moodlenet_get_share_info_activity extends external_api { - - /** - * Returns description of parameters. - * - * @return external_function_parameters - * @since Moodle 4.2 - */ - public static function execute_parameters(): external_function_parameters { - return new external_function_parameters([ - 'cmid' => new external_value(PARAM_INT, 'The cmid of the activity', VALUE_REQUIRED), - ]); - } - - /** - * External function to get the activity information. - * - * @param int $cmid The course module id. - * @return array - * @since Moodle 4.2 - */ - public static function execute(int $cmid): array { - global $CFG, $USER; - - [ - 'cmid' => $cmid - ] = self::validate_parameters(self::execute_parameters(), [ - 'cmid' => $cmid - ]); - - // Get course module. - $coursemodule = get_coursemodule_from_id(false, $cmid); - if (!$coursemodule) { - return self::return_errors($cmid, 'errorgettingactivityinformation', get_string('invalidcoursemodule', 'error')); - } - - // Get course. - $course = get_course($coursemodule->course); - - // Check capability. - $coursecontext = context_course::instance($course->id); - $usercanshare = utilities::can_user_share($coursecontext, $USER->id); - if (!$usercanshare) { - return self::return_errors($cmid, 'errorpermission', - get_string('nopermissions', 'error', get_string('moodlenet:sharetomoodlenet', 'moodle'))); - } - - $warnings = []; - $supporturl = utilities::get_support_url(); - $issuerid = get_config('moodlenet', 'oauthservice'); - - if (empty($issuerid)) { - return self::return_errors(0, 'errorissuernotset', get_string('moodlenet:issuerisnotset', 'moodle')); - } - - // Get the issuer. - $issuer = api::get_issuer($issuerid); - // Validate the issuer and check if it is enabled or not. - if (!utilities::is_valid_instance($issuer)) { - return self::return_errors($issuerid, 'errorissuernotenabled', get_string('moodlenet:issuerisnotenabled', 'moodle')); - } - - return [ - 'status' => true, - 'name' => $coursemodule->name, - 'type' => get_string('modulename', $coursemodule->modname), - 'server' => $issuer->get_display_name(), - 'supportpageurl' => $supporturl, - 'issuerid' => $issuerid, - 'warnings' => $warnings - ]; - } - - /** - * Describes the data returned from the external function. - * - * @return external_single_structure - * @since Moodle 4.2 - */ - public static function execute_returns(): external_single_structure { - return new external_single_structure([ - 'name' => new external_value(PARAM_TEXT, 'Activity name'), - 'type' => new external_value(PARAM_TEXT, 'Activity type'), - 'server' => new external_value(PARAM_TEXT, 'MoodleNet server'), - 'supportpageurl' => new external_value(PARAM_URL, 'Support page URL'), - 'issuerid' => new external_value(PARAM_INT, 'MoodleNet issuer id'), - 'status' => new external_value(PARAM_BOOL, 'status: true if success'), - 'warnings' => new external_warnings() - ]); - } - - /** - * Handle return error. - * - * @param int $itemid Item id. - * @param string $warningcode Warning code. - * @param string $message Message. - * @param int $issuerid Issuer id. - * @return array - */ - protected static function return_errors(int $itemid, string $warningcode, string $message, int $issuerid = 0): array { - $warnings[] = [ - 'item' => $itemid, - 'warningcode' => $warningcode, - 'message' => $message - ]; - - return [ - 'status' => false, - 'name' => '', - 'type' => '', - 'server' => '', - 'supportpageurl' => '', - 'issuerid' => $issuerid, - 'warnings' => $warnings - ]; - } -} diff --git a/public/lib/classes/external/moodlenet_get_shared_course_info.php b/public/lib/classes/external/moodlenet_get_shared_course_info.php deleted file mode 100644 index 656c9324d09..00000000000 --- a/public/lib/classes/external/moodlenet_get_shared_course_info.php +++ /dev/null @@ -1,143 +0,0 @@ -. - -namespace core\external; - -use context_course; -use core\moodlenet\utilities; -use core\oauth2\api; -use core_external\external_api; -use core_external\external_function_parameters; -use core_external\external_single_structure; -use core_external\external_value; -use core_external\external_warnings; - -/** - * The external API to get MoodleNet information about the course to be shared. - * - * @package core - * @copyright 2023 Safat Shahin - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @since Moodle 4.3 - */ -class moodlenet_get_shared_course_info extends external_api { - - /** - * Returns description of parameters. - * - * @return external_function_parameters - */ - public static function execute_parameters(): external_function_parameters { - return new external_function_parameters([ - 'courseid' => new external_value(PARAM_INT, 'The course id', VALUE_REQUIRED), - ]); - } - - /** - * External function to get the course information. - * - * @param int $courseid The course id - * @return array - */ - public static function execute(int $courseid): array { - global $USER; - - [ - 'courseid' => $courseid - ] = self::validate_parameters(self::execute_parameters(), [ - 'courseid' => $courseid - ]); - - // Get course. - $course = get_course($courseid); - - // Check capability. - $coursecontext = context_course::instance($course->id); - if (!utilities::can_user_share($coursecontext, $USER->id, 'course')) { - return self::return_errors($courseid, 'errorpermission', - get_string('nopermissions', 'error', get_string('moodlenet:sharetomoodlenet', 'moodle'))); - } - - $warnings = []; - $supporturl = utilities::get_support_url(); - $issuerid = get_config('moodlenet', 'oauthservice'); - - if (empty($issuerid)) { - return self::return_errors(0, 'errorissuernotset', get_string('moodlenet:issuerisnotset', 'moodle')); - } - - // Get the issuer. - $issuer = api::get_issuer($issuerid); - // Validate the issuer and check if it is enabled or not. - if (!utilities::is_valid_instance($issuer)) { - return self::return_errors($issuerid, 'errorissuernotenabled', get_string('moodlenet:issuerisnotenabled', 'moodle')); - } - - return [ - 'status' => true, - 'name' => $course->fullname, - 'type' => get_string('course'), - 'server' => $issuer->get_display_name(), - 'supportpageurl' => $supporturl, - 'issuerid' => $issuerid, - 'warnings' => $warnings - ]; - } - - /** - * Describes the data returned from the external function. - * - * @return external_single_structure - */ - public static function execute_returns(): external_single_structure { - return new external_single_structure([ - 'name' => new external_value(PARAM_TEXT, 'Course short name'), - 'type' => new external_value(PARAM_TEXT, 'Course type'), - 'server' => new external_value(PARAM_TEXT, 'MoodleNet server'), - 'supportpageurl' => new external_value(PARAM_URL, 'Support page URL'), - 'issuerid' => new external_value(PARAM_INT, 'MoodleNet issuer id'), - 'status' => new external_value(PARAM_BOOL, 'status: true if success'), - 'warnings' => new external_warnings() - ]); - } - - /** - * Handle return error. - * - * @param int $itemid Item id. - * @param string $warningcode Warning code. - * @param string $message Message. - * @param int $issuerid Issuer id. - * @return array - */ - protected static function return_errors(int $itemid, string $warningcode, string $message, int $issuerid = 0): array { - $warnings[] = [ - 'item' => $itemid, - 'warningcode' => $warningcode, - 'message' => $message - ]; - - return [ - 'status' => false, - 'name' => '', - 'type' => '', - 'server' => '', - 'supportpageurl' => '', - 'issuerid' => $issuerid, - 'warnings' => $warnings - ]; - } -} diff --git a/public/lib/classes/external/moodlenet_send_activity.php b/public/lib/classes/external/moodlenet_send_activity.php deleted file mode 100644 index 33320f27570..00000000000 --- a/public/lib/classes/external/moodlenet_send_activity.php +++ /dev/null @@ -1,185 +0,0 @@ -. - -namespace core\external; - -use context_course; -use core\http_client; -use core\moodlenet\activity_sender; -use core\moodlenet\moodlenet_client; -use core\moodlenet\utilities; -use core\moodlenet\share_recorder; -use core\oauth2\api; -use core_external\external_api; -use core_external\external_function_parameters; -use core_external\external_single_structure; -use core_external\external_value; -use core_external\external_warnings; -use moodle_url; - -/** - * The external API to send activity to MoodleNet. - * - * @package core - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class moodlenet_send_activity extends external_api { - - /** - * Describes the parameters for sending the activity. - * - * @return external_function_parameters - * @since Moodle 4.2 - */ - public static function execute_parameters(): external_function_parameters { - return new external_function_parameters([ - 'issuerid' => new external_value(PARAM_INT, 'OAuth 2 issuer ID', VALUE_REQUIRED), - 'cmid' => new external_value(PARAM_INT, 'Course module ID', VALUE_REQUIRED), - 'shareformat' => new external_value(PARAM_INT, 'Share format', VALUE_REQUIRED), - ]); - } - - /** - * External function to send the activity to MoodleNet. - * - * @param int $issuerid The MoodleNet OAuth 2 issuer ID - * @param int $cmid The course module ID of the activity that being shared - * @param int $shareformat The share format being used, as defined by \core\moodlenet\activity_sender - * @return array - * @since Moodle 4.2 - */ - public static function execute(int $issuerid, int $cmid, int $shareformat): array { - global $CFG, $USER; - - [ - 'issuerid' => $issuerid, - 'cmid' => $cmid, - 'shareformat' => $shareformat, - ] = self::validate_parameters(self::execute_parameters(), [ - 'issuerid' => $issuerid, - 'cmid' => $cmid, - 'shareformat' => $shareformat, - ]); - - // Check capability. - [$course] = get_course_and_cm_from_cmid($cmid); - $coursecontext = context_course::instance($course->id); - $usercanshare = utilities::can_user_share($coursecontext, $USER->id); - if (!$usercanshare) { - return self::return_errors($cmid, 'errorpermission', - get_string('nopermissions', 'error', get_string('moodlenet:sharetomoodlenet', 'moodle'))); - } - - // Check format. - if (!in_array($shareformat, [activity_sender::SHARE_FORMAT_BACKUP])) { - return self::return_errors($shareformat, 'errorinvalidformat', get_string('invalidparameter', 'debug')); - } - - // Get the issuer. - $issuer = api::get_issuer($issuerid); - // Validate the issuer and check if it is enabled or not. - if (!utilities::is_valid_instance($issuer)) { - return self::return_errors($issuerid, 'errorissuernotenabled', get_string('invalidparameter', 'debug')); - } - - // Get the OAuth Client. - if (!$oauthclient = api::get_user_oauth_client( - $issuer, - new moodle_url($CFG->wwwroot), - moodlenet_client::API_SCOPE_CREATE_RESOURCE - )) { - return self::return_errors($issuerid, 'erroroauthclient', get_string('invalidparameter', 'debug')); - } - - // Check login state. - if (!$oauthclient->is_logged_in()) { - return self::return_errors($issuerid, 'erroroauthclient', get_string('moodlenet:issuerisnotauthorized', 'moodle')); - } - - // Get the HTTP Client. - $client = new http_client(); - - // Share activity. - try { - // Record activity share progress. - $shareid = share_recorder::insert_share_progress(share_recorder::TYPE_ACTIVITY, $USER->id, $course->id, $cmid); - - $moodlenetclient = new moodlenet_client($client, $oauthclient); - $activitysender = new activity_sender($cmid, $USER->id, $moodlenetclient, $oauthclient, $shareformat); - $result = $activitysender->share_resource(); - if (empty($result['drafturl'])) { - - share_recorder::update_share_progress($shareid, share_recorder::STATUS_ERROR); - - return self::return_errors($result['responsecode'], 'errorsendingactivity', - get_string('moodlenet:cannotconnecttoserver', 'moodle')); - } - } catch (\moodle_exception $e) { - - share_recorder::update_share_progress($shareid, share_recorder::STATUS_ERROR); - - return self::return_errors(0, 'errorsendingactivity', $e->getMessage()); - } - - share_recorder::update_share_progress($shareid, share_recorder::STATUS_SENT, $result['drafturl']); - - return [ - 'status' => true, - 'resourceurl' => $result['drafturl'], - 'warnings' => [], - ]; - } - - /** - * Describes the data returned from the external function. - * - * @return external_single_structure - * @since Moodle 4.2 - */ - public static function execute_returns(): external_single_structure { - return new external_single_structure([ - 'status' => new external_value(PARAM_BOOL, 'Status: true if success'), - // We used PARAM_TEXT instead of PARAM_URL because the URL return from MoodleNet may contain some characters. - // It does not match with PARAM_URL, but the URL still works. - // Since we just show the response resource URL to the user for them to navigate to MoodleNet, it would be safe. - 'resourceurl' => new external_value(PARAM_TEXT, 'Resource URL from MoodleNet'), - 'warnings' => new external_warnings(), - ]); - } - - /** - * Handle return error. - * - * @param int $itemid Item id - * @param string $warningcode Warning code - * @param string $message Message - * @return array - */ - protected static function return_errors(int $itemid, string $warningcode, string $message): array { - $warnings[] = [ - 'item' => $itemid, - 'warningcode' => $warningcode, - 'message' => $message, - ]; - - return [ - 'status' => false, - 'resourceurl' => '', - 'warnings' => $warnings, - ]; - } -} diff --git a/public/lib/classes/external/moodlenet_send_course.php b/public/lib/classes/external/moodlenet_send_course.php deleted file mode 100644 index d625e98ea6e..00000000000 --- a/public/lib/classes/external/moodlenet_send_course.php +++ /dev/null @@ -1,244 +0,0 @@ -. - -namespace core\external; - -use context_course; -use core\http_client; -use core\moodlenet\course_partial_sender; -use core\moodlenet\course_sender; -use core\moodlenet\moodlenet_client; -use core\moodlenet\share_recorder; -use core\moodlenet\utilities; -use core\oauth2\api; -use core_external\external_api; -use core_external\external_function_parameters; -use core_external\external_multiple_structure; -use core_external\external_single_structure; -use core_external\external_value; -use core_external\external_warnings; -use moodle_url; - -/** - * The external API to send course to MoodleNet. - * - * @package core - * @copyright 2023 Safat Shahin - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class moodlenet_send_course extends external_api { - - /** - * Describes the parameters for sending the course. - * - * @return external_function_parameters - */ - public static function execute_parameters(): external_function_parameters { - return new external_function_parameters([ - 'issuerid' => new external_value(PARAM_INT, 'OAuth 2 issuer ID', VALUE_REQUIRED), - 'courseid' => new external_value(PARAM_INT, 'Course ID', VALUE_REQUIRED), - 'shareformat' => new external_value(PARAM_INT, 'Share format', VALUE_REQUIRED), - 'cmids' => new external_multiple_structure( - new external_value(PARAM_INT, 'Course module id', VALUE_DEFAULT, null, NULL_ALLOWED), - 'List for course module ids', VALUE_DEFAULT, [] - ), - ]); - } - - /** - * External function to send the course to MoodleNet. - * - * @param int $issuerid The MoodleNet OAuth 2 issuer ID - * @param int $courseid The course ID - * @param int $shareformat The share format being used, as defined by \core\moodlenet\course_sender - * @param array $cmids The course module ids - * @return array - */ - public static function execute( - int $issuerid, - int $courseid, - int $shareformat, - array $cmids = [], - ): array { - global $CFG, $USER; - - [ - 'issuerid' => $issuerid, - 'courseid' => $courseid, - 'shareformat' => $shareformat, - 'cmids' => $cmids, - ] = self::validate_parameters(self::execute_parameters(), [ - 'issuerid' => $issuerid, - 'courseid' => $courseid, - 'shareformat' => $shareformat, - 'cmids' => $cmids, - ]); - - // Partial sharing check. - $ispartialsharing = count($cmids) > 0; - - // Check capability. - $coursecontext = context_course::instance($courseid); - $usercanshare = utilities::can_user_share($coursecontext, $USER->id, 'course'); - if (!$usercanshare) { - return self::return_errors( - $courseid, - 'errorpermission', - get_string('nopermissions', 'error', get_string('moodlenet:sharetomoodlenet', 'moodle')) - ); - } - - // Check format. - if ($shareformat !== course_sender::SHARE_FORMAT_BACKUP) { - return self::return_errors( - $shareformat, - 'errorinvalidformat', - get_string('invalidparameter', 'debug') - ); - } - - if ($ispartialsharing) { - // Check course modules in the course. - $modinfo = get_fast_modinfo($courseid); - $cms = $modinfo->get_cms(); - foreach ($cmids as $cmid) { - if (!array_key_exists($cmid, $cms)) { - return self::return_errors( - $cmid, - 'errorinvalidcmids', - get_string('invalidparameter', 'debug') - ); - } - } - } - - // Get the issuer. - $issuer = api::get_issuer($issuerid); - // Validate the issuer and check if it is enabled or not. - if (!utilities::is_valid_instance($issuer)) { - return self::return_errors( - $issuerid, - 'errorissuernotenabled', - get_string('invalidparameter', 'debug') - ); - } - - // Get the OAuth Client. - if (!$oauthclient = api::get_user_oauth_client( - $issuer, - new moodle_url($CFG->wwwroot), - moodlenet_client::API_SCOPE_CREATE_RESOURCE - )) { - return self::return_errors( - $issuerid, - 'erroroauthclient', - get_string('invalidparameter', 'debug') - ); - } - - // Check login state. - if (!$oauthclient->is_logged_in()) { - return self::return_errors( - $issuerid, - 'erroroauthclient', - get_string('moodlenet:issuerisnotauthorized', 'moodle') - ); - } - - // Get the HTTP Client. - $client = new http_client(); - - // Share course. - try { - // Record course share progress. - $shareid = share_recorder::insert_share_progress(share_recorder::TYPE_COURSE, $USER->id, $courseid); - - $moodlenetclient = new moodlenet_client($client, $oauthclient); - if ($ispartialsharing) { - $coursesender = new course_partial_sender($courseid, $USER->id, $moodlenetclient, - $oauthclient, $cmids, $shareformat); - } else { - $coursesender = new course_sender($courseid, $USER->id, $moodlenetclient, $oauthclient, $shareformat); - } - $result = $coursesender->share_resource(); - if (empty($result['drafturl'])) { - - share_recorder::update_share_progress($shareid, share_recorder::STATUS_ERROR); - - return self::return_errors( - $result['responsecode'], - 'errorsendingcourse', - get_string('moodlenet:cannotconnecttoserver', 'moodle') - ); - } - } catch (\moodle_exception | \JsonException $e) { - - share_recorder::update_share_progress($shareid, share_recorder::STATUS_ERROR); - - return self::return_errors( - 0, - 'errorsendingcourse', - $e->getMessage() - ); - } - - share_recorder::update_share_progress($shareid, share_recorder::STATUS_SENT, $result['drafturl']); - - return [ - 'status' => true, - 'resourceurl' => $result['drafturl'], - 'warnings' => [], - ]; - } - - /** - * Describes the data returned from the external function. - * - * @return external_single_structure - */ - public static function execute_returns(): external_single_structure { - return new external_single_structure([ - 'status' => new external_value(PARAM_BOOL, 'Status: true if success'), - // We used PARAM_TEXT instead of PARAM_URL because the URL return from MoodleNet may contain some characters. - // It does not match with PARAM_URL, but the URL still works. - // Since we just show the response resource URL to the user for them to navigate to MoodleNet, it would be safe. - 'resourceurl' => new external_value(PARAM_TEXT, 'Resource URL from MoodleNet'), - 'warnings' => new external_warnings(), - ]); - } - - /** - * Handle return error. - * - * @param int $itemid Item id - * @param string $warningcode Warning code - * @param string $message Message - * @return array - */ - protected static function return_errors(int $itemid, string $warningcode, string $message): array { - $warnings[] = [ - 'item' => $itemid, - 'warningcode' => $warningcode, - 'message' => $message, - ]; - - return [ - 'status' => false, - 'resourceurl' => '', - 'warnings' => $warnings, - ]; - } -} diff --git a/public/lib/classes/hub/registration.php b/public/lib/classes/hub/registration.php index c7816ab7c13..9e87e22c496 100644 --- a/public/lib/classes/hub/registration.php +++ b/public/lib/classes/hub/registration.php @@ -517,7 +517,7 @@ class registration { // The most conservative limit for the redirect URL length is 2000 characters. Only pass parameters before // we reach this limit. The next registration update will update all fields. - // We will also update registration after we receive confirmation from moodle.net. + // We will also update registration after we receive confirmation from stats.moodle.org. $url = new moodle_url(HUB_MOODLEORGHUBURL . '/local/hub/siteregistration.php', ['token' => $hub->token, 'url' => $params['url']]); foreach ($params as $key => $value) { @@ -618,8 +618,12 @@ class registration { * } * * @return array|null + * @deprecated since Moodle 5.2 - please do not use this function any more */ + #[\core\attribute\deprecated(reason: 'It is no longer used', since: '5.2', mdl: 'MDL-87350')] public static function get_moodlenet_info() { + \core\deprecation::emit_deprecation([self::class, __FUNCTION__]); + try { return api::get_hub_info(); } catch (moodle_exception $e) { diff --git a/public/lib/classes/moodlenet/activity_packager.php b/public/lib/classes/moodlenet/activity_packager.php deleted file mode 100644 index 23e4fe30091..00000000000 --- a/public/lib/classes/moodlenet/activity_packager.php +++ /dev/null @@ -1,69 +0,0 @@ -. - -namespace core\moodlenet; - -use backup; -use backup_controller; -use cm_info; - -defined('MOODLE_INTERNAL') || die(); - -require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php'); - -/** - * Packager to prepare appropriate backup of an activity to share to MoodleNet. - * - * @package core - * @copyright 2023 Raquel Ortega - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class activity_packager extends resource_packager { - - /** - * Constructor. - * - * @param cm_info $cminfo context module information about the resource being packaged. - * @param int $userid The ID of the user performing the packaging. - */ - public function __construct( - cm_info $cminfo, - int $userid, - ) { - // Check backup/restore support. - if (!plugin_supports('mod', $cminfo->modname , FEATURE_BACKUP_MOODLE2)) { - throw new \coding_exception("Cannot backup module $cminfo->modname. This module doesn't support the backup feature."); - } - - parent::__construct($cminfo, $userid, $cminfo->modname); - } - - /** - * Get the backup controller for the activity. - * - * @return backup_controller the backup controller for the activity. - */ - protected function get_backup_controller(): backup_controller { - return new backup_controller( - backup::TYPE_1ACTIVITY, - $this->cminfo->id, - backup::FORMAT_MOODLE, - backup::INTERACTIVE_NO, - backup::MODE_GENERAL, - $this->userid - ); - } -} diff --git a/public/lib/classes/moodlenet/activity_sender.php b/public/lib/classes/moodlenet/activity_sender.php deleted file mode 100644 index 93e575f1955..00000000000 --- a/public/lib/classes/moodlenet/activity_sender.php +++ /dev/null @@ -1,176 +0,0 @@ -. - -namespace core\moodlenet; - -use cm_info; -use core\event\moodlenet_resource_exported; -use core\oauth2\client; -use moodle_exception; -use stored_file; - -/** - * API for sharing Moodle LMS activities to MoodleNet instances. - * - * @package core - * @copyright 2023 Michael Hawkins - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class activity_sender extends resource_sender { - - /** - * @var cm_info The context module info object for the activity being shared. - */ - protected cm_info $cminfo; - - /** - * Class constructor. - * - * @param int $cmid The course module ID of the activity being shared - * @param int $userid The user ID who is sharing the activity - * @param moodlenet_client $moodlenetclient The moodlenet_client object used to perform the share - * @param client $oauthclient The OAuth 2 client for the MoodleNet instance - * @param int $shareformat The data format to share in. Defaults to a Moodle backup (SHARE_FORMAT_BACKUP) - */ - public function __construct( - int $cmid, - protected int $userid, - protected moodlenet_client $moodlenetclient, - protected client $oauthclient, - protected int $shareformat = self::SHARE_FORMAT_BACKUP, - ) { - parent::__construct($cmid, $userid, $moodlenetclient, $oauthclient, $shareformat); - [$this->course, $this->cminfo] = get_course_and_cm_from_cmid($cmid); - $this->packager = new activity_packager($this->cminfo, $this->userid); - } - - /** - * Share an activity/resource to MoodleNet. - * - * @return array The HTTP response code from MoodleNet and the MoodleNet draft resource URL (URL empty string on fail). - * Format: ['responsecode' => 201, 'drafturl' => 'https://draft.mnurl/here'] - */ - public function share_resource(): array { - $accesstoken = ''; - $resourceurl = ''; - $issuer = $this->oauthclient->get_issuer(); - - // Check user can share to the requested MoodleNet instance. - $coursecontext = \core\context\course::instance($this->course->id); - $usercanshare = utilities::can_user_share($coursecontext, $this->userid); - - if ($usercanshare && utilities::is_valid_instance($issuer) && $this->oauthclient->is_logged_in()) { - $accesstoken = $this->oauthclient->get_accesstoken()->token; - } - - // Throw an exception if the user is not currently set up to be able to share to MoodleNet. - if (!$accesstoken) { - throw new moodle_exception('moodlenet:usernotconfigured'); - } - - // Attempt to prepare and send the resource if validation has passed and we have an OAuth 2 token. - - // Prepare file in requested format. - $filedata = $this->prepare_share_contents(); - - // If we have successfully prepared a file to share of permitted size, share it to MoodleNet. - if (!empty($filedata)) { - // Avoid sending a file larger than the defined limit. - $filesize = $filedata->get_filesize(); - if ($filesize > self::MAX_FILESIZE) { - $filedata->delete(); - throw new moodle_exception('moodlenet:sharefilesizelimitexceeded', 'core', '', [ - 'filesize' => $filesize, - 'filesizelimit' => self::MAX_FILESIZE, - ]); - } - - // MoodleNet only accept plaintext descriptions. - $resourcedescription = $this->get_resource_description($coursecontext); - - $response = $this->moodlenetclient->create_resource_from_stored_file( - $filedata, - $this->cminfo->name, - $resourcedescription, - ); - $responsecode = $response->getStatusCode(); - - $responsebody = json_decode($response->getBody()); - $resourceurl = $responsebody->homepage ?? ''; - - // Delete the generated file now it is no longer required. - // (It has either been sent, or failed - retries not currently supported). - $filedata->delete(); - } - - // Log every attempt to share (and whether or not it was successful). - $this->log_event($coursecontext, $this->cminfo->id, $resourceurl, $responsecode); - - return [ - 'responsecode' => $responsecode, - 'drafturl' => $resourceurl, - ]; - } - - /** - * Log an event to the admin logs for an outbound share attempt. - * - * @param \context $coursecontext The course context being shared from. - * @param int $cmid The CMID of the activity being shared. - * @param string $resourceurl The URL of the draft resource if it was created. - * @param int $responsecode The HTTP response code describing the outcome of the attempt. - * @return void - */ - protected function log_event( - \core\context $coursecontext, - int $cmid, - string $resourceurl, - int $responsecode, - ): void { - $event = moodlenet_resource_exported::create([ - 'context' => $coursecontext, - 'other' => [ - 'cmids' => [$cmid], - 'resourceurl' => $resourceurl, - 'success' => ($responsecode == 201), - ], - ]); - $event->trigger(); - } - - /** - * Fetch the description for the resource being created, in a supported text format. - * - * @param \context $coursecontext The course context being shared from. - * @return string Converted activity description. - */ - protected function get_resource_description( - \context $coursecontext, - ): string { - global $PAGE, $DB; - // We need to set the page context here because content_to_text and format_text will need the page context to work. - $PAGE->set_context($coursecontext); - - $intro = $DB->get_record($this->cminfo->modname, ['id' => $this->cminfo->instance], 'intro, introformat', MUST_EXIST); - $processeddescription = strip_tags($intro->intro); - $processeddescription = content_to_text(format_text( - $processeddescription, - $intro->introformat, - ), $intro->introformat); - - return $processeddescription; - } -} diff --git a/public/lib/classes/moodlenet/course_packager.php b/public/lib/classes/moodlenet/course_packager.php deleted file mode 100644 index 713afa74ebe..00000000000 --- a/public/lib/classes/moodlenet/course_packager.php +++ /dev/null @@ -1,64 +0,0 @@ -. - -namespace core\moodlenet; - -use backup; -use backup_controller; -use stdClass; - -defined('MOODLE_INTERNAL') || die(); - -require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php'); - -/** - * Packager to prepare appropriate backup of a course to share to MoodleNet. - * - * @package core - * @copyright 2023 Safat Shahin - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class course_packager extends resource_packager { - - /** - * Constructor for course packager. - * - * @param stdClass $course The course to package - * @param int $userid The ID of the user performing the packaging - */ - public function __construct( - stdClass $course, - int $userid, - ) { - parent::__construct($course, $userid, $course->shortname); - } - - /** - * Get the backup controller for the course. - * - * @return backup_controller the backup controller for the course. - */ - protected function get_backup_controller(): backup_controller { - return new backup_controller( - backup::TYPE_1COURSE, - $this->course->id, - backup::FORMAT_MOODLE, - backup::INTERACTIVE_NO, - backup::MODE_GENERAL, - $this->userid, - ); - } -} diff --git a/public/lib/classes/moodlenet/course_partial_packager.php b/public/lib/classes/moodlenet/course_partial_packager.php deleted file mode 100644 index f722199bf56..00000000000 --- a/public/lib/classes/moodlenet/course_partial_packager.php +++ /dev/null @@ -1,99 +0,0 @@ -. - -namespace core\moodlenet; - -use backup_activity_task; -use backup_controller; -use stdClass; -use stored_file; - -/** - * Packager to prepare appropriate backup of a number of activities in a course to share to MoodleNet. - * - * @package core - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class course_partial_packager extends course_packager { - - /** - * @var int[] $cmids List of course module ids of selected activities. - */ - protected array $cmids; - - /** - * Constructor for course partial packager. - * - * @param stdClass $course The course to package - * @param array $cmids List of course module id of selected activities. - * @param int $userid The ID of the user performing the packaging - */ - public function __construct( - stdClass $course, - array $cmids, - int $userid, - ) { - $this->cmids = $cmids; - parent::__construct($course, $userid); - } - - /** - * Package the resource identified by resource id into a new stored_file. - * - * @param backup_controller $controller The backup controller. - * @return stored_file - */ - protected function package(backup_controller $controller): stored_file { - $this->remove_unselected_activities($controller); - return parent::package($controller); - } - - /** - * Remove unselected activities in the course backup. - * - * @param backup_controller $controller The backup controller. - */ - protected function remove_unselected_activities(backup_controller $controller): void { - foreach ($this->get_all_activity_tasks($controller) as $task) { - foreach ($task->get_settings() as $setting) { - if (in_array($task->get_moduleid(), $this->cmids) && - str_contains($setting->get_name(), '_included') !== false) { - $setting->set_value(1); - } else { - $setting->set_value(0); - } - } - } - } - - /** - * Get all the activity tasks in the controller. - * - * @param backup_controller $controller The backup controller. - * @return backup_activity_task[] Array of activity tasks. - */ - protected function get_all_activity_tasks(backup_controller $controller): array { - $tasks = []; - foreach ($controller->get_plan()->get_tasks() as $task) { - if (! $task instanceof backup_activity_task) { // Only for activity tasks. - continue; - } - $tasks[] = $task; - } - return $tasks; - } -} diff --git a/public/lib/classes/moodlenet/course_partial_sender.php b/public/lib/classes/moodlenet/course_partial_sender.php deleted file mode 100644 index d29b066b6e2..00000000000 --- a/public/lib/classes/moodlenet/course_partial_sender.php +++ /dev/null @@ -1,100 +0,0 @@ -. - -namespace core\moodlenet; - -use core\event\moodlenet_resource_exported; -use core\oauth2\client; -use moodle_exception; - -/** - * API for sharing a number of Moodle LMS activities as a course backup to MoodleNet instances. - * - * @package core - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class course_partial_sender extends course_sender { - - /** - * Constructor for course sender. - * - * @param int $courseid The course ID of the course being shared - * @param int $userid The user ID who is sharing the activity - * @param moodlenet_client $moodlenetclient The moodlenet_client object used to perform the share - * @param client $oauthclient The OAuth 2 client for the MoodleNet instance - * @param int $shareformat The data format to share in. Defaults to a Moodle backup (SHARE_FORMAT_BACKUP) - */ - public function __construct( - int $courseid, - protected int $userid, - protected moodlenet_client $moodlenetclient, - protected client $oauthclient, - protected array $cmids, - protected int $shareformat = self::SHARE_FORMAT_BACKUP, - ) { - parent::__construct($courseid, $userid, $moodlenetclient, $oauthclient, $shareformat); - $this->validate_course_module_ids($this->course, $this->cmids); - $this->packager = new course_partial_packager($this->course, $this->cmids, $this->userid); - } - - /** - * Log an event to the admin logs for an outbound share attempt. - * - * @param string $resourceurl The URL of the draft resource if it was created - * @param int $responsecode The HTTP response code describing the outcome of the attempt - * @return void - */ - protected function log_event( - string $resourceurl, - int $responsecode, - ): void { - $event = moodlenet_resource_exported::create([ - 'context' => $this->coursecontext, - 'other' => [ - 'cmids' => $this->cmids, - 'courseid' => [$this->course->id], - 'resourceurl' => $resourceurl, - 'success' => ($responsecode === 201), - ], - ]); - $event->trigger(); - } - - /** - * Validate the course module ids. - * - * @param \stdClass $course Course object - * @param array $cmids List of course module ids to check - * @return void - */ - protected function validate_course_module_ids( - \stdClass $course, - array $cmids, - ): void { - if (empty($cmids)) { - throw new moodle_exception('invalidcoursemodule'); - } - $modinfo = get_fast_modinfo($course); - $cms = $modinfo->get_cms(); - foreach ($cmids as $cmid) { - if (!array_key_exists($cmid, $cms)) { - throw new moodle_exception('invalidcoursemodule'); - } - } - } - -} diff --git a/public/lib/classes/moodlenet/course_sender.php b/public/lib/classes/moodlenet/course_sender.php deleted file mode 100644 index 40885ccf17f..00000000000 --- a/public/lib/classes/moodlenet/course_sender.php +++ /dev/null @@ -1,180 +0,0 @@ -. - -namespace core\moodlenet; - -use core\event\moodlenet_resource_exported; -use core\oauth2\client; -use moodle_exception; -use stored_file; - -/** - * API for sharing Moodle LMS courses to MoodleNet instances. - * - * @package core - * @copyright 2023 Safat Shahin - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class course_sender extends resource_sender { - - /** - * @var \core\context\course|false The course context. - */ - protected \core\context\course|false $coursecontext; - - /** - * Constructor for course sender. - * - * @param int $courseid The course ID of the course being shared - * @param int $userid The user ID who is sharing the activity - * @param moodlenet_client $moodlenetclient The moodlenet_client object used to perform the share - * @param client $oauthclient The OAuth 2 client for the MoodleNet instance - * @param int $shareformat The data format to share in. Defaults to a Moodle backup (SHARE_FORMAT_BACKUP) - */ - public function __construct( - int $courseid, - protected int $userid, - protected moodlenet_client $moodlenetclient, - protected client $oauthclient, - protected int $shareformat = self::SHARE_FORMAT_BACKUP, - ) { - parent::__construct($courseid, $userid, $moodlenetclient, $oauthclient, $shareformat); - $this->course = get_course($courseid); - $this->coursecontext = \core\context\course::instance($courseid); - $this->packager = new course_packager($this->course, $this->userid); - } - - /** - * Share a course to MoodleNet. - * - * @return array The HTTP response code from MoodleNet and the MoodleNet draft resource URL (URL empty string on fail). - * Format: ['responsecode' => 201, 'drafturl' => 'https://draft.mnurl/here'] - */ - public function share_resource(): array { - - $accesstoken = ''; - $issuer = $this->oauthclient->get_issuer(); - - // Check user can share to the requested MoodleNet instance. - $usercanshare = utilities::can_user_share($this->coursecontext, $this->userid, 'course'); - - if ($usercanshare && utilities::is_valid_instance($issuer) && $this->oauthclient->is_logged_in()) { - $accesstoken = $this->oauthclient->get_accesstoken()->token; - } - - // Throw an exception if the user is not currently set up to be able to share to MoodleNet. - if (!$accesstoken) { - throw new moodle_exception('moodlenet:usernotconfigured'); - } - - // Attempt to prepare and send the resource if validation has passed and we have an OAuth 2 token. - - // Prepare file in requested format. - $filedata = $this->prepare_share_contents(); - - // Avoid sending a file larger than the defined limit. - $filesize = $filedata->get_filesize(); - if ($filesize > self::MAX_FILESIZE) { - $filedata->delete(); - throw new moodle_exception('moodlenet:sharefilesizelimitexceeded', 'core', '', [ - 'filesize' => $filesize, - 'filesizelimit' => self::MAX_FILESIZE, - ]); - } - - // MoodleNet only accept plaintext descriptions. - $resourcedescription = $this->get_resource_description(); - - $response = $this->moodlenetclient->create_resource_from_stored_file( - $filedata, - $this->course->fullname, - $resourcedescription, - ); - $responsecode = $response->getStatusCode(); - - $responsebody = json_decode($response->getBody(), false, 512, JSON_THROW_ON_ERROR); - $resourceurl = $responsebody->homepage ?? ''; - - // Delete the generated file now it is no longer required. - // (It has either been sent, or failed - retries not currently supported). - $filedata->delete(); - - // Log every attempt to share (and whether it was successful). - $this->log_event($resourceurl, $responsecode); - - return [ - 'responsecode' => $responsecode, - 'drafturl' => $resourceurl, - ]; - } - - /** - * Log an event to the admin logs for an outbound share attempt. - * - * @param string $resourceurl The URL of the draft resource if it was created - * @param int $responsecode The HTTP response code describing the outcome of the attempt - * @return void - */ - protected function log_event( - string $resourceurl, - int $responsecode, - ): void { - $event = moodlenet_resource_exported::create([ - 'context' => $this->coursecontext, - 'other' => [ - 'courseid' => [$this->course->id], - 'resourceurl' => $resourceurl, - 'success' => ($responsecode === 201), - ], - ]); - $event->trigger(); - } - - /** - * Return the list of supported share formats. - * - * @return array Array of supported share format values. - */ - protected static function get_allowed_share_formats(): array { - return [ - self::SHARE_FORMAT_BACKUP, - ]; - } - - /** - * Fetch the description for the resource being created, in a supported text format. - * - * @return string Converted course description. - */ - protected function get_resource_description(): string { - global $PAGE; - - // We need to set the page context here because content_to_text and format_text will need the page context to work. - $PAGE->set_context($this->coursecontext); - - $processeddescription = strip_tags($this->course->summary); - $processeddescription = content_to_text - ( - format_text( - $processeddescription, - $this->course->summaryformat, - ), - $this->course->summaryformat - ); - - return $processeddescription; - } -} diff --git a/public/lib/classes/moodlenet/moodlenet_client.php b/public/lib/classes/moodlenet/moodlenet_client.php deleted file mode 100644 index 8fe1e4ee7b7..00000000000 --- a/public/lib/classes/moodlenet/moodlenet_client.php +++ /dev/null @@ -1,139 +0,0 @@ -. - -namespace core\moodlenet; - -use core\http_client; -use core\oauth2\client; -use stored_file; -use Psr\Http\Message\ResponseInterface; -use Psr\Http\Message\StreamInterface; - -/** - * MoodleNet client which handles direct outbound communication with MoodleNet instances. - * - * @package core - * @copyright 2023 Michael Hawkins - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class moodlenet_client { - /** - * @var string MoodleNet resource creation endpoint URI. - */ - protected const API_CREATE_RESOURCE_URI = '/.pkg/@moodlenet/ed-resource/basic/v1/create'; - - /** - * @var string MoodleNet scope for creating resources. - */ - public const API_SCOPE_CREATE_RESOURCE = '@moodlenet/ed-resource:write.own'; - - - /** - * Constructor. - * - * @param http_client $httpclient The httpclient object being used to perform the share. - * @param client $oauthclient The OAuth 2 client for the MoodleNet site being shared to. - */ - public function __construct( - protected http_client $httpclient, - protected client $oauthclient, - ) { - // All properties promoted, nothing further required. - } - - /** - * Create a resource on MoodleNet which includes a file. - * - * @param stored_file $file The file data to send to MoodleNet. - * @param string $resourcename The name of the resource being shared. - * @param string $resourcedescription A description of the resource being shared. - * @return \Psr\Http\Message\ResponseInterface The HTTP client response from MoodleNet. - */ - public function create_resource_from_stored_file( - stored_file $file, - string $resourcename, - string $resourcedescription, - ): ResponseInterface { - // This may take a long time if a lot of data is being shared. - \core_php_time_limit::raise(); - - $moodleneturl = $this->oauthclient->get_issuer()->get('baseurl'); - $apiurl = rtrim($moodleneturl, '/') . self::API_CREATE_RESOURCE_URI; - $stream = $file->get_psr_stream(); - - $requestdata = $this->prepare_file_share_request_data( - $file->get_filename(), - $file->get_mimetype(), - $stream, - $resourcename, - $resourcedescription, - ); - - try { - $response = $this->httpclient->request('POST', $apiurl, $requestdata); - } finally { - $stream->close(); // Always close the request stream ASAP. Or it will remain open till shutdown/destruct. - } - - return $response; - } - - /** - * Prepare the request data required for sharing a file to MoodleNet. - * This creates an array in the format used by \core\httpclient options to send a multipart request. - * - * @param string $filename Name of the file being shared. - * @param string $mimetype Mime type of the file being shared. - * @param StreamInterface $stream Stream of the file being shared. - * @param string $resourcename The name of the resource being shared. - * @param string $resourcedescription A description of the resource being shared. - * @return array Data in the format required to send a file to MoodleNet using \core\httpclient. - */ - protected function prepare_file_share_request_data( - string $filename, - string $mimetype, - StreamInterface $stream, - string $resourcename, - string $resourcedescription, - ): array { - return [ - 'headers' => [ - 'Authorization' => 'Bearer ' . $this->oauthclient->get_accesstoken()->token, - ], - 'multipart' => [ - [ - 'name' => 'metadata', - 'contents' => json_encode([ - 'name' => $resourcename, - 'description' => $resourcedescription, - ]), - 'headers' => [ - 'Content-Disposition' => 'form-data; name="."', - ], - ], - [ - 'name' => 'filecontents', - 'contents' => $stream, - 'headers' => [ - 'Content-Disposition' => 'form-data; name=".resource"; filename="' . $filename . '"', - 'Content-Type' => $mimetype, - 'Content-Transfer-Encoding' => 'binary', - ], - ], - ], - ]; - } -} diff --git a/public/lib/classes/moodlenet/resource_packager.php b/public/lib/classes/moodlenet/resource_packager.php deleted file mode 100644 index 01dad78dc88..00000000000 --- a/public/lib/classes/moodlenet/resource_packager.php +++ /dev/null @@ -1,191 +0,0 @@ -. - -namespace core\moodlenet; - -use backup_controller; -use backup_root_task; -use cm_info; -use core\context\user; -use stdClass; -use stored_file; - -defined('MOODLE_INTERNAL') || die(); - -require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php'); - -/** - * Base packager to prepare appropriate backup of a resource to share to MoodleNet. - * - * @package core - * @copyright 2023 Safat Shahin - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -abstract class resource_packager { - - /** - * @var string $resourcefilename The filename for the resource. - */ - protected string $resourcefilename = 'resource'; - - /** - * @var stdClass $course The course which the resource belongs to. - */ - protected stdClass $course; - - /** - * @var cm_info $cminfo The course module which the resource belongs to. - */ - protected cm_info $cminfo; - - /** - * @var int $userid The ID of the user performing the packaging. - */ - protected int $userid; - - /** - * Constructor for the base packager. - * - * @param stdClass|cm_info $resource The resource object - * @param int $userid The user id - */ - public function __construct( - stdClass|cm_info $resource, - int $userid, - string $resourcefilename, - ) { - if ($resource instanceof cm_info) { - $this->cminfo = $resource; - $this->course = $resource->get_course(); - } else { - $this->course = $resource; - } - - $this->userid = $userid; - $this->resourcefilename = $resourcefilename; - } - - /** - * Get the backup controller for the course. - * - * @return backup_controller The backup controller instance that will be used to package the resource. - */ - abstract protected function get_backup_controller(): backup_controller; - - /** - * Prepare the backup file using appropriate setting overrides and return relevant information. - * - * @return stored_file - */ - public function get_package(): stored_file { - $controller = $this->get_backup_controller(); - $alltasksettings = $this->get_all_task_settings($controller); - - // Override relevant settings to remove user data when packaging to share to MoodleNet. - $this->override_task_setting($alltasksettings, 'setting_root_users', 0); - $this->override_task_setting($alltasksettings, 'setting_root_role_assignments', 0); - $this->override_task_setting($alltasksettings, 'setting_root_blocks', 0); - $this->override_task_setting($alltasksettings, 'setting_root_comments', 0); - $this->override_task_setting($alltasksettings, 'setting_root_badges', 0); - $this->override_task_setting($alltasksettings, 'setting_root_userscompletion', 0); - $this->override_task_setting($alltasksettings, 'setting_root_logs', 0); - $this->override_task_setting($alltasksettings, 'setting_root_grade_histories', 0); - $this->override_task_setting($alltasksettings, 'setting_root_groups', 0); - - $storedfile = $this->package($controller); - - $controller->destroy(); // We are done with the controller, destroy it. - - return $storedfile; - } - - /** - * Get all backup settings available for override. - * - * @return array the associative array of taskclass => settings instances. - */ - protected function get_all_task_settings(backup_controller $controller): array { - $tasksettings = []; - foreach ($controller->get_plan()->get_tasks() as $task) { - $taskclass = get_class($task); - $tasksettings[$taskclass] = $task->get_settings(); - } - return $tasksettings; - } - - /** - * Override a backup task setting with a given value. - * - * @param array $alltasksettings All task settings. - * @param string $settingname The name of the setting to be overridden (task class name format). - * @param int $settingvalue Value to be given to the setting. - */ - protected function override_task_setting(array $alltasksettings, string $settingname, int $settingvalue): void { - if (empty($rootsettings = $alltasksettings[backup_root_task::class])) { - return; - } - - foreach ($rootsettings as $setting) { - $name = $setting->get_ui_name(); - if ($name == $settingname && $settingvalue != $setting->get_value()) { - $setting->set_value($settingvalue); - return; - } - } - } - - /** - * Package the resource identified by resource id into a new stored_file. - * - * @param backup_controller $controller The backup controller. - * @return stored_file - */ - protected function package(backup_controller $controller): stored_file { - // Execute the backup and fetch the result. - $controller->execute_plan(); - $result = $controller->get_results(); - - if (!isset($result['backup_destination'])) { - throw new \moodle_exception('Failed to package resource.'); - } - - $backupfile = $result['backup_destination']; - - if (!$backupfile->get_contenthash()) { - throw new \moodle_exception('Failed to package resource (invalid file).'); - } - - // Create the location we want to copy this file to. - $filerecord = [ - 'contextid' => user::instance($this->userid)->id, - 'userid' => $this->userid, - 'component' => 'user', - 'filearea' => 'draft', - 'itemid' => file_get_unused_draft_itemid(), - 'filepath' => '/', - 'filename' => $this->resourcefilename . '_backup.mbz', - ]; - - // Create the local file based on the backup. - $fs = get_file_storage(); - $file = $fs->create_file_from_storedfile($filerecord, $backupfile); - - // Delete the backup now it has been created in the file area. - $backupfile->delete(); - - return $file; - } -} diff --git a/public/lib/classes/moodlenet/resource_sender.php b/public/lib/classes/moodlenet/resource_sender.php deleted file mode 100644 index 29e4c29cf46..00000000000 --- a/public/lib/classes/moodlenet/resource_sender.php +++ /dev/null @@ -1,103 +0,0 @@ -. - -namespace core\moodlenet; - -use core\oauth2\client; -use moodle_exception; -use stdClass; -use stored_file; - -/** - * API for sharing Moodle LMS resources to MoodleNet instances. - * - * @package core - * @copyright 2023 Safat Shahin - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -abstract class resource_sender { - - /** - * @var int Backup share format - the content is being shared as a Moodle backup file. - */ - public const SHARE_FORMAT_BACKUP = 0; - - /** - * @var int Maximum upload file size (1.07 GB). - */ - public const MAX_FILESIZE = 1070000000; - - /** - * @var stdClass The course where the activity is located. - */ - protected stdClass $course; - - /** @var resource_packager Resource packager. */ - protected resource_packager $packager; - - /** - * Class constructor. - * - * @param int $resourceid The resource ID of the resource being shared. - * @param int $userid The user ID who is sharing the activity. - * @param moodlenet_client $moodlenetclient The moodlenet_client object used to perform the share. - * @param client $oauthclient The OAuth 2 client for the MoodleNet instance. - * @param int $shareformat The data format to share in. Defaults to a Moodle backup (SHARE_FORMAT_BACKUP). - * @throws moodle_exception - */ - public function __construct( - int $resourceid, - protected int $userid, - protected moodlenet_client $moodlenetclient, - protected client $oauthclient, - protected int $shareformat = self::SHARE_FORMAT_BACKUP, - ) { - if (!in_array($shareformat, self::get_allowed_share_formats(), true)) { - throw new moodle_exception('moodlenet:invalidshareformat'); - } - } - - /** - * Return the list of supported share formats. - * - * @return array Array of supported share format values. - */ - protected static function get_allowed_share_formats(): array { - return [ - self::SHARE_FORMAT_BACKUP, - ]; - } - - /** - * Share a resource to MoodleNet. - * - * @return array The HTTP response code from MoodleNet and the MoodleNet draft resource URL (URL empty string on fail). - * Format: ['responsecode' => 201, 'drafturl' => 'https://draft.mnurl/here'] - */ - abstract public function share_resource(): array; - - /** - * Prepare the data for sharing, in the format specified. - * - * @return stored_file - */ - protected function prepare_share_contents(): stored_file { - return match ($this->shareformat) { - self::SHARE_FORMAT_BACKUP => $this->packager->get_package(), - default => throw new \coding_exception("Unknown share format: {$this->shareformat}'"), - }; - } -} diff --git a/public/lib/classes/moodlenet/share_progress_table.php b/public/lib/classes/moodlenet/share_progress_table.php deleted file mode 100644 index cc46c2c99b3..00000000000 --- a/public/lib/classes/moodlenet/share_progress_table.php +++ /dev/null @@ -1,252 +0,0 @@ -. - -/** - * MoodleNet share progress table. - * - * @package core - * @copyright 2023 David Woloszyn - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -namespace core\moodlenet; - -defined('MOODLE_INTERNAL') || die(); - -require_once($CFG->libdir . '/tablelib.php'); - -use html_writer; -use moodle_url; -use stdClass; -use table_sql; - -/** - * MoodleNet share progress table. - * - * @package core - * @copyright 2023 David Woloszyn - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class share_progress_table extends table_sql { - - /** @var int The user id records will be displayed for. */ - protected $userid; - - /** - * Set up the table. - * - * @param string $uniqueid Unique id of table. - * @param moodle_url $url The base URL. - * @param int $userid The user id. - */ - public function __construct($uniqueid, $url, $userid) { - parent::__construct($uniqueid); - $this->userid = $userid; - $this->define_table_columns(); - $this->define_baseurl($url); - $this->define_table_configs(); - } - - /** - * Define table configs. - */ - protected function define_table_configs() { - $this->collapsible(false); - $this->sortable(false); - $this->pageable(true); - $this->set_default_per_page(25); - } - - /** - * Set up the columns and headers. - */ - protected function define_table_columns() { - // Define headers and columns. - $cols = [ - 'name' => get_string('name'), - 'type' => get_string('moodlenet:columntype'), - 'timecreated' => get_string('moodlenet:columnsenddate'), - 'status' => get_string('moodlenet:columnsendstatus'), - ]; - - $this->define_columns(array_keys($cols)); - $this->define_headers(array_values($cols)); - $this->column_class('status', 'text-center'); - } - - /** - * Name column. - * - * @param stdClass $row Row data. - * @return string - */ - protected function col_name(stdClass $row): string { - global $OUTPUT; - - $class = ''; - // Track deletion of resources on Moodle. - $deleted = false; - // Courses. - if ($row->type == share_recorder::TYPE_COURSE) { - if ($row->fullname) { - $name = $row->fullname; - } else { - $name = get_string('moodlenet:deletedcourse'); - $deleted = true; - } - // Activities. - } else if ($row->type == share_recorder::TYPE_ACTIVITY) { - if ($cm = get_coursemodule_from_id('', $row->cmid)) { - $name = $cm->name; - } else { - $name = get_string('moodlenet:deletedactivity'); - $deleted = true; - } - } - if ($deleted) { - $class = 'fst-italic'; - } - // Add a link to the resource if it was recorded. - if (!empty($row->resourceurl)) { - // Apply bold to resource links that aren't deleted. - if (!$deleted) { - $class = 'fw-bold'; - } - $icon = $OUTPUT->pix_icon('i/externallink', get_string('opensinnewwindow'), 'moodle', ['class' => 'ms-1']); - $text = $name . $icon; - $attributes = [ - 'target' => '_blank', - 'rel' => 'noopener noreferrer', - ]; - $name = html_writer::link($row->resourceurl, $text, $attributes); - } - - return html_writer::span($name, $class); - } - - /** - * Type column. - * - * @param stdClass $row Row data. - * @return string - */ - protected function col_type(stdClass $row): string { - // Courses. - if ($row->type == share_recorder::TYPE_COURSE) { - $type = get_string('course'); - // Activities. - } else if ($row->type == share_recorder::TYPE_ACTIVITY) { - if ($row->modname) { - $type = get_string('modulename', $row->modname); - } else { - // Alternatively, default to 'activity'. - $type = get_string('activity'); - } - } - - return $type; - } - - /** - * Time created column (Send date). - * - * @param stdClass $row Row data. - * @return string - */ - protected function col_timecreated(stdClass $row): string { - $format = get_string('strftimedatefullshort', 'core_langconfig'); - return userdate($row->timecreated, $format); - } - - /** - * Status column (Send status). - * - * @param stdClass $row Row data. - * @return string - */ - protected function col_status(stdClass $row): string { - // Display a badge indicating the status of the share. - if ($row->status == share_recorder::STATUS_IN_PROGRESS) { - $status = html_writer::span(get_string('inprogress'), 'badge bg-warning text-dark'); - } else if ($row->status == share_recorder::STATUS_SENT) { - $status = html_writer::span(get_string('sent'), 'badge bg-success text-white'); - } else if ($row->status == share_recorder::STATUS_ERROR) { - $status = html_writer::span(get_string('error'), 'badge bg-danger text-white'); - } - - return $status; - } - - /** - * Builds the SQL query. - * - * @param bool $count When true, return the count SQL. - * @return array containing sql to use and an array of params. - */ - protected function get_sql_and_params($count = false) { - if ($count) { - $select = "COUNT(1)"; - } else { - $select = "msp.id, msp.type, msp.courseid, msp.cmid, msp.timecreated, " . - "msp.resourceurl, msp.status, c.fullname, md.name AS modname"; - } - - $sql = "SELECT $select - FROM {moodlenet_share_progress} msp - LEFT JOIN {course} c ON c.id = msp.courseid - LEFT JOIN {course_modules} cm ON cm.course = msp.courseid - AND cm.id = msp.cmid - LEFT JOIN {modules} md ON md.id = cm.module - WHERE msp.userid = :userid"; - - $params = ['userid' => $this->userid]; - - if (!$count) { - $sql .= " ORDER BY msp.status DESC, msp.timecreated DESC"; - } - - return [$sql, $params]; - } - - /** - * Query the DB. - * - * @param int $pagesize size of page for paginated displayed table. - * @param bool $useinitialsbar do you want to use the initials bar. - */ - public function query_db($pagesize, $useinitialsbar = true) { - global $DB; - - list($countsql, $countparams) = $this->get_sql_and_params(true); - list($sql, $params) = $this->get_sql_and_params(); - $total = $DB->count_records_sql($countsql, $countparams); - $this->pagesize($pagesize, $total); - $this->rawdata = $DB->get_records_sql($sql, $params, $this->get_page_start(), $this->get_page_size()); - - // Set initial bars. - if ($useinitialsbar) { - $this->initialbars($total > $pagesize); - } - } - - /** - * Notification to display when there are no results. - */ - public function print_nothing_to_display() { - global $OUTPUT; - echo $OUTPUT->notification(get_string('moodlenet:nosharedresources'), 'info'); - } -} diff --git a/public/lib/classes/moodlenet/share_recorder.php b/public/lib/classes/moodlenet/share_recorder.php deleted file mode 100644 index 22d2318b663..00000000000 --- a/public/lib/classes/moodlenet/share_recorder.php +++ /dev/null @@ -1,132 +0,0 @@ -. - -namespace core\moodlenet; - -use moodle_exception; -use stdClass; - -/** - * Record the sharing of content to MoodleNet. - * - * @package core - * @copyright 2023 David Woloszyn - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class share_recorder { - - /** - * @var int The content being shared is a course. - */ - public const TYPE_COURSE = 1; - - /** - * @var int The content being shared is an activity. - */ - public const TYPE_ACTIVITY = 2; - - /** - * @var int The status of the share is 'sent'. - */ - public const STATUS_SENT = 1; - - /** - * @var int The status of the share is 'in progress'. - */ - public const STATUS_IN_PROGRESS = 2; - - /** - * @var int The status of the share is 'error'. - */ - public const STATUS_ERROR = 3; - - /** - * Get all allowed share types. - * - * @return array - */ - protected static function get_allowed_share_types(): array { - - return [ - self::TYPE_ACTIVITY, - self::TYPE_COURSE - ]; - } - - /** - * Get all allowed share statuses. - * Note that the particular status values aid in sorting. - * - * @return array - */ - protected static function get_allowed_share_statuses(): array { - - return [ - self::STATUS_SENT, - self::STATUS_IN_PROGRESS, - self::STATUS_ERROR, - ]; - } - - /** - * Create a new share progress record in the DB. - * - * @param int $sharetype The type of share (e.g. TYPE_COURSE). - * @param int $userid The ID of the user performing the share. - * @param int $courseid The associated course id. - * @param int|null $cmid The associated course module id (when sharing activity). - * @return int Returns the inserted record id. - */ - public static function insert_share_progress(int $sharetype, int $userid, int $courseid, ?int $cmid = null): int { - global $DB, $USER; - - if (!in_array($sharetype, self::get_allowed_share_types())) { - throw new moodle_exception('moodlenet:invalidsharetype'); - } - - $data = new stdClass(); - $data->type = $sharetype; - $data->courseid = $courseid; - $data->cmid = $cmid; - $data->userid = $userid; - $data->timecreated = time(); - $data->status = self::STATUS_IN_PROGRESS; - - return $DB->insert_record('moodlenet_share_progress', $data); - } - - /** - * Update the share progress record in the DB. - * - * @param int $shareid The id of the share progress row being updated. - * @param int $status The status of the share progress (e.g. STATUS_SENT). - * @param string|null $resourceurl The resource url returned from MoodleNet. - */ - public static function update_share_progress(int $shareid, int $status, ?string $resourceurl = null): void { - global $DB; - - if (!in_array($status, self::get_allowed_share_statuses())) { - throw new moodle_exception('moodlenet:invalidsharestatus'); - } - - $data = new stdClass(); - $data->id = $shareid; - $data->resourceurl = $resourceurl; - $data->status = $status; - - $DB->update_record('moodlenet_share_progress', $data); - } -} diff --git a/public/lib/classes/moodlenet/utilities.php b/public/lib/classes/moodlenet/utilities.php deleted file mode 100644 index 09098952ba8..00000000000 --- a/public/lib/classes/moodlenet/utilities.php +++ /dev/null @@ -1,123 +0,0 @@ -. - -namespace core\moodlenet; - -use core\oauth2\issuer; - -/** - * Class containing static utilities (such as various checks) required by the MoodleNet API. - * - * @package core - * @copyright 2023 Michael Hawkins - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class utilities { - /** - * Check whether the specified issuer is configured as a MoodleNet instance that can be shared to. - * - * @param issuer $issuer The OAuth 2 issuer being validated. - * @return bool true if the issuer is enabled and available to share to. - */ - public static function is_valid_instance(issuer $issuer): bool { - global $CFG; - - $issuerid = $issuer->get('id'); - $allowedissuer = get_config('moodlenet', 'oauthservice'); - - return ($CFG->enablesharingtomoodlenet && $issuerid == $allowedissuer && $issuer->get('enabled') && - $issuer->get('servicetype') == 'moodlenet'); - } - - /** - * Check whether a user has the capabilities required to share activities or courses to MoodleNet. - * - * @param \core\context\course $coursecontext Course context where the activity or course would be shared from. - * @param int $userid The user ID being checked. - * @param string $type The type of resource being checked (either 'activity' or 'course'). - * @return boolean - * @throws \coding_exception If an invalid resource type is provided. - */ - public static function can_user_share(\core\context\course $coursecontext, int $userid, string $type = 'activity'): bool { - if ($type === 'course') { - return (has_capability('moodle/moodlenet:sharecourse', $coursecontext, $userid) && - has_capability('moodle/backup:backupcourse', $coursecontext, $userid)); - } else if ($type === 'activity') { - return (has_capability('moodle/moodlenet:shareactivity', $coursecontext, $userid) && - has_capability('moodle/backup:backupactivity', $coursecontext, $userid)); - } - - throw new \coding_exception('Invalid resource type'); - } - - /** - * Get the support url. - * - * @return string - */ - public static function get_support_url(): string { - global $CFG; - $supporturl = ''; - - if ($CFG->supportavailability && $CFG->supportavailability !== CONTACT_SUPPORT_DISABLED) { - if (!empty($CFG->supportpage)) { - $supporturl = $CFG->supportpage; - } else { - $supporturl = $CFG->wwwroot . '/user/contactsitesupport.php'; - } - } - - return $supporturl; - } - - /** - * Check the user has a valid capability in any course they are enrolled in. - * - * @param int $userid The user id to query - * @return string Returns 'yes' if capability found, 'no' if not - */ - public static function does_user_have_capability_in_any_course(int $userid): string { - // We are checking this way because we are not always in the course context and need - // a way to retrieve the user's courses to see if any of them have the correct capability. - $capabilities = [ - 'moodle/moodlenet:sharecourse', - 'moodle/moodlenet:shareactivity' - ]; - // We are using 'no' instead of false to avoid confusing a cache key - // that was not found (returns false) with a user who does not have the capablity. - $isallowed = 'no'; - $cache = \cache::make('core', 'moodlenet_usercanshare'); - $cachedvalue = $cache->get($userid); - - if ($cachedvalue === false) { - foreach ($capabilities as $capability) { - // Find at least one course that contains a capability match. - $course = get_user_capability_course($capability, $userid, true, '', 'id', 1); - - if (!empty($course)) { - // Set the cache to 'yes' and break out of the loop. - $isallowed = 'yes'; - break; - } - } - $cache->set($userid, $isallowed); - } else { - $isallowed = $cachedvalue; - } - - return $isallowed; - } -} diff --git a/public/lib/classes/navigation/settings_navigation.php b/public/lib/classes/navigation/settings_navigation.php index 702bae44c76..516149028e7 100644 --- a/public/lib/classes/navigation/settings_navigation.php +++ b/public/lib/classes/navigation/settings_navigation.php @@ -29,7 +29,6 @@ use core\exception\coding_exception; use core\output\action_link; use core\output\pix_icon; use core\url; -use core\moodlenet\utilities; use core_contentbank\contentbank; use core_plugin_manager; use dml_missing_record_exception; @@ -425,46 +424,6 @@ class settings_navigation extends navigation_node { $coursenode->force_open(); } - // MoodleNet links. - if ($this->page->user_is_editing()) { - $this->page->requires->js_call_amd('core/moodlenet/mutations', 'init'); - } - $usercanshare = utilities::can_user_share($coursecontext, $USER->id, 'course'); - $issuerid = get_config('moodlenet', 'oauthservice'); - try { - $issuer = \core\oauth2\api::get_issuer($issuerid); - $isvalidinstance = utilities::is_valid_instance($issuer); - if ($usercanshare && $isvalidinstance) { - $this->page->requires->js_call_amd('core/moodlenet/send_resource', 'init'); - $action = new action_link(new url(''), '', null, [ - 'data-action' => 'sendtomoodlenet', - 'data-type' => 'course', - ]); - // Share course to MoodleNet link. - $coursenode->add( - get_string('moodlenet:sharetomoodlenet', 'moodle'), - $action, - self::TYPE_SETTING, - null, - 'exportcoursetomoodlenet' - )->set_force_into_more_menu(true); - // MoodleNet share progress link. - $url = new url('/moodlenet/shareprogress.php'); - $coursenode->add( - get_string('moodlenet:shareprogress'), - $url, - self::TYPE_SETTING, - null, - 'moodlenetshareprogress' - )->set_force_into_more_menu(true); - } - } catch (dml_missing_record_exception $e) { - debugging( - "Invalid MoodleNet OAuth 2 service set in site administration: 'moodlenet | oauthservice'. " . - "This must be a valid issuer." - ); - } - if ($adminoptions->update) { // Add the course settings link. $url = new url('/course/edit.php', ['id' => $course->id]); @@ -884,31 +843,6 @@ class settings_navigation extends navigation_node { $function($this, $modulenode); } - // Send activity to MoodleNet. - $usercanshare = utilities::can_user_share($this->context->get_course_context(), $USER->id); - $issuerid = get_config('moodlenet', 'oauthservice'); - try { - $issuer = \core\oauth2\api::get_issuer($issuerid); - $isvalidinstance = utilities::is_valid_instance($issuer); - if ($usercanshare && $isvalidinstance) { - $this->page->requires->js_call_amd('core/moodlenet/send_resource', 'init'); - $action = new action_link(new url(''), '', null, [ - 'data-action' => 'sendtomoodlenet', - 'data-type' => 'activity', - ]); - $modulenode->add( - get_string('moodlenet:sharetomoodlenet', 'moodle'), - $action, - self::TYPE_SETTING, - null, - 'exportmoodlenet' - )->set_force_into_more_menu(true); - } - } catch (dml_missing_record_exception $e) { - debugging("Invalid MoodleNet OAuth 2 service set in site administration: 'moodlenet | oauthservice'. " . - "This must be a valid issuer."); - } - // Remove the module node if there are no children. if ($modulenode->children->count() <= 0) { $modulenode->remove(); diff --git a/public/lib/classes/navigation/views/secondary.php b/public/lib/classes/navigation/views/secondary.php index 7140325c4f7..f47922018ea 100644 --- a/public/lib/classes/navigation/views/secondary.php +++ b/public/lib/classes/navigation/views/secondary.php @@ -124,7 +124,6 @@ class secondary extends view { 'backup' => 9, 'restore' => 10, 'competencybreakdown' => 11, - 'sendtomoodlenet' => 16, ], self::TYPE_CUSTOM => [ 'advgrading' => 2, diff --git a/public/lib/classes/oauth2/api.php b/public/lib/classes/oauth2/api.php index cc6d443e71e..260ea355305 100644 --- a/public/lib/classes/oauth2/api.php +++ b/public/lib/classes/oauth2/api.php @@ -76,8 +76,8 @@ class api { /** * Create one of the standard issuers. * - * @param string $type One of google, facebook, microsoft, MoodleNet, nextcloud or imsobv2p1 - * @param string|false $baseurl Baseurl (only required for nextcloud, imsobv2p1 and moodlenet) + * @param string $type One of google, facebook, microsoft, nextcloud or imsobv2p1 + * @param string|false $baseurl Baseurl (only required for nextcloud and imsobv2p1) * @return \core\oauth2\issuer */ public static function create_standard_issuer($type, $baseurl = false) { @@ -92,10 +92,6 @@ class api { if (!$baseurl) { throw new moodle_exception('Nextcloud service type requires the baseurl parameter.'); } - case 'moodlenet': - if (!$baseurl) { - throw new moodle_exception('MoodleNet service type requires the baseurl parameter.'); - } case 'google': case 'facebook': case 'microsoft': diff --git a/public/lib/classes/oauth2/service/moodlenet.php b/public/lib/classes/oauth2/service/moodlenet.php deleted file mode 100644 index 4ceee2de547..00000000000 --- a/public/lib/classes/oauth2/service/moodlenet.php +++ /dev/null @@ -1,189 +0,0 @@ -. - -namespace core\oauth2\service; - -use core\http_client; -use core\oauth2\discovery\auth_server_config_reader; -use core\oauth2\endpoint; -use core\oauth2\issuer; -use GuzzleHttp\Psr7\Request; - -/** - * MoodleNet OAuth 2 configuration. - * - * @package core - * @copyright 2023 Jake Dallimore - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class moodlenet implements issuer_interface { - - /** - * Get the issuer template to display in the form. - * - * @return issuer the issuer. - */ - public static function init(): ?issuer { - $record = (object) [ - 'name' => 'MoodleNet', - 'image' => 'https://moodle.net/favicon.ico', - 'baseurl' => 'https://moodle.net', - 'loginscopes' => '', - 'loginscopesoffline' => '', - 'loginparamsoffline' => '', - 'showonloginpage' => issuer::SERVICEONLY, - 'servicetype' => 'moodlenet', - ]; - $issuer = new issuer(0, $record); - - return $issuer; - } - - /** - * Create the endpoints for the issuer. - * - * @param issuer $issuer the issuer instance. - * @return issuer the issuer instance. - */ - public static function create_endpoints(issuer $issuer): issuer { - self::discover_endpoints($issuer); - return $issuer; - } - - /** - * Read the OAuth 2 Auth Server Metadata. - * - * @param issuer $issuer the issuer instance. - * @return int the number of endpoints created. - */ - public static function discover_endpoints($issuer): int { - $baseurl = $issuer->get('baseurl'); - if (empty($baseurl)) { - return 0; - } - - $endpointscreated = 0; - $config = []; - if (defined('BEHAT_SITE_RUNNING')) { - $config['verify'] = false; - } - $configreader = new auth_server_config_reader(new http_client($config)); - try { - $config = $configreader->read_configuration(new \moodle_url($baseurl)); - - foreach ($config as $key => $value) { - if (substr_compare($key, '_endpoint', -strlen('_endpoint')) === 0) { - $record = new \stdClass(); - $record->issuerid = $issuer->get('id'); - $record->name = $key; - $record->url = $value; - - $endpoint = new endpoint(0, $record); - $endpoint->create(); - $endpointscreated++; - } - - if ($key == 'scopes_supported') { - $issuer->set('scopessupported', implode(' ', $value)); - $issuer->update(); - } - } - } catch (\Exception $e) { - throw new \moodle_exception('Could not read service configuration for issuer: ' . $issuer->get('name')); - } - - try { - self::client_registration($issuer); - } catch (\Exception $e) { - throw new \moodle_exception('Could not register client for issuer: ' . $issuer->get('name')); - } - - return $endpointscreated; - } - - /** - * Perform (open) OAuth 2 Dynamic Client Registration with the MoodleNet application. - * - * @param issuer $issuer the issuer instance containing the service baseurl. - * @return void - */ - protected static function client_registration(issuer $issuer): void { - global $CFG, $SITE; - - $clientid = $issuer->get('clientid'); - $clientsecret = $issuer->get('clientsecret'); - - if (empty($clientid) && empty($clientsecret)) { - $url = $issuer->get_endpoint_url('registration'); - if ($url) { - $scopes = str_replace("\r", " ", $issuer->get('scopessupported')); - $hosturl = $CFG->wwwroot; - - $request = [ - 'client_name' => $SITE->fullname, - 'client_uri' => $hosturl, - 'logo_uri' => $hosturl . '/pix/moodlelogo.png', - 'tos_uri' => $hosturl, - 'policy_uri' => $hosturl, - 'software_id' => 'moodle', - 'software_version' => $CFG->version, - 'redirect_uris' => [ - $hosturl . '/admin/oauth2callback.php' - ], - 'token_endpoint_auth_method' => 'client_secret_basic', - 'grant_types' => [ - 'authorization_code', - 'refresh_token' - ], - 'response_types' => [ - 'code' - ], - 'scope' => $scopes - ]; - - $config = []; - if (defined('BEHAT_SITE_RUNNING')) { - $config['verify'] = false; - } - $client = new http_client($config); - $request = new Request( - 'POST', - $url, - [ - 'Content-type' => 'application/json', - 'Accept' => 'application/json', - ], - json_encode($request) - ); - - try { - $response = $client->send($request); - $responsebody = $response->getBody()->getContents(); - $decodedbody = json_decode($responsebody, true); - if (is_null($decodedbody)) { - throw new \moodle_exception('Error: ' . __METHOD__ . ': Failed to decode response body. Invalid JSON.'); - } - $issuer->set('clientid', $decodedbody['client_id']); - $issuer->set('clientsecret', $decodedbody['client_secret']); - $issuer->update(); - } catch (\Exception $e) { - $msg = "Could not self-register {$issuer->get('name')}. Wrong URL or JSON data [URL: $url]"; - throw new \moodle_exception($msg); - } - } - } - } -} diff --git a/public/lib/classes/privacy/provider.php b/public/lib/classes/privacy/provider.php index 565bf542c5a..a888d299315 100644 --- a/public/lib/classes/privacy/provider.php +++ b/public/lib/classes/privacy/provider.php @@ -53,7 +53,7 @@ class provider implements * @return collection The collection object filled out with information about this component. */ public static function get_metadata(collection $collection): collection { - // Except for moodlenet_share_progress, these tables are really data about site configuration and not user data. + // Except for shortlink, these tables are really data about site configuration and not user data. // The config_log includes information about which user performed a configuration change. // The value and oldvalue may contain sensitive information such as accounts for service passwords.. @@ -126,22 +126,6 @@ class provider implements 'scopehash' => 'privacy:metadata:oauth2_refresh_token:scopehash' ], 'privacy:metadata:oauth2_refresh_token'); - // The moodlenet_share_progress includes details of an attempted share of a resource to MoodleNet. - $collection->add_database_table('moodlenet_share_progress', [ - 'type' => 'privacy:metadata:moodlenet_share_progress:type', - 'courseid' => 'privacy:metadata:moodlenet_share_progress:courseid', - 'cmid' => 'privacy:metadata:moodlenet_share_progress:cmid', - 'userid' => 'privacy:metadata:moodlenet_share_progress:userid', - 'timecreated' => 'privacy:metadata:moodlenet_share_progress:timecreated', - 'resourceurl' => 'privacy:metadata:moodlenet_share_progress:resourceurl', - 'status' => 'privacy:metadata:moodlenet_share_progress:status', - ], 'privacy:metadata:moodlenet_share_progress'); - - // This resourceurl field is an external link from MoodleNet. - $collection->add_external_location_link('moodlenet_share_progress', [ - 'resourceurl' => 'privacy:metadata:moodlenet_share_progress:resourceurl', - ], 'privacy:metadata:moodlenet_share_progress'); - // The shortlink table includes data that associates a user with a shortlink URL. $collection->add_database_table('shortlink', [ 'shortcode' => 'privacy:metadata:shortlink:shortcode', @@ -163,15 +147,6 @@ class provider implements public static function get_contexts_for_userid(int $userid): contextlist { $contextlist = new contextlist(); - // MoodleNet share progress uses the user context. - $sql = "SELECT ctx.id - FROM {context} ctx - JOIN {moodlenet_share_progress} msp ON ctx.instanceid = msp.userid - AND ctx.contextlevel = :contextlevel - WHERE msp.userid = :userid"; - $params = ['userid' => $userid, 'contextlevel' => CONTEXT_USER]; - $contextlist->add_from_sql($sql, $params); - // Shortlink. $sql = "SELECT ctx.id FROM {context} ctx @@ -192,16 +167,6 @@ class provider implements public static function get_users_in_context(userlist $userlist) { $context = $userlist->get_context(); - // MoodleNet share progress uses the user context. - if ($context->contextlevel == CONTEXT_USER) { - // Get all distinct userids from the table. - $sql = "SELECT DISTINCT userid - FROM {moodlenet_share_progress} - WHERE userid = :userid"; - $params = ['userid' => $context->instanceid]; - $userlist->add_from_sql('userid', $sql, $params); - } - // Shortlink. if ($context->contextlevel == CONTEXT_USER) { // Get all distinct userids from the table. @@ -219,16 +184,11 @@ class provider implements * @param approved_contextlist $contextlist The approved contexts to export information for. */ public static function export_user_data(approved_contextlist $contextlist) { - // Except for moodlenet_share_progress and shortlink, none of the core tables should be exported. + // Except for shortlink, none of the core tables should be exported. global $DB; foreach ($contextlist as $context) { if ($context->contextlevel == CONTEXT_USER && $context->instanceid == $contextlist->get_user()->id) { - // Get the user's MoodleNet share progress data. - $sharedata = $DB->get_records('moodlenet_share_progress', ['userid' => $context->instanceid]); - $subcontext = get_string('privacy:metadata:moodlenet_share_progress', 'moodle'); - writer::with_context($context)->export_data([$subcontext], (object) $sharedata); - // Get the user's shortlink data. $shortlinkdata = $DB->get_records('shortlink', ['userid' => $context->instanceid]); $subcontext = get_string('privacy:metadata:shortlink', 'moodle'); @@ -243,14 +203,9 @@ class provider implements * @param \context $context The specific context to delete data for. */ public static function delete_data_for_all_users_in_context(\context $context) { - // Except for moodlenet_share_progress and shortlink, none of the data from these tables should be deleted. + // Except for shortlink, none of the data from these tables should be deleted. global $DB; - // MoodleNet share progress uses the user context. - if ($context->contextlevel == CONTEXT_USER) { - $DB->delete_records('moodlenet_share_progress', ['userid' => $context->instanceid]); - } - // Shortlink. if ($context->contextlevel == CONTEXT_USER) { $DB->delete_records('shortlink', ['userid' => $context->instanceid]); @@ -263,15 +218,13 @@ class provider implements * @param approved_contextlist $contextlist The approved contexts and user information to delete information for. */ public static function delete_data_for_user(approved_contextlist $contextlist) { - // Except for moodlenet_share_progress and shortlink, none of the data from these tables should be deleted. + // Except for shortlink, none of the data from these tables should be deleted. // Note: Although it may be tempting to delete the adhoc task data, do not do so. // The delete process is run as an adhoc task. global $DB; foreach ($contextlist as $context) { if ($context->contextlevel == CONTEXT_USER && $context->instanceid == $contextlist->get_user()->id) { - // MoodleNet share progress uses the user context. - $DB->delete_records('moodlenet_share_progress', ['userid' => $context->instanceid]); // Shortlink. $DB->delete_records('shortlink', ['userid' => $context->instanceid]); } @@ -284,7 +237,7 @@ class provider implements * @param approved_userlist $userlist The approved context and user information to delete information for. */ public static function delete_data_for_users(approved_userlist $userlist) { - // Except for moodlenet_share_progress and shortlink, none of the data from these tables should be deleted. + // Except for shortlink, none of the data from these tables should be deleted. // Note: Although it may be tempting to delete the adhoc task data, do not do so. // The delete process is run as an adhoc task. global $DB; @@ -296,8 +249,6 @@ class provider implements } if ($context->contextlevel == CONTEXT_USER) { - // MoodleNet share progress uses the user context. - $DB->delete_records('moodlenet_share_progress', ['userid' => $context->instanceid]); // Shortlink. $DB->delete_records('shortlink', ['userid' => $context->instanceid]); } diff --git a/public/lib/db/access.php b/public/lib/db/access.php index 9c0c402ac2c..53e99f65af1 100644 --- a/public/lib/db/access.php +++ b/public/lib/db/access.php @@ -2767,16 +2767,6 @@ $capabilities = array( 'archetypes' => [], ], - // Allow users to share activities to MoodleNet. - 'moodle/moodlenet:shareactivity' => [ - 'captype' => 'read', - 'contextlevel' => CONTEXT_COURSE, - 'archetypes' => [ - 'editingteacher' => CAP_ALLOW, - 'manager' => CAP_ALLOW, - ] - ], - // Allow users to configure course communication rooms. 'moodle/course:configurecoursecommunication' => [ 'captype' => 'write', @@ -2787,16 +2777,6 @@ $capabilities = array( ] ], - // Allow users to share courses to MoodleNet. - 'moodle/moodlenet:sharecourse' => [ - 'captype' => 'read', - 'contextlevel' => CONTEXT_COURSE, - 'archetypes' => [ - 'editingteacher' => CAP_ALLOW, - 'manager' => CAP_ALLOW, - ] - ], - // Allow users to edit course welcome messages. 'moodle/course:editcoursewelcomemessage' => [ 'captype' => 'write', diff --git a/public/lib/db/caches.php b/public/lib/db/caches.php index 376e979fe51..50193fe03d9 100644 --- a/public/lib/db/caches.php +++ b/public/lib/db/caches.php @@ -592,19 +592,6 @@ $definitions = array( 'staticaccelerationsize' => 100, ], - // Cache if a user has the capability to share to MoodleNet. - 'moodlenet_usercanshare' => [ - 'mode' => cache_store::MODE_SESSION, - 'simplekeys' => true, - 'simpledata' => true, - 'ttl' => 1800, - 'invalidationevents' => [ - 'changesincoursecat', - 'changesincategoryenrolment', - 'changesincourse', - ], - ], - // A theme has been used in context to override the default theme. // Applies to user, cohort, category and course. 'theme_usedincontext' => [ diff --git a/public/lib/db/install.xml b/public/lib/db/install.xml index 209ea8115c6..46907a5781f 100644 --- a/public/lib/db/install.xml +++ b/public/lib/db/install.xml @@ -915,7 +915,6 @@ - @@ -4884,21 +4883,6 @@ - - - - - - - - - - - - - - -
diff --git a/public/lib/db/services.php b/public/lib/db/services.php index 174a6838742..9876330cb66 100644 --- a/public/lib/db/services.php +++ b/public/lib/db/services.php @@ -3247,36 +3247,6 @@ $functions = array( 'type' => 'write', 'ajax' => true, ], - 'core_moodlenet_send_activity' => [ - 'classname' => 'core\external\moodlenet_send_activity', - 'description' => 'Send activity to MoodleNet', - 'type' => 'read', - 'ajax' => true, - ], - 'core_moodlenet_get_share_info_activity' => [ - 'classname' => 'core\external\moodlenet_get_share_info_activity', - 'description' => 'Get information about an activity being shared', - 'type' => 'read', - 'ajax' => true, - ], - 'core_moodlenet_auth_check' => [ - 'classname' => 'core\external\moodlenet_auth_check', - 'description' => 'Check a user has authorized for a given MoodleNet site', - 'type' => 'write', - 'ajax' => true, - ], - 'core_moodlenet_get_shared_course_info' => [ - 'classname' => 'core\external\moodlenet_get_shared_course_info', - 'description' => 'Get information about an course being shared', - 'type' => 'read', - 'ajax' => true, - ], - 'core_moodlenet_send_course' => [ - 'classname' => 'core\external\moodlenet_send_course', - 'description' => 'Send course to MoodleNet', - 'type' => 'read', - 'ajax' => true, - ], 'core_output_poll_stored_progress' => [ 'classname' => 'core\external\output\poll_stored_progress', 'methodname' => 'execute', diff --git a/public/lib/db/upgrade.php b/public/lib/db/upgrade.php index bcee4c7a846..1ff1868fecf 100644 --- a/public/lib/db/upgrade.php +++ b/public/lib/db/upgrade.php @@ -1043,7 +1043,7 @@ function xmldb_main_upgrade($oldversion) { // Handle custom params. if (isset($action['settings']['modelextraparams'])) { $modelsettings['custom']['modelextraparams'] = $action['settings']['modelextraparams'] ?? ''; - // Handle known models and their keys. + // Handle known models and their keys. } else if (isset($affectedkeys[$model])) { foreach ($affectedkeys[$model] as $key) { $modelsettings[$model][$key] = $action['settings'][$key] ?? ''; @@ -1445,7 +1445,7 @@ function xmldb_main_upgrade($oldversion) { $dbman->add_field($table, $field); } - // Define field area to be added to customfield_data. + // Define field area to be added to customfield_data. $table = new xmldb_table('customfield_data'); $field = new xmldb_field('area', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, 'component'); @@ -1621,7 +1621,7 @@ function xmldb_main_upgrade($oldversion) { } if ($oldversion < 2025121900.01) { - // Define field nextversion to be added to question_bank_entries. + // Define field nextversion to be added to question_bank_entries. $table = new xmldb_table('question_bank_entries'); $field = new xmldb_field('nextversion', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'ownerid'); @@ -1771,5 +1771,68 @@ function xmldb_main_upgrade($oldversion) { upgrade_main_savepoint(true, 2026030600.01); } + if ($oldversion < 2026030600.02) { + // Remove MoodleNet outbound sharing functionality. + + // Drop the moodlenet_share_progress table if it exists. + $table = new xmldb_table('moodlenet_share_progress'); + if ($dbman->table_exists($table)) { + $dbman->drop_table($table); + } + + // Remove the enablesharingtomoodlenet config setting. + unset_config('enablesharingtomoodlenet'); + + // Remove MoodleNet outbound OAuth2 configuration. + unset_config('oauthservice', 'moodlenet'); + $issuerids = $DB->get_fieldset_select('oauth2_issuer', 'id', "servicetype = ?", ['moodlenet']); + if (!empty($issuerids)) { + $DB->delete_records_list('oauth2_endpoint', 'issuerid', $issuerids); + $DB->delete_records_list('oauth2_access_token', 'issuerid', $issuerids); + $DB->delete_records_list('oauth2_refresh_token', 'issuerid', $issuerids); + $DB->delete_records_list('oauth2_system_account', 'issuerid', $issuerids); + $DB->delete_records_list('oauth2_user_field_mapping', 'issuerid', $issuerids); + $DB->delete_records_list('oauth2_issuer', 'id', $issuerids); + } + + // Main savepoint reached. + upgrade_main_savepoint(true, 2026030600.02); + } + + if ($oldversion < 2026030600.03) { + require_once($CFG->dirroot . '/lib/db/upgradelib.php'); + + // Check if the moodlenetprofile column exists in the user table. + $table = new xmldb_table('user'); + $field = new xmldb_field('moodlenetprofile'); + + if ($dbman->field_exists($table, $field)) { + // Move the MoodleNet profile. + moodlenet_migrate_profile_field(); + + // Remove the moodlenetprofile column from the user table. + $dbman->drop_field($table, $field); + } + + // Main savepoint reached. + upgrade_main_savepoint(true, 2026030600.03); + } + + if ($oldversion < 2026030600.04) { + // Remove tool_moodlenet if no longer present. + if (!file_exists($CFG->dirroot . '/admin/tool/moodlenet/version.php')) { + // Reset activity chooser footer if set to tool_moodlenet. + if (get_config('core', 'activitychooseractivefooter') === 'tool_moodlenet') { + set_config('activitychooseractivefooter', 'hidden'); + } + + // Uninstall the plugin. + uninstall_plugin('tool', 'moodlenet'); + } + + // Main savepoint reached. + upgrade_main_savepoint(true, 2026030600.04); + } + return true; } diff --git a/public/lib/db/upgradelib.php b/public/lib/db/upgradelib.php index 6ba4e91210f..f1f6d832bb2 100644 --- a/public/lib/db/upgradelib.php +++ b/public/lib/db/upgradelib.php @@ -2113,3 +2113,72 @@ function upgrade_create_async_mimetype_upgrade_task(string $mimetype, array $ext $DB->insert_record('task_adhoc', $record); } + +/** + * Creates MoodleNet profile field and migrates data from user.moodlenetprofile. + */ +function moodlenet_migrate_profile_field(): void { + global $DB, $CFG; + + // Check if there are users with moodlenetprofile data first. + if (!$DB->record_exists_select('user', "moodlenetprofile IS NOT NULL AND moodlenetprofile <> ''")) { + // No data to migrate, skip creating the field. + return; + } + + require_once($CFG->dirroot . '/user/profile/definelib.php'); + require_once($CFG->dirroot . '/user/profile/field/text/define.class.php'); + + // Get or create the MoodleNet category. + $categoryname = 'MoodleNet'; + $category = $DB->get_record('user_info_category', ['name' => $categoryname]); + + if (!$category) { + $data = new \stdClass(); + $data->sortorder = $DB->count_records('user_info_category') + 1; + $data->name = $categoryname; + $data->id = $DB->insert_record('user_info_category', $data); + $category = $DB->get_record('user_info_category', ['id' => $data->id]); + \core\event\user_info_category_created::create_from_category($category)->trigger(); + } + + // Get or create the moodlenetprofile field. + $field = $DB->get_record('user_info_field', [ + 'shortname' => 'moodlenetprofile', + 'categoryid' => $category->id, + ]); + + if (!$field) { + $profileclass = new \profile_define_text(); + $data = (object) [ + 'shortname' => 'moodlenetprofile', + 'name' => 'MoodleNet profile ID', + 'datatype' => 'text', + 'description' => 'Your MoodleNet profile ID links your MoodleNet profile with this site.', + 'descriptionformat' => 1, + 'categoryid' => $category->id, + 'signup' => 1, + 'forceunique' => 1, + 'visible' => 2, + 'param1' => 30, + 'param2' => 2048, + ]; + + $profileclass->define_save($data); + $field = $DB->get_record('user_info_field', ['shortname' => 'moodlenetprofile']); + } + + // Migrate data from user.moodlenetprofile to custom field, skipping already-migrated rows. + $sql = "INSERT INTO {user_info_data} (userid, fieldid, data, dataformat) + SELECT u.id, :fieldid, u.moodlenetprofile, 0 + FROM {user} u + WHERE u.moodlenetprofile IS NOT NULL + AND u.moodlenetprofile <> '' + AND NOT EXISTS ( + SELECT 1 + FROM {user_info_data} uid + WHERE uid.userid = u.id + AND uid.fieldid = :fieldid2 + )"; + $DB->execute($sql, ['fieldid' => $field->id, 'fieldid2' => $field->id]); +} diff --git a/public/lib/myprofilelib.php b/public/lib/myprofilelib.php index 8b197430cea..aff98f5a2ec 100644 --- a/public/lib/myprofilelib.php +++ b/public/lib/myprofilelib.php @@ -165,12 +165,6 @@ function core_myprofile_navigation(core_user\output\myprofile\tree $tree, $user, $tree->add_node($node); } - if (!isset($hiddenfields['moodlenetprofile']) && $user->moodlenetprofile) { - $node = new core_user\output\myprofile\node('contact', 'moodlenetprofile', get_string('moodlenetprofile', 'user'), null, - null, $user->moodlenetprofile); - $tree->add_node($node); - } - if (!isset($hiddenfields['country']) && $user->country) { $node = new core_user\output\myprofile\node('contact', 'country', get_string('country'), null, null, get_string($user->country, 'countries')); diff --git a/public/lib/templates/moodlenet/send_activity_modal_base.mustache b/public/lib/templates/moodlenet/send_activity_modal_base.mustache deleted file mode 100644 index ff2521e5660..00000000000 --- a/public/lib/templates/moodlenet/send_activity_modal_base.mustache +++ /dev/null @@ -1,60 +0,0 @@ -{{! - 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 . -}} -{{! - @template core/moodlenet/send_activity_modal_base - Modal to send activity to MoodleNet - Example context (json): - { - "uniqid": 123456, - "activitytype": "assignment", - "activityname": "Test assignment", - "sharetype": "resource" - } -}} - diff --git a/public/lib/templates/moodlenet/send_activity_modal_done.mustache b/public/lib/templates/moodlenet/send_activity_modal_done.mustache deleted file mode 100644 index 4d13ce686cb..00000000000 --- a/public/lib/templates/moodlenet/send_activity_modal_done.mustache +++ /dev/null @@ -1,57 +0,0 @@ -{{! - 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 . -}} -{{! - @template core/moodlenet/send_activity_modal_done - This template renders done state for share modal. - Example context (json): - { - "success": true, - "sitesupporturl": "https://moodle.test/contactsitesupport.php" - } -}} -
-
- - {{#success}} - {{#pix}} t/check, core {{/pix}} - {{/success}} - {{^success}} - {{#pix}} fp/cross, theme {{/pix}} - {{/success}} - - - {{#success}} - {{#str}} moodlenet:sharesuccesstitle, moodle {{/str}} - {{/success}} - {{^success}} - {{#str}} moodlenet:sharefailtitle, moodle {{/str}} - {{/success}} - -
-
- - {{#success}} - {{#str}} moodlenet:sharesuccesstext, moodle {{/str}} - {{/success}} - {{^success}} - {{#sitesupporturl}} - {{#str}} moodlenet:sharefailtextwithsitesupport, moodle, {{sitesupporturl}} {{/str}} - {{/sitesupporturl}} - {{^sitesupporturl}} - {{#str}} moodlenet:sharefailtext, moodle {{/str}} - {{/sitesupporturl}} - {{/success}} - -
-
diff --git a/public/lib/templates/moodlenet/send_activity_modal_footer_share.mustache b/public/lib/templates/moodlenet/send_activity_modal_footer_share.mustache deleted file mode 100644 index df065ac03d6..00000000000 --- a/public/lib/templates/moodlenet/send_activity_modal_footer_share.mustache +++ /dev/null @@ -1,28 +0,0 @@ -{{! - 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 . -}} -{{! - @template core/moodlenet/send_activity_modal_footer_share - Render the footer for sharing activity - Example context (json): - { - "server": "MoodleNet Local" - } -}} -
- {{#str}} moodlenet:sharingto, moodle {{/str}}{{server}} -
-
- - -
diff --git a/public/lib/templates/moodlenet/send_activity_modal_footer_view.mustache b/public/lib/templates/moodlenet/send_activity_modal_footer_view.mustache deleted file mode 100644 index 93ca6b33ab4..00000000000 --- a/public/lib/templates/moodlenet/send_activity_modal_footer_view.mustache +++ /dev/null @@ -1,26 +0,0 @@ -{{! - 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 . -}} -{{! - @template core/moodlenet/send_activity_modal_footer_view - Render the footer for sharing activity - Example context (json): - { - "resourceurl": "https://moodlenet.test/draft/activity.mbz" - } -}} - diff --git a/public/lib/templates/moodlenet/send_activity_modal_packaging.mustache b/public/lib/templates/moodlenet/send_activity_modal_packaging.mustache deleted file mode 100644 index 7de46341eb0..00000000000 --- a/public/lib/templates/moodlenet/send_activity_modal_packaging.mustache +++ /dev/null @@ -1,28 +0,0 @@ -{{! - 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 . -}} -{{! - @template core/moodlenet/send_activity_modal_packaging - This template renders the packaging stage for MoodleNet. - Example context (json): - { - } -}} -
-
{{#str}} moodlenet:sharingstatus, moodle {{/str}}
-
{{#str}} moodlenet:sharinglargefile, moodle {{/str}}
-
- {{> core/loading }} -
-
{{#str}} moodlenet:packagingandsending, moodle {{/str}}
-
diff --git a/public/lib/tests/behat/behat_moodlenet.php b/public/lib/tests/behat/behat_moodlenet.php deleted file mode 100644 index c849d955f58..00000000000 --- a/public/lib/tests/behat/behat_moodlenet.php +++ /dev/null @@ -1,56 +0,0 @@ -. - -// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php. - -use Moodle\BehatExtension\Exception\SkippedException; - -require_once(__DIR__ . '/../../behat/behat_base.php'); - -/** - * Steps definitions related to MoodleNet. - * - * @package core - * @category test - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class behat_moodlenet extends behat_base { - - /** - * Check that the TEST_MOODLENET_MOCK_SERVER is defined, so we can connect to the mock server. - * - * @Given /^a MoodleNet mock server is configured$/ - */ - public function mock_is_configured(): void { - if (!defined('TEST_MOODLENET_MOCK_SERVER')) { - throw new SkippedException( - 'The TEST_MOODLENET_MOCK_SERVER constant must be defined to run MoodleNet tests' - ); - } - } - - /** - * Change the service base url to the TEST_MOODLENET_MOCK_SERVER url. - * - * @Given /^I change the MoodleNet field "(?P(?:[^"]|\\")*)" to mock server$/ - * @param string $field Field name - */ - public function change_service_base_url_to_mock_url(string $field): void { - $field = behat_field_manager::get_form_field_from_label($field, $this); - $field->set_value(TEST_MOODLENET_MOCK_SERVER); - } -} diff --git a/public/lib/tests/behat/moodlenet_outbound.feature b/public/lib/tests/behat/moodlenet_outbound.feature deleted file mode 100644 index a9db6e08ffe..00000000000 --- a/public/lib/tests/behat/moodlenet_outbound.feature +++ /dev/null @@ -1,94 +0,0 @@ -@core -Feature: MoodleNet outbound send activity - In order to send activity to MoodleNet server - As a teacher - I need to be able package the activity and share to MoodleNet - - Background: - Given I log in as "admin" - And a MoodleNet mock server is configured - And the following config values are set as admin: - | enablesharingtomoodlenet | 1 | - And I navigate to "Server > OAuth 2 services" in site administration - And I press "MoodleNet" - And I should see "Create new service: MoodleNet" - And I change the MoodleNet field "Service base URL" to mock server - And I press "Save changes" - And I navigate to "MoodleNet > MoodleNet outbound settings" in site administration - And I set the field "Auth 2 service" to "MoodleNet" - And I press "Save changes" - And the following course exists: - | name | Test course | - | shortname | C1 | - And the following "users" exist: - | username | firstname | lastname | email | - | student1 | Student | 1 | student1@example.com | - | teacher1 | Teacher | 1 | teacher1@example.com | - | manager1 | Manager | 1 | manager1@example.com | - And the following "course enrolments" exist: - | user | course | role | - | manager1 | C1 | manager | - | teacher1 | C1 | editingteacher | - | student1 | C1 | student | - And the following "activities" exist: - | activity | course | idnumber | name | intro | - | assign | C1 | assign1 | Test Assignment 1 | Test Assignment 1 | - - Scenario: Share to MoodleNet menu only be available for teachers and managers - Given I am on the "Test Assignment 1" "assign activity" page logged in as student1 - Then "Share to MoodleNet" "link" should not exist in current page administration - And I am on the "Test Assignment 1" "assign activity" page logged in as teacher1 - And "Share to MoodleNet" "link" should exist in current page administration - And I am on the "Test Assignment 1" "assign activity" page logged in as manager1 - And "Share to MoodleNet" "link" should exist in current page administration - - Scenario: Share to MoodleNet menu only be available for user that has capability only - Given the following "permission overrides" exist: - | capability | permission | role | contextlevel | reference | - | moodle/moodlenet:shareactivity | Prohibit | editingteacher | Course | C1 | - When I am on the "Test Assignment 1" "assign activity" page logged in as teacher1 - Then "Share to MoodleNet" "link" should not exist in current page administration - And I am on the "Test Assignment 1" "assign activity" page logged in as manager1 - And "Share to MoodleNet" "link" should exist in current page administration - And the following "permission overrides" exist: - | capability | permission | role | contextlevel | reference | - | moodle/moodlenet:shareactivity | Prohibit | manager | Course | C1 | - And I am on the "Test Assignment 1" "assign activity" page logged in as manager1 - And "Share to MoodleNet" "link" should not exist in current page administration - - @javascript - Scenario: User can share activity to MoodleNet - Given I am on the "Test Assignment 1" "assign activity" page logged in as teacher1 - When I navigate to "Share to MoodleNet" in current page administration - Then I should see "Assignment" in the "Share to MoodleNet" "dialogue" - And I should see "Test Assignment 1" in the "Share to MoodleNet" "dialogue" - And I should see "This activity is being shared with MoodleNet as a resource." in the "Share to MoodleNet" "dialogue" - And I click on "Share" "button" in the "Share to MoodleNet" "dialogue" - And I switch to "moodlenet_auth" window - And I press "Allow" and switch to main window - And I should see "Saved to MoodleNet drafts" - And "Go to MoodleNet drafts" "link" should exist in the "Share to MoodleNet" "dialogue" - - @javascript - Scenario: User can see their shared resources on the MoodleNet share progress page - Given I am on the "C1" course page logged in as teacher1 - When I navigate to "MoodleNet share progress" in current page administration - And I should see "There are no shared resources to display at this time." - And I am on "C1" course homepage - And I navigate to "Share to MoodleNet" in current page administration - And I click on "Share" "button" in the "Share to MoodleNet" "dialogue" - And I switch to "moodlenet_auth" window - And I press "Allow" and switch to main window - And I click on "Close" "button" in the "Share to MoodleNet" "dialogue" - And I am on the "Test Assignment 1" "assign activity" page - And I navigate to "Share to MoodleNet" in current page administration - And I click on "Share" "button" in the "Share to MoodleNet" "dialogue" - And I click on "Close" "button" in the "Share to MoodleNet" "dialogue" - And I am on "C1" course homepage - And I navigate to "MoodleNet share progress" in current page administration - Then "Test course 1" row "Name" column of "generaltable" table should contain "Test course 1" - And "Test course 1" row "Type" column of "generaltable" table should contain "Course" - And "Test course 1" row "Send status" column of "generaltable" table should contain "Sent" - And "Test Assignment 1" row "Name" column of "generaltable" table should contain "Test Assignment 1" - And "Test Assignment 1" row "Type" column of "generaltable" table should contain "Assignment" - And "Test Assignment 1" row "Send status" column of "generaltable" table should contain "Sent" diff --git a/public/lib/tests/behat/moodlenet_share_course.feature b/public/lib/tests/behat/moodlenet_share_course.feature deleted file mode 100644 index e7c549d471a..00000000000 --- a/public/lib/tests/behat/moodlenet_share_course.feature +++ /dev/null @@ -1,67 +0,0 @@ -@core -Feature: MoodleNet outbound share course - In order to send a course to MoodleNet server - As a teacher - I need to be able to backup the course and share to MoodleNet - - Background: - Given the following course exists: - | name | Test course | - | shortname | C1 | - And the following "users" exist: - | username | firstname | lastname | email | - | student1 | Student | 1 | student1@example.com | - | teacher1 | Teacher | 1 | teacher1@example.com | - | manager1 | Manager | 1 | manager1@example.com | - And the following "course enrolments" exist: - | user | course | role | - | manager1 | C1 | manager | - | teacher1 | C1 | editingteacher | - | student1 | C1 | student | - And I log in as "admin" - And a MoodleNet mock server is configured - And the following config values are set as admin: - | enablesharingtomoodlenet | 1 | - And I navigate to "Server > OAuth 2 services" in site administration - And I press "MoodleNet" - And I should see "Create new service: MoodleNet" - And I change the MoodleNet field "Service base URL" to mock server - And I press "Save changes" - And I navigate to "MoodleNet > MoodleNet outbound settings" in site administration - And I set the field "Auth 2 service" to "MoodleNet" - And I press "Save changes" - - Scenario: Share course to MoodleNet option only be available for teachers and managers - Given I am on the "C1" "course" page logged in as student1 - And "Share to MoodleNet" "link" should not exist in current page administration - When I am on the "C1" "course" page logged in as teacher1 - And "Share to MoodleNet" "link" should exist in current page administration - Then I am on the "C1" "course" page logged in as manager1 - And "Share to MoodleNet" "link" should exist in current page administration - - Scenario: Share course to MoodleNet option only be available for user that has capability only - Given the following "permission overrides" exist: - | capability | permission | role | contextlevel | reference | - | moodle/moodlenet:sharecourse | Prohibit | editingteacher | Course | C1 | - When I am on the "C1" "course" page logged in as teacher1 - Then "Share to MoodleNet" "link" should not exist in current page administration - And I am on the "C1" "course" page logged in as manager1 - And "Share to MoodleNet" "link" should exist in current page administration - And the following "permission overrides" exist: - | capability | permission | role | contextlevel | reference | - | moodle/moodlenet:sharecourse | Prohibit | manager | Course | C1 | - And I am on the "C1" "course" page logged in as manager1 - And "Share to MoodleNet" "link" should not exist in current page administration - - @javascript - Scenario: User can share course to MoodleNet - Given I am on the "C1" "course" page logged in as teacher1 - When I navigate to "Share to MoodleNet" in current page administration - Then I should see "Course" in the "Share to MoodleNet" "dialogue" - And I should see "Test course 1" in the "Share to MoodleNet" "dialogue" - And I should see "This course is being shared with MoodleNet as a resource." in the "Share to MoodleNet" "dialogue" - And I click on "Share" "button" in the "Share to MoodleNet" "dialogue" - And I switch to "moodlenet_auth" window - And I press "Allow" and switch to main window - And I should see "Saved to MoodleNet drafts" - And "Go to MoodleNet drafts" "link" should exist in the "Share to MoodleNet" "dialogue" diff --git a/public/lib/tests/behat/moodlenet_share_partial_course.feature b/public/lib/tests/behat/moodlenet_share_partial_course.feature deleted file mode 100644 index 7ee70c4e827..00000000000 --- a/public/lib/tests/behat/moodlenet_share_partial_course.feature +++ /dev/null @@ -1,97 +0,0 @@ -@core -Feature: MoodleNet outbound share selected activities in a course - In order to send a number of selected activities in a course to MoodleNet server - As a teacher - I need to be able to backup the selected activities in a course and share to MoodleNet - - Background: - Given the following course exists: - | name | Test course | - | shortname | C1 | - And the following "activities" exist: - | activity | course | idnumber | name | intro | - | assign | C1 | assign1 | Test Assignment 1 | Test Assignment 1 | - | assign | C1 | assign2 | Test Assignment 2 | Test Assignment 2 | - | assign | C1 | assign3 | Test Assignment 3 | Test Assignment 3 | - And the following "users" exist: - | username | firstname | lastname | email | - | student1 | Student | 1 | student1@example.com | - | teacher1 | Teacher | 1 | teacher1@example.com | - | manager1 | Manager | 1 | manager1@example.com | - And the following "course enrolments" exist: - | user | course | role | - | manager1 | C1 | manager | - | teacher1 | C1 | editingteacher | - | student1 | C1 | student | - And I log in as "admin" - And a MoodleNet mock server is configured - And the following config values are set as admin: - | enablesharingtomoodlenet | 1 | - And I navigate to "Server > OAuth 2 services" in site administration - And I press "MoodleNet" - And I should see "Create new service: MoodleNet" - And I change the MoodleNet field "Service base URL" to mock server - And I press "Save changes" - And I navigate to "MoodleNet > MoodleNet outbound settings" in site administration - And I set the field "Auth 2 service" to "MoodleNet" - And I press "Save changes" - - @javascript - Scenario: Share to MoodleNet bulk option should only be available for users with the capability - Given the following "permission overrides" exist: - | capability | permission | role | contextlevel | reference | - | moodle/moodlenet:sharecourse | Prohibit | editingteacher | Course | C1 | - When I am on the "C1" "course" page logged in as teacher1 - And I turn editing mode on - And I click on "Bulk actions" "button" - And I click on "Select activity Test Assignment 1" "checkbox" - Then "Share to MoodleNet" "button" should not exist in the "sticky-footer" "region" - And I am on the "C1" "course" page logged in as manager1 - And I turn editing mode on - And I click on "Bulk actions" "button" - And I click on "Select activity Test Assignment 1" "checkbox" - And "Share to MoodleNet" "button" should exist in the "sticky-footer" "region" - And the following "permission overrides" exist: - | capability | permission | role | contextlevel | reference | - | moodle/moodlenet:sharecourse | Prohibit | manager | Course | C1 | - And I am on the "C1" "course" page logged in as manager1 - And I turn editing mode on - And I click on "Bulk actions" "button" - And I click on "Select activity Test Assignment 1" "checkbox" - And "Share to MoodleNet" "button" should not exist in the "sticky-footer" "region" - - @javascript - Scenario: User can share selected activities in a course to MoodleNet - Given I am on the "C1" "course" page logged in as teacher1 - And I turn editing mode on - And I click on "Bulk actions" "button" - When I click on "Share to MoodleNet" "button" in the "sticky-footer" "region" - Then "Share to MoodleNet" "dialogue" should not exist - And I click on "Select activity Test Assignment 1" "checkbox" - And I click on "Select activity Test Assignment 2" "checkbox" - And I click on "Share to MoodleNet" "button" in the "sticky-footer" "region" - And "Share to MoodleNet" "dialogue" should exist - And I should see "Test course 1" in the "Share to MoodleNet" "dialogue" - And I should see "The selected activities are being shared with MoodleNet as a resource." in the "Share to MoodleNet" "dialogue" - And I should see "2 activities will be included in the course." in the "Share to MoodleNet" "dialogue" - And I click on "Share" "button" in the "Share to MoodleNet" "dialogue" - And I switch to "moodlenet_auth" window - And I press "Allow" and switch to main window - And I should see "Saved to MoodleNet drafts" - And "Go to MoodleNet drafts" "link" should exist in the "Share to MoodleNet" "dialogue" - - @javascript - Scenario: User can share activity directly in a course bulk mode to MoodleNet - Given I am on the "C1" "course" page logged in as teacher1 - And I turn editing mode on - And I click on "Bulk actions" "button" - And I click on "Select activity Test Assignment 1" "checkbox" - When I click on "Share to MoodleNet" "button" in the "sticky-footer" "region" - Then I should see "Test Assignment 1" in the "Share to MoodleNet" "dialogue" - And I should see "This activity is being shared with MoodleNet as a resource." in the "Share to MoodleNet" "dialogue" - And I should not see "1 activities will be included in the course." in the "Share to MoodleNet" "dialogue" - And I click on "Share" "button" in the "Share to MoodleNet" "dialogue" - And I switch to "moodlenet_auth" window - And I press "Allow" and switch to main window - And I should see "Saved to MoodleNet drafts" - And "Go to MoodleNet drafts" "link" should exist in the "Share to MoodleNet" "dialogue" diff --git a/public/lib/tests/external/moodlenet_auth_check_test.php b/public/lib/tests/external/moodlenet_auth_check_test.php deleted file mode 100644 index 7a7977ecafe..00000000000 --- a/public/lib/tests/external/moodlenet_auth_check_test.php +++ /dev/null @@ -1,84 +0,0 @@ -. - -namespace core\external; - -defined('MOODLE_INTERNAL') || die(); - -use core\oauth2\api; -use core_external\external_api; - -global $CFG; - -require_once($CFG->dirroot . '/lib/tests/moodlenet/helpers.php'); - -/** - * External functions test for moodlenet_auth_check. - * - * @package core - * @category test - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @coversDefaultClass \core\external\moodlenet_auth_check - */ -final class moodlenet_auth_check_test extends \core_external\tests\externallib_testcase { - /** - * Test the behaviour of moodlenet_auth_check(). - * - * @covers ::execute - */ - public function test_moodlenet_auth_check(): void { - global $CFG; - $this->resetAfterTest(); - $this->setAdminUser(); - $CFG->enablesharingtomoodlenet = true; - - // Generate data. - $generator = $this->getDataGenerator(); - $course = $generator->create_course(); - $user = $generator->create_user(); - $generator->enrol_user($user->id, $course->id, 'student'); - - // Create dummy issuer. - $issuer = \core\moodlenet\helpers::get_mock_issuer(0); - - // Test with the user does not have permission. - $this->setUser($user); - $result = moodlenet_auth_check::execute($issuer->get('id'), $course->id); - $result = external_api::clean_returnvalue(moodlenet_auth_check::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals('errorpermission', $result['warnings'][0]['warningcode']); - - // Test with the issuer is not enabled. - $this->setAdminUser(); - $result = moodlenet_auth_check::execute($issuer->get('id'), $course->id); - $result = external_api::clean_returnvalue(moodlenet_auth_check::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals('errorissuernotenabled', $result['warnings'][0]['warningcode']); - - // Test with the issuer is enabled and not logged in. - $issuer->set('enabled', 1); - $irecord = $issuer->to_record(); - api::update_issuer($irecord); - set_config('oauthservice', $issuer->get('id'), 'moodlenet'); - $result = moodlenet_auth_check::execute($issuer->get('id'), $course->id); - $result = external_api::clean_returnvalue(moodlenet_auth_check::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertNotEmpty($result['loginurl']); - } -} diff --git a/public/lib/tests/external/moodlenet_get_share_info_activity_test.php b/public/lib/tests/external/moodlenet_get_share_info_activity_test.php deleted file mode 100644 index f33eb6e831f..00000000000 --- a/public/lib/tests/external/moodlenet_get_share_info_activity_test.php +++ /dev/null @@ -1,137 +0,0 @@ -. - -namespace core\external; - -use core\oauth2\api; -use core_external\external_api; - -defined('MOODLE_INTERNAL') || die(); - -global $CFG; - -require_once($CFG->dirroot . '/lib/tests/moodlenet/helpers.php'); - -/** - * External functions test for moodlenet_get_share_info_activity. - * - * @package core - * @category test - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @coversDefaultClass \core\external\moodlenet_get_share_info_activity - */ -final class moodlenet_get_share_info_activity_test extends \core_external\tests\externallib_testcase { - /** - * Test the behaviour of moodlenet_get_share_info_activity(). - * @covers ::execute - */ - public function test_moodlenet_get_share_info_activity(): void { - global $CFG; - $this->resetAfterTest(); - $this->setAdminUser(); - $CFG->enablesharingtomoodlenet = true; - - // Generate course and activities. - $course = $this->getDataGenerator()->create_course(); - $activity1 = $this->getDataGenerator()->create_module('page', ['course' => $course->id, 'name' => 'Page activity']); - $activity2 = $this->getDataGenerator()->create_module('assign', ['course' => $course->id, 'name' => 'Assign activity']); - $activity3 = $this->getDataGenerator()->create_module('quiz', ['course' => $course->id, 'name' => 'Quiz activity']); - - // Create dummy enabled issuer. - $issuer = \core\moodlenet\helpers::get_mock_issuer(1); - - // Test the 1st activity with no OAuth2 setup yet. - $result = moodlenet_get_share_info_activity::execute($activity1->cmid); - $result = external_api::clean_returnvalue(moodlenet_get_share_info_activity::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertEmpty($result['name']); - $this->assertEmpty($result['type']); - $this->assertEmpty($result['server']); - $this->assertEmpty($result['supportpageurl']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals(0, $result['warnings'][0]['item']); - $this->assertEquals('errorissuernotset', $result['warnings'][0]['warningcode']); - $this->assertEquals(get_string('moodlenet:issuerisnotset', 'moodle'), $result['warnings'][0]['message']); - - // Test the 1st activity with OAuth2 disabled. - set_config('oauthservice', $issuer->get('id'), 'moodlenet'); - $issuer->set('enabled', 0); - $irecord = $issuer->to_record(); - api::update_issuer($irecord); - - $result = moodlenet_get_share_info_activity::execute($activity1->cmid); - $result = external_api::clean_returnvalue(moodlenet_get_share_info_activity::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertEmpty($result['name']); - $this->assertEmpty($result['type']); - $this->assertEmpty($result['server']); - $this->assertEmpty($result['supportpageurl']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals($issuer->get('id'), $result['warnings'][0]['item']); - $this->assertEquals('errorissuernotenabled', $result['warnings'][0]['warningcode']); - $this->assertEquals(get_string('moodlenet:issuerisnotenabled', 'moodle'), $result['warnings'][0]['message']); - - // Test the 1st activity with support url is set to the internal contact site support page. - $issuer->set('enabled', 1); - $irecord = $issuer->to_record(); - api::update_issuer($irecord); - - $expectedsupporturl = $CFG->wwwroot . '/user/contactsitesupport.php'; - $result = moodlenet_get_share_info_activity::execute($activity1->cmid); - $result = external_api::clean_returnvalue(moodlenet_get_share_info_activity::execute_returns(), $result); - $this->assertTrue($result['status']); - $this->assertEquals($activity1->name, $result['name']); - $this->assertEquals(get_string('modulename', 'mod_page'), $result['type']); - $this->assertEquals($issuer->get_display_name(), $result['server']); - $this->assertEquals($expectedsupporturl, $result['supportpageurl']); - - // Test the 2nd activity with support url is set to the external contact site support page. - $expectedsupporturl = 'https://moodle.org/'; - $CFG->supportpage = $expectedsupporturl; - $result = moodlenet_get_share_info_activity::execute($activity2->cmid); - $result = external_api::clean_returnvalue(moodlenet_get_share_info_activity::execute_returns(), $result); - $this->assertTrue($result['status']); - $this->assertEquals($activity2->name, $result['name']); - $this->assertEquals(get_string('modulename', 'mod_assign'), $result['type']); - $this->assertEquals($expectedsupporturl, $result['supportpageurl']); - - // Test the 3rd activity with contact site support is disabled. - $CFG->supportavailability = CONTACT_SUPPORT_DISABLED; - $result = moodlenet_get_share_info_activity::execute($activity3->cmid); - $result = external_api::clean_returnvalue(moodlenet_get_share_info_activity::execute_returns(), $result); - $this->assertTrue($result['status']); - $this->assertEquals($activity3->name, $result['name']); - $this->assertEquals(get_string('modulename', 'mod_quiz'), $result['type']); - $this->assertEmpty($result['supportpageurl']); - - // Test with an invalid activity. - // Get a random cmid that not in the created activity list. - $cmids = [$activity1->cmid, $activity2->cmid, $activity3->cmid]; - do { - $randomcmid = random_int(5, 25); - } while (in_array($randomcmid, $cmids)); - $result = moodlenet_get_share_info_activity::execute($randomcmid); - $result = external_api::clean_returnvalue(moodlenet_get_share_info_activity::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertEmpty($result['name']); - $this->assertEmpty($result['type']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals($randomcmid, $result['warnings'][0]['item']); - $this->assertEquals('errorgettingactivityinformation', $result['warnings'][0]['warningcode']); - $this->assertEquals(get_string('invalidcoursemodule', 'error'), $result['warnings'][0]['message']); - } -} diff --git a/public/lib/tests/external/moodlenet_get_shared_course_info_test.php b/public/lib/tests/external/moodlenet_get_shared_course_info_test.php deleted file mode 100644 index 3bf147ba3bb..00000000000 --- a/public/lib/tests/external/moodlenet_get_shared_course_info_test.php +++ /dev/null @@ -1,100 +0,0 @@ -. - -namespace core\external; - -use core\oauth2\api; -use core_external\external_api; - -defined('MOODLE_INTERNAL') || die(); - -global $CFG; - -require_once($CFG->dirroot . '/lib/tests/moodlenet/helpers.php'); - -/** - * External functions test for moodlenet_get_shared_course_info. - * - * @package core - * @category test - * @copyright 2023 Safat Shahin - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @coversDefaultClass \core\external\moodlenet_get_shared_course_info - */ -final class moodlenet_get_shared_course_info_test extends \core_external\tests\externallib_testcase { - /** - * Test the behaviour of moodlenet_get_shared_course_info(). - * - * @covers ::execute - */ - public function test_moodlenet_get_shared_course_info(): void { - global $CFG; - $this->resetAfterTest(); - $this->setAdminUser(); - $CFG->enablesharingtomoodlenet = true; - - // Generate course and activities. - $course = $this->getDataGenerator()->create_course(); - - // Create dummy enabled issuer. - $issuer = \core\moodlenet\helpers::get_mock_issuer(1); - - // Test the course with no OAuth2 setup yet. - $result = moodlenet_get_shared_course_info::execute($course->id); - $result = external_api::clean_returnvalue(moodlenet_get_shared_course_info::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertEmpty($result['name']); - $this->assertEmpty($result['type']); - $this->assertEmpty($result['server']); - $this->assertEmpty($result['supportpageurl']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals(0, $result['warnings'][0]['item']); - $this->assertEquals('errorissuernotset', $result['warnings'][0]['warningcode']); - $this->assertEquals(get_string('moodlenet:issuerisnotset', 'moodle'), $result['warnings'][0]['message']); - - // Test the course with OAuth2 disabled. - set_config('oauthservice', $issuer->get('id'), 'moodlenet'); - $issuer->set('enabled', 0); - $irecord = $issuer->to_record(); - api::update_issuer($irecord); - - $result = moodlenet_get_shared_course_info::execute($course->id); - $result = external_api::clean_returnvalue(moodlenet_get_shared_course_info::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertEmpty($result['name']); - $this->assertEmpty($result['type']); - $this->assertEmpty($result['server']); - $this->assertEmpty($result['supportpageurl']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals($issuer->get('id'), $result['warnings'][0]['item']); - $this->assertEquals('errorissuernotenabled', $result['warnings'][0]['warningcode']); - $this->assertEquals(get_string('moodlenet:issuerisnotenabled', 'moodle'), $result['warnings'][0]['message']); - - // Test the course with support url is set to the internal contact site support page. - $issuer->set('enabled', 1); - $irecord = $issuer->to_record(); - api::update_issuer($irecord); - - $expectedsupporturl = $CFG->wwwroot . '/user/contactsitesupport.php'; - $result = moodlenet_get_shared_course_info::execute($course->id); - $result = external_api::clean_returnvalue(moodlenet_get_shared_course_info::execute_returns(), $result); - $this->assertTrue($result['status']); - $this->assertEquals($course->fullname, $result['name']); - $this->assertEquals(get_string('course'), $result['type']); - $this->assertEquals($issuer->get_display_name(), $result['server']); - $this->assertEquals($expectedsupporturl, $result['supportpageurl']); - } -} diff --git a/public/lib/tests/external/moodlenet_send_activity_test.php b/public/lib/tests/external/moodlenet_send_activity_test.php deleted file mode 100644 index 87db25bf4d4..00000000000 --- a/public/lib/tests/external/moodlenet_send_activity_test.php +++ /dev/null @@ -1,168 +0,0 @@ -. - -namespace core\external; - -use core\oauth2\api; -use core_external\external_api; - -defined('MOODLE_INTERNAL') || die(); - -global $CFG; - -require_once($CFG->dirroot . '/lib/tests/moodlenet/helpers.php'); - -/** - * External functions test for moodlenet_send_activity. - * - * @package core - * @category test - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @coversDefaultClass \core\external\moodlenet_send_activity - */ -final class moodlenet_send_activity_test extends \core_external\tests\externallib_testcase { - /** - * Test the behaviour of moodlenet_send_activity(). - * - * @covers ::execute - */ - public function test_moodlenet_send_activity(): void { - global $CFG; - $this->resetAfterTest(); - $this->setAdminUser(); - - // Generate data. - $generator = $this->getDataGenerator(); - $course = $generator->create_course(); - $moduleinstance = $generator->create_module('assign', ['course' => $course->id]); - $user = $generator->create_user(); - $generator->enrol_user($user->id, $course->id, 'student'); - - // Create dummy issuer. - $issuer = \core\moodlenet\helpers::get_mock_issuer(0); - - // Test with the experimental flag off. - $result = moodlenet_send_activity::execute($issuer->get('id'), $moduleinstance->cmid, 0); - $result = external_api::clean_returnvalue(moodlenet_send_activity::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals('errorissuernotenabled', $result['warnings'][0]['warningcode']); - - $CFG->enablesharingtomoodlenet = true; - - // Test with invalid format. - $result = moodlenet_send_activity::execute($issuer->get('id'), $moduleinstance->cmid, 5); - $result = external_api::clean_returnvalue(moodlenet_send_activity::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals('errorinvalidformat', $result['warnings'][0]['warningcode']); - - // Test with the user does not have permission. - $this->setUser($user); - $result = moodlenet_send_activity::execute($issuer->get('id'), $moduleinstance->cmid, 0); - $result = external_api::clean_returnvalue(moodlenet_send_activity::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals('errorpermission', $result['warnings'][0]['warningcode']); - - $this->setAdminUser(); - - // Test with the issuer is not enabled. - $result = moodlenet_send_activity::execute($issuer->get('id'), $moduleinstance->cmid, 0); - $result = external_api::clean_returnvalue(moodlenet_send_activity::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals('errorissuernotenabled', $result['warnings'][0]['warningcode']); - - // Test with the issuer is enabled but not set in the MN Outbound setting. - $issuer->set('enabled', 1); - $irecord = $issuer->to_record(); - api::update_issuer($irecord); - $result = moodlenet_send_activity::execute($issuer->get('id'), $moduleinstance->cmid, 0); - $result = external_api::clean_returnvalue(moodlenet_send_activity::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals('errorissuernotenabled', $result['warnings'][0]['warningcode']); - - set_config('oauthservice', $issuer->get('id'), 'moodlenet'); - // Test with the issuer not yet authorized. - $result = moodlenet_send_activity::execute($issuer->get('id'), $moduleinstance->cmid, 0); - $result = external_api::clean_returnvalue(moodlenet_send_activity::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals('erroroauthclient', $result['warnings'][0]['warningcode']); - $this->assertEquals($issuer->get('id'), $result['warnings'][0]['item']); - $this->assertEquals(get_string('moodlenet:issuerisnotauthorized', 'moodle'), $result['warnings'][0]['message']); - } - - /** - * Test execute_returns() method. - * - * @dataProvider return_resource_url_provider - * @covers ::execute_returns - */ - public function test_moodlenet_send_activity_return_resource_url(bool $state, string $resourceurl): void { - $this->resetAfterTest(); - // Create dummy result with the resourceurl. - $result = [ - 'status' => true, - 'resourceurl' => $resourceurl, - 'warnings' => [], - ]; - if (!$state) { - $this->expectException(\invalid_response_exception::class); - } - $result = external_api::clean_returnvalue(moodlenet_send_activity::execute_returns(), $result); - if ($state) { - $this->assertEquals($resourceurl, $result['resourceurl']); - } - } - - /** - * Provider for test_moodlenet_send_activity_return_resource_url(). - * - * @return array Test data. - */ - public static function return_resource_url_provider(): array { - return [ - 'Success 1' => [ - true, - 'https://moodlenet.example.com/drafts/view/testactivity_backup.mbz', - ], - 'Success 2' => [ - true, - 'https://moodlenet.example.com/drafts/view/testactivity_backup with spaces.mbz', - ], - 'Success 3' => [ - true, - 'https://moodlenet.example.com/drafts/view/testactivity_backup with " character.mbz', - ], - 'Success 4' => [ - true, - "https://moodlenet.example.com/drafts/view/testactivity_backup with ' character.mbz", - ], - 'Success 5' => [ - true, - 'https://moodlenet.example.com/drafts/view/testactivity_backup with < and > characters.mbz', - ], - 'Fail 1' => [ - false, - 'https://moodlenet.example.com/drafts/view/testactivity_backupwithahtml.mbz', - ], - ]; - } -} diff --git a/public/lib/tests/external/moodlenet_send_course_test.php b/public/lib/tests/external/moodlenet_send_course_test.php deleted file mode 100644 index b22e996b4a7..00000000000 --- a/public/lib/tests/external/moodlenet_send_course_test.php +++ /dev/null @@ -1,174 +0,0 @@ -. - -namespace core\external; - -use core\oauth2\api; -use core_external\external_api; - -defined('MOODLE_INTERNAL') || die(); - -global $CFG; - -require_once($CFG->dirroot . '/lib/tests/moodlenet/helpers.php'); - -/** - * External functions test for moodlenet_send_course. - * - * @package core - * @category test - * @copyright 2023 Safat Shahin - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @coversDefaultClass \core\external\moodlenet_send_course - */ -final class moodlenet_send_course_test extends \core_external\tests\externallib_testcase { - /** - * Test the behaviour of moodlenet_send_course(). - * - * @covers ::execute - */ - public function test_moodlenet_send_course(): void { - global $CFG; - $this->resetAfterTest(); - $this->setAdminUser(); - - // Generate data. - $generator = $this->getDataGenerator(); - $course = $generator->create_course(); - $user = $generator->create_user(); - $generator->enrol_user($user->id, $course->id, 'student'); - - // Create dummy issuer. - $issuer = \core\moodlenet\helpers::get_mock_issuer(0); - - // Test with the experimental flag off. - $result = moodlenet_send_course::execute($issuer->get('id'), $course->id, 0); - $result = external_api::clean_returnvalue(moodlenet_send_course::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals('errorissuernotenabled', $result['warnings'][0]['warningcode']); - - $CFG->enablesharingtomoodlenet = true; - - // Test with invalid format. - $result = moodlenet_send_course::execute($issuer->get('id'), $course->id, 5); - $result = external_api::clean_returnvalue(moodlenet_send_course::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals('errorinvalidformat', $result['warnings'][0]['warningcode']); - - // Test with invalid course module id. - $result = moodlenet_send_course::execute($issuer->get('id'), $course->id, 0, [random_int(5, 30)]); - $result = external_api::clean_returnvalue(moodlenet_send_course::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals('errorinvalidcmids', $result['warnings'][0]['warningcode']); - - // Test with the user does not have permission. - $this->setUser($user); - $result = moodlenet_send_course::execute($issuer->get('id'), $course->id, 0); - $result = external_api::clean_returnvalue(moodlenet_send_course::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals('errorpermission', $result['warnings'][0]['warningcode']); - - $this->setAdminUser(); - - // Test with the issuer is not enabled. - $result = moodlenet_send_course::execute($issuer->get('id'), $course->id, 0); - $result = external_api::clean_returnvalue(moodlenet_send_course::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals('errorissuernotenabled', $result['warnings'][0]['warningcode']); - - // Test with the issuer is enabled but not set in the MN Outbound setting. - $issuer->set('enabled', 1); - $irecord = $issuer->to_record(); - api::update_issuer($irecord); - $result = moodlenet_send_course::execute($issuer->get('id'), $course->id, 0); - $result = external_api::clean_returnvalue(moodlenet_send_course::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals('errorissuernotenabled', $result['warnings'][0]['warningcode']); - - set_config('oauthservice', $issuer->get('id'), 'moodlenet'); - // Test with the issuer not yet authorized. - $result = moodlenet_send_course::execute($issuer->get('id'), $course->id, 0); - $result = external_api::clean_returnvalue(moodlenet_send_course::execute_returns(), $result); - $this->assertFalse($result['status']); - $this->assertNotEmpty($result['warnings']); - $this->assertEquals('erroroauthclient', $result['warnings'][0]['warningcode']); - $this->assertEquals($issuer->get('id'), $result['warnings'][0]['item']); - $this->assertEquals(get_string('moodlenet:issuerisnotauthorized', 'moodle'), $result['warnings'][0]['message']); - } - - /** - * Test execute_returns() method. - * - * @dataProvider return_resource_url_provider - * @covers ::execute_returns - */ - public function test_moodlenet_send_course_return_resource_url(bool $state, string $resourceurl): void { - $this->resetAfterTest(); - // Create dummy result with the resourceurl. - $result = [ - 'status' => true, - 'resourceurl' => $resourceurl, - 'warnings' => [], - ]; - if (!$state) { - $this->expectException(\invalid_response_exception::class); - } - $result = external_api::clean_returnvalue(moodlenet_send_course::execute_returns(), $result); - if ($state) { - $this->assertEquals($resourceurl, $result['resourceurl']); - } - } - - /** - * Provider for test_moodlenet_send_course_return_resource_url(). - * - * @return array Test data. - */ - public static function return_resource_url_provider(): array { - return [ - 'Success 1' => [ - true, - 'https://moodlenet.example.com/drafts/view/testcourse_backup.mbz', - ], - 'Success 2' => [ - true, - 'https://moodlenet.example.com/drafts/view/testcourse_backup with spaces.mbz', - ], - 'Success 3' => [ - true, - 'https://moodlenet.example.com/drafts/view/testcourse_backup with " character.mbz', - ], - 'Success 4' => [ - true, - "https://moodlenet.example.com/drafts/view/testcourse_backup with ' character.mbz", - ], - 'Success 5' => [ - true, - 'https://moodlenet.example.com/drafts/view/testcourse_backup with < and > characters.mbz', - ], - 'Fail 1' => [ - false, - 'https://moodlenet.example.com/drafts/view/testcourse_backupwithahtml.mbz', - ], - ]; - } -} diff --git a/public/lib/tests/moodlenet/activity_packager_test.php b/public/lib/tests/moodlenet/activity_packager_test.php deleted file mode 100644 index 33c0983e584..00000000000 --- a/public/lib/tests/moodlenet/activity_packager_test.php +++ /dev/null @@ -1,139 +0,0 @@ -. - -namespace core\moodlenet; - -use core\context\user; - -/** - * Unit tests for {@see activity_packager}. - * - * @coversDefaultClass \core\moodlenet\activity_packager - * @package core - * @copyright 2023 Michael Hawkins - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -final class activity_packager_test extends \advanced_testcase { - - /** - * Test fetching and overriding a backup task setting. - * - * @covers ::override_task_setting - * @covers ::get_all_task_settings - * @covers ::get_backup_controller - */ - public function test_override_task_setting(): void { - global $USER; - $this->resetAfterTest(); - $this->setAdminUser(); - - $generator = $this->getDataGenerator(); - $course = $generator->create_course(); - $assigndata = [ - 'course' => $course->id, - 'name' => 'Extremely interesting assignment', - 'intro' => 'A great assignment to share', - ]; - $assign = $generator->create_module('assign', $assigndata); - $cminfo = get_fast_modinfo($course->id)->get_cm($assign->cmid); - $packager = new activity_packager($cminfo, $USER->id); - - // Fetch all backup task settings. - $rc = new \ReflectionClass(activity_packager::class); - $rcmgetbackup = $rc->getMethod('get_backup_controller'); - $controller = $rcmgetbackup->invoke($packager); - $rcmgetall = $rc->getMethod('get_all_task_settings'); - $tasksettings = $rcmgetall->invoke($packager, $controller); - - // Fetch the default settings and grab an example value (setting_root_users). - $rootsettings = $tasksettings[\backup_root_task::class]; - $testsettingname = 'setting_root_users'; - - $oldvalue = 99; - foreach ($rootsettings as $setting) { - $name = $setting->get_ui_name(); - if ($name == $testsettingname) { - $oldvalue = $setting->get_value(); - break; - } - } - - // Check we found the setting value (either 0 or 1 are valid). - $this->assertNotEquals(99, $oldvalue); - $this->assertLessThanOrEqual(1, $oldvalue); - - // Override the setting_root_users value, then re-fetch the settings to check the change is reflected. - $overridevalue = ($oldvalue == 1) ? 0 : 1; - $rcmoverridesetting = $rc->getMethod('override_task_setting'); - $rcmoverridesetting->invoke($packager, $tasksettings, $testsettingname, $overridevalue); - $tasksettings = $rcmgetall->invoke($packager, $controller); - $rootsettings = $tasksettings[\backup_root_task::class]; - - $newvalue = 99; - foreach ($rootsettings as $setting) { - $name = $setting->get_ui_name(); - if ($name == $testsettingname) { - $newvalue = $setting->get_value(); - break; - } - } - - $this->assertEquals($overridevalue, $newvalue); - - // We have finished with the backup controller, so destroy it. - $controller->destroy(); - } - - /** - * Test overriding a backup task setting. - * - * @covers ::get_package - * @covers ::package - */ - public function test_get_package(): void { - global $USER; - $this->resetAfterTest(); - $this->setAdminUser(); - - $currenttime = time(); - $generator = $this->getDataGenerator(); - $course = $generator->create_course(); - - $assigndata = [ - 'course' => $course->id, - 'name' => 'Extremely interesting assignment', - 'intro' => 'A great assignment to share', - ]; - $assign = $generator->create_module('assign', $assigndata); - $cminfo = get_fast_modinfo($course->id)->get_cm($assign->cmid); - $packager = new activity_packager($cminfo, $USER->id); - $package = $packager->get_package(); - - // Confirm the expected stored_file object is returned. - $this->assertInstanceOf(\stored_file::class, $package); - - // Check some known values in the returned stored_file object to confirm they match the file we have packaged. - $this->assertNotEmpty($package->get_contenthash()); - $this->assertEquals(user::instance($USER->id)->id, $package->get_contextid()); - $this->assertEquals('user', $package->get_component()); - $this->assertEquals('draft', $package->get_filearea()); - $this->assertEquals('assign_backup.mbz', $package->get_filename()); - $this->assertGreaterThan(0, $package->get_filesize()); - $timecreated = $package->get_timecreated(); - $this->assertGreaterThanOrEqual($currenttime, $timecreated); - $this->assertEquals($timecreated, $package->get_timemodified()); - } -} diff --git a/public/lib/tests/moodlenet/activity_sender_test.php b/public/lib/tests/moodlenet/activity_sender_test.php deleted file mode 100644 index 13ec211433d..00000000000 --- a/public/lib/tests/moodlenet/activity_sender_test.php +++ /dev/null @@ -1,312 +0,0 @@ -. - -namespace core\moodlenet; - -use context_course; -use core\http_client; -use core\oauth2\issuer; -use GuzzleHttp\Exception\ClientException; -use GuzzleHttp\Handler\MockHandler; -use GuzzleHttp\HandlerStack; -use GuzzleHttp\Psr7\Response; -use PHPUnit\Framework\MockObject\MockObject; -use Psr\Http\Message\ResponseInterface; -use ReflectionMethod; -use stdClass; -use testing_data_generator; - -/** - * Unit tests for {@see activity_sender}. - * - * @coversDefaultClass \core\moodlenet\activity_sender - * @package core - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -final class activity_sender_test extends \advanced_testcase { - - /** @var testing_data_generator Data generator. */ - private testing_data_generator $generator; - /** @var stdClass Course object. */ - private stdClass $course; - /** @var stdClass Activity object, */ - private stdClass $moduleinstance; - /** @var context_course Course context instance. */ - private context_course $coursecontext; - /** @var issuer $issuer Dummy issuer. */ - private issuer $issuer; - /** @var MockObject $mockoauthclient Mock OAuth client. */ - private MockObject $mockoauthclient; - - public static function setUpBeforeClass(): void { - parent::setUpBeforeClass(); - - require_once(__DIR__ . '/helpers.php'); - } - - /** - * Set up function for tests. - */ - protected function setUp(): void { - parent::setUp(); - - $this->resetAfterTest(); - // Get data generator. - $this->generator = $this->getDataGenerator(); - // Create course. - $this->course = $this->generator->create_course(); - $this->moduleinstance = $this->generator->create_module('assign', ['course' => $this->course->id]); - $this->coursecontext = context_course::instance($this->course->id); - // Create mock issuer. - $this->issuer = helpers::get_mock_issuer(1); - // Create mock builder for OAuth2 client. - $mockbuilder = $this->getMockBuilder('core\oauth2\client'); - $mockbuilder->onlyMethods(['get_issuer', 'is_logged_in', 'get_accesstoken']); - $mockbuilder->setConstructorArgs([$this->issuer, '', '']); - // Get the OAuth2 client mock. - $this->mockoauthclient = $mockbuilder->getMock(); - } - - /** - * Test prepare_share_contents method. - * - * @covers ::prepare_share_contents - */ - public function test_prepare_share_contents(): void { - global $USER; - $this->setAdminUser(); - - $httpclient = new http_client(); - $moodlenetclient = new moodlenet_client($httpclient, $this->mockoauthclient); - - // Set get_file method accessibility. - $method = new ReflectionMethod(activity_sender::class, 'prepare_share_contents'); - - // Test with invalid share format. - $this->expectException(\moodle_exception::class); - $this->expectExceptionMessage(get_string('moodlenet:invalidshareformat', 'error')); - $package = $method->invoke(new activity_sender( - $this->moduleinstance->cmid, - $USER->id, - $moodlenetclient, - $this->mockoauthclient, - random_int(5, 30) - )); - - // Test with valid share format and invalid course module. - $package = $method->invoke(new activity_sender( - random_int(5, 30), - $USER->id, - $moodlenetclient, - $this->mockoauthclient, - resource_sender::SHARE_FORMAT_BACKUP - )); - $this->assertEmpty($package); - - // Test with valid share format and valid course module. - $package = $method->invoke(new activity_sender( - $this->moduleinstance->cmid, - $USER->id, - $moodlenetclient, - $this->mockoauthclient, - resource_sender::SHARE_FORMAT_BACKUP - )); - $this->assertNotEmpty($package); - - // Confirm the expected stored_file object is returned. - $this->assertInstanceOf(\stored_file::class, $package); - } - - /** - * Test get_resource_description method. - * - * @covers ::get_resource_description - */ - public function test_get_resource_description(): void { - global $USER; - $this->setAdminUser(); - - $activity = $this->generator->create_module('assign', [ - 'course' => $this->course->id, - 'intro' => '

This is an example Moodle activity description.

-

 

-

This is a formatted intro

-

 

-

This thing has many lines.

-

 

-

The last word of this sentence is in bold

' - ]); - - $httpclient = new http_client(); - $moodlenetclient = new moodlenet_client($httpclient, $this->mockoauthclient); - - // Set get_resource_description method accessibility. - $method = new ReflectionMethod(activity_sender::class, 'get_resource_description'); - - // Test the processed description. - $processeddescription = $method->invoke(new activity_sender( - $activity->cmid, - $USER->id, - $moodlenetclient, - $this->mockoauthclient, - resource_sender::SHARE_FORMAT_BACKUP - ), $this->coursecontext); - - $this->assertEquals('This is an example Moodle activity description. -  -This is a formatted intro -  -This thing has many lines. -  -The last word of this sentence is in bold', $processeddescription); - } - - /** - * Test share_resource() method. - * - * @dataProvider share_resource_provider - * @covers ::share_resource - * @covers ::log_event - * @covers \core\moodlenet\moodlenet_client::create_resource_from_stored_file - * @covers \core\moodlenet\moodlenet_client::prepare_file_share_request_data - * @param ResponseInterface $httpresponse - * @param array $expected - */ - public function test_share_resource(ResponseInterface $httpresponse, array $expected): void { - global $CFG, $USER; - $this->setAdminUser(); - - // Enable the experimental flag. - $CFG->enablesharingtomoodlenet = true; - - // Set OAuth 2 service in the outbound setting to the dummy issuer. - set_config('oauthservice', $this->issuer->get('id'), 'moodlenet'); - - // Generate access token for the mock. - $accesstoken = new stdClass(); - $accesstoken->token = random_string(64); - - // Get the OAuth2 client mock and set the return value for necessary methods. - $this->mockoauthclient->method('get_issuer')->will($this->returnValue($this->issuer)); - $this->mockoauthclient->method('is_logged_in')->will($this->returnValue(true)); - $this->mockoauthclient->method('get_accesstoken')->will($this->returnValue($accesstoken)); - - // Create Guzzle mock. - $mockguzzlehandler = new MockHandler([$httpresponse]); - $handlerstack = HandlerStack::create($mockguzzlehandler); - $httpclient = new http_client(['handler' => $handlerstack]); - - // Create events sink. - $sink = $this->redirectEvents(); - - // Create activity sender. - $moodlenetclient = new moodlenet_client($httpclient, $this->mockoauthclient); - $activitysender = new activity_sender( - $this->moduleinstance->cmid, - $USER->id, - $moodlenetclient, - $this->mockoauthclient, - resource_sender::SHARE_FORMAT_BACKUP - ); - - if (isset($expected['exception'])) { - $this->expectException(ClientException::class); - $this->expectExceptionMessage($expected['exception']); - } - // Call the API. - $result = $activitysender->share_resource(); - - // Verify the result. - $this->assertEquals($expected['response_code'], $result['responsecode']); - $this->assertEquals($expected['resource_url'], $result['drafturl']); - - // Verify the events. - $events = $sink->get_events(); - $event = reset($events); - $this->assertInstanceOf('\core\event\moodlenet_resource_exported', $event); - $this->assertEquals($USER->id, $event->userid); - - if ($result['responsecode'] == 201) { - $description = "The user with id '{$USER->id}' successfully shared activities to MoodleNet with the " . - "following course module ids, from context with id '{$this->coursecontext->id}': '{$this->moduleinstance->cmid}'."; - } else { - $description = "The user with id '{$USER->id}' failed to share activities to MoodleNet with the " . - "following course module ids, from context with id '{$this->coursecontext->id}': '{$this->moduleinstance->cmid}'."; - } - $this->assertEquals($description, $event->get_description()); - } - - /** - * Provider for test share_resource(). - * - * @return array Test data. - */ - public static function share_resource_provider(): array { - return [ - 'Success' => [ - 'httpresponse' => new Response( - 201, - ['Content-Type' => 'application/json'], - json_encode([ - 'homepage' => 'https://moodlenet.example.com/drafts/view/activity_backup_1.mbz', - ]), - ), - 'expected' => [ - 'response_code' => 201, - 'resource_url' => 'https://moodlenet.example.com/drafts/view/activity_backup_1.mbz', - ], - ], - 'Fail with 200 status code' => [ - 'httpresponse' => new Response( - 200, - ['Content-Type' => 'application/json'], - json_encode([ - 'homepage' => 'https://moodlenet.example.com/drafts/view/activity_backup_2.mbz', - ]), - ), - 'expected' => [ - 'response_code' => 200, - 'resource_url' => 'https://moodlenet.example.com/drafts/view/activity_backup_2.mbz', - ], - ], - 'Fail with 401 status code' => [ - 'httpresponse' => new Response( - 401, - ), - 'expected' => [ - 'response_code' => 401, - 'resource_url' => '', - 'exception' => 'Client error: ' . - '`POST https://moodlenet.example.com/.pkg/@moodlenet/ed-resource/basic/v1/create` ' . - 'resulted in a `401 Unauthorized` response', - ], - ], - 'Fail with 404 status code' => [ - 'httpresponse' => new Response( - 404, - ), - 'expected' => [ - 'response_code' => 404, - 'resource_url' => '', - 'exception' => 'Client error: '. - '`POST https://moodlenet.example.com/.pkg/@moodlenet/ed-resource/basic/v1/create` ' . - 'resulted in a `404 Not Found` response', - ], - ], - ]; - } -} diff --git a/public/lib/tests/moodlenet/course_packager_test.php b/public/lib/tests/moodlenet/course_packager_test.php deleted file mode 100644 index 8ed05953f95..00000000000 --- a/public/lib/tests/moodlenet/course_packager_test.php +++ /dev/null @@ -1,128 +0,0 @@ -. - -namespace core\moodlenet; - -use core\context\user; - -/** - * Test coverage for moodlenet course packager. - * - * @package core - * @copyright 2023 Safat Shahin - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @coversDefaultClass \core\moodlenet\course_packager - */ -final class course_packager_test extends \advanced_testcase { - - /** - * Test fetching and overriding a backup task setting. - * - * @covers ::override_task_setting - * @covers ::get_all_task_settings - * @covers ::get_backup_controller - */ - public function test_override_task_setting(): void { - global $USER; - $this->resetAfterTest(); - $this->setAdminUser(); - - $generator = $this->getDataGenerator(); - $course = $generator->create_course(); - - // Load the course packager. - $packager = new course_packager($course, $USER->id); - - // Fetch all backup task settings. - $rc = new \ReflectionClass(course_packager::class); - $rcmgetbackup = $rc->getMethod('get_backup_controller'); - $controller = $rcmgetbackup->invoke($packager); - $rcmgetall = $rc->getMethod('get_all_task_settings'); - $tasksettings = $rcmgetall->invoke($packager, $controller); - - // Fetch the default settings and grab an example value (setting_root_users). - $rootsettings = $tasksettings[\backup_root_task::class]; - $testsettingname = 'setting_root_users'; - - $oldvalue = 99; - foreach ($rootsettings as $setting) { - $name = $setting->get_ui_name(); - if ($name == $testsettingname) { - $oldvalue = $setting->get_value(); - break; - } - } - - // Check we found the setting value (either 0 or 1 are valid). - $this->assertNotEquals(99, $oldvalue); - $this->assertLessThanOrEqual(1, $oldvalue); - - // Override the setting_root_users value, then re-fetch the settings to check the change is reflected. - $overridevalue = ($oldvalue == 1) ? 0 : 1; - $rcmoverridesetting = $rc->getMethod('override_task_setting'); - $rcmoverridesetting->invoke($packager, $tasksettings, $testsettingname, $overridevalue); - $tasksettings = $rcmgetall->invoke($packager, $controller); - $rootsettings = $tasksettings[\backup_root_task::class]; - - $newvalue = 99; - foreach ($rootsettings as $setting) { - $name = $setting->get_ui_name(); - if ($name == $testsettingname) { - $newvalue = $setting->get_value(); - break; - } - } - - $this->assertEquals($overridevalue, $newvalue); - - // We have finished with the backup controller, so destroy it. - $controller->destroy(); - } - - /** - * Test the course package file. - * - * @covers ::get_package - * @covers ::package - */ - public function test_get_package(): void { - global $USER; - $this->resetAfterTest(); - $this->setAdminUser(); - - $currenttime = time(); - $generator = $this->getDataGenerator(); - $course = $generator->create_course(); - - // Load the course packager. - $packager = new course_packager($course, $USER->id); - $package = $packager->get_package(); - - // Confirm the expected stored_file object is returned. - $this->assertInstanceOf(\stored_file::class, $package); - - // Check some known values in the returned stored_file object to confirm they match the file we have packaged. - $this->assertNotEmpty($package->get_contenthash()); - $this->assertEquals(user::instance($USER->id)->id, $package->get_contextid()); - $this->assertEquals('user', $package->get_component()); - $this->assertEquals('draft', $package->get_filearea()); - $this->assertEquals($course->shortname . '_backup.mbz', $package->get_filename()); - $this->assertGreaterThan(0, $package->get_filesize()); - $timecreated = $package->get_timecreated(); - $this->assertGreaterThanOrEqual($currenttime, $timecreated); - $this->assertEquals($timecreated, $package->get_timemodified()); - } -} diff --git a/public/lib/tests/moodlenet/course_partial_packager_test.php b/public/lib/tests/moodlenet/course_partial_packager_test.php deleted file mode 100644 index b35ccb86ad7..00000000000 --- a/public/lib/tests/moodlenet/course_partial_packager_test.php +++ /dev/null @@ -1,92 +0,0 @@ -. - -namespace core\moodlenet; - -use backup_activity_task; - -/** - * Unit tests for {@see \core\moodlenet\course_partial_packager}. - * - * @coversDefaultClass \core\moodlenet\course_partial_packager - * @package core - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -final class course_partial_packager_test extends \advanced_testcase { - - /** - * Test fetching task settings. - * - * @covers ::remove_unselected_activities - * @covers ::get_all_activity_tasks - * @covers ::get_backup_controller - */ - public function test_remove_unselected_activities(): void { - global $USER; - $this->resetAfterTest(); - $this->setAdminUser(); - - $generator = $this->getDataGenerator(); - $course = $generator->create_course(); - $page1 = $generator->create_module('page', ['course' => $course->id]); - $page2 = $generator->create_module('page', ['course' => $course->id]); - - // Load the course packager. - $packager = new course_partial_packager($course, [$page1->cmid], $USER->id); - - // Fetch all backup task settings. - $rc = new \ReflectionClass(course_partial_packager::class); - $rcmgetbackup = $rc->getMethod('get_backup_controller'); - $controller = $rcmgetbackup->invoke($packager); - - $rcmremove = $rc->getMethod('remove_unselected_activities'); - $rcmremove->invoke($packager, $controller); - - // Fetch all backup task settings for asserting them. - $finalsetting = []; - foreach ($controller->get_plan()->get_tasks() as $task) { - if (! $task instanceof backup_activity_task) { // Only for activity tasks. - continue; - } - $tasksettings = $task->get_settings(); - foreach ($tasksettings as $setting) { - if (in_array($task->get_moduleid(), [$page1->cmid, $page2->cmid]) && - strpos($setting->get_name(), '_included') !== false) { - $finalsetting[$task->get_moduleid()] = [ - 'name' => $setting->get_name(), - 'value' => $setting->get_value(), - ]; - } - } - } - - // Check the number of partial sharing tasks. - // Expected 2, Page 1 and Page 2. - $this->assertCount(2, $finalsetting); - - // Check the value of the task of Page 1. 1 mean enabled, the backup will include the Page 1 activity. - $this->assertEquals('page_' . $page1->cmid . '_included', $finalsetting[$page1->cmid]['name']); - $this->assertEquals(1, $finalsetting[$page1->cmid]['value']); - - // Check the value of the task of Page 2. 0 mean disabled, the backup will not include the Page 2 activity. - $this->assertEquals('page_' . $page2->cmid . '_included', $finalsetting[$page2->cmid]['name']); - $this->assertEquals(0, $finalsetting[$page2->cmid]['value']); - - // We have finished with the backup controller, so destroy it. - $controller->destroy(); - } -} diff --git a/public/lib/tests/moodlenet/course_partial_sender_test.php b/public/lib/tests/moodlenet/course_partial_sender_test.php deleted file mode 100644 index 633b4c5b79a..00000000000 --- a/public/lib/tests/moodlenet/course_partial_sender_test.php +++ /dev/null @@ -1,313 +0,0 @@ -. - -namespace core\moodlenet; - -use context_course; -use core\http_client; -use core\oauth2\issuer; -use GuzzleHttp\Exception\ClientException; -use GuzzleHttp\Handler\MockHandler; -use GuzzleHttp\HandlerStack; -use GuzzleHttp\Psr7\Response; -use moodle_exception; -use PHPUnit\Framework\MockObject\MockObject; -use Psr\Http\Message\ResponseInterface; -use ReflectionMethod; -use stdClass; -use testing_data_generator; - -defined('MOODLE_INTERNAL') || die(); - -global $CFG; - -require_once($CFG->dirroot . '/lib/tests/moodlenet/helpers.php'); - -/** - * Unit tests for {@see \core\moodlenet\course_partial_sender}. - * - * @coversDefaultClass \core\moodlenet\course_partial_sender - * @package core - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -final class course_partial_sender_test extends \advanced_testcase { - - /** @var testing_data_generator Data generator. */ - private testing_data_generator $generator; - /** @var stdClass Course object. */ - private stdClass $course; - /** @var context_course Course context instance. */ - private context_course $coursecontext; - /** @var array List of activities. */ - private array $activities; - /** @var issuer $issuer Dummy issuer. */ - private issuer $issuer; - /** @var MockObject $mockoauthclient Mock OAuth client. */ - private MockObject $mockoauthclient; - - /** - * Set up function for tests. - */ - protected function setUp(): void { - parent::setUp(); - - $this->resetAfterTest(); - // Get data generator. - $this->generator = $this->getDataGenerator(); - // Create course. - $this->course = $this->generator->create_course(['shortname' => 'testcourse']); - $this->coursecontext = context_course::instance($this->course->id); - // Create activities. - $this->activities[1] = $this->generator->create_module('page', ['course' => $this->course->id]); - $this->activities[2] = $this->generator->create_module('page', ['course' => $this->course->id]); - // Create mock issuer. - $this->issuer = helpers::get_mock_issuer(1); - // Create mock builder for OAuth2 client. - $mockbuilder = $this->getMockBuilder('core\oauth2\client'); - $mockbuilder->onlyMethods(['get_issuer', 'is_logged_in', 'get_accesstoken']); - $mockbuilder->setConstructorArgs([$this->issuer, '', '']); - // Get the OAuth2 client mock. - $this->mockoauthclient = $mockbuilder->getMock(); - } - - /** - * Test prepare_share_contents method. - * - * @covers ::prepare_share_contents - */ - public function test_prepare_share_contents(): void { - global $USER; - $this->setAdminUser(); - - // Set get_file method accessibility. - $method = new ReflectionMethod(course_partial_sender::class, 'prepare_share_contents'); - - $httpclient = new http_client(); - $moodlenetclient = new moodlenet_client($httpclient, $this->mockoauthclient); - - $this->expectException(moodle_exception::class); - $this->expectExceptionMessage(get_string('invalidcoursemodule', 'error')); - - // Test with valid share format and invalid course module id. - $package = $method->invoke(new course_partial_sender( - $this->course->id, - $USER->id, - $moodlenetclient, - $this->mockoauthclient, - [random_int(5, 30)], - resource_sender::SHARE_FORMAT_BACKUP - )); - $this->assertEmpty($package); - - // Test with valid share format and valid course module ids. - $package = $method->invoke(new course_partial_sender( - $this->course->id, - $USER->id, - $moodlenetclient, - $this->mockoauthclient, - [$this->activities[1]->cmid, $this->activities[2]->cmid], - resource_sender::SHARE_FORMAT_BACKUP - )); - $this->assertNotEmpty($package); - - // Confirm the expected stored_file object is returned. - $this->assertInstanceOf(\stored_file::class, $package); - } - - /** - * Test get_resource_description method. - * - * @covers ::get_resource_description - */ - public function test_get_resource_description(): void { - global $USER; - $this->setAdminUser(); - - $course = $this->generator->create_course([ - 'summary' => '

This is an example Moodle course description.

-

 

-

This is a formatted intro

-

 

-

This thing has many lines.

-

 

-

The last word of this sentence is in bold

' - ]); - $page = $this->generator->create_module('page', ['course' => $course->id]); - - // Set get_resource_description method accessibility. - $method = new ReflectionMethod(course_partial_sender::class, 'get_resource_description'); - - // Test the processed description. - $httpclient = new http_client(); - $moodlenetclient = new moodlenet_client($httpclient, $this->mockoauthclient); - $processeddescription = $method->invoke(new course_partial_sender( - $course->id, - $USER->id, - $moodlenetclient, - $this->mockoauthclient, - [$page->cmid], - resource_sender::SHARE_FORMAT_BACKUP - ), $this->coursecontext); - - $this->assertEquals('This is an example Moodle course description. -  -This is a formatted intro -  -This thing has many lines. -  -The last word of this sentence is in bold', $processeddescription); - } - - /** - * Test share_resource() method. - * - * @dataProvider share_resource_provider - * @covers ::share_resource - * @covers ::log_event - * @covers \core\moodlenet\moodlenet_client::create_resource_from_stored_file - * @covers \core\moodlenet\moodlenet_client::prepare_file_share_request_data - * @param ResponseInterface $httpresponse - * @param array $expected - */ - public function test_share_resource(ResponseInterface $httpresponse, array $expected): void { - global $CFG, $USER; - $this->setAdminUser(); - - // Enable the experimental flag. - $CFG->enablesharingtomoodlenet = true; - - // Set OAuth 2 service in the outbound setting to the dummy issuer. - set_config('oauthservice', $this->issuer->get('id'), 'moodlenet'); - - // Generate access token for the mock. - $accesstoken = new stdClass(); - $accesstoken->token = random_string(64); - - // Get the OAuth2 client mock and set the return value for necessary methods. - $this->mockoauthclient->method('get_issuer')->will($this->returnValue($this->issuer)); - $this->mockoauthclient->method('is_logged_in')->will($this->returnValue(true)); - $this->mockoauthclient->method('get_accesstoken')->will($this->returnValue($accesstoken)); - - // Create Guzzle mock. - $mockguzzlehandler = new MockHandler([$httpresponse]); - $handlerstack = HandlerStack::create($mockguzzlehandler); - $httpclient = new http_client(['handler' => $handlerstack]); - - // Create events sink. - $sink = $this->redirectEvents(); - - // Create sender. - $moodlenetclient = new moodlenet_client($httpclient, $this->mockoauthclient); - $coursepartialsender = new course_partial_sender( - $this->course->id, - $USER->id, - $moodlenetclient, - $this->mockoauthclient, - [$this->activities[1]->cmid, $this->activities[2]->cmid], - resource_sender::SHARE_FORMAT_BACKUP - ); - - if (isset($expected['exception'])) { - $this->expectException(ClientException::class); - $this->expectExceptionMessage($expected['exception']); - } - // Call the API. - $result = $coursepartialsender->share_resource(); - - // Verify the result. - $this->assertEquals($expected['response_code'], $result['responsecode']); - $this->assertEquals($expected['resource_url'], $result['drafturl']); - - // Verify the events. - $events = $sink->get_events(); - - $event = end($events); - $this->assertInstanceOf('\core\event\moodlenet_resource_exported', $event); - $this->assertEquals($USER->id, $event->userid); - - $cmidslist = implode("', '", [$this->activities[1]->cmid, $this->activities[2]->cmid]); - if ($result['responsecode'] == 201) { - $description = "The user with id '{$USER->id}' successfully shared activities to MoodleNet with the " . - "following course module ids, from context with id '{$this->coursecontext->id}': '{$cmidslist}'."; - } else { - $description = "The user with id '{$USER->id}' failed to share activities to MoodleNet with the " . - "following course module ids, from context with id '{$this->coursecontext->id}': '{$cmidslist}'."; - } - $this->assertEquals($description, $event->get_description()); - } - - /** - * Provider for test share_resource(). - * - * @return array Test data. - */ - public static function share_resource_provider(): array { - return [ - 'Success' => [ - 'httpresponse' => new Response( - 201, - ['Content-Type' => 'application/json'], - json_encode([ - 'homepage' => 'https://moodlenet.example.com/drafts/view/testcourse_backup_1.mbz', - ]), - ), - 'expected' => [ - 'response_code' => 201, - 'resource_url' => 'https://moodlenet.example.com/drafts/view/testcourse_backup_1.mbz', - ], - ], - 'Fail with 200 status code' => [ - 'httpresponse' => new Response( - 200, - ['Content-Type' => 'application/json'], - json_encode([ - 'homepage' => 'https://moodlenet.example.com/drafts/view/testcourse_backup_2.mbz', - ]), - ), - 'expected' => [ - 'response_code' => 200, - 'resource_url' => 'https://moodlenet.example.com/drafts/view/testcourse_backup_2.mbz', - ], - ], - 'Fail with 401 status code' => [ - 'httpresponse' => new Response( - 401, - ), - 'expected' => [ - 'response_code' => 401, - 'resource_url' => '', - 'exception' => 'Client error: ' . - '`POST https://moodlenet.example.com/.pkg/@moodlenet/ed-resource/basic/v1/create` ' . - 'resulted in a `401 Unauthorized` response', - ], - ], - 'Fail with 404 status code' => [ - 'httpresponse' => new Response( - 404, - ), - 'expected' => [ - 'response_code' => 404, - 'resource_url' => '', - 'exception' => 'Client error: '. - '`POST https://moodlenet.example.com/.pkg/@moodlenet/ed-resource/basic/v1/create` ' . - 'resulted in a `404 Not Found` response', - ], - ], - ]; - } - -} diff --git a/public/lib/tests/moodlenet/course_sender_test.php b/public/lib/tests/moodlenet/course_sender_test.php deleted file mode 100644 index f59bd85c1ed..00000000000 --- a/public/lib/tests/moodlenet/course_sender_test.php +++ /dev/null @@ -1,318 +0,0 @@ -. - -namespace core\moodlenet; - -use context_course; -use core\http_client; -use core\oauth2\issuer; -use GuzzleHttp\Exception\ClientException; -use GuzzleHttp\Handler\MockHandler; -use GuzzleHttp\HandlerStack; -use GuzzleHttp\Psr7\Response; -use PHPUnit\Framework\MockObject\MockObject; -use Psr\Http\Message\ResponseInterface; -use ReflectionMethod; -use stdClass; -use testing_data_generator; - -/** - * Test coverage for moodlenet course sender. - * - * @package core - * @copyright 2023 Safat Shahin - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @coversDefaultClass \core\moodlenet\course_sender - */ -final class course_sender_test extends \advanced_testcase { - - /** @var testing_data_generator Data generator. */ - private testing_data_generator $generator; - /** @var stdClass Course object. */ - private stdClass $course; - - /** @var context_course Course context instance. */ - private context_course $coursecontext; - /** @var issuer $issuer Dummy issuer. */ - private issuer $issuer; - /** @var MockObject $mockoauthclient Mock OAuth client. */ - private MockObject $mockoauthclient; - - public static function setUpBeforeClass(): void { - parent::setUpBeforeClass(); - - require_once(__DIR__ . '/helpers.php'); - } - - /** - * Set up function for tests. - */ - protected function setUp(): void { - parent::setUp(); - - $this->resetAfterTest(); - // Get data generator. - $this->generator = $this->getDataGenerator(); - // Create course. - $this->course = $this->generator->create_course(['shortname' => 'testcourse']); - $this->coursecontext = context_course::instance($this->course->id); - // Create mock issuer. - $this->issuer = helpers::get_mock_issuer(1); - // Create mock builder for OAuth2 client. - $mockbuilder = $this->getMockBuilder('core\oauth2\client'); - $mockbuilder->onlyMethods(['get_issuer', 'is_logged_in', 'get_accesstoken']); - $mockbuilder->setConstructorArgs([$this->issuer, '', '']); - // Get the OAuth2 client mock. - $this->mockoauthclient = $mockbuilder->getMock(); - } - - /** - * Test prepare_share_contents method. - * - * @covers ::prepare_share_contents - */ - public function test_prepare_share_contents(): void { - global $USER; - $this->setAdminUser(); - - // Set get_file method accessibility. - $method = new ReflectionMethod(course_sender::class, 'prepare_share_contents'); - - // Test with invalid share format. - $this->expectException(\moodle_exception::class); - $this->expectExceptionMessage(get_string('moodlenet:invalidshareformat', 'error')); - - $httpclient = new http_client(); - $moodlenetclient = new moodlenet_client($httpclient, $this->mockoauthclient); - $coursesender = new course_sender( - random_int(5, 30), - $USER->id, - $moodlenetclient, - $this->mockoauthclient, - random_int(5, 30) - ); - $coursesender = $method->invoke(new course_sender( - $this->course->id, - $USER->id, - $moodlenetclient, - $this->mockoauthclient, - resource_sender::SHARE_FORMAT_BACKUP - )); - - // Test with valid share format and invalid course module. - $package = $method->invoke(new course_sender( - $this->course->id, - $USER->id, - $moodlenetclient, - $this->mockoauthclient, - resource_sender::SHARE_FORMAT_BACKUP - )); - $this->assertEmpty($package); - - // Test with valid share format and valid course module. - $package = $method->invoke(new course_sender( - $this->course->id, - $USER->id, - $moodlenetclient, - $this->mockoauthclient, - resource_sender::SHARE_FORMAT_BACKUP - )); - $this->assertNotEmpty($package); - - // Confirm the expected stored_file object is returned. - $this->assertInstanceOf(\stored_file::class, $package); - } - - /** - * Test get_resource_description method. - * - * @covers ::get_resource_description - */ - public function test_get_resource_description(): void { - global $USER; - $this->setAdminUser(); - - $course = $this->generator->create_course([ - 'summary' => '

This is an example Moodle course description.

-

 

-

This is a formatted intro

-

 

-

This thing has many lines.

-

 

-

The last word of this sentence is in bold

' - ]); - - // Set get_resource_description method accessibility. - $method = new ReflectionMethod(course_sender::class, 'get_resource_description'); - - // Test the processed description. - $httpclient = new http_client(); - $moodlenetclient = new moodlenet_client($httpclient, $this->mockoauthclient); - $processeddescription = $method->invoke(new course_sender( - $course->id, - $USER->id, - $moodlenetclient, - $this->mockoauthclient, - resource_sender::SHARE_FORMAT_BACKUP - ), $this->coursecontext); - - $this->assertEquals('This is an example Moodle course description. -  -This is a formatted intro -  -This thing has many lines. -  -The last word of this sentence is in bold', $processeddescription); - } - - /** - * Test share_resource() method. - * - * @dataProvider share_resource_provider - * @covers ::share_resource - * @covers ::log_event - * @covers \core\moodlenet\moodlenet_client::create_resource_from_stored_file - * @covers \core\moodlenet\moodlenet_client::prepare_file_share_request_data - * @param ResponseInterface $httpresponse - * @param array $expected - */ - public function test_share_resource(ResponseInterface $httpresponse, array $expected): void { - global $CFG, $USER; - $this->setAdminUser(); - - // Enable the experimental flag. - $CFG->enablesharingtomoodlenet = true; - - // Set OAuth 2 service in the outbound setting to the dummy issuer. - set_config('oauthservice', $this->issuer->get('id'), 'moodlenet'); - - // Generate access token for the mock. - $accesstoken = new stdClass(); - $accesstoken->token = random_string(64); - - // Get the OAuth2 client mock and set the return value for necessary methods. - $this->mockoauthclient->method('get_issuer')->will($this->returnValue($this->issuer)); - $this->mockoauthclient->method('is_logged_in')->will($this->returnValue(true)); - $this->mockoauthclient->method('get_accesstoken')->will($this->returnValue($accesstoken)); - - // Create Guzzle mock. - $mockguzzlehandler = new MockHandler([$httpresponse]); - $handlerstack = HandlerStack::create($mockguzzlehandler); - $httpclient = new http_client(['handler' => $handlerstack]); - - // Create events sink. - $sink = $this->redirectEvents(); - - // Create sender. - $moodlenetclient = new moodlenet_client($httpclient, $this->mockoauthclient); - $coursesender = new course_sender( - $this->course->id, - $USER->id, - $moodlenetclient, - $this->mockoauthclient, - resource_sender::SHARE_FORMAT_BACKUP - ); - - if (isset($expected['exception'])) { - $this->expectException(ClientException::class); - $this->expectExceptionMessage($expected['exception']); - } - // Call the API. - $result = $coursesender->share_resource(); - - // Verify the result. - $this->assertEquals($expected['response_code'], $result['responsecode']); - $this->assertEquals($expected['resource_url'], $result['drafturl']); - - // Verify the events. - $events = $sink->get_events(); - - $event = end($events); - $this->assertInstanceOf('\core\event\moodlenet_resource_exported', $event); - $this->assertEquals($USER->id, $event->userid); - - if ($result['responsecode'] == 201) { - $description = "The user with id '{$USER->id}' successfully shared course to MoodleNet with the " . - "following course id, from context with id '{$this->coursecontext->id}': '{$this->course->id}'."; - } else { - $description = "The user with id '{$USER->id}' failed to share course to MoodleNet with the " . - "following course id, from context with id '{$this->coursecontext->id}': '{$this->course->id}'."; - } - $this->assertEquals($description, $event->get_description()); - } - - /** - * Provider for test share_resource(). - * - * @return array Test data. - */ - public static function share_resource_provider(): array { - return [ - 'Success' => [ - 'httpresponse' => new Response( - 201, - ['Content-Type' => 'application/json'], - json_encode([ - 'homepage' => 'https://moodlenet.example.com/drafts/view/testcourse_backup_1.mbz', - ]), - ), - 'expected' => [ - 'response_code' => 201, - 'resource_url' => 'https://moodlenet.example.com/drafts/view/testcourse_backup_1.mbz', - ], - ], - 'Fail with 200 status code' => [ - 'httpresponse' => new Response( - 200, - ['Content-Type' => 'application/json'], - json_encode([ - 'homepage' => 'https://moodlenet.example.com/drafts/view/testcourse_backup_2.mbz', - ]), - ), - 'expected' => [ - 'response_code' => 200, - 'resource_url' => 'https://moodlenet.example.com/drafts/view/testcourse_backup_2.mbz', - ], - ], - 'Fail with 401 status code' => [ - 'httpresponse' => new Response( - 401, - ), - 'expected' => [ - 'response_code' => 401, - 'resource_url' => '', - 'exception' => 'Client error: ' . - '`POST https://moodlenet.example.com/.pkg/@moodlenet/ed-resource/basic/v1/create` ' . - 'resulted in a `401 Unauthorized` response', - ], - ], - 'Fail with 404 status code' => [ - 'httpresponse' => new Response( - 404, - ), - 'expected' => [ - 'response_code' => 404, - 'resource_url' => '', - 'exception' => 'Client error: '. - '`POST https://moodlenet.example.com/.pkg/@moodlenet/ed-resource/basic/v1/create` ' . - 'resulted in a `404 Not Found` response', - ], - ], - ]; - } - - -} diff --git a/public/lib/tests/moodlenet/helpers.php b/public/lib/tests/moodlenet/helpers.php deleted file mode 100644 index 4c2b67852dc..00000000000 --- a/public/lib/tests/moodlenet/helpers.php +++ /dev/null @@ -1,52 +0,0 @@ -. - -namespace core\moodlenet; - -use core\oauth2\issuer; - -/** - * Helper for tests related to MoodleNet integration. - * - * @package core - * @copyright 2023 Michael Hawkins - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -class helpers { - /** - * Create and return a mock MoodleNet issuer. - * - * @param int $enabled Whether the issuer is enabled. - * @return issuer The issuer that has been created. - */ - public static function get_mock_issuer(int $enabled): issuer { - $record = (object) [ - 'name' => 'MoodleNet', - 'image' => 'https://moodle.net/favicon.ico', - 'baseurl' => 'https://moodlenet.example.com', - 'loginscopes' => '', - 'loginscopesoffline' => '', - 'loginparamsoffline' => '', - 'showonloginpage' => issuer::SERVICEONLY, - 'servicetype' => 'moodlenet', - 'enabled' => $enabled, - ]; - $issuer = new issuer(0, $record); - $issuer->create(); - - return $issuer; - } -} diff --git a/public/lib/tests/moodlenet/share_recorder_test.php b/public/lib/tests/moodlenet/share_recorder_test.php deleted file mode 100644 index 53c3d6445dd..00000000000 --- a/public/lib/tests/moodlenet/share_recorder_test.php +++ /dev/null @@ -1,134 +0,0 @@ -. - -namespace core\moodlenet; - -use core\moodlenet\share_recorder; - -/** - * Test coverage for moodlenet share recorder. - * - * @package core - * @copyright 2023 David Woloszyn - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - * @coversDefaultClass \core\moodlenet\share_recorder - */ -final class share_recorder_test extends \advanced_testcase { - - /** - * Test inserting and updating an activity share progress to MoodleNet. - * - * @covers ::insert_share_progress - * @covers ::update_share_progress - */ - public function test_activity_share_progress(): void { - global $DB, $USER; - $this->resetAfterTest(); - - $courseid = 10; - $cmid = 20; - $resourceurl = 'https://moodlenet.test/files/testresource.mbz'; - - // Insert the activity share progress and test the returned id. - $shareid = share_recorder::insert_share_progress(share_recorder::TYPE_ACTIVITY, $USER->id, $courseid, $cmid); - $this->assertNotNull($shareid); - - // Test we have set the fields correctly. - $record = $DB->get_record('moodlenet_share_progress', ['id' => $shareid]); - $this->assertEquals(share_recorder::TYPE_ACTIVITY, $record->type); - $this->assertEquals(share_recorder::STATUS_IN_PROGRESS, $record->status); - $this->assertEquals($courseid, $record->courseid); - $this->assertEquals($cmid, $record->cmid); - $this->assertTimeCurrent($record->timecreated); - $this->assertEquals($USER->id, $record->userid); - - // Update the record with the returned data from MoodleNet. - share_recorder::update_share_progress($shareid, share_recorder::STATUS_SENT, $resourceurl); - - // Test we have set the fields correctly. - $record = $DB->get_record('moodlenet_share_progress', ['id' => $shareid]); - $this->assertEquals($resourceurl, $record->resourceurl); - $this->assertEquals(share_recorder::STATUS_SENT, $record->status); - } - - /** - * Test inserting and updating a course share progress to MoodleNet. - * We will also force an error status and test that too. - * - * @covers ::insert_share_progress - * @covers ::update_share_progress - */ - public function test_course_share_progress(): void { - global $DB, $USER; - $this->resetAfterTest(); - - $courseid = 10; - - // Insert the course share progress and test the returned id. - $shareid = share_recorder::insert_share_progress(share_recorder::TYPE_COURSE, $USER->id, $courseid); - $this->assertNotNull($shareid); - - // Test we have set the fields correctly (we expect cmid to be null for course shares). - $record = $DB->get_record('moodlenet_share_progress', ['id' => $shareid]); - $this->assertEquals(share_recorder::TYPE_COURSE, $record->type); - $this->assertEquals(share_recorder::STATUS_IN_PROGRESS, $record->status); - $this->assertEquals($courseid, $record->courseid); - $this->assertNull($record->cmid); - $this->assertTimeCurrent($record->timecreated); - $this->assertEquals($USER->id, $record->userid); - - // Update the record, but let's test with an error status. - share_recorder::update_share_progress($shareid, share_recorder::STATUS_ERROR); - - // Test we have set the field correctly. - $record = $DB->get_record('moodlenet_share_progress', ['id' => $shareid]); - $this->assertEquals(share_recorder::STATUS_ERROR, $record->status); - } - - /** - * Tests the share type is one of the allowed values. - * - * @covers ::get_allowed_share_types - */ - public function test_invalid_share_type(): void { - global $USER; - $this->resetAfterTest(); - - $courseid = 10; - $invalidsharetype = 99; - - $this->expectException(\moodle_exception::class); - share_recorder::insert_share_progress($invalidsharetype, $USER->id, $courseid); - } - - /** - * Tests the share status is one of the allowed values. - * - * @covers ::get_allowed_share_statuses - */ - public function test_invalid_share_status(): void { - global $USER; - $this->resetAfterTest(); - - $courseid = 10; - $invalidsharestatus = 66; - - $recordid = share_recorder::insert_share_progress(share_recorder::TYPE_COURSE, $USER->id, $courseid); - - $this->expectException(\moodle_exception::class); - share_recorder::update_share_progress($recordid, $invalidsharestatus); - } -} diff --git a/public/lib/tests/moodlenet/utilities_test.php b/public/lib/tests/moodlenet/utilities_test.php deleted file mode 100644 index a6510e978ec..00000000000 --- a/public/lib/tests/moodlenet/utilities_test.php +++ /dev/null @@ -1,193 +0,0 @@ -. - -namespace core\moodlenet; - -use context_course; -use stdClass; -use testing_data_generator; - -/** - * Unit tests for {@see utilities}. - * - * @coversDefaultClass \core\moodlenet\utilities - * @package core - * @copyright 2023 Huong Nguyen - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ -final class utilities_test extends \advanced_testcase { - - /** @var testing_data_generator Data generator. */ - private testing_data_generator $generator; - - /** @var stdClass Activity object, */ - private stdClass $course; - - /** @var context_course Course context instance. */ - private context_course $coursecontext; - - /** - * Set up function for tests. - */ - protected function setUp(): void { - parent::setUp(); - - $this->resetAfterTest(); - $this->generator = $this->getDataGenerator(); - $this->course = $this->generator->create_course(); - $this->coursecontext = context_course::instance($this->course->id); - } - - /** - * Test is_valid_instance method. - * - * @covers ::is_valid_instance - * @return void - */ - public function test_is_valid_instance(): void { - global $CFG; - $this->setAdminUser(); - - // Create dummy issuer. - $issuer = new \core\oauth2\issuer(0); - $issuer->set('enabled', 0); - $issuer->set('servicetype', 'google'); - - // Can not share if the experimental flag it set to false. - $CFG->enablesharingtomoodlenet = false; - $this->assertFalse(utilities::is_valid_instance($issuer)); - - // Enable the experimental flag. - $CFG->enablesharingtomoodlenet = true; - - // Can not share if the OAuth 2 service in the outbound setting is not matched the given one. - set_config('oauthservice', random_int(1, 30), 'moodlenet'); - $this->assertFalse(utilities::is_valid_instance($issuer)); - - // Can not share if the OAuth 2 service in the outbound setting is not enabled. - set_config('oauthservice', $issuer->get('id'), 'moodlenet'); - $this->assertFalse(utilities::is_valid_instance($issuer)); - - // Can not share if the OAuth 2 service type is not moodlenet. - $issuer->set('enabled', 1); - $this->assertFalse(utilities::is_valid_instance($issuer)); - - // All good now. - $issuer->set('servicetype', 'moodlenet'); - $this->assertTrue(utilities::is_valid_instance($issuer)); - } - - - /** - * Test can_user_share method. - * - * @covers ::can_user_share - * @return void - */ - public function test_can_user_share(): void { - global $DB; - - // Generate data. - $student1 = $this->generator->create_user(); - $teacher1 = $this->generator->create_user(); - $teacher2 = $this->generator->create_user(); - $manager1 = $this->generator->create_user(); - - // Enrol users. - $this->generator->enrol_user($student1->id, $this->course->id, 'student'); - $this->generator->enrol_user($teacher1->id, $this->course->id, 'teacher'); - $this->generator->enrol_user($teacher2->id, $this->course->id, 'editingteacher'); - $this->generator->enrol_user($manager1->id, $this->course->id, 'manager'); - - // Get roles. - $teacherrole = $DB->get_record('role', ['shortname' => 'teacher'], 'id', MUST_EXIST); - $editingteacherrole = $DB->get_record('role', ['shortname' => 'editingteacher'], 'id', MUST_EXIST); - - // Test with default settings. - // Student and Teacher cannot share the activity. - $this->assertFalse(utilities::can_user_share($this->coursecontext, $student1->id)); - $this->assertFalse(utilities::can_user_share($this->coursecontext, $teacher1->id)); - // Editing-teacher and Manager can share the activity. - $this->assertTrue(utilities::can_user_share($this->coursecontext, $teacher2->id)); - $this->assertTrue(utilities::can_user_share($this->coursecontext, $manager1->id)); - - // Teacher who has the capabilities can share the activity. - assign_capability('moodle/moodlenet:shareactivity', CAP_ALLOW, $teacherrole->id, $this->coursecontext); - assign_capability('moodle/backup:backupactivity', CAP_ALLOW, $teacherrole->id, $this->coursecontext); - $this->assertTrue(utilities::can_user_share($this->coursecontext, $teacher1->id)); - - // Editing-teacher who does not have the capabilities can not share the activity. - assign_capability('moodle/moodlenet:shareactivity', CAP_PROHIBIT, $editingteacherrole->id, $this->coursecontext); - $this->assertFalse(utilities::can_user_share($this->coursecontext, $teacher2->id)); - - // Test with default settings for course. - // Student and Teacher cannot share the course. - $this->assertFalse(utilities::can_user_share($this->coursecontext, $student1->id, 'course')); - $this->assertFalse(utilities::can_user_share($this->coursecontext, $teacher1->id, 'course')); - // Editing-teacher and Manager can share the course. - $this->assertTrue(utilities::can_user_share($this->coursecontext, $teacher2->id, 'course')); - $this->assertTrue(utilities::can_user_share($this->coursecontext, $manager1->id, 'course')); - - // Teacher who has the capabilities can share the course. - assign_capability('moodle/moodlenet:sharecourse', CAP_ALLOW, $teacherrole->id, $this->coursecontext); - assign_capability('moodle/backup:backupcourse', CAP_ALLOW, $teacherrole->id, $this->coursecontext); - $this->assertTrue(utilities::can_user_share($this->coursecontext, $teacher1->id, 'course')); - - // Editing-teacher who does not have the capabilities can not share the course. - assign_capability('moodle/moodlenet:sharecourse', CAP_PROHIBIT, $editingteacherrole->id, $this->coursecontext); - $this->assertFalse(utilities::can_user_share($this->coursecontext, $teacher2->id, 'course')); - } - - /** - * Test does_user_have_capability_in_any_course method. - * - * @covers ::does_user_have_capability_in_any_course - * @return void - */ - public function test_does_user_have_capability_in_any_course(): void { - global $DB; - - // Prepare data. - $teacher1 = $this->generator->create_user(); - $student1 = $this->generator->create_user(); - $teacherrole = $DB->get_record('role', ['shortname' => 'teacher'], 'id', MUST_EXIST); - $studentrole = $DB->get_record('role', ['shortname' => 'student'], 'id', MUST_EXIST); - - // Enrol users, - $this->generator->enrol_user($teacher1->id, $this->course->id, $teacherrole->id); - $this->generator->enrol_user($student1->id, $this->course->id, $studentrole->id); - - // Assign a valid capability to the teacher. - assign_capability('moodle/moodlenet:shareactivity', CAP_ALLOW, $teacherrole->id, $this->coursecontext); - - // Check the method's results are as expected (this is cached). - $this->assertSame('yes', utilities::does_user_have_capability_in_any_course($teacher1->id)); - $this->assertSame('no', utilities::does_user_have_capability_in_any_course($student1->id)); - - // Compare to cache. - $teachercachedvalue = \cache::make('core', 'moodlenet_usercanshare')->get($teacher1->id); - $this->assertSame('yes', $teachercachedvalue); - $studentcachedvalue = \cache::make('core', 'moodlenet_usercanshare')->get($student1->id); - $this->assertSame('no', $studentcachedvalue); - - // Change the teacher's role and check the moodlenet_usercanshare cache is invalidated for everyone. - $this->generator->role_assign($studentrole->id, $teacher1->id, $this->coursecontext->id); - $teachercachedvalue = \cache::make('core', 'moodlenet_usercanshare')->get($teacher1->id); - $this->assertFalse($teachercachedvalue); - $studentcachedvalue = \cache::make('core', 'moodlenet_usercanshare')->get($student1->id); - $this->assertFalse($studentcachedvalue); - } -} diff --git a/public/lib/tests/privacy/provider_test.php b/public/lib/tests/privacy/provider_test.php index 041efd09bca..35a2bc085e5 100644 --- a/public/lib/tests/privacy/provider_test.php +++ b/public/lib/tests/privacy/provider_test.php @@ -20,7 +20,6 @@ use core_privacy\local\request\approved_contextlist; use core_privacy\local\request\writer; use core_privacy\tests\provider_testcase; use core_privacy\local\request\approved_userlist; -use core\moodlenet\share_recorder; /** * Privacy provider tests class. @@ -40,30 +39,17 @@ final class provider_test extends provider_testcase { */ public function test_get_contexts_for_userid(): void { $this->resetAfterTest(); - $user1 = $this->getDataGenerator()->create_user(); - $user2 = $this->getDataGenerator()->create_user(); - - // Check that there are no contexts used for the user yet. - $this->assertEmpty(provider::get_contexts_for_userid($user1->id)); + $user = $this->getDataGenerator()->create_user(); // Insert a record. - $this->insert_dummy_moodlenet_share_progress_record($user1->id); - $this->insert_dummy_shortlink_record($user2->id); + $this->insert_dummy_shortlink_record($user->id); - // Check that we only get back one context for user1. - $contextlist = provider::get_contexts_for_userid($user1->id); + // Check that we only get back one context for user. + $contextlist = provider::get_contexts_for_userid($user->id); $this->assertCount(1, $contextlist); // Check that the context returned is the expected one. - $usercontext = \context_user::instance($user1->id); - $this->assertEquals($usercontext->id, $contextlist->get_contextids()[0]); - - // Check that we only get back one context for user2. - $contextlist = provider::get_contexts_for_userid($user2->id); - $this->assertCount(1, $contextlist); - - // Check that the context returned is the expected one. - $usercontext = \context_user::instance($user2->id); + $usercontext = \context_user::instance($user->id); $this->assertEquals($usercontext->id, $contextlist->get_contextids()[0]); } @@ -76,46 +62,22 @@ final class provider_test extends provider_testcase { $this->resetAfterTest(); // Create some users. - $user1 = $this->getDataGenerator()->create_user(); - $user2 = $this->getDataGenerator()->create_user(); - $user3 = $this->getDataGenerator()->create_user(); - $usercontext1 = \context_user::instance($user1->id); - $usercontext2 = \context_user::instance($user2->id); - $usercontext3 = \context_user::instance($user3->id); + $user = $this->getDataGenerator()->create_user(); + $usercontext = \context_user::instance($user->id); // Get userlists and check they are empty for now. - $userlist1 = new \core_privacy\local\request\userlist($usercontext1, 'core'); - provider::get_users_in_context($userlist1); - $this->assertCount(0, $userlist1); + $userlist = new \core_privacy\local\request\userlist($usercontext, 'core'); + provider::get_users_in_context($userlist); + $this->assertCount(0, $userlist); - $userlist2 = new \core_privacy\local\request\userlist($usercontext2, 'core'); - provider::get_users_in_context($userlist2); - $this->assertCount(0, $userlist2); - - $userlist3 = new \core_privacy\local\request\userlist($usercontext3, 'core'); - provider::get_users_in_context($userlist3); - $this->assertCount(0, $userlist3); - - // Insert records for both users. - $this->insert_dummy_moodlenet_share_progress_record($user1->id); - $this->insert_dummy_moodlenet_share_progress_record($user2->id); - $this->insert_dummy_shortlink_record($user3->id); + // Insert records for the user. + $this->insert_dummy_shortlink_record($user->id); // Check the userlists contain the correct users. - $userlist1 = new \core_privacy\local\request\userlist($usercontext1, 'core'); - provider::get_users_in_context($userlist1); - $this->assertCount(1, $userlist1); - $this->assertEquals($user1->id, $userlist1->get_userids()[0]); - - $userlist2 = new \core_privacy\local\request\userlist($usercontext2, 'core'); - provider::get_users_in_context($userlist2); - $this->assertCount(1, $userlist2); - $this->assertEquals($user2->id, $userlist2->get_userids()[0]); - - $userlist3 = new \core_privacy\local\request\userlist($usercontext3, 'core'); - provider::get_users_in_context($userlist3); - $this->assertCount(1, $userlist3); - $this->assertEquals($user3->id, $userlist3->get_userids()[0]); + $userlist = new \core_privacy\local\request\userlist($usercontext, 'core'); + provider::get_users_in_context($userlist); + $this->assertCount(1, $userlist); + $this->assertEquals($user->id, $userlist->get_userids()[0]); } /** @@ -127,61 +89,29 @@ final class provider_test extends provider_testcase { global $DB; $this->resetAfterTest(); - // Create some users. - $user1 = $this->getDataGenerator()->create_user(); - $user2 = $this->getDataGenerator()->create_user(); - $user3 = $this->getDataGenerator()->create_user(); + // Create user. + $user = $this->getDataGenerator()->create_user(); - // Insert a record for each user. - $this->insert_dummy_moodlenet_share_progress_record($user1->id); - $this->insert_dummy_moodlenet_share_progress_record($user2->id); - $this->insert_dummy_shortlink_record($user3->id); - - $subcontexts = [ - get_string('privacy:metadata:moodlenet_share_progress', 'moodle') - ]; - - // Check if user1 has any exported data yet. - $usercontext1 = \context_user::instance($user1->id); - $writer = writer::with_context($usercontext1); - $this->assertFalse($writer->has_any_data()); - - // Export user1's data and check the count. - $approvedlist = new approved_contextlist($user1, 'core', [$usercontext1->id]); - provider::export_user_data($approvedlist); - $data = (array)$writer->get_data($subcontexts); - $this->assertCount(1, $data); - - // Get the inserted data. - $userdata = $DB->get_record('moodlenet_share_progress', ['userid' => $user1->id]); - - // Check exported data against the inserted data. - $this->assertEquals($userdata->id, reset($data)->id); - $this->assertEquals($userdata->type, reset($data)->type); - $this->assertEquals($userdata->courseid, reset($data)->courseid); - $this->assertEquals($userdata->cmid, reset($data)->cmid); - $this->assertEquals($userdata->userid, reset($data)->userid); - $this->assertEquals($userdata->timecreated, reset($data)->timecreated); - $this->assertEquals($userdata->resourceurl, reset($data)->resourceurl); - $this->assertEquals($userdata->status, reset($data)->status); + // Insert a record for the user. + $this->insert_dummy_shortlink_record($user->id); $subcontexts = [ get_string('privacy:metadata:shortlink', 'moodle') ]; - // Check if user3 has any exported data yet. - $usercontext3 = \context_user::instance($user3->id); - $writer = writer::with_context($usercontext3); + // Check if user has any exported data yet. + $usercontext = \context_user::instance($user->id); + $writer = writer::with_context($usercontext); $this->assertFalse($writer->has_any_data()); - // Export user3's data and check the count. - $approvedlist = new approved_contextlist($user3, 'core', [$usercontext3->id]); + // Export user's data and check the count. + $approvedlist = new approved_contextlist($user, 'core', [$usercontext->id]); provider::export_user_data($approvedlist); $data = (array)$writer->get_data($subcontexts); $this->assertCount(1, $data); // Get the inserted data. - $userdata = $DB->get_record('shortlink', ['userid' => $user3->id]); + $userdata = $DB->get_record('shortlink', ['userid' => $user->id]); // Check exported data against the inserted data. $this->assertEquals($userdata->id, reset($data)->id); @@ -206,14 +136,10 @@ final class provider_test extends provider_testcase { $user2 = $this->getDataGenerator()->create_user(); // Insert a record for each user. - $this->insert_dummy_moodlenet_share_progress_record($user1->id); - $this->insert_dummy_moodlenet_share_progress_record($user2->id); $this->insert_dummy_shortlink_record($user1->id); $this->insert_dummy_shortlink_record($user2->id); // Get all users' data. - $usersdata = $DB->get_records('moodlenet_share_progress', []); - $this->assertCount(2, $usersdata); $usersdata = $DB->get_records('shortlink', []); $this->assertCount(2, $usersdata); @@ -222,9 +148,6 @@ final class provider_test extends provider_testcase { provider::delete_data_for_all_users_in_context($usercontext1); // Check what is remaining belongs to user2. - $usersdata = $DB->get_records('moodlenet_share_progress', []); - $this->assertCount(1, $usersdata); - $this->assertEquals($user2->id, reset($usersdata)->userid); $usersdata = $DB->get_records('shortlink', []); $this->assertCount(1, $usersdata); $this->assertEquals($user2->id, reset($usersdata)->userid); @@ -244,14 +167,10 @@ final class provider_test extends provider_testcase { $user2 = $this->getDataGenerator()->create_user(); // Insert a record for each user. - $this->insert_dummy_moodlenet_share_progress_record($user1->id); - $this->insert_dummy_moodlenet_share_progress_record($user2->id); $this->insert_dummy_shortlink_record($user1->id); $this->insert_dummy_shortlink_record($user2->id); // Get all users' data. - $usersdata = $DB->get_records('moodlenet_share_progress', []); - $this->assertCount(2, $usersdata); $usersdata = $DB->get_records('shortlink', []); $this->assertCount(2, $usersdata); @@ -261,9 +180,6 @@ final class provider_test extends provider_testcase { provider::delete_data_for_user($approvedlist); // Check what is remaining belongs to user2. - $usersdata = $DB->get_records('moodlenet_share_progress', []); - $this->assertCount(1, $usersdata); - $this->assertEquals($user2->id, reset($usersdata)->userid); $usersdata = $DB->get_records('shortlink', []); $this->assertCount(1, $usersdata); $this->assertEquals($user2->id, reset($usersdata)->userid); @@ -285,22 +201,16 @@ final class provider_test extends provider_testcase { $usercontext2 = \context_user::instance($user2->id); // Insert a record for each user. - $this->insert_dummy_moodlenet_share_progress_record($user1->id); - $this->insert_dummy_moodlenet_share_progress_record($user2->id); $this->insert_dummy_shortlink_record($user1->id); $this->insert_dummy_shortlink_record($user2->id); // Check the count on all user's data. - $usersdata = $DB->get_records('moodlenet_share_progress', []); - $this->assertCount(2, $usersdata); $usersdata = $DB->get_records('shortlink', []); $this->assertCount(2, $usersdata); // Attempt to delete data for user1 using user2's context (should have no effect). $approvedlist = new approved_userlist($usercontext2, 'core', [$user1->id]); provider::delete_data_for_users($approvedlist); - $usersdata = $DB->get_records('moodlenet_share_progress', []); - $this->assertCount(2, $usersdata); $usersdata = $DB->get_records('shortlink', []); $this->assertCount(2, $usersdata); @@ -309,26 +219,11 @@ final class provider_test extends provider_testcase { provider::delete_data_for_users($approvedlist); // Check what is remaining belongs to user2. - $usersdata = $DB->get_records('moodlenet_share_progress', []); - $this->assertCount(1, $usersdata); - $this->assertEquals($user2->id, reset($usersdata)->userid); $usersdata = $DB->get_records('shortlink', []); $this->assertCount(1, $usersdata); $this->assertEquals($user2->id, reset($usersdata)->userid); } - /** - * Helper function to insert a MoodleNet share progress record for use in the tests. - * - * @param int $userid The ID of the user to link the record to. - */ - protected function insert_dummy_moodlenet_share_progress_record(int $userid): void { - $sharetype = share_recorder::TYPE_ACTIVITY; - $courseid = 123; - $cmid = 456; - share_recorder::insert_share_progress($sharetype, $userid, $courseid, $cmid); - } - /** * Helper function to insert a shortlink record for use in the tests. * diff --git a/public/lib/tests/upgradelib_test.php b/public/lib/tests/upgradelib_test.php index b373d05988e..a8d9c06ea64 100644 --- a/public/lib/tests/upgradelib_test.php +++ b/public/lib/tests/upgradelib_test.php @@ -1763,4 +1763,81 @@ calendar,core_calendar|/calendar/view.php?view=month', $this->assertEquals('Aurora compatibility', $result->getInfo()); $this->assertFalse($result->getStatus()); } + + /** + * Test moodlenet_migrate_profile_field creates category, field and migrates data. + * + * @covers ::moodlenet_migrate_profile_field + */ + public function test_moodlenet_migrate_profile_field(): void { + global $DB; + + $this->resetAfterTest(); + + $dbman = $DB->get_manager(); + $table = new xmldb_table('user'); + $field = new xmldb_field('moodlenetprofile', XMLDB_TYPE_CHAR, '255', null, null, null, null, 'city'); + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + $generator = $this->getDataGenerator(); + $user1 = $generator->create_user(); // Normal value. + $user2 = $generator->create_user(); // Empty string. + $user3 = $generator->create_user(); // Not set. + + // Run migration with no MoodleNet data: no category/field should be created. + moodlenet_migrate_profile_field(); + $this->assertFalse($DB->record_exists('user_info_category', ['name' => 'MoodleNet'])); + $this->assertFalse($DB->record_exists('user_info_field', ['shortname' => 'moodlenetprofile'])); + + // Set moodlenetprofile values. + $DB->set_field('user', 'moodlenetprofile', '@user1@moodlenet.org', ['id' => $user1->id]); + $DB->set_field('user', 'moodlenetprofile', '', ['id' => $user2->id]); + + // Run the migration. + moodlenet_migrate_profile_field(); + + // Verify that the MoodleNet category was created. + $category = $DB->get_record('user_info_category', ['name' => 'MoodleNet']); + $this->assertNotEmpty($category); + + // Verify that the moodlenetprofile custom profile field was created. + $field = $DB->get_record('user_info_field', [ + 'shortname' => 'moodlenetprofile', + 'categoryid' => $category->id, + ]); + $this->assertNotEmpty($field); + $this->assertEquals('MoodleNet profile ID', $field->name); + $this->assertEquals('text', $field->datatype); + + // Verify that only one record was migrated (non-empty value only). + $userinfodata = $DB->get_records('user_info_data', ['fieldid' => $field->id]); + $this->assertCount(1, $userinfodata); + + // User 1: Verify that the moodlenetprofile value was migrated correctly. + $data1 = $DB->get_record('user_info_data', [ + 'userid' => $user1->id, + 'fieldid' => $field->id, + ]); + $this->assertEquals('@user1@moodlenet.org', $data1->data); + + // User 2: Verify that no data was created because the value is an empty string. + $data2 = $DB->get_record('user_info_data', [ + 'userid' => $user2->id, + 'fieldid' => $field->id, + ]); + $this->assertFalse($data2); + + // User 3: Verify that no data was created because no value was set. + $data3 = $DB->get_record('user_info_data', [ + 'userid' => $user3->id, + 'fieldid' => $field->id, + ]); + $this->assertFalse($data3); + + // Re-run migration to confirm that it does not create duplicates. + moodlenet_migrate_profile_field(); + $this->assertCount(1, $DB->get_records('user_info_data', ['fieldid' => $field->id])); + } } diff --git a/public/moodlenet/shareprogress.php b/public/moodlenet/shareprogress.php deleted file mode 100644 index d7653a2900b..00000000000 --- a/public/moodlenet/shareprogress.php +++ /dev/null @@ -1,56 +0,0 @@ -. - -/** - * View the progress of MoodleNet shares. - * - * @package core - * @copyright 2023 David Woloszyn - * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */ - -use core\moodlenet\utilities; - -require_once('../config.php'); - -require_login(); -if (isguestuser()) { - throw new \moodle_exception('noguest'); -} - -// Capability was not found. -if (utilities::does_user_have_capability_in_any_course($USER->id) === 'no') { - throw new \moodle_exception('nocapabilitytousethisservice'); -} - -$pageurl = $CFG->wwwroot . '/moodlenet/shareprogress.php'; -$PAGE->set_url($pageurl); -$PAGE->set_context(context_system::instance()); -$PAGE->set_title(get_string('moodlenet:shareprogress')); -$PAGE->set_heading(get_string('moodlenet:shareprogress')); -$PAGE->set_pagelayout('standard'); - -echo $OUTPUT->header(); - -// Intro paragraph. -echo html_writer::div(get_string('moodlenet:shareprogressinfo'), 'mb-4'); - -// Build table. -$table = new core\moodlenet\share_progress_table('moodlenet-share-progress', $pageurl, $USER->id); -$perpage = $table->get_default_per_page(); -$table->out($perpage, true); - -echo $OUTPUT->footer(); diff --git a/public/reportbuilder/classes/local/entities/user.php b/public/reportbuilder/classes/local/entities/user.php index 7e0dcfa3d62..48e7645540c 100644 --- a/public/reportbuilder/classes/local/entities/user.php +++ b/public/reportbuilder/classes/local/entities/user.php @@ -405,7 +405,6 @@ class user extends base { 'confirmed' => new lang_string('confirmed', 'admin'), 'username' => new lang_string('username'), 'auth' => new lang_string('authentication', 'moodle'), - 'moodlenetprofile' => new lang_string('moodlenetprofile', 'user'), 'timecreated' => new lang_string('timecreated', 'core_reportbuilder'), 'timemodified' => new lang_string('timemodified', 'core_reportbuilder'), 'lastip' => new lang_string('lastip'), diff --git a/public/theme/boost/scss/moodle.scss b/public/theme/boost/scss/moodle.scss index d8c7e3715c3..d564f7f99f9 100644 --- a/public/theme/boost/scss/moodle.scss +++ b/public/theme/boost/scss/moodle.scss @@ -48,7 +48,6 @@ @import "moodle/secondarynavigation"; @import "moodle/tertiarynavigation"; @import "moodle/process-monitor"; -@import "moodle/moodlenet"; @import "moodle/dropdown"; @import "moodle/deprecated"; @import "moodle/task-indicator"; diff --git a/public/theme/boost/scss/moodle/modchooser.scss b/public/theme/boost/scss/moodle/modchooser.scss index fb69cd373ea..32457d78672 100644 --- a/public/theme/boost/scss/moodle/modchooser.scss +++ b/public/theme/boost/scss/moodle/modchooser.scss @@ -64,16 +64,6 @@ .modal-footer { height: 70px; background: $modal-content-bg; - - .moodlenet-logo { - .icon { - height: 2.5rem; - width: 6rem; - max-height: 2.5rem; - max-width: 6rem; - margin-bottom: .6rem; - } - } } } diff --git a/public/theme/boost/scss/moodle/moodlenet.scss b/public/theme/boost/scss/moodle/moodlenet.scss deleted file mode 100644 index 2ad432e00df..00000000000 --- a/public/theme/boost/scss/moodle/moodlenet.scss +++ /dev/null @@ -1,105 +0,0 @@ -.moodlenet-share-dialog { - min-height: 500px; - - .modal-header { - .moodlenet-share-moodlenetinfo { - align-items: baseline; - - .moodlenet-logo { - display: flex; - - .icon { - max-width: initial; - width: auto; - height: 1.3rem; - } - } - - .moodlenet-title { - display: flex; - padding-left: 0.5em; - } - } - - &.no-border { - border-bottom: none; - } - - &.no-header-text { - .moodlenet-share-moodlenetinfo { - .moodlenet-title { - display: none; - } - } - } - } - - .modal-body { - .moodlenet-share-activity-info { - color: $body-color; - border-color: $primary-light-border; - @include gradient-bg($primary-light-background); - @include border-radius(); - border-width: 1px; - border-style: solid; - padding: 0.6em 1.5em; - margin-bottom: 1rem; - - .moodlenet-share-activity-info-hr { - border-bottom: 1px solid $gray-300; - } - - .moodlenet-activity-type, - .moodlenet-activity-name { - display: block; - } - } - - .moodlenet-share-notice { - background-color: $moodlenet-share-notice-bg; - padding: 1rem; - } - - .moodlenet-share-modal-content { - .loading-icon { - .icon { - max-width: 4em; - max-height: 4em; - font-size: 4em; - } - } - - .moodlenet-circle-status { - height: 18rem; - margin: auto; - - &.success { - background: radial-gradient(circle, rgba(25, 143, 81, 0.1) 9rem, transparent 9rem); - } - - &.fail { - background: radial-gradient(circle, rgba(202, 49, 32, 0.1) 9rem, transparent 9rem); - } - - span { - display: block; - margin: auto; - - &.status-icon { - .icon { - font-size: 8rem; - max-width: initial; - margin: 0; - } - } - } - } - } - } - - .modal-footer { - .moodlenet-share-to { - margin-right: auto; - } - } -} diff --git a/public/theme/boost/scss/moodle/variables.scss b/public/theme/boost/scss/moodle/variables.scss index c283c4ba54f..b38a41eee18 100644 --- a/public/theme/boost/scss/moodle/variables.scss +++ b/public/theme/boost/scss/moodle/variables.scss @@ -256,10 +256,6 @@ $modules-forum-post-border-color: #dee2e6 !default; $modules-highlight-bg: rgba(0, 123, 255, 0.5) !default; -// Moodlenet -$moodlenet-share-notice-bg: #f8f9fa !default; - - // Popover $popover-standard-border-color: #ddd !default; $popover-region-toggle-border-bottom-color: $white !default; diff --git a/public/theme/boost/style/moodle.css b/public/theme/boost/style/moodle.css index d8b3fe924ef..9bbdb9edb9b 100644 --- a/public/theme/boost/style/moodle.css +++ b/public/theme/boost/style/moodle.css @@ -31855,13 +31855,6 @@ body:not(.editing) [id^=module-]:target, body.editing [id^=module-]:target .acti height: 70px; background: var(--bs-body-bg); } -.modchooser.modal-dialog .modal-footer .moodlenet-logo .icon { - height: 2.5rem; - width: 6rem; - max-height: 2.5rem; - max-width: 6rem; - margin-bottom: 0.6rem; -} /* Main container layout styles. */ .modchoosercontainer { @@ -41195,79 +41188,6 @@ div.editor_atto_toolbar button .icon { border-bottom: 0; } -.moodlenet-share-dialog { - min-height: 500px; -} -.moodlenet-share-dialog .modal-header .moodlenet-share-moodlenetinfo { - align-items: baseline; -} -.moodlenet-share-dialog .modal-header .moodlenet-share-moodlenetinfo .moodlenet-logo { - display: flex; -} -.moodlenet-share-dialog .modal-header .moodlenet-share-moodlenetinfo .moodlenet-logo .icon { - max-width: initial; - width: auto; - height: 1.3rem; -} -.moodlenet-share-dialog .modal-header .moodlenet-share-moodlenetinfo .moodlenet-title { - display: flex; - padding-left: 0.5em; -} -.moodlenet-share-dialog .modal-header.no-border { - border-bottom: none; -} -.moodlenet-share-dialog .modal-header.no-header-text .moodlenet-share-moodlenetinfo .moodlenet-title { - display: none; -} -.moodlenet-share-dialog .modal-body .moodlenet-share-activity-info { - color: #1d2125; - border-color: #3f89cc; - background-color: #e7f0f9; - border-radius: 0.5rem; - border-width: 1px; - border-style: solid; - padding: 0.6em 1.5em; - margin-bottom: 1rem; -} -.moodlenet-share-dialog .modal-body .moodlenet-share-activity-info .moodlenet-share-activity-info-hr { - border-bottom: 1px solid #dee2e6; -} -.moodlenet-share-dialog .modal-body .moodlenet-share-activity-info .moodlenet-activity-type, -.moodlenet-share-dialog .modal-body .moodlenet-share-activity-info .moodlenet-activity-name { - display: block; -} -.moodlenet-share-dialog .modal-body .moodlenet-share-notice { - background-color: #f8f9fa; - padding: 1rem; -} -.moodlenet-share-dialog .modal-body .moodlenet-share-modal-content .loading-icon .icon { - max-width: 4em; - max-height: 4em; - font-size: 4em; -} -.moodlenet-share-dialog .modal-body .moodlenet-share-modal-content .moodlenet-circle-status { - height: 18rem; - margin: auto; -} -.moodlenet-share-dialog .modal-body .moodlenet-share-modal-content .moodlenet-circle-status.success { - background: radial-gradient(circle, rgba(25, 143, 81, 0.1) 9rem, transparent 9rem); -} -.moodlenet-share-dialog .modal-body .moodlenet-share-modal-content .moodlenet-circle-status.fail { - background: radial-gradient(circle, rgba(202, 49, 32, 0.1) 9rem, transparent 9rem); -} -.moodlenet-share-dialog .modal-body .moodlenet-share-modal-content .moodlenet-circle-status span { - display: block; - margin: auto; -} -.moodlenet-share-dialog .modal-body .moodlenet-share-modal-content .moodlenet-circle-status span.status-icon .icon { - font-size: 8rem; - max-width: initial; - margin: 0; -} -.moodlenet-share-dialog .modal-footer .moodlenet-share-to { - margin-right: auto; -} - /** * Dropdown menu Moodle specific styles. */ diff --git a/public/theme/classic/style/moodle.css b/public/theme/classic/style/moodle.css index b2c3b83ff1e..d6c3a7d3257 100644 --- a/public/theme/classic/style/moodle.css +++ b/public/theme/classic/style/moodle.css @@ -31855,13 +31855,6 @@ body:not(.editing) [id^=module-]:target, body.editing [id^=module-]:target .acti height: 70px; background: var(--bs-body-bg); } -.modchooser.modal-dialog .modal-footer .moodlenet-logo .icon { - height: 2.5rem; - width: 6rem; - max-height: 2.5rem; - max-width: 6rem; - margin-bottom: 0.6rem; -} /* Main container layout styles. */ .modchoosercontainer { @@ -41129,79 +41122,6 @@ div.editor_atto_toolbar button .icon { border-bottom: 0; } -.moodlenet-share-dialog { - min-height: 500px; -} -.moodlenet-share-dialog .modal-header .moodlenet-share-moodlenetinfo { - align-items: baseline; -} -.moodlenet-share-dialog .modal-header .moodlenet-share-moodlenetinfo .moodlenet-logo { - display: flex; -} -.moodlenet-share-dialog .modal-header .moodlenet-share-moodlenetinfo .moodlenet-logo .icon { - max-width: initial; - width: auto; - height: 1.3rem; -} -.moodlenet-share-dialog .modal-header .moodlenet-share-moodlenetinfo .moodlenet-title { - display: flex; - padding-left: 0.5em; -} -.moodlenet-share-dialog .modal-header.no-border { - border-bottom: none; -} -.moodlenet-share-dialog .modal-header.no-header-text .moodlenet-share-moodlenetinfo .moodlenet-title { - display: none; -} -.moodlenet-share-dialog .modal-body .moodlenet-share-activity-info { - color: #1d2125; - border-color: #3f89cc; - background-color: #e7f0f9; - border-radius: 0.375rem; - border-width: 1px; - border-style: solid; - padding: 0.6em 1.5em; - margin-bottom: 1rem; -} -.moodlenet-share-dialog .modal-body .moodlenet-share-activity-info .moodlenet-share-activity-info-hr { - border-bottom: 1px solid #dee2e6; -} -.moodlenet-share-dialog .modal-body .moodlenet-share-activity-info .moodlenet-activity-type, -.moodlenet-share-dialog .modal-body .moodlenet-share-activity-info .moodlenet-activity-name { - display: block; -} -.moodlenet-share-dialog .modal-body .moodlenet-share-notice { - background-color: #f8f9fa; - padding: 1rem; -} -.moodlenet-share-dialog .modal-body .moodlenet-share-modal-content .loading-icon .icon { - max-width: 4em; - max-height: 4em; - font-size: 4em; -} -.moodlenet-share-dialog .modal-body .moodlenet-share-modal-content .moodlenet-circle-status { - height: 18rem; - margin: auto; -} -.moodlenet-share-dialog .modal-body .moodlenet-share-modal-content .moodlenet-circle-status.success { - background: radial-gradient(circle, rgba(25, 143, 81, 0.1) 9rem, transparent 9rem); -} -.moodlenet-share-dialog .modal-body .moodlenet-share-modal-content .moodlenet-circle-status.fail { - background: radial-gradient(circle, rgba(202, 49, 32, 0.1) 9rem, transparent 9rem); -} -.moodlenet-share-dialog .modal-body .moodlenet-share-modal-content .moodlenet-circle-status span { - display: block; - margin: auto; -} -.moodlenet-share-dialog .modal-body .moodlenet-share-modal-content .moodlenet-circle-status span.status-icon .icon { - font-size: 8rem; - max-width: initial; - margin: 0; -} -.moodlenet-share-dialog .modal-footer .moodlenet-share-to { - margin-right: auto; -} - /** * Dropdown menu Moodle specific styles. */ diff --git a/public/user/classes/privacy/provider.php b/public/user/classes/privacy/provider.php index 705392115bb..b2a57413695 100644 --- a/public/user/classes/privacy/provider.php +++ b/public/user/classes/privacy/provider.php @@ -100,7 +100,6 @@ class provider implements 'firstnamephonetic' => 'privacy:metadata:firstnamephonetic', 'middlename' => 'privacy:metadata:middlename', 'alternatename' => 'privacy:metadata:alternatename', - 'moodlenetprofile' => 'privacy:metadata:moodlenetprofile' ]; $passwordhistory = [ diff --git a/public/user/editlib.php b/public/user/editlib.php index 2f47e30700a..abcf55ba9a3 100644 --- a/public/user/editlib.php +++ b/public/user/editlib.php @@ -292,12 +292,6 @@ function useredit_shared_definition(&$mform, $editoroptions, $filemanageroptions $mform->setDefault('maildisplay', core_user::get_property_default('maildisplay')); $mform->addHelpButton('maildisplay', 'emaildisplay'); - if (get_config('tool_moodlenet', 'enablemoodlenet')) { - $mform->addElement('text', 'moodlenetprofile', get_string('moodlenetprofile', 'user'), 'maxlength="255" size="30"'); - $mform->setType('moodlenetprofile', PARAM_NOTAGS); - $mform->addHelpButton('moodlenetprofile', 'moodlenetprofile', 'user'); - } - $mform->addElement('text', 'city', get_string('city'), 'maxlength="120" size="21"'); $mform->setType('city', PARAM_TEXT); if (!empty($CFG->defaultcity)) { diff --git a/public/user/tests/reportbuilder/datasource/users_test.php b/public/user/tests/reportbuilder/datasource/users_test.php index 31bf27ab1d4..c01ba036ae4 100644 --- a/public/user/tests/reportbuilder/datasource/users_test.php +++ b/public/user/tests/reportbuilder/datasource/users_test.php @@ -109,7 +109,6 @@ final class users_test extends core_reportbuilder_testcase { $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:suspended']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:confirmed']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:auth']); - $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:moodlenetprofile']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:timecreated']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:timemodified']); $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:lastip']); @@ -171,7 +170,6 @@ final class users_test extends core_reportbuilder_testcase { $suspended, $confirmed, $auth, - $moodlenetprofile, $timecreated, $timemodified, $lastip, @@ -206,7 +204,6 @@ final class users_test extends core_reportbuilder_testcase { $this->assertEquals('No', $suspended); $this->assertEquals('Yes', $confirmed); $this->assertEquals('Manual accounts', $auth); - $this->assertEquals($user->moodlenetprofile, $moodlenetprofile); $this->assertNotEmpty($timecreated); $this->assertNotEmpty($timemodified); $this->assertEquals('0.0.0.0', $lastip); @@ -458,14 +455,6 @@ final class users_test extends core_reportbuilder_testcase { 'user:department_operator' => text::IS_EQUAL_TO, 'user:department_value' => 'Office', ], false], - 'Filter moodlenetprofile' => ['user:moodlenetprofile', [ - 'user:moodlenetprofile_operator' => text::IS_EQUAL_TO, - 'user:moodlenetprofile_value' => '@zoe1@example.com', - ], true], - 'Filter moodlenetprofile (no match)' => ['user:moodlenetprofile', [ - 'user:moodlenetprofile_operator' => text::IS_EQUAL_TO, - 'user:moodlenetprofile_value' => '@alfie1@example.com', - ], false], 'Filter suspended' => ['user:suspended', [ 'user:suspended_operator' => boolean_select::NOT_CHECKED, ], true], @@ -580,7 +569,6 @@ final class users_test extends core_reportbuilder_testcase { 'timezone' => 'Europe/Barcelona', 'theme' => 'boost', 'description' => 'Hello there', - 'moodlenetprofile' => '@zoe1@example.com', 'interests' => ['Horses'], 'lastip' => '0.0.0.0', ]); diff --git a/public/version.php b/public/version.php index 64f8c99444e..d2df3094214 100644 --- a/public/version.php +++ b/public/version.php @@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die(); -$version = 2026030600.01; // YYYYMMDD = weekly release date of this DEV branch. +$version = 2026030600.04; // YYYYMMDD = weekly release date of this DEV branch. // RR = release increments - 00 in DEV branches. // .XX = incremental changes. $release = '5.2dev (Build: 20260306)'; // Human-friendly version name