MDL-78267 core: Partial course sharing for MoodleNet

This commit is contained in:
Huong Nguyen 2023-07-25 17:08:10 +07:00
parent 705a721c90
commit 4ead50e696
No known key found for this signature in database
GPG Key ID: 40D88AB693A3E72A
25 changed files with 414 additions and 77 deletions

View File

@ -16,6 +16,7 @@
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;
@ -131,6 +132,18 @@ class bulkedittools implements named_templatable, renderable {
];
}
$usercanshare = utilities::can_user_share($context, $user->id, 'course');
if ($usercanshare) {
$controls['sharetomoodlenet'] = [
'id' => 'cmShareToMoodleNet',
'icon' => 'i/share',
'action' => 'cmShareToMoodleNet',
'name' => get_string('moodlenet:sharetomoodlenet'),
'title' => get_string('moodlenet:sharetomoodlenet'),
'bulk' => 'cm',
];
}
return $controls;
}

View File

@ -1392,7 +1392,9 @@ $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:sharenotice'] = 'You are sharing this to MoodleNet as a {$a}';
$string['moodlenet:sharenotice'] = 'This {$a->type} is being shared with MoodleNet as a {$a->sharetype}';
$string['moodlenet:sharenoticepartial'] = 'The selected activities are being shared with MoodleNet as a {$a}';
$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.<br>Please try again later.';
$string['moodlenet:sharefailtextwithsitesupport'] = 'There was an error sharing your content to MoodleNet.<br>Please try again later or <a href="{$a}">contact site support</a>.';

View File

@ -0,0 +1,11 @@
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 <huongnv13@gmail.com>
* @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+"<br><br>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

View File

@ -0,0 +1 @@
{"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 <http://www.gnu.org/licenses/>.\n\n/**\n * MoodleNet authorization.\n *\n * @module core/moodlenet/authorize\n * @copyright 2023 Huong Nguyen <huongnv13@gmail.com>\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 + '<br><br>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"}

3
lib/amd/build/moodlenet/events.min.js vendored Normal file
View File

@ -0,0 +1,3 @@
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

View File

@ -0,0 +1 @@
{"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 <http://www.gnu.org/licenses/>.\n\n/**\n * MoodleNet events.\n *\n * @module core/moodlenet/events\n * @copyright 2023 Huong Nguyen <huongnv13@gmail.com>\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"}

View File

@ -0,0 +1,3 @@
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){this.cmLock(stateManager,cmIds,!0),(0,_send_resource.handleModal)("partial","resource",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

View File

@ -0,0 +1 @@
{"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 <http://www.gnu.org/licenses/>.\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 <huongnv13@gmail.com>\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 this.cmLock(stateManager, cmIds, true);\n handleModal('partial', 'resource', 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","cmLock","MoodleNetEvents","MOODLENET_SHARE_STARTED","bulkReset","addMutations","addActions","cmShareToMoodleNet"],"mappings":"ymBAgCMA,2BAA2BC,6EAQVC,eAAeC,aAAcC,YACvCC,OAAOF,aAAcC,OAAO,kCACrB,UAAW,WAAYA,YAC9BC,OAAOF,aAAcC,OAAO,yBACvBE,gBAAgBC,yBAAyB,UAE1CC,UAAUL,4KAQP,MACK,0CACRM,aAAa,IAAIT,qCAEhBU,WAAW,CACrBC,mBAAoB"}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -6,6 +6,6 @@ define("core/moodlenet/service",["exports","core/ajax"],(function(_exports,_ajax
* @copyright 2023 Huong Nguyen <huongnv13@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since 4.2
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_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.authorizationCheck=(issuerId,courseId)=>{const request={methodname:"core_moodlenet_auth_check",args:{issuerid:issuerId,courseid:courseId}};return _ajax.default.call([request])[0]}}));
*/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

View File

@ -1 +1 @@
{"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 <http://www.gnu.org/licenses/>.\n\n/**\n * A javascript module to handle MoodleNet ajax actions.\n *\n * @module core/moodlenet/service\n * @copyright 2023 Huong Nguyen <huongnv13@gmail.com>\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 * 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"],"mappings":";;;;;;;;4RAgCuCA,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,gCAUE,CAACQ,SAAUC,kBACnCT,QAAU,CACZC,WAAY,4BACZC,KAAM,CACFS,SAAUH,SACVD,SAAUE,kBAIXL,cAAKC,KAAK,CAACL,UAAU"}
{"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 <http://www.gnu.org/licenses/>.\n\n/**\n * A javascript module to handle MoodleNet ajax actions.\n *\n * @module core/moodlenet/service\n * @copyright 2023 Huong Nguyen <huongnv13@gmail.com>\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"}

