ÿØÿà 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(\׾$#$#course_handler.phpnu[. /** * Course handler for custom fields * * @package core_course * @copyright 2018 David Matamoros * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace core_course\customfield; defined('MOODLE_INTERNAL') || die; use core_customfield\api; use core_customfield\field_controller; /** * Course handler for custom fields * * @package core_course * @copyright 2018 David Matamoros * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class course_handler extends \core_customfield\handler { /** * @var course_handler */ static protected $singleton; /** * @var \context */ protected $parentcontext; /** @var int Field is displayed in the course listing, visible to everybody */ const VISIBLETOALL = 2; /** @var int Field is displayed in the course listing but only for teachers */ const VISIBLETOTEACHERS = 1; /** @var int Field is not displayed in the course listing */ const NOTVISIBLE = 0; /** * Returns a singleton * * @param int $itemid * @return \core_course\customfield\course_handler */ public static function create(int $itemid = 0): \core_customfield\handler { if (static::$singleton === null) { self::$singleton = new static(0); } return self::$singleton; } /** * Run reset code after unit tests to reset the singleton usage. */ public static function reset_caches(): void { if (!PHPUNIT_TEST) { throw new \coding_exception('This feature is only intended for use in unit tests'); } static::$singleton = null; } /** * The current user can configure custom fields on this component. * * @return bool true if the current can configure custom fields, false otherwise */ public function can_configure(): bool { return has_capability('moodle/course:configurecustomfields', $this->get_configuration_context()); } /** * The current user can edit custom fields on the given course. * * @param field_controller $field * @param int $instanceid id of the course to test edit permission * @return bool true if the current can edit custom fields, false otherwise */ public function can_edit(field_controller $field, int $instanceid = 0): bool { if ($instanceid) { $context = $this->get_instance_context($instanceid); return (!$field->get_configdata_property('locked') || has_capability('moodle/course:changelockedcustomfields', $context)); } else { $context = $this->get_parent_context(); if ($context->contextlevel == CONTEXT_SYSTEM) { return (!$field->get_configdata_property('locked') || has_capability('moodle/course:changelockedcustomfields', $context)); } else { return (!$field->get_configdata_property('locked') || guess_if_creator_will_have_course_capability('moodle/course:changelockedcustomfields', $context)); } } } /** * The current user can view custom fields on the given course. * * @param field_controller $field * @param int $instanceid id of the course to test edit permission * @return bool true if the current can edit custom fields, false otherwise */ public function can_view(field_controller $field, int $instanceid): bool { $visibility = $field->get_configdata_property('visibility'); if ($visibility == self::NOTVISIBLE) { return false; } else if ($visibility == self::VISIBLETOTEACHERS) { return has_capability('moodle/course:update', $this->get_instance_context($instanceid)); } else { return true; } } /** * Sets parent context for the course * * This may be needed when course is being created, there is no course context but we need to check capabilities * * @param \context $context */ public function set_parent_context(\context $context) { $this->parentcontext = $context; } /** * Returns the parent context for the course * * @return \context */ protected function get_parent_context(): \context { global $PAGE; if ($this->parentcontext) { return $this->parentcontext; } else if ($PAGE->context && $PAGE->context instanceof \context_coursecat) { return $PAGE->context; } return \context_system::instance(); } /** * Context that should be used for new categories created by this handler * * @return \context the context for configuration */ public function get_configuration_context(): \context { return \context_system::instance(); } /** * URL for configuration of the fields on this handler. * * @return \moodle_url The URL to configure custom fields for this component */ public function get_configuration_url(): \moodle_url { return new \moodle_url('/course/customfield.php'); } /** * Returns the context for the data associated with the given instanceid. * * @param int $instanceid id of the record to get the context for * @return \context the context for the given record */ public function get_instance_context(int $instanceid = 0): \context { if ($instanceid > 0) { return \context_course::instance($instanceid); } else { return \context_system::instance(); } } /** * Allows to add custom controls to the field configuration form that will be saved in configdata * * @param \MoodleQuickForm $mform */ public function config_form_definition(\MoodleQuickForm $mform) { $mform->addElement('header', 'course_handler_header', get_string('customfieldsettings', 'core_course')); $mform->setExpanded('course_handler_header', true); // If field is locked. $mform->addElement('selectyesno', 'configdata[locked]', get_string('customfield_islocked', 'core_course')); $mform->addHelpButton('configdata[locked]', 'customfield_islocked', 'core_course'); // Field data visibility. $visibilityoptions = [self::VISIBLETOALL => get_string('customfield_visibletoall', 'core_course'), self::VISIBLETOTEACHERS => get_string('customfield_visibletoteachers', 'core_course'), self::NOTVISIBLE => get_string('customfield_notvisible', 'core_course')]; $mform->addElement('select', 'configdata[visibility]', get_string('customfield_visibility', 'core_course'), $visibilityoptions); $mform->addHelpButton('configdata[visibility]', 'customfield_visibility', 'core_course'); } /** * Creates or updates custom field data. * * @param \restore_task $task * @param array $data * * @return int|void Conditionally returns the ID of the created or updated record. */ public function restore_instance_data_from_backup(\restore_task $task, array $data) { $courseid = $task->get_courseid(); $context = $this->get_instance_context($courseid); $editablefields = $this->get_editable_fields($courseid); $records = api::get_instance_fields_data($editablefields, $courseid); $target = $task->get_target(); $override = ($target != \backup::TARGET_CURRENT_ADDING && $target != \backup::TARGET_EXISTING_ADDING); foreach ($records as $d) { $field = $d->get_field(); if ($field->get('shortname') === $data['shortname'] && $field->get('type') === $data['type']) { if (!$d->get('id') || $override) { $d->set($d->datafield(), $data['value']); $d->set('value', $data['value']); $d->set('valueformat', $data['valueformat']); $d->set('valuetrust', !empty($data['valuetrust'])); $d->set('contextid', $context->id); $d->save(); } return $d->get('id'); } } } } PKˌ\5kkcohort_handler.phpnu[. namespace core_cohort\customfield; use core_customfield\handler; use core_customfield\field_controller; /** * Cohort handler for custom fields. * * @package core_cohort * @copyright 2023 Dmitrii Metelkin * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class cohort_handler extends handler { /** * @var cohort_handler */ static protected $singleton; /** * Returns a singleton. * * @param int $itemid * @return \core_customfield\handler */ public static function create(int $itemid = 0): handler { if (static::$singleton === null) { self::$singleton = new static(0); } return self::$singleton; } /** * Run reset code after unit tests to reset the singleton usage. */ public static function reset_caches(): void { if (!PHPUNIT_TEST) { throw new \coding_exception('This feature is only intended for use in unit tests'); } static::$singleton = null; } /** * The current user can configure custom fields on this component. * * @return bool true if the current can configure custom fields, false otherwise */ public function can_configure(): bool { return has_capability('moodle/cohort:configurecustomfields', $this->get_configuration_context()); } /** * The current user can edit custom fields on the given cohort. * * @param field_controller $field * @param int $instanceid id of the cohort to test edit permission * @return bool true if the current can edit custom field, false otherwise */ public function can_edit(field_controller $field, int $instanceid = 0): bool { return has_capability('moodle/cohort:manage', $this->get_instance_context($instanceid)); } /** * The current user can view custom fields on the given cohort. * * @param field_controller $field * @param int $instanceid id of the cohort to test edit permission * @return bool true if the current can view custom field, false otherwise */ public function can_view(field_controller $field, int $instanceid): bool { return has_any_capability(['moodle/cohort:manage', 'moodle/cohort:view'], $this->get_instance_context($instanceid)); } /** * Context that should be used for new categories created by this handler. * * @return \context the context for configuration */ public function get_configuration_context(): \context { return \context_system::instance(); } /** * URL for configuration of the fields on this handler. * * @return \moodle_url The URL to configure custom fields for this component */ public function get_configuration_url(): \moodle_url { return new \moodle_url('/cohort/customfield.php'); } /** * Returns the context for the data associated with the given instanceid. * * @param int $instanceid id of the record to get the context for * @return \context the context for the given record */ public function get_instance_context(int $instanceid = 0): \context { global $DB; if ($instanceid > 0) { $cohort = $DB->get_record('cohort', ['id' => $instanceid], '*', MUST_EXIST); return \context::instance_by_id($cohort->contextid, MUST_EXIST); } else { return \context_system::instance(); } } } PK\:;;cohort_handler_test.phpnu[. namespace core_cohort\customfield; use advanced_testcase; use context_system; use context_coursecat; use moodle_url; use core_customfield\field_controller; /** * Unit tests for cohort custom field handler. * * @package core_cohort * @covers \core_cohort\customfield\cohort_handler * @copyright 2022 Dmitrii Metelkin * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ final class cohort_handler_test extends advanced_testcase { /** * Test custom field handler. * @var \core_customfield\handler */ protected $handler; /** * Setup. */ public function setUp(): void { parent::setUp(); $this->handler = cohort_handler::create(); } /** * Create Cohort custom field for testing. * * @return field_controller */ protected function create_cohort_custom_field(): field_controller { $fieldcategory = self::getDataGenerator()->create_custom_field_category([ 'component' => 'core_cohort', 'area' => 'cohort', ]); return self::getDataGenerator()->create_custom_field([ 'shortname' => 'testfield1', 'type' => 'text', 'categoryid' => $fieldcategory->get('id'), ]); } /** * Test configuration context. */ public function test_get_configuration_context(): void { $this->assertInstanceOf(context_system::class, $this->handler->get_configuration_context()); } /** * Test getting config URL. */ public function test_get_configuration_url(): void { $this->assertInstanceOf(moodle_url::class, $this->handler->get_configuration_url()); $this->assertEquals('/cohort/customfield.php', $this->handler->get_configuration_url()->out_as_local_url()); } /** * Test can configure check. */ public function test_can_configure(): void { $this->resetAfterTest(); $user = self::getDataGenerator()->create_user(); self::setUser($user); $this->assertFalse($this->handler->can_configure()); $roleid = self::getDataGenerator()->create_role(); assign_capability('moodle/cohort:configurecustomfields', CAP_ALLOW, $roleid, context_system::instance()->id, true); role_assign($roleid, $user->id, context_system::instance()->id); $this->assertTrue($this->handler->can_configure()); } /** * Test getting instance context. */ public function test_get_instance_context(): void { $this->resetAfterTest(); $category = self::getDataGenerator()->create_category(); $catcontext = context_coursecat::instance($category->id); $systemcontext = context_system::instance(); $cohortsystem = self::getDataGenerator()->create_cohort(); $cohortcategory = self::getDataGenerator()->create_cohort(['contextid' => $catcontext->id]); $this->assertInstanceOf(context_system::class, $this->handler->get_instance_context($cohortsystem->id)); $this->assertSame($systemcontext, $this->handler->get_instance_context($cohortsystem->id)); $this->assertInstanceOf(context_coursecat::class, $this->handler->get_instance_context($cohortcategory->id)); $this->assertSame($catcontext, $this->handler->get_instance_context($cohortcategory->id)); } /** * Test can edit functionality. */ public function test_can_edit(): void { $this->resetAfterTest(); $roleid = self::getDataGenerator()->create_role(); assign_capability('moodle/cohort:manage', CAP_ALLOW, $roleid, context_system::instance()->id, true); $field = $this->create_cohort_custom_field(); $user = self::getDataGenerator()->create_user(); self::setUser($user); $this->assertFalse($this->handler->can_edit($field, 0)); role_assign($roleid, $user->id, context_system::instance()->id); $this->assertTrue($this->handler->can_edit($field, 0)); } /** * Test can view functionality. */ public function test_can_view(): void { $this->resetAfterTest(); $manageroleid = self::getDataGenerator()->create_role(); assign_capability('moodle/cohort:manage', CAP_ALLOW, $manageroleid, context_system::instance()->id, true); $viewroleid = self::getDataGenerator()->create_role(); assign_capability('moodle/cohort:view', CAP_ALLOW, $viewroleid, context_system::instance()->id, true); $viewandmanageroleid = self::getDataGenerator()->create_role(); assign_capability('moodle/cohort:manage', CAP_ALLOW, $viewandmanageroleid, context_system::instance()->id, true); assign_capability('moodle/cohort:view', CAP_ALLOW, $viewandmanageroleid, context_system::instance()->id, true); $field = $this->create_cohort_custom_field(); $cohort = self::getDataGenerator()->create_cohort(); $user1 = self::getDataGenerator()->create_user(); $user2 = self::getDataGenerator()->create_user(); $user3 = self::getDataGenerator()->create_user(); self::setUser($user1); $this->assertFalse($this->handler->can_view($field, $cohort->id)); self::setUser($user2); $this->assertFalse($this->handler->can_view($field, $cohort->id)); self::setUser($user3); $this->assertFalse($this->handler->can_view($field, $cohort->id)); role_assign($manageroleid, $user1->id, context_system::instance()->id); role_assign($viewroleid, $user2->id, context_system::instance()->id); role_assign($viewandmanageroleid, $user3->id, context_system::instance()->id); self::setUser($user1); $this->assertTrue($this->handler->can_view($field, $cohort->id)); self::setUser($user2); $this->assertTrue($this->handler->can_view($field, $cohort->id)); self::setUser($user3); $this->assertTrue($this->handler->can_view($field, $cohort->id)); } } PK(\׾$#$#course_handler.phpnu[PKˌ\5kkf#cohort_handler.phpnu[PK\:;;4cohort_handler_test.phpnu[PKN