first commit

This commit is contained in:
CHIEFSOFT\ameye
2024-09-30 18:11:26 -04:00
commit e592ca6823
27270 changed files with 5002257 additions and 0 deletions
+133
View File
@@ -0,0 +1,133 @@
<?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/>.
/**
* Class for exporting summary information for a course category.
*
* @package core
* @copyright 2017 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core\external;
defined('MOODLE_INTERNAL') || die();
use renderer_base;
use moodle_url;
/**
* Class for exporting a course summary from an stdClass.
*
* @copyright 2017 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class coursecat_summary_exporter extends \core\external\exporter {
/**
* @var \core_course_category $category
*/
protected $category;
public function __construct(\core_course_category $category, $related) {
$this->category = $category;
$data = [];
// Specify some defaults.
foreach ($category as $key => $value) {
$data[$key] = $value;
}
return parent::__construct($data, $related);
}
protected static function define_related() {
return [
'context' => 'context',
];
}
public static function define_other_properties() {
return [
'nestedname' => [
'type' => PARAM_RAW,
],
'url' => [
'type' => PARAM_URL,
],
];
}
protected function get_other_values(renderer_base $output) {
$return = [
'nestedname' => $this->category->get_nested_name(),
'url' => (new moodle_url('/course/index.php', [
'categoryid' => $this->category->id,
]))->out(false),
];
return $return;
}
public static function define_properties() {
return [
'id' => [
'type' => PARAM_INT,
],
'name' => [
'type' => PARAM_TEXT,
'default' => '',
],
'idnumber' => [
'type' => PARAM_RAW,
'null' => NULL_ALLOWED,
],
'description' => [
'type' => PARAM_RAW,
'optional' => true,
],
'parent' => [
'type' => PARAM_INT,
],
'coursecount' => [
'type' => PARAM_INT,
'default' => 0,
],
'visible' => [
'type' => PARAM_INT,
'default' => 1,
],
'timemodified' => [
'type' => PARAM_INT,
'default' => 0,
],
'depth' => [
'type' => PARAM_INT,
'default' => 0,
],
];
}
/**
* Get the formatting parameters for the summary.
*
* @return array
*/
protected function get_format_parameters_for_description() {
return [
'component' => 'coursecat',
'filearea' => 'description',
];
}
}
+108
View File
@@ -0,0 +1,108 @@
<?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/>.
declare(strict_types=1);
namespace core\external;
use coding_exception;
use context_system;
use core\output\dynamic_tabs\base;
use core_external\external_api;
use core_external\external_function_parameters;
use core_external\external_single_structure;
use core_external\external_value;
/**
* External method for getting tab contents
*
* @package core
* @copyright 2021 David Matamoros <davidmc@moodle.com> based on code from Marina Glancy
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class dynamic_tabs_get_content extends external_api {
/**
* External method parameters
*
* @return external_function_parameters
*/
public static function execute_parameters(): external_function_parameters {
return new external_function_parameters([
'tab' => new external_value(PARAM_RAW_TRIMMED, 'Tab class', VALUE_REQUIRED),
'jsondata' => new external_value(PARAM_RAW, 'Json-encoded data', VALUE_REQUIRED),
]);
}
/**
* Tab content
*
* @param string $tabclass class of the tab
* @param string $jsondata
* @return array
*/
public static function execute(string $tabclass, string $jsondata): array {
global $PAGE, $OUTPUT;
[
'tab' => $tabclass,
'jsondata' => $jsondata,
] = self::validate_parameters(self::execute_parameters(), [
'tab' => $tabclass,
'jsondata' => $jsondata,
]);
$data = @json_decode($jsondata, true);
$context = context_system::instance();
self::validate_context($context);
// This call is needed to avoid debug messages on webserver log.
$PAGE->set_url('/');
// This call is needed to initiate moodle page.
$OUTPUT->header();
if (!class_exists($tabclass) || !is_subclass_of($tabclass, base::class)) {
throw new coding_exception('unknown dynamic tab class', $tabclass);
}
/** @var base $tab */
$tab = new $tabclass($data);
$tab->require_access();
$PAGE->start_collecting_javascript_requirements();
$content = $tab->export_for_template($PAGE->get_renderer('core'));
$jsfooter = $PAGE->requires->get_end_code();
return [
'template' => $tab->get_template(),
'content' => json_encode($content),
'javascript' => $jsfooter,
];
}
/**
* External method return value
*
* @return external_single_structure
*/
public static function execute_returns(): external_single_structure {
return new external_single_structure([
'template' => new external_value(PARAM_PATH, 'Template name'),
'content' => new external_value(PARAM_RAW, 'JSON-encoded data for template'),
'javascript' => new external_value(PARAM_RAW, 'JavaScript fragment'),
]);
}
}
+85
View File
@@ -0,0 +1,85 @@
<?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 core_external\external_api;
use core_external\external_function_parameters;
use core_external\external_single_structure;
use core_external\external_value;
/**
* Web service to change the edit mode.
*
* @package core
* @copyright 2021 Bas Brands <bas@sonsbeekmedia.nl>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class editmode extends external_api {
/**
* Description of the parameters suitable for the `change_editmode` function.
*
* @return external_function_parameters
*/
public static function change_editmode_parameters(): external_function_parameters {
return new external_function_parameters(
[
'setmode' => new external_value(PARAM_BOOL, 'Set edit mode to'),
'context' => new external_value(PARAM_INT, 'Page context id')
]
);
}
/**
* Set the given edit mode
*
* @param bool $setmode the new edit mode
* @param int $contextid the current page context id
* @return array
*/
public static function change_editmode(bool $setmode, int $contextid): array {
global $USER;
$params = self::validate_parameters(
self::change_editmode_parameters(),
[
'setmode' => $setmode,
'context' => $contextid
]
);
$context = \context_helper::instance_by_id($params['context']);
self::validate_context($context);
$USER->editing = $params['setmode'];
return ['success' => true];
}
/**
* Description of the return value for the `change_editmode` function.
*
* @return external_single_structure
*/
public static function change_editmode_returns(): external_single_structure {
$keys = [
'success' => new external_value(PARAM_BOOL, 'The edit mode was changed', VALUE_REQUIRED),
];
return new external_single_structure($keys, 'editmode');
}
}
+615
View File
@@ -0,0 +1,615 @@
<?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/>.
/**
* Generic exporter to take a stdClass and prepare it for return by webservice.
*
* @package core
* @copyright 2015 Damyon Wiese
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core\external;
use stdClass;
use renderer_base;
use context;
use coding_exception;
use core_external\external_format_value;
use core_external\external_multiple_structure;
use core_external\external_single_structure;
use core_external\external_value;
/**
* Generic exporter to take a stdClass and prepare it for return by webservice, or as the context for a template.
*
* templatable classes implementing export_for_template, should always use a standard exporter if it exists.
* External functions should always use a standard exporter if it exists.
*
* @copyright 2015 Damyon Wiese
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class exporter {
/** @var array $related List of related objects used to avoid DB queries. */
protected $related = array();
/** @var stdClass|array The data of this exporter. */
protected $data = null;
/**
* Constructor - saves the persistent object, and the related objects.
*
* @param mixed $data - Either an stdClass or an array of values.
* @param array $related - An optional list of pre-loaded objects related to this object.
*/
public function __construct($data, $related = array()) {
$this->data = $data;
// Cache the valid related objects.
foreach (static::define_related() as $key => $classname) {
$isarray = false;
$nullallowed = false;
// Allow ? to mean null is allowed.
if (substr($classname, -1) === '?') {
$classname = substr($classname, 0, -1);
$nullallowed = true;
}
// Allow [] to mean an array of values.
if (substr($classname, -2) === '[]') {
$classname = substr($classname, 0, -2);
$isarray = true;
}
$missingdataerr = 'Exporter class is missing required related data: (' . get_called_class() . ') ';
$scalartypes = ['string', 'int', 'bool', 'float'];
$scalarcheck = 'is_' . $classname;
if ($nullallowed && (!array_key_exists($key, $related) || $related[$key] === null)) {
$this->related[$key] = null;
} else if ($isarray) {
if (array_key_exists($key, $related) && is_array($related[$key])) {
foreach ($related[$key] as $index => $value) {
if (!$value instanceof $classname && !$scalarcheck($value)) {
throw new coding_exception($missingdataerr . $key . ' => ' . $classname . '[]');
}
}
$this->related[$key] = $related[$key];
} else {
throw new coding_exception($missingdataerr . $key . ' => ' . $classname . '[]');
}
} else {
if (array_key_exists($key, $related) &&
((in_array($classname, $scalartypes) && $scalarcheck($related[$key])) ||
($related[$key] instanceof $classname))) {
$this->related[$key] = $related[$key];
} else {
throw new coding_exception($missingdataerr . $key . ' => ' . $classname);
}
}
}
}
/**
* Function to export the renderer data in a format that is suitable for a
* mustache template. This means raw records are generated as in to_record,
* but all strings are correctly passed through \core_external\util::format_text (or \core_external\util::format_string).
*
* @param renderer_base $output Used to do a final render of any components that need to be rendered for export.
* @return stdClass
*/
final public function export(renderer_base $output) {
$data = new stdClass();
$properties = self::read_properties_definition();
$values = (array) $this->data;
$othervalues = $this->get_other_values($output);
if (array_intersect_key($values, $othervalues)) {
// Attempt to replace a standard property.
throw new coding_exception('Cannot override a standard property value.');
}
$values += $othervalues;
$record = (object) $values;
foreach ($properties as $property => $definition) {
if (isset($data->$property)) {
// This happens when we have already defined the format properties.
continue;
} else if (!property_exists($record, $property) && array_key_exists('default', $definition)) {
// We have a default value for this property.
$record->$property = $definition['default'];
} else if (!property_exists($record, $property) && !empty($definition['optional'])) {
// Fine, this property can be omitted.
continue;
} else if (!property_exists($record, $property)) {
// Whoops, we got something that wasn't defined.
throw new coding_exception('Unexpected property ' . $property);
}
$data->$property = $record->$property;
// If the field is PARAM_RAW and has a format field.
if ($propertyformat = self::get_format_field($properties, $property)) {
$formatdefinition = $properties[$propertyformat];
if (!property_exists($record, $propertyformat) && !array_key_exists('default', $formatdefinition)) {
// Whoops, we got something that wasn't defined.
throw new coding_exception('Unexpected property ' . $propertyformat);
}
$formatparams = $this->get_format_parameters($property);
$format = $record->$propertyformat ?? $formatdefinition['default'];
list($text, $format) = \core_external\util::format_text($data->$property, $format, $formatparams['context'],
$formatparams['component'], $formatparams['filearea'], $formatparams['itemid'], $formatparams['options']);
$data->$property = $text;
$data->$propertyformat = $format;
} else if ($definition['type'] === PARAM_TEXT) {
$formatparams = $this->get_format_parameters($property);
if (!empty($definition['multiple'])) {
foreach ($data->$property as $key => $value) {
$data->{$property}[$key] = \core_external\util::format_string($value, $formatparams['context'],
$formatparams['striplinks'], $formatparams['options']);
}
} else {
$data->$property = \core_external\util::format_string($data->$property, $formatparams['context'],
$formatparams['striplinks'], $formatparams['options']);
}
}
}
return $data;
}
/**
* Get the format parameters.
*
* This method returns the parameters to use with the functions \core_external\util::format_text(), and
* \core_external\util::format_string(). To override the default parameters, you can define a protected method
* called 'get_format_parameters_for_<propertyName>'. For example, 'get_format_parameters_for_description',
* if your property is 'description'.
*
* Your method must return an array containing any of the following keys:
* - context: The context to use. Defaults to $this->related['context'] if defined, else throws an exception.
* - component: The component to use with \core_external\util::format_text(). Defaults to null.
* - filearea: The filearea to use with \core_external\util::format_text(). Defaults to null.
* - itemid: The itemid to use with \core_external\util::format_text(). Defaults to null.
* - options: An array of options accepted by \core_external\util::format_text()
* or \core_external\util::format_string().
* Defaults to [].
* - striplinks: Whether to strip the links with \core_external\util::format_string(). Defaults to true.
*
* @param string $property The property to get the parameters for.
* @return array
*/
final protected function get_format_parameters($property) {
$parameters = [
'component' => null,
'filearea' => null,
'itemid' => null,
'options' => [],
'striplinks' => true,
];
$candidate = 'get_format_parameters_for_' . $property;
if (method_exists($this, $candidate)) {
$parameters = array_merge($parameters, $this->{$candidate}());
}
if (!isset($parameters['context'])) {
if (!isset($this->related['context']) || !($this->related['context'] instanceof context)) {
throw new coding_exception("Unknown context to use for formatting the property '$property' in the " .
"exporter '" . get_class($this) . "'. You either need to add 'context' to your related objects, " .
"or create the method '$candidate' and return the context from there.");
}
$parameters['context'] = $this->related['context'];
} else if (!($parameters['context'] instanceof context)) {
throw new coding_exception("The context given to format the property '$property' in the exporter '" .
get_class($this) . "' is invalid.");
}
return $parameters;
}
/**
* Get the additional values to inject while exporting.
*
* These are additional generated values that are not passed in through $data
* to the exporter. For a persistent exporter - these are generated values that
* do not exist in the persistent class. For your convenience the format_text or
* format_string functions do not need to be applied to PARAM_TEXT fields,
* it will be done automatically during export.
*
* These values are only used when returning data via {@link self::export()},
* they are not used when generating any of the different external structures.
*
* Note: These must be defined in {@link self::define_other_properties()}.
*
* @param renderer_base $output The renderer.
* @return array Keys are the property names, values are their values.
*/
protected function get_other_values(renderer_base $output) {
return array();
}
/**
* Get the read properties definition of this exporter. Read properties combines the
* default properties from the model (persistent or stdClass) with the properties defined
* by {@link self::define_other_properties()}.
*
* @return array Keys are the property names, and value their definition.
*/
final public static function read_properties_definition() {
$properties = static::properties_definition();
$customprops = static::define_other_properties();
$customprops = static::format_properties($customprops);
$properties += $customprops;
return $properties;
}
/**
* Recursively formats a given property definition with the default fields required.
*
* @param array $properties List of properties to format
* @return array Formatted array
*/
final public static function format_properties($properties) {
foreach ($properties as $property => $definition) {
// Ensures that null is set to its default.
if (!isset($definition['null'])) {
$properties[$property]['null'] = NULL_NOT_ALLOWED;
}
if (!isset($definition['description'])) {
$properties[$property]['description'] = $property;
}
// If an array is provided, it may be a nested array that is unformatted so rinse and repeat.
if (is_array($definition['type'])) {
$properties[$property]['type'] = static::format_properties($definition['type']);
}
}
return $properties;
}
/**
* Get the properties definition of this exporter used for create, and update structures.
* The read structures are returned by: {@link self::read_properties_definition()}.
*
* @return array Keys are the property names, and value their definition.
*/
final public static function properties_definition() {
$properties = static::define_properties();
foreach ($properties as $property => $definition) {
// Ensures that null is set to its default.
if (!isset($definition['null'])) {
$properties[$property]['null'] = NULL_NOT_ALLOWED;
}
if (!isset($definition['description'])) {
$properties[$property]['description'] = $property;
}
}
return $properties;
}
/**
* Return the list of additional properties used only for display.
*
* Additional properties are only ever used for the read structure, and during
* export of the persistent data.
*
* The format of the array returned by this method has to match the structure
* defined in {@link \core\persistent::define_properties()}. The display properties
* can however do some more fancy things. They can define 'multiple' => true to wrap
* values in an external_multiple_structure automatically - or they can define the
* type as a nested array of more properties in order to generate a nested
* external_single_structure.
*
* You can specify an array of values by including a 'multiple' => true array value. This
* will result in a nested external_multiple_structure.
* E.g.
*
* 'arrayofbools' => array(
* 'type' => PARAM_BOOL,
* 'multiple' => true
* ),
*
* You can return a nested array in the type field, which will result in a nested external_single_structure.
* E.g.
* 'competency' => array(
* 'type' => competency_exporter::read_properties_definition()
* ),
*
* Other properties can be specifically marked as optional, in which case they do not need
* to be included in the export in {@link self::get_other_values()}. This is useful when exporting
* a substructure which cannot be set as null due to webservices protocol constraints.
* E.g.
* 'competency' => array(
* 'type' => competency_exporter::read_properties_definition(),
* 'optional' => true
* ),
*
* @return array
*/
protected static function define_other_properties() {
return array();
}
/**
* Return the list of properties.
*
* The format of the array returned by this method has to match the structure
* defined in {@link \core\persistent::define_properties()}. Howewer you can
* add a new attribute "description" to describe the parameter for documenting the API.
*
* Note that the type PARAM_TEXT should ONLY be used for strings which need to
* go through filters (multilang, etc...) and do not have a FORMAT_* associated
* to them. Typically strings passed through to format_string().
*
* Other filtered strings which use a FORMAT_* constant (hear used with format_text)
* must be defined as PARAM_RAW.
*
* @return array
*/
protected static function define_properties() {
return array();
}
/**
* Returns a list of objects that are related to this persistent.
*
* Only objects listed here can be cached in this object.
*
* The class name can be suffixed:
* - with [] to indicate an array of values.
* - with ? to indicate that 'null' is allowed.
*
* @return array of 'propertyname' => array('type' => classname, 'required' => true)
*/
protected static function define_related() {
return array();
}
/**
* Get the context structure.
*
* @return array
*/
final protected static function get_context_structure() {
return array(
'contextid' => new external_value(PARAM_INT, 'The context id', VALUE_OPTIONAL),
'contextlevel' => new external_value(PARAM_ALPHA, 'The context level', VALUE_OPTIONAL),
'instanceid' => new external_value(PARAM_INT, 'The Instance id', VALUE_OPTIONAL),
);
}
/**
* Get the format field name.
*
* @param array $definitions List of properties definitions.
* @param string $property The name of the property that may have a format field.
* @return bool|string False, or the name of the format property.
*/
final protected static function get_format_field($definitions, $property) {
$formatproperty = $property . 'format';
if (($definitions[$property]['type'] == PARAM_RAW || $definitions[$property]['type'] == PARAM_CLEANHTML)
&& isset($definitions[$formatproperty])
&& $definitions[$formatproperty]['type'] == PARAM_INT) {
return $formatproperty;
}
return false;
}
/**
* Get the format structure.
*
* @param string $property The name of the property on which the format applies.
* @param array $definition The definition of the format property.
* @param int $required Constant VALUE_*.
* @return external_format_value
*/
final protected static function get_format_structure($property, $definition, $required = VALUE_REQUIRED) {
$default = null;
if (array_key_exists('default', $definition)) {
$required = VALUE_DEFAULT;
$default = $definition['default'];
}
return new external_format_value($property, $required, $default);
}
/**
* Returns the create structure.
*
* @return external_single_structure
*/
final public static function get_create_structure() {
$properties = self::properties_definition();
$returns = array();
foreach ($properties as $property => $definition) {
if ($property == 'id') {
// The can not be set on create.
continue;
} else if (isset($returns[$property]) && substr($property, -6) === 'format') {
// We've already treated the format.
continue;
}
$required = VALUE_REQUIRED;
$default = null;
// We cannot use isset here because we want to detect nulls.
if (array_key_exists('default', $definition)) {
$required = VALUE_DEFAULT;
$default = $definition['default'];
}
// Magically treat the contextid fields.
if ($property == 'contextid') {
if (isset($properties['context'])) {
throw new coding_exception('There cannot be a context and a contextid column');
}
$returns += self::get_context_structure();
} else {
$returns[$property] = new external_value($definition['type'], $definition['description'], $required, $default,
$definition['null']);
// Magically treat the format properties.
if ($formatproperty = self::get_format_field($properties, $property)) {
if (isset($returns[$formatproperty])) {
throw new coding_exception('The format for \'' . $property . '\' is already defined.');
}
$returns[$formatproperty] = self::get_format_structure($property,
$properties[$formatproperty], VALUE_REQUIRED);
}
}
}
return new external_single_structure($returns);
}
/**
* Returns the read structure.
*
* @param int $required Whether is required.
* @param mixed $default The default value.
*
* @return external_single_structure
*/
final public static function get_read_structure($required = VALUE_REQUIRED, $default = null) {
$properties = self::read_properties_definition();
return self::get_read_structure_from_properties($properties, $required, $default);
}
/**
* Returns the read structure from a set of properties (recursive).
*
* @param array $properties The properties.
* @param int $required Whether is required.
* @param mixed $default The default value.
* @return external_single_structure
*/
final protected static function get_read_structure_from_properties($properties, $required = VALUE_REQUIRED, $default = null) {
$returns = array();
foreach ($properties as $property => $definition) {
if (isset($returns[$property]) && substr($property, -6) === 'format') {
// We've already treated the format.
continue;
}
$thisvalue = null;
$type = $definition['type'];
$proprequired = VALUE_REQUIRED;
$propdefault = null;
if (array_key_exists('default', $definition)) {
$propdefault = $definition['default'];
}
if (array_key_exists('optional', $definition)) {
// Mark as optional. Note that this should only apply to "reading" "other" properties.
$proprequired = VALUE_OPTIONAL;
}
if (is_array($type)) {
// This is a nested array of more properties.
$thisvalue = self::get_read_structure_from_properties($type, $proprequired, $propdefault);
} else {
if ($definition['type'] == PARAM_TEXT || $definition['type'] == PARAM_CLEANHTML) {
// PARAM_TEXT always becomes PARAM_RAW because filters may be applied.
$type = PARAM_RAW;
}
$thisvalue = new external_value($type, $definition['description'], $proprequired, $propdefault, $definition['null']);
}
if (!empty($definition['multiple'])) {
$returns[$property] = new external_multiple_structure($thisvalue, $definition['description'], $proprequired,
$propdefault);
} else {
$returns[$property] = $thisvalue;
// Magically treat the format properties (not possible for arrays).
if ($formatproperty = self::get_format_field($properties, $property)) {
if (isset($returns[$formatproperty])) {
throw new coding_exception('The format for \'' . $property . '\' is already defined.');
}
$formatpropertydef = $properties[$formatproperty];
$formatpropertyrequired = VALUE_REQUIRED;
if (!empty($formatpropertydef['optional'])) {
$formatpropertyrequired = VALUE_OPTIONAL;
}
$returns[$formatproperty] = self::get_format_structure($property, $formatpropertydef, $formatpropertyrequired);
}
}
}
return new external_single_structure($returns, '', $required, $default);
}
/**
* Returns the update structure.
*
* This structure can never be included at the top level for an external function signature
* because it contains optional parameters.
*
* @return external_single_structure
*/
final public static function get_update_structure() {
$properties = self::properties_definition();
$returns = array();
foreach ($properties as $property => $definition) {
if (isset($returns[$property]) && substr($property, -6) === 'format') {
// We've already treated the format.
continue;
}
$default = null;
$required = VALUE_OPTIONAL;
if ($property == 'id') {
$required = VALUE_REQUIRED;
}
// Magically treat the contextid fields.
if ($property == 'contextid') {
if (isset($properties['context'])) {
throw new coding_exception('There cannot be a context and a contextid column');
}
$returns += self::get_context_structure();
} else {
$returns[$property] = new external_value($definition['type'], $definition['description'], $required, $default,
$definition['null']);
// Magically treat the format properties.
if ($formatproperty = self::get_format_field($properties, $property)) {
if (isset($returns[$formatproperty])) {
throw new coding_exception('The format for \'' . $property . '\' is already defined.');
}
$returns[$formatproperty] = self::get_format_structure($property,
$properties[$formatproperty], VALUE_OPTIONAL);
}
}
}
return new external_single_structure($returns);
}
}
+148
View File
@@ -0,0 +1,148 @@
<?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 <huongnv13@gmail.com>
* @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,
];
}
}
@@ -0,0 +1,152 @@
<?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 <huongnv13@gmail.com>
* @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
];
}
}
@@ -0,0 +1,143 @@
<?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 <safat.shahin@gmail.com>
* @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
];
}
}
+185
View File
@@ -0,0 +1,185 @@
<?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 <huongnv13@gmail.com>
* @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,
];
}
}
+244
View File
@@ -0,0 +1,244 @@
<?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 <safat.shahin@gmail.com>
* @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,
];
}
}
@@ -0,0 +1,89 @@
<?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\output\icon_system;
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\output\icon_system_fontawesome;
use theme_config;
/**
* Web service to load font awesome icon maps.
*
* @package core
* @category external
* @copyright 2020 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class load_fontawesome_map extends external_api {
/**
* Description of the parameters suitable for the `execute` function.
*
* @return external_function_parameters
*/
public static function execute_parameters() {
return new external_function_parameters([
'themename' => new external_value(PARAM_ALPHANUMEXT, 'The theme to fetch the map for'),
]);
}
/**
* Return a mapping of icon names to icons.
*
* @param string $themename The theme to fetch icons for
* @return array the mapping
*/
public static function execute(string $themename) {
[
'themename' => $themename,
] = self::validate_parameters(self::execute_parameters(), [
'themename' => $themename,
]);
$theme = theme_config::load($themename);
$instance = icon_system_fontawesome::instance($theme->get_icon_system());
$result = [];
foreach ($instance->get_icon_name_map() as $from => $to) {
[$component, $pix] = explode(':', $from);
$result[] = [
'component' => $component,
'pix' => $pix,
'to' => $to,
];
}
return $result;
}
/**
* Description of the return value for the `execute` function.
*
* @return \core_external\external_description
*/
public static function execute_returns() {
return new external_multiple_structure(new external_single_structure([
'component' => new external_value(PARAM_COMPONENT, 'The component for the icon.'),
'pix' => new external_value(PARAM_RAW, 'Value to map the icon from.'),
'to' => new external_value(PARAM_RAW, 'Value to map the icon to.'),
]));
}
}
+131
View File
@@ -0,0 +1,131 @@
<?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/>.
/**
* Paged Content exporter.
*
* @package core
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core\external;
defined('MOODLE_INTERNAL') || die();
use renderer_base;
/**
* Paged Content exporter.
*
* @copyright 2019 Andrew Nicols <andrew@nicols.co.uk>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class paged_content_exporter extends exporter {
/** @var int pagesize The number of records to show on each page */
private $pagesize;
/** @var int pagenumber The current page number */
private $pagenumber;
/** @var int recordcount The total number of records available */
private $recordcount;
/** @var callable The callback to use to determine a page URL */
private $pageurlcallback;
/**
* Constructor.
*
* @param int $pagesize The number of records to show on each page
* @param int $pagenumber The current page number
* @param int $recordcount The total number of records available
* @param callable $pageurlcallback The callback to use to determine a page URL
* @param array $related List of related elements
*/
public function __construct(int $pagesize, int $pagenumber, int $recordcount, callable $pageurlcallback, array $related = []) {
$this->pagesize = $pagesize;
$this->pagenumber = $pagenumber;
$this->recordcount = $recordcount;
$this->pageurlcallback = $pageurlcallback;
return parent::__construct([], $related);
}
/**
* Return the list of additional properties.
*
* @return array
*/
protected static function define_other_properties() {
return [
'itemsperpage' => ['type' => PARAM_INT],
'buttons' => [
'type' => [
'first' => ['type' => PARAM_BOOL],
'previous' => ['type' => PARAM_BOOL],
'next' => ['type' => PARAM_BOOL],
'last' => ['type' => PARAM_BOOL],
],
],
'pages' => [
'multiple' => true,
'type' => [
'page' => ['type' => PARAM_INT],
'url' => ['type' => PARAM_URL],
'active' => ['type' => PARAM_BOOL],
'content' => [
'optional' => true,
'type' => PARAM_RAW,
],
],
],
];
}
/**
* Get the additional values to inject while exporting.
*
* @param renderer_base $output The renderer.
* @return array Keys are the property names, values are their values.
*/
protected function get_other_values(renderer_base $output) {
$pagecount = ceil($this->recordcount / $this->pagesize);
$pages = [];
if ($pagecount > 1) {
for ($pageno = 1; $pageno <= $pagecount; $pageno++) {
$pages[] = [
'page' => $pageno,
'url' => call_user_func_array($this->pageurlcallback, [$pageno, $this->pagesize]),
'active' => $pageno === $this->pagenumber,
'content' => null,
];
}
}
return [
'itemsperpage' => $this->pagesize,
'buttons' => [
'first' => false,
'previous' => false,
'next' => false,
'last' => false,
],
'pages' => $pages,
];
}
}
+81
View File
@@ -0,0 +1,81 @@
<?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/>.
/**
* Exporter based on persistent.
*
* @package core
* @copyright 2015 Damyon Wiese
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
namespace core\external;
use coding_exception;
/**
* Abstract exporter based on the persistent model.
*
* This automatically fills in the properties of the exporter from those of the persistent.
*
* @copyright 2015 Damyon Wiese
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
abstract class persistent_exporter extends exporter {
/** @var \core\persistent The persistent object we will export. */
protected $persistent = null;
/**
* Constructor - saves the persistent object, and the related objects.
*
* @param \core\persistent $persistent The persistent object to export.
* @param array $related - An optional list of pre-loaded objects related to this persistent.
*/
public function __construct(\core\persistent $persistent, $related = array()) {
$classname = static::define_class();
if (!$persistent instanceof $classname) {
throw new coding_exception('Invalid type for persistent. ' .
'Expected: ' . $classname . ' got: ' . get_class($persistent));
}
$this->persistent = $persistent;
if (method_exists($this->persistent, 'get_context') && !isset($this->related['context'])) {
$this->related['context'] = $this->persistent->get_context();
}
$data = $persistent->to_record();
parent::__construct($data, $related);
}
/**
* Persistent exporters get their standard properties from the persistent class.
*
* @return array Keys are the property names, and value their definition.
*/
final protected static function define_properties() {
$classname = static::define_class();
return $classname::properties_definition();
}
/**
* Returns the specific class the persistent should be an instance of.
*
* @return string
*/
protected static function define_class() {
throw new coding_exception('define_class() must be overidden.');
}
}
+84
View File
@@ -0,0 +1,84 @@
<?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 core_external\external_api;
use core_external\external_function_parameters;
use core_external\external_value;
/**
* The external API to record users action on the feedback notification.
*
* @package core
* @copyright 2020 Shamim Rezaie <shamim@moodle.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class record_userfeedback_action extends external_api {
/**
* Returns description of parameters.
*
* @return external_function_parameters
*/
public static function execute_parameters() {
return new external_function_parameters([
'action' => new external_value(PARAM_ALPHA, 'The action taken by user'),
'contextid' => new external_value(PARAM_INT, 'The context id of the page the user is in'),
]);
}
/**
* Record users action to the feedback CTA
*
* @param string $action The action the user took
* @param int $contextid The context id
* @throws \invalid_parameter_exception
*/
public static function execute(string $action, int $contextid) {
external_api::validate_parameters(self::execute_parameters(), [
'action' => $action,
'contextid' => $contextid,
]);
$context = \context::instance_by_id($contextid);
self::validate_context($context);
switch ($action) {
case 'give':
set_user_preference('core_userfeedback_give', time());
$event = \core\event\userfeedback_give::create(['context' => $context]);
$event->trigger();
break;
case 'remind':
set_user_preference('core_userfeedback_remind', time());
$event = \core\event\userfeedback_remind::create(['context' => $context]);
$event->trigger();
break;
default:
throw new \invalid_parameter_exception('Invalid value for action parameter (value: ' . $action . '),' .
'allowed values are: give,remind');
}
}
/**
* Returns description of method result value
*
* @return null
*/
public static function execute_returns() {
return null;
}
}