View File

@ -0,0 +1,67 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* MoodleNet authorization.
*
* @module core/moodlenet/authorize
* @copyright 2023 Huong Nguyen <huongnv13@gmail.com>
* @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 + '<br><br>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);
};

View File

@ -0,0 +1,27 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* MoodleNet events.
*
* @module core/moodlenet/events
* @copyright 2023 Huong Nguyen <huongnv13@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @since 4.3
*/
export default {
MOODLENET_SHARE_STARTED: 'moodlenet-share-started',
};

View File

@ -0,0 +1,62 @@
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
* 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 <huongnv13@gmail.com>
* @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) {
this.cmLock(stateManager, cmIds, true);
handleModal('partial', 'resource', 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'
});
};

View File

@ -23,15 +23,19 @@
*/
import Config from 'core/config';
import {alert as displayAlert, addNotification, exception as displayException} from 'core/notification';
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;
@ -41,6 +45,7 @@ let courseId;
let resourceId;
let shareFormat;
let type;
let selectedCmIds;
/**
* Handle send to MoodleNet.
@ -49,7 +54,7 @@ let type;
* @param {int} resourceId The resource ID, it can be a course or an activity.
* @param {int} shareFormat The share format.
*/
const sendToMoodleNet = (issuerId, resourceId, shareFormat) => {
export const sendToMoodleNet = (issuerId, resourceId, shareFormat) => {
const $modal = currentModal.getModal();
const modal = $modal[0];
modal.querySelector('.modal-header').classList.remove('no-border');
@ -63,6 +68,12 @@ const sendToMoodleNet = (issuerId, resourceId, shareFormat) => {
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;
@ -94,61 +105,46 @@ const responseFromMoodleNet = (status, resourceUrl = '') => {
}
};
/**
* Handle authorization with MoodleNet server.
*
* @param {Number} issuerId The OAuth 2 issuer ID.
* @return {promise}
*/
const handleAuthorization = (issuerId) => {
const windowsizewidth = 550;
const windowsizeheight = 550;
// Check if the user is authorized with MoodleNet or not.
return MoodleNetService.authorizationCheck(issuerId, courseId).then((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);
} else if (error !== 'access_denied') {
displayAlert(
'Authorization error',
'Error: ' + error + '<br><br>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);
};
/**
* Render the modal to send resource to MoodleNet.
*
* @param {object} data The data of the resource to be shared.
* @param {string} shareType The type of the resource to be shared.
* @param {array} selectedActivities Selected activities.
*/
const renderModal = async(data, shareType) => {
const renderModal = async(data, shareType, selectedActivities) => {
if (data.status) {
siteSupportUrl = data.supportpageurl;
issuerId = data.issuerid;
return SendActivityModal.create({
let modalConfig = {
templateContext: {
activitytype: data.type,
activityname: data.name,
sharetype: await getString(`moodlenet:sharetype${shareType}`, 'moodle'),
server: data.server,
'activitytype': data.type,
'activityname': data.name,
'server': data.server,
}
});
};
const sharetype = await getString('moodlenet:sharetype' + shareType, 'moodle');
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', sharetype);
} else {
modalConfig.templateContext.fullsharing = true;
if (type === TYPE_PARTIAL_COURSE && selectedActivities.length == 1) {
modalConfig.templateContext.sharenotice = await getString('moodlenet:sharenotice',
'moodle', {'type': TYPE_ACTIVITY, 'sharetype': sharetype});
} else {
modalConfig.templateContext.sharenotice = await getString('moodlenet:sharenotice',
'moodle', {'type': type, 'sharetype': sharetype});
}
}
return SendActivityModal.create(modalConfig);
} else {
return addNotification({
message: data.warnings[0].message,
@ -157,6 +153,43 @@ const renderModal = async(data, shareType) => {
}
};
/**
* Handle modal.
* @param {string} shareActionType Share action type.
* @param {string} shareType Share type.
* @param {array} selectedActivities Selected activities.
*/
export const handleModal = (shareActionType, shareType, 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, shareType, selectedActivities);
})
.then((modal) => {
currentModal = modal;
return currentModal;
})
.catch(displayException);
};
/**
* Register events.
*/
@ -168,31 +201,16 @@ const registerEventListeners = () => {
e.preventDefault();
type = shareAction.getAttribute('data-type');
const shareType = shareAction.getAttribute('data-sharetype');
Promise.resolve(type)
.then((type) => {
if (type === TYPE_ACTIVITY) {
return MoodleNetService.getActivityInformation(Config.contextInstanceId);
} else if (type === TYPE_COURSE) {
return MoodleNetService.getCourseInformation(Config.contextInstanceId);
}
throw new Error(`Unknown type ${type}`);
})
.then((data) => {
return renderModal(data, shareType);
})
.then((modal) => {
currentModal = modal;
return currentModal;
})
.catch(displayException);
handleModal(shareAction.getAttribute('data-type'), shareType);
}
if (sendAction) {
e.preventDefault();
publish(MoodleNetEvents.MOODLENET_SHARE_STARTED, {});
courseId = Config.courseId;
resourceId = Config.contextInstanceId;
shareFormat = 0;
handleAuthorization(issuerId);
MoodleNetAuthorize.handleAuthorization(issuerId, courseId, resourceId, shareFormat);
}
});
};
@ -208,6 +226,8 @@ export const init = () => {
'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',
'core/moodlenet/send_course_modal_base',
]);
registerEventListeners();
listenersRegistered = true;

