MDL-81031 core: Add some new WS
This commit is contained in:
@@ -0,0 +1,157 @@
|
||||
<?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\route\api;
|
||||
|
||||
use core\exception;
|
||||
use core\param;
|
||||
use core\router\route;
|
||||
use core\output\mustache_template_source_loader;
|
||||
use core\router\schema\response\payload_response;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* Template Controller.
|
||||
*
|
||||
* @package core
|
||||
* @copyright Andrew Lyons <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class templates {
|
||||
use \core\router\route_controller;
|
||||
|
||||
/**
|
||||
* Fetch a single template for a component in a theme.
|
||||
*
|
||||
* @param ResponseInterface $response
|
||||
* @param string $themename
|
||||
* @param string $component
|
||||
* @param null|string $identifier
|
||||
* @return payload_response
|
||||
*/
|
||||
#[route(
|
||||
path: '/templates/{themename}/{component}/{identifier}',
|
||||
method: ['GET'],
|
||||
title: 'Fetch a single template',
|
||||
description: 'Fetch a single template for a component in a theme',
|
||||
security: [],
|
||||
pathtypes: [
|
||||
new \core\router\parameters\path_themename(),
|
||||
new \core\router\parameters\path_component(),
|
||||
new \core\router\schema\parameters\path_parameter(
|
||||
name: 'identifier',
|
||||
type: param::SAFEPATH,
|
||||
),
|
||||
],
|
||||
queryparams: [
|
||||
new \core\router\schema\parameters\query_parameter(
|
||||
name: 'includecomments',
|
||||
type: param::BOOL,
|
||||
description: 'Include comments in the template',
|
||||
default: false,
|
||||
),
|
||||
],
|
||||
headerparams: [
|
||||
new \core\router\parameters\header_language(),
|
||||
],
|
||||
responses: [
|
||||
new \core\router\schema\response\response(
|
||||
statuscode: 200,
|
||||
description: 'OK',
|
||||
content: [
|
||||
new \core\router\schema\response\content\json_media_type(
|
||||
schema: new \core\router\schema\objects\schema_object(
|
||||
content: [
|
||||
'templates' => new \core\router\schema\objects\array_of_strings(
|
||||
keyparamtype: param::TEXT,
|
||||
valueparamtype: param::RAW,
|
||||
),
|
||||
'strings' => new \core\router\schema\objects\array_of_strings(
|
||||
keyparamtype: param::TEXT,
|
||||
valueparamtype: param::RAW,
|
||||
),
|
||||
],
|
||||
),
|
||||
examples: [
|
||||
new \core\router\schema\example(
|
||||
name: 'Single template value',
|
||||
summary: 'A json response containing the template for a single template',
|
||||
value: [
|
||||
'templates' => [
|
||||
"mod_example/template_identifier" => "<div class=\"example\">Hello World</div>",
|
||||
"mod_example/other_template" => "<div class=\"example\">Hello World</div>",
|
||||
],
|
||||
'strings' => [
|
||||
'core/loading' => 'Loading',
|
||||
],
|
||||
],
|
||||
),
|
||||
]
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)]
|
||||
public function get_templates(
|
||||
ServerRequestInterface $request,
|
||||
ResponseInterface $response,
|
||||
mustache_template_source_loader $loader,
|
||||
string $themename,
|
||||
string $component,
|
||||
string $identifier,
|
||||
): payload_response {
|
||||
global $PAGE;
|
||||
|
||||
$PAGE->set_context(\core\context\system::instance());
|
||||
|
||||
$params = $request->getQueryParams();
|
||||
$comments = $params['includecomments'];
|
||||
|
||||
try {
|
||||
$dependencies = $loader->load_with_dependencies(
|
||||
templatecomponent: $component,
|
||||
templatename: $identifier,
|
||||
themename: $themename,
|
||||
includecomments: $comments,
|
||||
lang: $request->getHeaderLine('language'),
|
||||
);
|
||||
} catch (\moodle_exception $e) {
|
||||
throw new exception\not_found_exception('template', "{$component}/{$identifier}");
|
||||
}
|
||||
|
||||
$result = [
|
||||
'templates' => [],
|
||||
'strings' => [],
|
||||
];
|
||||
|
||||
foreach ($dependencies['templates'] as $component => $templates) {
|
||||
foreach ($templates as $template => $value) {
|
||||
$result['templates']["{$component}/{$template}"] = $value;
|
||||
}
|
||||
}
|
||||
foreach ($dependencies['strings'] as $component => $templates) {
|
||||
foreach ($templates as $template => $value) {
|
||||
$result['strings']["{$component}/{$template}"] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return new payload_response(
|
||||
payload: $result,
|
||||
request: $request,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
<?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\route\api;
|
||||
|
||||
use core\tests\route_testcase;
|
||||
|
||||
/**
|
||||
* Tests for Templates API.
|
||||
*
|
||||
* @package core
|
||||
* @category test
|
||||
* @copyright 2024 Andrew Lyons <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @covers \core\route\api\templates
|
||||
*/
|
||||
final class templates_test extends route_testcase {
|
||||
/**
|
||||
* Test fetching templates.
|
||||
*
|
||||
* Note: This is a risky test because it relies on data in other parts of Moodle.
|
||||
*
|
||||
* @dataProvider fetch_templates_provider
|
||||
* @param string $path
|
||||
* @param array $requiredtemplates
|
||||
* @param array $requiredstrings
|
||||
*/
|
||||
public function test_fetch_known_templates(
|
||||
string $path,
|
||||
array $requiredtemplates,
|
||||
array $requiredstrings,
|
||||
): void {
|
||||
$this->add_class_routes_to_route_loader(\core\route\api\templates::class);
|
||||
$response = $this->process_api_request('GET', "/templates/{$path}");
|
||||
|
||||
$this->assert_valid_response($response);
|
||||
$payload = $this->decode_response($response, true);
|
||||
|
||||
$this->assert_payload_contains($payload, $requiredtemplates, $requiredstrings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data propvider for template tests.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function fetch_templates_provider(): array {
|
||||
return [
|
||||
'fetch single template' => [
|
||||
'boost/core/modal',
|
||||
['core/modal'],
|
||||
[],
|
||||
],
|
||||
'foo' => [
|
||||
'boost/core/notification',
|
||||
[
|
||||
'core/notification',
|
||||
'core/notification_success',
|
||||
'core/notification_warning',
|
||||
'core/notification_error',
|
||||
'core/notification_info',
|
||||
],
|
||||
[
|
||||
'core/dismissnotification',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Assertthat the payload contains the required templates and strings.
|
||||
*
|
||||
* @param array $payload
|
||||
* @param array $requiredtemplates
|
||||
* @param array $requiredstrings
|
||||
*/
|
||||
protected function assert_payload_contains(
|
||||
array $payload,
|
||||
array $requiredtemplates = [],
|
||||
array $requiredstrings = [],
|
||||
): void {
|
||||
$this->assertArrayHasKey('templates', $payload);
|
||||
$this->assertArrayHasKey('strings', $payload);
|
||||
|
||||
foreach ($requiredtemplates as $template) {
|
||||
$this->assertArrayHasKey($template, $payload['templates']);
|
||||
}
|
||||
foreach ($requiredstrings as $string) {
|
||||
$this->assertArrayHasKey($string, $payload['strings']);
|
||||
}
|
||||
}
|
||||
|
||||
public function test_template_missing(): void {
|
||||
$this->add_class_routes_to_route_loader(\core\route\api\templates::class);
|
||||
$response = $this->process_api_request('GET', '/templates/boost/core/missing');
|
||||
|
||||
$this->assert_not_found_response($response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
<?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_user\route\api;
|
||||
|
||||
use core\exception\coding_exception;
|
||||
use core\exception\invalid_parameter_exception;
|
||||
use core\param;
|
||||
use core\router\route;
|
||||
use core\router\schema\objects\scalar_type;
|
||||
use core\router\schema\response\payload_response;
|
||||
use core\router\schema\response\content\payload_response_type;
|
||||
use core\router\schema\response\response_type;
|
||||
use core\user;
|
||||
use core_user\route\responses\user_preferences_response;
|
||||
use stdClass;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
|
||||
/**
|
||||
* User preference API handler.
|
||||
*
|
||||
* @package core_user
|
||||
* @copyright Andrew Lyons <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
#[route(
|
||||
path: '/{user}/preferences',
|
||||
pathtypes: [
|
||||
new \core\router\parameters\path_user(),
|
||||
],
|
||||
)]
|
||||
class preferences {
|
||||
/**
|
||||
* Fetch all user preferences, or a specific user preference.
|
||||
*
|
||||
* @param ResponseInterface $response
|
||||
* @param ServerRequestInterface $request
|
||||
* @param stdClass $user
|
||||
* @param null|string $preference
|
||||
* @return payload_response
|
||||
*/
|
||||
#[route(
|
||||
path: '[/{preference}]',
|
||||
title: 'Fetch user preferences',
|
||||
description: 'Fetch one user preference, or all user preferences',
|
||||
pathtypes: [
|
||||
new \core\router\schema\parameters\path_parameter(
|
||||
name: 'preference',
|
||||
type: param::RAW,
|
||||
),
|
||||
],
|
||||
responses: [
|
||||
new user_preferences_response(),
|
||||
],
|
||||
)]
|
||||
public function get_preferences(
|
||||
ResponseInterface $response,
|
||||
ServerRequestInterface $request,
|
||||
stdClass $user,
|
||||
?string $preference,
|
||||
): payload_response {
|
||||
$this->check_user($user);
|
||||
|
||||
$result = get_user_preferences(
|
||||
name: $preference,
|
||||
user: $user,
|
||||
);
|
||||
|
||||
if (!is_array($result)) {
|
||||
// Check if we received just one preference.
|
||||
$result = [$preference => $result];
|
||||
}
|
||||
|
||||
return new payload_response($result, $request, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a set of user preferences.
|
||||
*
|
||||
* @param ResponseInterface $response
|
||||
* @param stdClass $user
|
||||
* @return payload_response
|
||||
*/
|
||||
#[route(
|
||||
method: ['POST'],
|
||||
title: 'Set or update multiple user preferences',
|
||||
requestbody: new \core\router\schema\request_body(
|
||||
content: new payload_response_type(
|
||||
schema: new \core\router\schema\objects\schema_object(
|
||||
content: [
|
||||
'preferences' => new \core\router\schema\objects\array_of_strings(
|
||||
keyparamtype: param::TEXT,
|
||||
valueparamtype: param::RAW,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
responses: [
|
||||
new user_preferences_response(),
|
||||
],
|
||||
)]
|
||||
public function set_preferences(
|
||||
ResponseInterface $response,
|
||||
ServerRequestInterface $request,
|
||||
stdClass $user,
|
||||
): payload_response {
|
||||
$this->check_user($user);
|
||||
|
||||
$values = $request->getParsedBody();
|
||||
$preferences = $values['preferences'] ?? [];
|
||||
|
||||
foreach ($preferences as $preference => $value) {
|
||||
$this->set_single_preference($user, $preference, $value);
|
||||
}
|
||||
|
||||
$result = array_filter(
|
||||
get_user_preferences(
|
||||
user: $user,
|
||||
),
|
||||
fn ($preference) => array_key_exists($preference, $preferences),
|
||||
ARRAY_FILTER_USE_KEY,
|
||||
);
|
||||
|
||||
return new payload_response($result, $request, $response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a single user preference.
|
||||
*
|
||||
* @param ResponseInterface $response
|
||||
* @param string $themename
|
||||
* @param string $component
|
||||
* @param null|string $identifier
|
||||
* @return response_type
|
||||
*/
|
||||
#[route(
|
||||
path: '/{preference}',
|
||||
method: ['POST'],
|
||||
title: 'Set a single user preference',
|
||||
description: 'Set a single user preference',
|
||||
pathtypes: [
|
||||
new \core\router\schema\parameters\path_parameter(
|
||||
name: 'preference',
|
||||
type: param::RAW,
|
||||
),
|
||||
],
|
||||
requestbody: new \core\router\schema\request_body(
|
||||
content: new payload_response_type(
|
||||
schema: new \core\router\schema\objects\schema_object(
|
||||
content: [
|
||||
'value' => new scalar_type(param::RAW),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
responses: [
|
||||
new \core\router\schema\response\response(
|
||||
statuscode: 200,
|
||||
description: 'OK',
|
||||
content: [
|
||||
new \core\router\schema\response\content\json_media_type(
|
||||
schema: new \core\router\schema\objects\array_of_strings(
|
||||
keyparamtype: param::TEXT,
|
||||
valueparamtype: param::RAW,
|
||||
),
|
||||
examples: [
|
||||
new \core\router\schema\example(
|
||||
name: 'A single preference value',
|
||||
summary: 'A json response containing a single preference',
|
||||
value: [
|
||||
"drawers-open-index" => "1",
|
||||
],
|
||||
),
|
||||
]
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)]
|
||||
public function set_preference(
|
||||
ResponseInterface $response,
|
||||
ServerRequestInterface $request,
|
||||
stdClass $user,
|
||||
?string $preference,
|
||||
): response_type {
|
||||
$this->check_user($user);
|
||||
|
||||
$values = $request->getParsedBody();
|
||||
$value = $values['value'] ?? null;
|
||||
$this->set_single_preference($user, $preference, $value);
|
||||
|
||||
return $this->get_preferences($response, $request, $user, $preference);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a single user preference.
|
||||
*
|
||||
* @param \stdClass $user
|
||||
* @param string $preference
|
||||
* @param mixed $value
|
||||
* @throws \core\exception\access_denied_exception
|
||||
* @throws \invalid_parameter_exception
|
||||
*/
|
||||
protected function set_single_preference(
|
||||
stdClass $user,
|
||||
string $preference,
|
||||
mixed $value,
|
||||
): void {
|
||||
try {
|
||||
$definition = user::get_preference_definition($preference);
|
||||
} catch (coding_exception $e) {
|
||||
throw new invalid_parameter_exception("Invalid preference '$preference'");
|
||||
}
|
||||
|
||||
if (!user::can_edit_preference($preference, $user)) {
|
||||
throw new \core\exception\access_denied_exception('You do not have permission to edit this preference.');
|
||||
}
|
||||
|
||||
if (isset($definition['type'])) {
|
||||
$type = param::from_type($definition['type']);
|
||||
$value = $this->standardise_value($type, $value);
|
||||
}
|
||||
|
||||
$cleanvalue = user::clean_preference($value, $preference);
|
||||
if ($cleanvalue !== $value) {
|
||||
throw new \invalid_parameter_exception("Invalid value for preference '$preference': '{$value}'");
|
||||
}
|
||||
$value = $cleanvalue;
|
||||
set_user_preference($preference, $value, $user->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the requested user meets the requirements.
|
||||
*
|
||||
* @param stdClass $user
|
||||
* @throws invalid_parameter_exception
|
||||
*/
|
||||
protected function check_user(stdClass $user): void {
|
||||
global $USER;
|
||||
|
||||
if ($user->id !== $USER->id) {
|
||||
throw new \core\exception\access_denied_exception(
|
||||
'You do not have permission to view or edit preferences for other users.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Standardise value based on type.
|
||||
*
|
||||
* Note: We cannot use \core\param here because we only want to cast some types.
|
||||
* Requests do not have an inherent understanding of anything but strings. We need to be strict on typing of integers and bools.
|
||||
*
|
||||
* @param string param $type
|
||||
* @param mixed $value
|
||||
* @return mixed
|
||||
*/
|
||||
protected function standardise_value(param $type, mixed $value): mixed {
|
||||
if (is_numeric($value) || is_bool($value)) {
|
||||
switch ($type) {
|
||||
case param::INT:
|
||||
case param::BOOL:
|
||||
$value = (int) $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?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_user\route\responses;
|
||||
|
||||
use core\param;
|
||||
use core\router\schema\response\content\payload_response_type;
|
||||
|
||||
/**
|
||||
* A standard response for user preferences.
|
||||
*
|
||||
* @package core_user
|
||||
* @copyright 2023 Andrew Lyons <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class user_preferences_response extends \core\router\schema\response\response {
|
||||
/**
|
||||
* Constructor for a standard user preference response.
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct(
|
||||
content: new payload_response_type(
|
||||
schema: new \core\router\schema\objects\array_of_strings(
|
||||
keyparamtype: param::TEXT,
|
||||
valueparamtype: param::RAW,
|
||||
),
|
||||
examples: [
|
||||
new \core\router\schema\example(
|
||||
name: 'A single preference value',
|
||||
summary: 'A json response containing a single preference',
|
||||
value: [
|
||||
"drawers-open-index" => "1",
|
||||
],
|
||||
),
|
||||
new \core\router\schema\example(
|
||||
name: 'A set of preference values',
|
||||
summary: 'A json response containing a set of preferences',
|
||||
value: [
|
||||
"drawers-open-index" => "1",
|
||||
"login_failed_count_since_success" => "1",
|
||||
"coursesectionspreferences_2" => "{\"contentcollapsed\":[]}",
|
||||
],
|
||||
),
|
||||
]
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -16,24 +16,25 @@
|
||||
|
||||
namespace core_user\route\api;
|
||||
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use core\tests\route_testcase;
|
||||
use GuzzleHttp\Psr7\Utils;
|
||||
|
||||
/**
|
||||
* Tests for user preference API handler.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2023 Andrew Lyons <[email protected]>
|
||||
* @package core_user
|
||||
* @copyright Andrew Lyons <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @covers \core_user\route\api\preferences
|
||||
* @covers \core_user\route\responses\user_preferences_response
|
||||
*/
|
||||
class preferences_test extends \route_testcase {
|
||||
final class preferences_test extends route_testcase {
|
||||
/**
|
||||
* Ensure that preferences returned for a user without login are empty.
|
||||
*/
|
||||
public function test_preferences_no_login(): void {
|
||||
$response = $this->process_request('GET', '/user/preferences');
|
||||
$this->add_class_routes_to_route_loader(preferences::class);
|
||||
$response = $this->process_api_request('GET', '/current/preferences');
|
||||
|
||||
$this->assert_valid_response($response);
|
||||
$payload = $this->decode_response($response);
|
||||
@@ -47,50 +48,249 @@ class preferences_test extends \route_testcase {
|
||||
public function test_preferences_returned(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$this->setAdminUser();
|
||||
set_user_preference('testpreference', 'testvalue');
|
||||
$this->add_class_routes_to_route_loader(preferences::class);
|
||||
|
||||
$response = $this->process_request('GET', '/user/preferences');
|
||||
$this->setAdminUser();
|
||||
set_user_preference('filemanager_recentviewmode', 1);
|
||||
|
||||
$response = $this->process_api_request('GET', '/current/preferences');
|
||||
|
||||
$this->assert_valid_response($response);
|
||||
|
||||
$payload = $this->decode_response($response);
|
||||
|
||||
$this->assertObjectHasAttribute('testpreference', $payload);
|
||||
$this->assertEquals('testvalue', $payload->testpreference);
|
||||
$this->assertObjectHasProperty('filemanager_recentviewmode', $payload);
|
||||
$this->assertEquals(1, $payload->filemanager_recentviewmode);
|
||||
}
|
||||
|
||||
public function test_preference_returned(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$this->setAdminUser();
|
||||
set_user_preference('testpreference', 'testvalue');
|
||||
$this->add_class_routes_to_route_loader(preferences::class);
|
||||
|
||||
$response = $this->process_request('GET', '/user/preferences/testpreference');
|
||||
$this->setAdminUser();
|
||||
set_user_preference('filemanager_recentviewmode', 1);
|
||||
|
||||
$response = $this->process_api_request('GET', '/current/preferences/filemanager_recentviewmode');
|
||||
|
||||
$this->assert_valid_response($response);
|
||||
|
||||
$payload = $this->decode_response($response);
|
||||
|
||||
$this->assertObjectHasAttribute('testpreference', $payload);
|
||||
$this->assertEquals('testvalue', $payload->testpreference);
|
||||
$this->assertObjectHasProperty('filemanager_recentviewmode', $payload);
|
||||
$this->assertEquals(1, $payload->filemanager_recentviewmode);
|
||||
}
|
||||
|
||||
public function test_preferences_set(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$request = $this->create_request(
|
||||
$this->add_class_routes_to_route_loader(preferences::class);
|
||||
|
||||
$this->setAdminUser();
|
||||
|
||||
$response = $this->process_api_request(
|
||||
'POST',
|
||||
'/user/preferences',
|
||||
)->withBody(
|
||||
Utils::streamFor(json_encode([
|
||||
'/current/preferences',
|
||||
body: Utils::streamFor(json_encode([
|
||||
'preferences' => [
|
||||
'testpreference' => 'someothervalue',
|
||||
'filemanager_recentviewmode' => 2,
|
||||
'drawer-open-index' => 1,
|
||||
],
|
||||
])),
|
||||
);
|
||||
|
||||
$app = $this->get_app();
|
||||
$response = $app->handle($request);
|
||||
$this->assert_valid_response($response);
|
||||
|
||||
// Check that the response contained the updtaed parameter.
|
||||
$payload = (object) $this->decode_response($response);
|
||||
$this->assertObjectHasProperty('filemanager_recentviewmode', $payload);
|
||||
$this->assertObjectHasProperty('drawer-open-index', $payload);
|
||||
$this->assertEquals(2, $payload->filemanager_recentviewmode);
|
||||
|
||||
// Check that the preference was updated.
|
||||
$this->assertEquals(2, get_user_preferences('filemanager_recentviewmode'));
|
||||
$this->assertEquals(1, get_user_preferences('drawer-open-index'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that an invalid preference is rejected.
|
||||
*/
|
||||
public function test_preferences_set_invalid_value(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$this->add_class_routes_to_route_loader(preferences::class);
|
||||
|
||||
$this->setAdminUser();
|
||||
|
||||
$response = $this->process_api_request(
|
||||
'POST',
|
||||
'/current/preferences',
|
||||
body: Utils::streamFor(json_encode([
|
||||
'preferences' => [
|
||||
'filemanager_recentviewmode' => 4,
|
||||
],
|
||||
])),
|
||||
);
|
||||
|
||||
$this->assert_invalid_parameter_response($response);
|
||||
$payload = $this->decode_response($response);
|
||||
$this->assertStringContainsString('filemanager_recentviewmode', $payload->message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a preference the user does not have permission to is rejected.
|
||||
*/
|
||||
public function test_preferences_set_not_permitted_valid_login(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$this->add_class_routes_to_route_loader(preferences::class);
|
||||
|
||||
$this->setAdminUser();
|
||||
|
||||
$response = $this->process_api_request(
|
||||
'POST',
|
||||
'/current/preferences',
|
||||
body: Utils::streamFor(json_encode([
|
||||
'preferences' => [
|
||||
'auth_forcepasswordchange' => 4,
|
||||
],
|
||||
])),
|
||||
);
|
||||
|
||||
$this->assert_access_denied_response($response);
|
||||
}
|
||||
|
||||
public function test_preference_set(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$this->add_class_routes_to_route_loader(preferences::class);
|
||||
|
||||
$this->setAdminUser();
|
||||
|
||||
$response = $this->process_api_request(
|
||||
'POST',
|
||||
'/current/preferences/filemanager_recentviewmode',
|
||||
body: Utils::streamFor(json_encode([
|
||||
'value' => 2,
|
||||
])),
|
||||
);
|
||||
|
||||
$this->assert_valid_response($response);
|
||||
|
||||
// Check that the response contained the updtaed parameter.
|
||||
$payload = $this->decode_response($response);
|
||||
$this->assertObjectHasProperty('filemanager_recentviewmode', $payload);
|
||||
$this->assertEquals(2, $payload->filemanager_recentviewmode);
|
||||
|
||||
// Check that the preference was updated.
|
||||
$this->assertEquals(2, get_user_preferences('filemanager_recentviewmode'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that an invalid preference is rejected.
|
||||
*/
|
||||
public function test_preference_set_invalid_value(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$this->add_class_routes_to_route_loader(preferences::class);
|
||||
|
||||
$this->setAdminUser();
|
||||
|
||||
$response = $this->process_api_request(
|
||||
'POST',
|
||||
'/current/preferences/filemanager_recentviewmode',
|
||||
body: Utils::streamFor(json_encode([
|
||||
'value' => 4,
|
||||
])),
|
||||
);
|
||||
|
||||
$this->assert_invalid_parameter_response($response);
|
||||
$payload = $this->decode_response($response);
|
||||
$this->assertStringContainsString('filemanager_recentviewmode', $payload->message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that an invalid preference inentifier is rejected.
|
||||
*/
|
||||
public function test_preference_set_invalid_preference(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$this->add_class_routes_to_route_loader(preferences::class);
|
||||
|
||||
$this->setAdminUser();
|
||||
|
||||
$response = $this->process_api_request(
|
||||
'POST',
|
||||
'/current/preferences/what_a_fake',
|
||||
body: Utils::streamFor(json_encode([
|
||||
'value' => 4,
|
||||
])),
|
||||
);
|
||||
|
||||
$this->assert_invalid_parameter_response($response);
|
||||
$payload = $this->decode_response($response);
|
||||
$this->assertStringContainsString('what_a_fake', $payload->message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that a preference the user does not have permission to is rejected.
|
||||
*/
|
||||
public function test_preference_set_not_permitted_valid_login(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$this->add_class_routes_to_route_loader(preferences::class);
|
||||
|
||||
$this->setAdminUser();
|
||||
|
||||
$response = $this->process_api_request(
|
||||
'POST',
|
||||
'/current/preferences/auth_forcepasswordchange',
|
||||
body: Utils::streamFor(json_encode([
|
||||
'value' => 4,
|
||||
])),
|
||||
);
|
||||
|
||||
$this->assert_access_denied_response($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* A user cannot get or set preferences for anothe ruser.
|
||||
*/
|
||||
public function test_preference_get_other_user(): void {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
|
||||
$this->add_class_routes_to_route_loader(preferences::class);
|
||||
|
||||
// Get all preferences.
|
||||
$response = $this->process_api_request('GET', "/{$user->id}/preferences");
|
||||
$this->assert_access_denied_response($response);
|
||||
|
||||
// Get one preference.
|
||||
$response = $this->process_api_request('GET', "/{$user->id}/preferences/example");
|
||||
$this->assert_access_denied_response($response);
|
||||
|
||||
// Set all preferences.
|
||||
$response = $this->process_api_request(
|
||||
'POST',
|
||||
"/{$user->id}/preferences/filemanager_recentviewmode",
|
||||
body: Utils::streamFor(json_encode([
|
||||
'value' => 4,
|
||||
])),
|
||||
);
|
||||
$this->assert_access_denied_response($response);
|
||||
|
||||
// Get all preferences.
|
||||
$response = $this->process_api_request(
|
||||
'POST',
|
||||
"/{$user->id}/preferences",
|
||||
body: Utils::streamFor(json_encode([
|
||||
'preferences' => [
|
||||
'filemanager_recentviewmode' => 2,
|
||||
],
|
||||
])),
|
||||
);
|
||||
$this->assert_access_denied_response($response);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user