MDL-87708 core: Remove MoodleNet outbound sharing
Part of MDL-87350
This commit is contained in:
committed by
Huong Nguyen
parent
146fda5681
commit
f9979de2a9
@@ -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
|
||||
@@ -622,8 +622,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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -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.';
|
||||
|
||||
@@ -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 <a href="{$a}">create</a> 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.<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>.';
|
||||
$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.<br>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';
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -184,11 +184,6 @@
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"moodlenet": {
|
||||
"component": "core",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"navigation": {
|
||||
"component": "core",
|
||||
"allowedlevel2": true,
|
||||
|
||||
@@ -1,78 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core\event;
|
||||
|
||||
/**
|
||||
* MoodleNet send attempt event.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2023 Michael Hawkins <[email protected]>
|
||||
* @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']);
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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 <[email protected]>
|
||||
* @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,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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 <[email protected]>
|
||||
* @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
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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 <[email protected]>
|
||||
* @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
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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 <[email protected]>
|
||||
* @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,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,244 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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 <[email protected]>
|
||||
* @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,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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 <[email protected]>
|
||||
* @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
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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 <[email protected]>
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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 <[email protected]>
|
||||
* @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,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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 <[email protected]>
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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 <[email protected]>
|
||||
* @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');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,180 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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 <[email protected]>
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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 <[email protected]>
|
||||
* @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',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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 <[email protected]>
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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 <[email protected]>
|
||||
* @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}'"),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,252 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* MoodleNet share progress table.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2023 David Woloszyn <[email protected]>
|
||||
* @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 <[email protected]>
|
||||
* @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');
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core\moodlenet;
|
||||
|
||||
use moodle_exception;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Record the sharing of content to MoodleNet.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2023 David Woloszyn <[email protected]>
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
@@ -1,123 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
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 <[email protected]>
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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' => [
|
||||
|
||||
@@ -4884,21 +4884,6 @@
|
||||
<INDEX NAME="timemodified" UNIQUE="false" FIELDS="timemodified"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="moodlenet_share_progress" COMMENT="Records MoodleNet share progress">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="type" TYPE="int" LENGTH="2" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="cmid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
|
||||
<FIELD NAME="resourceurl" TYPE="char" LENGTH="255" NOTNULL="false" SEQUENCE="false"/>
|
||||
<FIELD NAME="status" TYPE="int" LENGTH="2" NOTNULL="false" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="stored_progress" COMMENT="Records for any long running tasks we want to poll for progress">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -1760,5 +1760,33 @@ function xmldb_main_upgrade($oldversion) {
|
||||
upgrade_main_savepoint(true, 2026022700.02);
|
||||
}
|
||||
|
||||
if ($oldversion < 2026030600.01) {
|
||||
// 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.01);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@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"
|
||||
}
|
||||
}}
|
||||
<div class="modal moodle-has-zindex" data-region="modal-container" aria-hidden="true" role="dialog">
|
||||
<div class="modal-dialog moodlenet-share-dialog" role="document" data-region="modal" aria-labelledby="{{uniqid}}-moodlenet-modal-title" tabindex="0">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header no-border" data-region="header">
|
||||
<div id="{{uniqid}}-moodlenet-modal-title" class="modal-title" data-region="title">
|
||||
<h5 class="visually-hidden modal-title">{{#str}} moodlenet:sharetomoodlenet, moodle {{/str}}</h5>
|
||||
<div class="d-flex moodlenet-share-moodlenetinfo">
|
||||
<span class="moodlenet-logo">{{#pix}} moodlenet, moodle, {{#str}} moodlenet:sharetomoodlenet, moodle {{/str}} {{/pix}}</span>
|
||||
<span class="moodlenet-title">{{#str}} moodlenet:sharetomoodlenet, moodle {{/str}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn-close" data-action="hide" aria-label="{{#cleanstr}}closebuttontitle{{/cleanstr}}"></button>
|
||||
</div>
|
||||
<div class="modal-body" data-region="body">
|
||||
<div class="moodlenet-share-modal-content">
|
||||
<div class="moodlenet-share-activity-info">
|
||||
<span class="moodlenet-activity-type text-uppercase">{{activitytype}}</span>
|
||||
<span class="moodlenet-activity-name">{{activityname}}</span>
|
||||
</div>
|
||||
<hr class="moodlenet-share-activity-info-hr">
|
||||
<div class="moodlenet-share-notice">
|
||||
{{sharenotice}}
|
||||
</div>
|
||||
{{^fullsharing}}
|
||||
<div class="moodlenet-share-total-activities fw-bold ps-2 ms-3">
|
||||
{{selectedactivitiesnotice}}
|
||||
</div>
|
||||
{{/fullsharing}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer" data-region="footer">
|
||||
{{> core/moodlenet/send_activity_modal_footer_share }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@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"
|
||||
}
|
||||
}}
|
||||
<div class="moodlenet-share-modal-content text-center">
|
||||
<div class="moodlenet-circle-status{{#success}} success{{/success}}{{^success}} fail{{/success}}">
|
||||
<span class="status-icon pt-5{{#success}} text-success{{/success}}{{^success}} text-danger{{/success}}">
|
||||
{{#success}}
|
||||
{{#pix}} t/check, core {{/pix}}
|
||||
{{/success}}
|
||||
{{^success}}
|
||||
{{#pix}} fp/cross, theme {{/pix}}
|
||||
{{/success}}
|
||||
</span>
|
||||
<span class="status-text fw-bold h5 pt-5">
|
||||
{{#success}}
|
||||
{{#str}} moodlenet:sharesuccesstitle, moodle {{/str}}
|
||||
{{/success}}
|
||||
{{^success}}
|
||||
{{#str}} moodlenet:sharefailtitle, moodle {{/str}}
|
||||
{{/success}}
|
||||
</span>
|
||||
</div>
|
||||
<div class="result pt-2">
|
||||
<span class="d-block h6 fw-normal pt-1 result-text">
|
||||
{{#success}}
|
||||
{{#str}} moodlenet:sharesuccesstext, moodle {{/str}}
|
||||
{{/success}}
|
||||
{{^success}}
|
||||
{{#sitesupporturl}}
|
||||
{{#str}} moodlenet:sharefailtextwithsitesupport, moodle, {{sitesupporturl}} {{/str}}
|
||||
{{/sitesupporturl}}
|
||||
{{^sitesupporturl}}
|
||||
{{#str}} moodlenet:sharefailtext, moodle {{/str}}
|
||||
{{/sitesupporturl}}
|
||||
{{/success}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template core/moodlenet/send_activity_modal_footer_share
|
||||
Render the footer for sharing activity
|
||||
Example context (json):
|
||||
{
|
||||
"server": "MoodleNet Local"
|
||||
}
|
||||
}}
|
||||
<div class="moodlenet-share-to">
|
||||
{{#str}} moodlenet:sharingto, moodle {{/str}}<span class="fw-bold">{{server}}</span>
|
||||
</div>
|
||||
<div class="moodlenet-action-buttons">
|
||||
<button type="button" class="btn btn-secondary" data-action="cancel">{{#str}} cancel, moodle {{/str}}</button>
|
||||
<button type="button" class="btn btn-primary" data-action="share">{{#str}} share, moodle {{/str}}</button>
|
||||
</div>
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template core/moodlenet/send_activity_modal_footer_view
|
||||
Render the footer for sharing activity
|
||||
Example context (json):
|
||||
{
|
||||
"resourceurl": "https://moodlenet.test/draft/activity.mbz"
|
||||
}
|
||||
}}
|
||||
<div class="moodlenet-action-buttons">
|
||||
<a class="btn btn-primary" href="{{resourceurl}}" target="_blank" rel="noopener noreferrer">
|
||||
{{#str}} moodlenet:gotomoodlenet, moodle {{/str}}
|
||||
</a>
|
||||
</div>
|
||||
@@ -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 <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template core/moodlenet/send_activity_modal_packaging
|
||||
This template renders the packaging stage for MoodleNet.
|
||||
Example context (json):
|
||||
{
|
||||
}
|
||||
}}
|
||||
<div class="moodlenet-share-modal-content text-center p-5">
|
||||
<div class="fw-bold h3 p-2">{{#str}} moodlenet:sharingstatus, moodle {{/str}}</div>
|
||||
<div class="h5 fw-normal p-2 test-share-large">{{#str}} moodlenet:sharinglargefile, moodle {{/str}}</div>
|
||||
<div class="p-5">
|
||||
{{> core/loading }}
|
||||
</div>
|
||||
<div class="h5 fw-normal p-2">{{#str}} moodlenet:packagingandsending, moodle {{/str}}</div>
|
||||
</div>
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* View the progress of MoodleNet shares.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2023 David Woloszyn <[email protected]>
|
||||
* @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();
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2026030600.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2026030600.01; // 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
|
||||
|
||||
Reference in New Issue
Block a user