View File

@ -101,6 +101,29 @@ export const sendActivity = (issuerId, cmId, 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.
*

View File

@ -53,7 +53,7 @@ class moodlenet_get_shared_course_info extends external_api {
* @return array
*/
public static function execute(int $courseid): array {
global $CFG, $USER;
global $USER;
[
'courseid' => $courseid

View File

@ -324,6 +324,7 @@ class icon_system_fontawesome extends icon_system_font {
'core:i/section' => 'fa-folder-o',
'core:i/sendmessage' => 'fa-paper-plane',
'core:i/settings' => 'fa-cog',
'core:i/share' => 'fa-share-square-o',
'core:i/show' => 'fa-eye-slash',
'core:i/siteevent' => 'fa-globe',
'core:i/star' => 'fa-star',

View File

@ -4638,6 +4638,9 @@ class settings_navigation extends navigation_node {
}
// 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 {

View File

@ -45,8 +45,13 @@
</div>
<hr class="moodlenet-share-activity-info-hr">
<div class="moodlenet-share-notice">
{{#pix}} e/help, core, {{#str}} moodlenet:sharenotice, moodle, {{sharetype}} {{/str}}{{/pix}} {{#str}} moodlenet:sharenotice, moodle, {{sharetype}} {{/str}}
{{sharenotice}}
</div>
{{^fullsharing}}
<div class="moodlenet-share-total-activities font-weight-bold pl-2 ml-3">
{{selectedactivitiesnotice}}
</div>
{{/fullsharing}}
</div>
</div>
<div class="modal-footer" data-region="footer">

View File

@ -62,7 +62,7 @@ Feature: MoodleNet outbound send activity
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 "You are sharing this to MoodleNet as a resource" 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

View File

@ -57,9 +57,9 @@ Feature: MoodleNet outbound share course
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 "C1" in the "Share to MoodleNet" "dialogue"
And I should see "You are sharing this to MoodleNet as a resource" in the "Share to MoodleNet" "dialogue"
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

View File

@ -0,0 +1,94 @@
@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"
And I click on "Select activity Test Assignment 1" "checkbox"
And I click on "Select activity Test Assignment 2" "checkbox"
When I click on "Share to MoodleNet" "button" in the "sticky-footer" "region"
Then 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"

View File

@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die();
$version = 2023091300.01; // YYYYMMDD = weekly release date of this DEV branch.
$version = 2023091300.02; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.
$release = '4.3dev+ (Build: 20230913)'; // Human-friendly version name