mirror of
https://github.com/moodle/moodle.git
synced 2025-01-31 20:53:53 +01:00
Merge branch 'MDL-71096' of https://github.com/stronk7/moodle
This commit is contained in:
commit
d98be6a34e
257
lib/apis.json
Normal file
257
lib/apis.json
Normal file
@ -0,0 +1,257 @@
|
||||
{
|
||||
"access": {
|
||||
"component": "core_access",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": false
|
||||
},
|
||||
"admin": {
|
||||
"component": "core_admin",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"adminpresets": {
|
||||
"component": "core_adminpresets",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": false
|
||||
},
|
||||
"analytics": {
|
||||
"component": "core_analytics",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"availability": {
|
||||
"component": "core_availability",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"backup": {
|
||||
"component": "core_backup",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"badges": {
|
||||
"component": "core_badges",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"cache": {
|
||||
"component": "core_cache",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"calendar": {
|
||||
"component": "core_calendar",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"check": {
|
||||
"component": "core",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"comment": {
|
||||
"component": "core_comment",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"competency": {
|
||||
"component": "core_competency",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"completion": {
|
||||
"component": "core_completion",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"core": {
|
||||
"component": null,
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"ddl": {
|
||||
"component": "core",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": false
|
||||
},
|
||||
"dml": {
|
||||
"component": "core",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": false
|
||||
},
|
||||
"enrol": {
|
||||
"component": "core_enrol",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"event": {
|
||||
"component": "core",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"external": {
|
||||
"component": "core",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"files": {
|
||||
"component": "core_files",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": false
|
||||
},
|
||||
"form": {
|
||||
"component": "core_form",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"grade": {
|
||||
"component": "core_grade",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"grading": {
|
||||
"component": "core_grading",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"group": {
|
||||
"component": "core_group",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"h5p": {
|
||||
"component": "core_h5p",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"lock": {
|
||||
"component": "core",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": false
|
||||
},
|
||||
"log": {
|
||||
"component": "core",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"media": {
|
||||
"component": "core_media",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"message": {
|
||||
"component": "core_message",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"navigation": {
|
||||
"component": "core",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"oauth2": {
|
||||
"component": "core",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"output": {
|
||||
"component": "core",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"page": {
|
||||
"component": "core",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"payment": {
|
||||
"component": "core_payment",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"plagiarism": {
|
||||
"component": "core_plagiarism",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"portfolio": {
|
||||
"component": "core_portfolio",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"preference": {
|
||||
"component": "core",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"privacy": {
|
||||
"component": "core_privacy",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"question": {
|
||||
"component": "core_question",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"rating": {
|
||||
"component": "core_rating",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"reportbuilder": {
|
||||
"component": "core_reportbuilder",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"rss": {
|
||||
"component": "core_rss",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"search": {
|
||||
"component": "core_search",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"string": {
|
||||
"component": "core",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"tag": {
|
||||
"component": "core_tag",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"task": {
|
||||
"component": "core",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
},
|
||||
"test": {
|
||||
"component": "core",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"time": {
|
||||
"component": "core",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"upgrade": {
|
||||
"component": "core",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": false
|
||||
},
|
||||
"webservice": {
|
||||
"component": "core_webservice",
|
||||
"allowedlevel2": false,
|
||||
"allowedspread": false
|
||||
},
|
||||
"xapi": {
|
||||
"component": "core_xapi",
|
||||
"allowedlevel2": true,
|
||||
"allowedspread": true
|
||||
}
|
||||
}
|
30
lib/apis.schema.json
Normal file
30
lib/apis.schema.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://moodle.org/apis.schema.json",
|
||||
"title": "APIs",
|
||||
"description": "Moodle valid APIs",
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[a-z][a-z0-9]+$": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"component": {
|
||||
"description": "Component the API belongs to, usually a subsystem or core. Null for the 'core' API itself",
|
||||
"type": [ "string", "null" ],
|
||||
"pattern": "^(core|[a-z][a-z0-9_]+)$"
|
||||
},
|
||||
"allowedlevel2": {
|
||||
"description": "Can the API be used as level 2 namespace",
|
||||
"type": "boolean"
|
||||
},
|
||||
"allowedspread": {
|
||||
"description": "Can the API be used out from its own component",
|
||||
"type": "boolean"
|
||||
}
|
||||
},
|
||||
"minProperties": 3,
|
||||
"maxProperties": 3,
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
@ -72,6 +72,8 @@ class core_component {
|
||||
protected static $parents = null;
|
||||
/** @var array subplugins */
|
||||
protected static $subplugins = null;
|
||||
/** @var array cache of core APIs */
|
||||
protected static $apis = null;
|
||||
/** @var array list of all known classes that can be autoloaded */
|
||||
protected static $classmap = null;
|
||||
/** @var array list of all classes that have been renamed to be autoloaded */
|
||||
@ -256,6 +258,7 @@ class core_component {
|
||||
self::$subsystems = $cache['subsystems'];
|
||||
self::$parents = $cache['parents'];
|
||||
self::$subplugins = $cache['subplugins'];
|
||||
self::$apis = $cache['apis'];
|
||||
self::$classmap = $cache['classmap'];
|
||||
self::$classmaprenames = $cache['classmaprenames'];
|
||||
self::$filemap = $cache['filemap'];
|
||||
@ -296,6 +299,7 @@ class core_component {
|
||||
self::$subsystems = $cache['subsystems'];
|
||||
self::$parents = $cache['parents'];
|
||||
self::$subplugins = $cache['subplugins'];
|
||||
self::$apis = $cache['apis'];
|
||||
self::$classmap = $cache['classmap'];
|
||||
self::$classmaprenames = $cache['classmaprenames'];
|
||||
self::$filemap = $cache['filemap'];
|
||||
@ -382,6 +386,7 @@ class core_component {
|
||||
'plugins' => self::$plugins,
|
||||
'parents' => self::$parents,
|
||||
'subplugins' => self::$subplugins,
|
||||
'apis' => self::$apis,
|
||||
'classmap' => self::$classmap,
|
||||
'classmaprenames' => self::$classmaprenames,
|
||||
'filemap' => self::$filemap,
|
||||
@ -406,6 +411,8 @@ $cache = '.var_export($cache, true).';
|
||||
self::$plugins[$type] = self::fetch_plugins($type, $fulldir);
|
||||
}
|
||||
|
||||
self::$apis = self::fetch_apis();
|
||||
|
||||
self::fill_classmap_cache();
|
||||
self::fill_classmap_renames_cache();
|
||||
self::fill_filemap_cache();
|
||||
@ -455,6 +462,14 @@ $cache = '.var_export($cache, true).';
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of core APIs.
|
||||
* @return stdClass[]
|
||||
*/
|
||||
protected static function fetch_apis() {
|
||||
return (array) json_decode(file_get_contents(__DIR__ . '/../apis.json'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of known plugin types.
|
||||
* @return array
|
||||
@ -751,6 +766,22 @@ $cache = '.var_export($cache, true).';
|
||||
return self::$subsystems;
|
||||
}
|
||||
|
||||
/**
|
||||
* List all core APIs and their attributes.
|
||||
*
|
||||
* This is a list of all the existing / allowed APIs in moodle, each one with the
|
||||
* following attributes:
|
||||
* - component: the component, usually a subsystem or core, the API belongs to.
|
||||
* - allowedlevel2: if the API is allowed as level2 namespace or no.
|
||||
* - allowedspread: if the API can spread out from its component or no.
|
||||
*
|
||||
* @return stdClass[] array of APIs (as keys) with their attributes as object instances.
|
||||
*/
|
||||
public static function get_core_apis() {
|
||||
self::init();
|
||||
return self::$apis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get list of available plugin types together with their location.
|
||||
*
|
||||
@ -1176,6 +1207,16 @@ $cache = '.var_export($cache, true).';
|
||||
return isset(self::$subsystems[$subsystemname]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if apiname is a core API.
|
||||
*
|
||||
* @param string $apiname name of the API.
|
||||
* @return bool true if core API.
|
||||
*/
|
||||
public static function is_core_api($apiname) {
|
||||
return isset(self::$apis[$apiname]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Records all class renames that have been made to facilitate autoloading.
|
||||
*/
|
||||
@ -1283,4 +1324,13 @@ $cache = '.var_export($cache, true).';
|
||||
}
|
||||
return $componentnames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of available API names.
|
||||
*
|
||||
* @return string[] the list of available API names.
|
||||
*/
|
||||
public static function get_core_api_names(): array {
|
||||
return array_keys(self::get_core_apis());
|
||||
}
|
||||
}
|
||||
|
@ -18,16 +18,11 @@
|
||||
* core_component related tests.
|
||||
*
|
||||
* @package core
|
||||
* @category phpunit
|
||||
* @category test
|
||||
* @copyright 2013 Petr Skoda {@link http://skodak.org}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
|
||||
/**
|
||||
* Class core_component_testcase.
|
||||
*
|
||||
* @covers \core_component
|
||||
*/
|
||||
class component_test extends advanced_testcase {
|
||||
|
||||
@ -843,4 +838,64 @@ class component_test extends advanced_testcase {
|
||||
$this->assertContains('tool_usertours', $componentnames);
|
||||
$this->assertContains('core_favourites', $componentnames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic tests for APIs related functions in the core_component class.
|
||||
*/
|
||||
public function test_apis_methods() {
|
||||
$apis = core_component::get_core_apis();
|
||||
$this->assertIsArray($apis);
|
||||
|
||||
$apinames = core_component::get_core_api_names();
|
||||
$this->assertIsArray($apis);
|
||||
|
||||
// Both should return the very same APIs.
|
||||
$this->assertEquals($apinames, array_keys($apis));
|
||||
|
||||
$this->assertFalse(core_component::is_core_api('lalala'));
|
||||
$this->assertTrue(core_component::is_core_api('privacy'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the apis.json structure matches expectations
|
||||
*
|
||||
* While we include an apis.schema.json file in core, there isn't any PHP built-in allowing us
|
||||
* to validate it (3rd part libraries needed). Plus the schema doesn't allow to validate things
|
||||
* like uniqueness or sorting. We are going to do all that here.
|
||||
*/
|
||||
public function test_apis_json_validation() {
|
||||
$apis = $sortedapis = core_component::get_core_apis();
|
||||
ksort($sortedapis); // We'll need this later.
|
||||
|
||||
// General structure validations.
|
||||
$this->assertIsArray($apis);
|
||||
$this->assertGreaterThan(25, count($apis));
|
||||
$this->assertArrayHasKey('privacy', $apis); // Verify a few.
|
||||
$this->assertArrayHasKey('external', $apis);
|
||||
$this->assertArrayHasKey('search', $apis);
|
||||
$this->assertEquals(array_keys($sortedapis), array_keys($apis)); // Verify json is sorted alphabetically.
|
||||
|
||||
// Iterate over all apis and perform more validations.
|
||||
foreach ($apis as $apiname => $attributes) {
|
||||
// Message, to be used later and easier finding the problem.
|
||||
$message = "Validation problem found with API: ${apiname}";
|
||||
|
||||
$this->assertIsObject($attributes, $message);
|
||||
$this->assertMatchesRegularExpression('/^[a-z][a-z0-9]+$/', $apiname, $message);
|
||||
$this->assertEquals(['component', 'allowedlevel2', 'allowedspread'], array_keys((array)$attributes), $message);
|
||||
|
||||
// Verify attributes.
|
||||
if ($apiname !== 'core') { // Exception for core api, it doesn't have component.
|
||||
$this->assertMatchesRegularExpression('/^(core|[a-z][a-z0-9_]+)$/', $attributes->component, $message);
|
||||
} else {
|
||||
$this->assertNull($attributes->component, $message);
|
||||
}
|
||||
|
||||
$this->assertIsBool($attributes->allowedlevel2, $message);
|
||||
$this->assertIsBool($attributes->allowedspread, $message);
|
||||
|
||||
// Cannot spread if level2 is not allowed.
|
||||
$this->assertLessThanOrEqual($attributes->allowedlevel2, $attributes->allowedspread, $message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2022120900.01; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2022120900.02; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
$release = '4.2dev (Build: 20221209)'; // Human-friendly version name
|
||||
|
Loading…
x
Reference in New Issue
Block a user