ÿØÿà JFIF    ÿÛ „  ( %!1"%)+...383-7(-.+  -%%--------+------------/----------------------------ÿÀ  ¶" ÿÄ     ÿÄ @    !1AQaq‘¡"±ÁÑð2’BRráS‚ñ3b¢CT²Ò #cÿÄ    ÿÄ '   1!AQ2a"‘±#ÿÚ   ? ò(/p‘—–¢·,M|¯G»R£üešT. ôŸEoCFñ‡ 4ÔkåóxR|µÁ¨ÓDà!Ç´µ˜‡p ÍQ‹§!þž^õWsŒy  åÁ§$á«%ºq˜™JyyË0y«^Ϗ -3ÃÏËÈ£Æ\P’ä„s&•‹Üs üô'àWt¹pñCp$bÚF`·7.^)¾!)ÒÙ˜–ÅÏš^h¾ø³·ìe±ŒaeÖ—Í,e=B}Jéߦ$$½—šÙÜCC¯¶è8β–Åkèwx LÉngT±æ¹£Ócœ¿Í/©Éÿ ‰ÚCÒ­mq;Tt¶–}0"zÖPcd1š­¤tˆ„ÐÓâqú[™öUCŠ2޿د­É(¸ßúçšmW,Ò ºf‹Ån™ÄLêÁ8üÁkÁ€L¥ÍuJ1œôrÂSŒÓöt!7EUíïb)AËi¬â-ÙHk8òÁiXYwÅ)O^"ÇØriÛô{»wRUKÙÏÚlÓ¬€‚’שT ] ªb—ÊîKC^×M“xùäñz¬zJ× {4[¹M'IÆeH1LCWÕ]œûº WDæà°OÅ‚¹c²ÞuA–rL`HšpCez‡V’— Ž‚Ë„–ñ­'µR0ÕÖ=À:±G»C\nÆÉ5*¢ †3šhQ4ýÒi$Õ1"Ü]¢p-q3zcQ$ªö¨¥æf›‘»´ÝÚHá„e²JÇ–iÊ:·à¬Øc5Åk»Laª*wi [0Ówk ¦a¦0Õ²ÅÅ‚T¸’³q:Æ<¹ú Ò˜Æ}2VE•Ѐp¡Ô3Úº …h³^LJºçì¥Ánó|˜ÖˆÎˆ+« ¦dø‘Mº–d\ªDðÛ„Ì×LÝ——Ð9Ç|•FèçVm™¨€™3õS–9Äå¢<̉Ìm¢±`·º˜&Z²ž Ë®D«¶»6™‰©­HÈ Àá«h­i³04æ’hxœi3ï¨(ÓL·†‹¶ËpŒ ƒÜÒ? :õdsÀ –3æÓ·Üjâ¬9—]8n¼&]I F£¼…ì–—Œ0v°LǐÅfÛ2TÖ’aµ˜N@ÖBSÏ^à´4-±°b×nÈÈœÆD=KdŒø…ÄÈK,›ÖR§fjü$^ÔÎ!„6^ s:Üun\ôkCÞò÷<—Lúl Í›G¹ÀPá¼Nc¡šÒ…ÙWͳœ±vÊáЄ×9‹P‰cEØ‘™›µŸP<×g1 º©Ø¬wiÁ^l5× I/';Ë+´Z‡ÓÄFÕp[Èð’ HÄ ó 9¬Dl4“é±Ï”V=^Hð;žLädÉa‚°Ë,#/Ž~²BÔÛ QãñQtIeórVB,ÏÂf‹4#Μc‹É3ZIÖ Œ¢¥·üxa‡Ãçè„jŠ[5 Ä!U?,3žÎ×…ðdÓ÷háŠA‰ìÄ4÷ÃÜZÃE{‰®+W\ZÍE[‰»µk»MÝ­`¢©†˜ÃV‹-f¢¡†¢a«eŠ%«Y¨©q%jâd,Ôq`) ¤¦…šˆ ¦E>0Ùb²t–Ÿ  ÷jsςҒKÈcø(é›;k(’#ôŒQ ™C> õ³M9óºÆµ¤çâ;uÀ)5>RÔ¸fÓ~Ȧ—’-$fe«"FâUˆÊwµPÏu w+"åÉó¨6s™Û9(À¨ù©hE°½†n`m~“@©›p!Vkhµ Á1šbEqqÊ@ºèl›2 –Yã%‘‚hÛ{a¶‡ÅÞM²¬çL34®Çl]®‹ŽØŒm'RÜe35æöˆ­Á­ cP9šeÁköo´L³Ì=p8]”‡B¶,šº|ɏdzXˆØk*ÇÚ{#ñ‰pã(€¶‡9ý'šÜ³½¯kƒ†Â’ëSOƒ•Å®H6+a¢µˆ‹Y¨b˜b+XˆÖ!°u!¢"µˆˆn2ˆ Å0Ä`Å Ô®c(ÓÜGº•Ä»Œ âWî%q.áÐÄ÷î%umÍ£+ÜQ,Vn¦-GphU¸¢X­&,Gt ·K¢ÅÅ·¥RÄÊÉbKn N­R2g$VµÕó Qr#–ÓZUÏð0ÎtÙÀœz ëöo“Îk¯n„T°"SÞ+³/…€½"ižãO%Í%&Δâ‘ËØ´IˆÓ°Ë‰ÞM3.™yçÁzit›`4C`k¢¼á!álÄï sÂ[×!¤l¾æo"ƒIÔ'@ªu)3›ô®“@Z à¾] üœ'‡4¸PÞkÁ-qÄH‰ÓÍBd´ÿ —¹°ÄA&ÊUC„öz‚‚RæŠtf¬>˜ÑidšEçÑL÷áý¡V±h§­c¿¥¨ƒ@g¼…Ýö^ÞËc.ž„æ“I[ ª+·zÐÒÚ,½Ð»¶€C›7jk$๖€Ž¾ÅÙpp¶ÍþéΤ ½ØÎŒq ñpæžÅ¥#Øâ49ÃÂK^MYV“,¶Éz_òæ:…;Õ«¦I3âJ£¤û5$7Èxün\â]Êe¯(Ÿ&Ž‹¶2<6Ćf× æ¢ƱqWı[(ÙÂŽç‚T7¨@ÈÉÍß‚ïÙ"&3TYlGށ†)†#5ŠA©^T2ÆÁ†)©†©†¤yGXÁ†©"†)©¼ÅV WS†#©]R–r‹q5ÕbâWþBh¯u+ªÅÄ×ü„nÑ^êkªÁj‰jeœWˆÕÕ`µDµ2Ì+Ä µDµµ5Ô{¤Þ0RF’H÷AÛ<ÊÁ§ ƈæ0Ñ£ê4 öÚµ[¬/1²€â<-¬šö²r×0o×w ´xÐÒË„ g01¬„åEM蛇Ã\6µE›‘fÙO k÷CºnÓ1`iîÒ² áÂ!ÑLÄÿ ³¬\õ*:M=Ç»c‹2[‰ØsÕLò\ŒK L^™üÄN\¶#» Ç\……ßïIœÉ$¸ÎñÍ®ÔHÇ Ûí/´>Li”„†g^$ 7NÍÑÑ2M2ªNg=k½Ð}Ÿl6‡ —JWˆ”ÞéT·+µ¦üÂFè¢Vs6ýÆ4»2+2IÝ9ô9®ÇGÙÇ1+Ä8;*Õ§ž½D*îÑWÚçá3Ma¤·ˆ¥t}š²Ü…Q+Æüµ8HíS”üxGéÁˆ¦Ël„éÈ 5 µÄƒ6äÜ(kIš¯S†fÖ&¸®×v|Äyˆ*禌Éù@7-®Ä[]ÎÖ¿ê`º…=:…žJVnݳvðÖKE¼‚ »mà ÷f®:Ë ™–4rð¡4` ܹçž~‹C=œ…¾Ïj|VDtK.ƒ"9 Ï ­–éXá³6WÒïIL-Ї Ç PK}\xSU&U&api/preferences_test.phpnu[. namespace core_user\route\api; use core\tests\router\route_testcase; use GuzzleHttp\Psr7\Utils; /** * Tests for user preference API handler. * * @package core_user * @copyright Andrew Lyons * @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 */ 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 { $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); $this->assertEmpty((array) $payload); } /** * Test that the preferences are returned when logged in. */ public function test_preferences_returned(): void { $this->resetAfterTest(); $this->add_class_routes_to_route_loader(preferences::class); $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->assertObjectHasProperty('filemanager_recentviewmode', $payload); $this->assertEquals(1, $payload->filemanager_recentviewmode); } public function test_preference_returned(): void { $this->resetAfterTest(); $this->add_class_routes_to_route_loader(preferences::class); $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->assertObjectHasProperty('filemanager_recentviewmode', $payload); $this->assertEquals(1, $payload->filemanager_recentviewmode); } public function test_preferences_set(): 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' => 2, 'drawer-open-index' => 1, ], ])), ); $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); } } PK&}\}7D"$"$api/preferences.phpnu[. 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 * @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; } } PK&}\BFR R 'responses/user_preferences_response.phpnu[. 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 * @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\":[]}", ], ), ] ), ); } } PK)\mlCCcontroller/tags_controller.phpnu[. namespace core_course\route\controller; use core\exception\moodle_exception; use core\router\parameters\query_returnurl; use core\router\route; use core\router\require_login; use core\router\util; use core_course\form\tags_form; use core_tag_tag; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; /** * Tag management for courses. * * @package core_course * @copyright Andrew Lyons * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class tags_controller { use \core\router\route_controller; /** * Administer course tags. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @param \stdClass $course * @param \core\context\course $coursecontext * @return ResponseInterface */ #[route( path: '/{course}/tags', method: ['GET', 'POST'], pathtypes: [ new \core\router\parameters\path_course(), ], queryparams: [ new query_returnurl(), ], requirelogin: new require_login( requirelogin: true, courseattributename: 'course', ), )] public function administer_tags( ServerRequestInterface $request, ResponseInterface $response, \stdClass $course, \core\context\course $coursecontext, ): ResponseInterface { global $CFG, $OUTPUT, $PAGE; if (!$course->visible && !has_capability('moodle/course:viewhiddencourses', $coursecontext)) { throw new moodle_exception('coursehidden', '', $CFG->wwwroot .'/'); } require_capability('moodle/course:tag', $coursecontext); $PAGE->set_course($course); $PAGE->set_pagelayout('incourse'); $PAGE->set_url(util::get_path_for_callable([self::class, 'administer_tags'], [ 'course' => $course->id, ])); $PAGE->set_title(get_string('coursetags', 'tag')); $PAGE->set_heading($course->fullname); $form = new tags_form(); $data = [ 'id' => $course->id, 'tags' => core_tag_tag::get_item_tags_array('core', 'course', $course->id), ]; $form->set_data($data); $redirecturl = $this->get_param($request, 'returnurl') ?? course_get_url($course); if ($form->is_cancelled()) { return util::redirect($response, $redirecturl); } else if ($data = $form->get_data()) { core_tag_tag::set_item_tags('core', 'course', $course->id, $coursecontext, $data->tags); return util::redirect($response, $redirecturl); } $response->getBody()->write($OUTPUT->header()); $response->getBody()->write($OUTPUT->heading(get_string('coursetags', 'tag'))); $response->getBody()->write($form->render()); $response->getBody()->write($OUTPUT->footer()); return $response; } } PK)\{> > controller/course_management.phpnu[. namespace core_course\route\controller; use core\router\route; use core\router\require_login; use navigation_node; use Psr\Http\Message\ResponseInterface; /** * Course Management. * * @package core_course * @copyright Andrew Lyons * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class course_management { use \core\router\route_controller; /** * Administer a course. * * @param ResponseInterface $response * @param \stdClass $course * @return ResponseInterface */ #[route( path: '/{course}/manage', pathtypes: [ new \core\router\parameters\path_course(), ], requirelogin: new require_login( requirelogin: true, courseattributename: 'course', ), )] public function administer_course( ResponseInterface $response, \stdClass $course, ): ResponseInterface { global $PAGE, $SITE, $OUTPUT; $PAGE->set_pagelayout('incourse'); if ($course->id == $SITE->id) { $title = get_string('frontpagesettings'); $node = $PAGE->settingsnav->find('frontpage', navigation_node::TYPE_SETTING); $PAGE->set_primary_active_tab('home'); } else { $title = get_string('courseadministration'); $node = $PAGE->settingsnav->find('courseadmin', navigation_node::TYPE_COURSE); } $PAGE->set_title($title); $PAGE->set_heading($course->fullname); $PAGE->navbar->add($title); $response->getBody()->write($OUTPUT->header()); $response->getBody()->write($OUTPUT->heading($title)); if ($node) { $response->getBody()->write($OUTPUT->render_from_template('core/settings_link_page', ['node' => $node])); } $response->getBody()->write($OUTPUT->footer()); return $response; } } PK)\'f  shim/course_routes.phpnu[. namespace core_course\route\shim; use core\param; use core\router\route; use core\router\route_controller; use core\router\schema\parameters\query_parameter; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; /** * A shim for the course routes. * * @package core_course * @copyright Andrew Lyons * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ final class course_routes { use route_controller; /** * Shim /course/admin.php to the course management controller. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @return ResponseInterface */ #[route( path: '/admin.php', queryparams: [ new query_parameter( name: 'courseid', type: param::INT, description: 'The course ID', required: true, ), ], )] public function administer_course( ServerRequestInterface $request, ResponseInterface $response, ): ResponseInterface { $params = $request->getQueryParams(); return self::redirect_to_callable( $request, $response, [\core_course\route\controller\course_management::class, 'administer_course'], pathparams: $params + ['course' => $params['courseid']], excludeparams: ['courseid'], ); } /** * Shim /course/tags.php to the course tag management controller. * * @param ServerRequestInterface $request * @param ResponseInterface $response * @return ResponseInterface */ #[route( path: '/tags.php', queryparams: [ new query_parameter( name: 'id', type: param::INT, description: 'The course ID', required: true, ), new query_parameter( name: 'returnurl', type: param::LOCALURL, description: 'The return URL', required: false, ), ], )] public function administer_tags( ServerRequestInterface $request, ResponseInterface $response, ): ResponseInterface { $params = $request->getQueryParams(); return self::redirect_to_callable( $request, $response, [\core_course\route\controller\tags_controller::class, 'administer_tags'], pathparams: $params + ['course' => $params['id']], excludeparams: ['id'], ); } } PK}\xSU&U&api/preferences_test.phpnu[PK&}\}7D"$"$&api/preferences.phpnu[PK&}\BFR R 'Kresponses/user_preferences_response.phpnu[PK)\mlCCTcontroller/tags_controller.phpnu[PK)\{> >