Merge branch 'MDL-77130-master-v2' of https://github.com/dmitriim/moodle

This commit is contained in:
Ilya Tregubov 2023-04-05 19:20:30 +08:00 committed by Sara Arjona
commit ac7f9b45a3
16 changed files with 1008 additions and 35 deletions

View File

@ -101,7 +101,15 @@ if ($hassiteconfig
$ADMIN->add('accounts', new admin_externalpage('profilefields', new lang_string('profilefields','admin'), "$CFG->wwwroot/user/profile/index.php", 'moodle/site:config'));
$ADMIN->add('accounts', new admin_externalpage('cohorts', new lang_string('cohorts', 'cohort'), $CFG->wwwroot . '/cohort/index.php', array('moodle/cohort:manage', 'moodle/cohort:view')));
$ADMIN->add(
'accounts',
new admin_externalpage(
'cohort_customfield',
new lang_string('cohort_customfield', 'admin'),
$CFG->wwwroot . '/cohort/customfield.php',
['moodle/cohort:configurecustomfields']
)
);
// Stuff under the "roles" subcategory.

View File

@ -0,0 +1,124 @@
<?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_cohort\customfield;
use core_customfield\handler;
use core_customfield\field_controller;
/**
* Cohort handler for custom fields.
*
* @package core_cohort
* @copyright 2023 Dmitrii Metelkin <dmitriim@catalyst-au.net>
* @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();
}
}
}

40
cohort/customfield.php Normal file
View File

@ -0,0 +1,40 @@
<?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/>.
/**
* Manage cohort custom fields
*
* @package core_cohort
* @copyright 2023 Dmitrii Metelkin <dmitriim@catalyst-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
use core_cohort\customfield\cohort_handler;
use core_customfield\output\management;
require_once('../config.php');
require_once($CFG->libdir . '/adminlib.php');
admin_externalpage_setup('cohort_customfield');
$output = $PAGE->get_renderer('core_customfield');
$handler = cohort_handler::create();
$outputpage = new management($handler);
echo $output->header(),
$output->heading(new lang_string('cohort_customfield', 'admin')),
$output->render($outputpage),
$output->footer();

View File

@ -69,8 +69,12 @@ class cohort_edit_form extends moodleform {
$mform->setType('returnurl', PARAM_LOCALURL);
}
$handler = core_cohort\customfield\cohort_handler::create();
$handler->instance_form_definition($mform, empty($cohort->id) ? 0 : $cohort->id);
$this->add_action_buttons();
$handler->instance_form_before_set_data($cohort);
$this->set_data($cohort);
}
@ -97,6 +101,9 @@ class cohort_edit_form extends moodleform {
}
}
$handler = core_cohort\customfield\cohort_handler::create();
$errors = array_merge($errors, $handler->instance_form_validation($data, $files));
return $errors;
}
@ -118,5 +125,14 @@ class cohort_edit_form extends moodleform {
}
return $options;
}
/**
* Apply a logic after data is set.
*/
public function definition_after_data() {
$cohortid = $this->_form->getElementValue('id');
$handler = core_cohort\customfield\cohort_handler::create();
$handler->instance_form_definition_after_data($this->_form, empty($cohortid) ? 0 : $cohortid);
}
}

View File

@ -23,6 +23,10 @@ use core_external\external_value;
use core_external\external_warnings;
use core_external\util;
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot . '/cohort/lib.php');
/**
* External cohort API
*
@ -62,6 +66,7 @@ class core_cohort_external extends external_api {
'the cohort theme. The allowcohortthemes setting must be enabled on Moodle',
VALUE_OPTIONAL
),
'customfields' => self::build_custom_fields_parameters_structure(),
)
)
)
@ -128,6 +133,16 @@ class core_cohort_external extends external_api {
// Validate format.
$cohort->descriptionformat = util::validate_format($cohort->descriptionformat);
// Custom fields.
if (!empty($cohort->customfields)) {
foreach ($cohort->customfields as $field) {
$fieldname = self::build_custom_field_name($field['shortname']);
$cohort->{$fieldname} = $field['value'];
}
unset($cohort->customfields);
}
$cohort->id = cohort_add_cohort($cohort);
list($cohort->description, $cohort->descriptionformat) =
@ -249,10 +264,14 @@ class core_cohort_external extends external_api {
if (empty($cohortids)) {
$cohorts = $DB->get_records('cohort');
if (!empty($cohorts)) {
$cohortids = array_keys($cohorts);
}
} else {
$cohorts = $DB->get_records_list('cohort', 'id', $params['cohortids']);
}
$customfieldsdata = self::get_custom_fields_data($cohortids);
$cohortsinfo = array();
foreach ($cohorts as $cohort) {
// Now security checks.
@ -274,6 +293,7 @@ class core_cohort_external extends external_api {
\core_external\util::format_text($cohort->description, $cohort->descriptionformat,
$context, 'cohort', 'description', $cohort->id);
$cohort->customfields = !empty($customfieldsdata[$cohort->id]) ? $customfieldsdata[$cohort->id] : [];
$cohortsinfo[] = (array) $cohort;
}
return $cohortsinfo;
@ -297,6 +317,7 @@ class core_cohort_external extends external_api {
'descriptionformat' => new external_format_value('description'),
'visible' => new external_value(PARAM_BOOL, 'cohort visible'),
'theme' => new external_value(PARAM_THEME, 'cohort theme', VALUE_OPTIONAL),
'customfields' => self::build_custom_fields_returns_structure(),
)
)
);
@ -391,6 +412,12 @@ class core_cohort_external extends external_api {
}
$cohorts = array();
if (!empty($results)) {
$cohortids = array_keys($results);
$customfieldsdata = self::get_custom_fields_data($cohortids);
}
foreach ($results as $key => $cohort) {
$cohortcontext = context::instance_by_id($cohort->contextid);
@ -410,6 +437,8 @@ class core_cohort_external extends external_api {
\core_external\util::format_text($cohort->description, $cohort->descriptionformat,
$cohortcontext, 'cohort', 'description', $cohort->id);
$cohort->customfields = !empty($customfieldsdata[$cohort->id]) ? $customfieldsdata[$cohort->id] : [];
$cohorts[$key] = $cohort;
}
@ -432,6 +461,7 @@ class core_cohort_external extends external_api {
'descriptionformat' => new external_format_value('description'),
'visible' => new external_value(PARAM_BOOL, 'cohort visible'),
'theme' => new external_value(PARAM_THEME, 'cohort theme', VALUE_OPTIONAL),
'customfields' => self::build_custom_fields_returns_structure(),
))
)
));
@ -469,6 +499,7 @@ class core_cohort_external extends external_api {
'the cohort theme. The allowcohortthemes setting must be enabled on Moodle',
VALUE_OPTIONAL
),
'customfields' => self::build_custom_fields_parameters_structure(),
)
)
)
@ -541,6 +572,15 @@ class core_cohort_external extends external_api {
$cohort->descriptionformat = util::validate_format($cohort->descriptionformat);
}
// Custom fields.
if (!empty($cohort->customfields)) {
foreach ($cohort->customfields as $field) {
$fieldname = self::build_custom_field_name($field['shortname']);
$cohort->{$fieldname} = $field['value'];
}
unset($cohort->customfields);
}
cohort_update_cohort($cohort);
}
@ -825,4 +865,77 @@ class core_cohort_external extends external_api {
)
);
}
/**
* Builds a structure for custom fields parameters.
*
* @return \core_external\external_multiple_structure
*/
protected static function build_custom_fields_parameters_structure(): external_multiple_structure {
return new external_multiple_structure(
new external_single_structure(
array(
'shortname' => new external_value(PARAM_ALPHANUMEXT, 'The shortname of the custom field'),
'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
)
), 'Custom fields for the cohort', VALUE_OPTIONAL
);
}
/**
* Builds a structure for custom fields returns.
*
* @return \core_external\external_multiple_structure
*/
protected static function build_custom_fields_returns_structure(): external_multiple_structure {
return new external_multiple_structure(
new external_single_structure(
array(
'name' => new external_value(PARAM_RAW, 'The name of the custom field'),
'shortname' => new external_value(PARAM_RAW,
'The shortname of the custom field - to be able to build the field class in the code'),
'type' => new external_value(PARAM_ALPHANUMEXT,
'The type of the custom field - text field, checkbox...'),
'valueraw' => new external_value(PARAM_RAW, 'The raw value of the custom field'),
'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
)
), 'Custom fields', VALUE_OPTIONAL
);
}
/**
* Returns custom fields data for provided cohorts.
*
* @param array $cohortids a list of cohort IDs to provide data for.
* @return array
*/
protected static function get_custom_fields_data(array $cohortids): array {
$result = [];
$customfieldsdata = cohort_get_custom_fields_data($cohortids);
foreach ($customfieldsdata as $cohortid => $fieldcontrollers) {
foreach ($fieldcontrollers as $fieldcontroller) {
$result[$cohortid][] = [
'type' => $fieldcontroller->get_field()->get('type'),
'value' => $fieldcontroller->export_value(),
'valueraw' => $fieldcontroller->get_value(),
'name' => $fieldcontroller->get_field()->get('name'),
'shortname' => $fieldcontroller->get_field()->get('shortname'),
];
}
}
return $result;
}
/**
* Builds a suitable name of a custom field for a custom field handler based on provided shortname.
*
* @param string $shortname shortname to use.
* @return string
*/
protected static function build_custom_field_name(string $shortname): string {
return 'customfield_' . $shortname;
}
}

View File

@ -73,6 +73,9 @@ function cohort_add_cohort($cohort) {
$cohort->id = $DB->insert_record('cohort', $cohort);
$handler = core_cohort\customfield\cohort_handler::create();
$handler->instance_form_save($cohort, true);
$event = \core\event\cohort_created::create(array(
'context' => context::instance_by_id($cohort->contextid),
'objectid' => $cohort->id,
@ -99,6 +102,11 @@ function cohort_update_cohort($cohort) {
unset($cohort->theme);
}
$cohort->timemodified = time();
// Update custom fields if there are any of them in the form.
$handler = core_cohort\customfield\cohort_handler::create();
$handler->instance_form_save($cohort);
$DB->update_record('cohort', $cohort);
$event = \core\event\cohort_updated::create(array(
@ -120,6 +128,9 @@ function cohort_delete_cohort($cohort) {
// TODO: add component delete callback
}
$handler = core_cohort\customfield\cohort_handler::create();
$handler->delete_instance($cohort->id);
$DB->delete_records('cohort_members', array('cohortid'=>$cohort->id));
$DB->delete_records('cohort', array('id'=>$cohort->id));
@ -234,9 +245,11 @@ function cohort_is_member($cohortid, $userid) {
* @param int $offset
* @param int $limit
* @param string $search
* @param bool $withcustomfields if set to yes, then cohort custom fields will be included in the results.
* @return array
*/
function cohort_get_available_cohorts($currentcontext, $withmembers = 0, $offset = 0, $limit = 25, $search = '') {
function cohort_get_available_cohorts($currentcontext, $withmembers = 0, $offset = 0, $limit = 25,
$search = '', $withcustomfields = false) {
global $DB;
$params = array();
@ -312,7 +325,18 @@ function cohort_get_available_cohorts($currentcontext, $withmembers = 0, $offset
ORDER BY c.name, c.idnumber";
}
return $DB->get_records_sql($sql, $params, $offset, $limit);
$cohorts = $DB->get_records_sql($sql, $params, $offset, $limit);
if ($withcustomfields) {
$cohortids = array_keys($cohorts);
$customfieldsdata = cohort_get_custom_fields_data($cohortids);
foreach ($cohorts as $cohort) {
$cohort->customfields = !empty($customfieldsdata[$cohort->id]) ? $customfieldsdata[$cohort->id] : [];
}
}
return $cohorts;
}
/**
@ -347,9 +371,10 @@ function cohort_can_view_cohort($cohortorid, $currentcontext) {
*
* @param stdClass|int $cohortorid cohort object or id
* @param context $currentcontext current context (course) where visibility is checked
* @param bool $withcustomfields if set to yes, then cohort custom fields will be included in the results.
* @return stdClass|boolean
*/
function cohort_get_cohort($cohortorid, $currentcontext) {
function cohort_get_cohort($cohortorid, $currentcontext, $withcustomfields = false) {
global $DB;
if (is_numeric($cohortorid)) {
$cohort = $DB->get_record('cohort', array('id' => $cohortorid), 'id, contextid, visible');
@ -358,15 +383,22 @@ function cohort_get_cohort($cohortorid, $currentcontext) {
}
if ($cohort && in_array($cohort->contextid, $currentcontext->get_parent_context_ids())) {
if ($cohort->visible) {
return $cohort;
}
$cohortcontext = context::instance_by_id($cohort->contextid);
if (has_capability('moodle/cohort:view', $cohortcontext)) {
return $cohort;
if (!$cohort->visible) {
$cohort = false;
} else {
$cohortcontext = context::instance_by_id($cohort->contextid);
if (!has_capability('moodle/cohort:view', $cohortcontext)) {
$cohort = false;
}
}
}
return false;
if ($cohort && $withcustomfields) {
$customfieldsdata = cohort_get_custom_fields_data([$cohort->id]);
$cohort->customfields = !empty($customfieldsdata[$cohort->id]) ? $customfieldsdata[$cohort->id] : [];
}
return $cohort;
}
/**
@ -413,9 +445,10 @@ function cohort_get_search_query($search, $tablealias = '') {
* @param int $page number of the current page
* @param int $perpage items per page
* @param string $search search string
* @param bool $withcustomfields if set to yes, then cohort custom fields will be included in the results.
* @return array Array(totalcohorts => int, cohorts => array, allcohorts => int)
*/
function cohort_get_cohorts($contextid, $page = 0, $perpage = 25, $search = '') {
function cohort_get_cohorts($contextid, $page = 0, $perpage = 25, $search = '', $withcustomfields = false) {
global $DB;
$fields = "SELECT *";
@ -437,6 +470,15 @@ function cohort_get_cohorts($contextid, $page = 0, $perpage = 25, $search = '')
}
$cohorts = $DB->get_records_sql($fields . $sql . $order, $params, $page*$perpage, $perpage);
if ($withcustomfields) {
$cohortids = array_keys($cohorts);
$customfieldsdata = cohort_get_custom_fields_data($cohortids);
foreach ($cohorts as $cohort) {
$cohort->customfields = !empty($customfieldsdata[$cohort->id]) ? $customfieldsdata[$cohort->id] : [];
}
}
return array('totalcohorts' => $totalcohorts, 'cohorts' => $cohorts, 'allcohorts' => $allcohorts);
}
@ -450,9 +492,10 @@ function cohort_get_cohorts($contextid, $page = 0, $perpage = 25, $search = '')
* @param int $page number of the current page
* @param int $perpage items per page
* @param string $search search string
* @param bool $withcustomfields if set to yes, then cohort custom fields will be included in the results.
* @return array Array(totalcohorts => int, cohorts => array, allcohorts => int)
*/
function cohort_get_all_cohorts($page = 0, $perpage = 25, $search = '') {
function cohort_get_all_cohorts($page = 0, $perpage = 25, $search = '', $withcustomfields = false) {
global $DB;
$fields = "SELECT c.*, ".context_helper::get_preload_record_columns_sql('ctx');
@ -480,9 +523,17 @@ function cohort_get_all_cohorts($page = 0, $perpage = 25, $search = '') {
$order = " ORDER BY c.name ASC, c.idnumber ASC";
$cohorts = $DB->get_records_sql($fields . $sql . $wheresql . $order, $params, $page*$perpage, $perpage);
// Preload used contexts, they will be used to check view/manage/assign capabilities and display categories names.
foreach (array_keys($cohorts) as $key) {
context_helper::preload_from_record($cohorts[$key]);
if ($withcustomfields) {
$cohortids = array_keys($cohorts);
$customfieldsdata = cohort_get_custom_fields_data($cohortids);
}
foreach ($cohorts as $cohort) {
// Preload used contexts, they will be used to check view/manage/assign capabilities and display categories names.
context_helper::preload_from_record($cohort);
if ($withcustomfields) {
$cohort->customfields = !empty($customfieldsdata[$cohort->id]) ? $customfieldsdata[$cohort->id] : [];
}
}
return array('totalcohorts' => $totalcohorts, 'cohorts' => $cohorts, 'allcohorts' => $allcohorts);
@ -492,16 +543,28 @@ function cohort_get_all_cohorts($page = 0, $perpage = 25, $search = '') {
* Get all the cohorts where the given user is member of.
*
* @param int $userid
* @param bool $withcustomfields if set to yes, then cohort custom fields will be included in the results.
* @return array Array
*/
function cohort_get_user_cohorts($userid) {
function cohort_get_user_cohorts($userid, $withcustomfields = false) {
global $DB;
$sql = 'SELECT c.*
FROM {cohort} c
JOIN {cohort_members} cm ON c.id = cm.cohortid
WHERE cm.userid = ? AND c.visible = 1';
return $DB->get_records_sql($sql, array($userid));
$cohorts = $DB->get_records_sql($sql, array($userid));
if ($withcustomfields) {
$cohortids = array_keys($cohorts);
$customfieldsdata = cohort_get_custom_fields_data($cohortids);
foreach ($cohorts as $cohort) {
$cohort->customfields = !empty($customfieldsdata[$cohort->id]) ? $customfieldsdata[$cohort->id] : [];
}
}
return $cohorts;
}
/**
@ -635,3 +698,20 @@ function cohort_get_list_of_themes() {
}
return $themes;
}
/**
* Returns custom fields data for provided cohorts.
*
* @param array $cohortids a list of cohort IDs to provide data for.
* @return \core_customfield\data_controller[]
*/
function cohort_get_custom_fields_data(array $cohortids): array {
$result = [];
if (!empty($cohortids)) {
$handler = core_cohort\customfield\cohort_handler::create();
$result = $handler->get_instances_data($cohortids, true);
}
return $result;
}

View File

@ -0,0 +1,39 @@
@core @core_cohort @core_customfield @javascript
Feature: Add and use cohort custom fields
In order to store an extra information about cohorts
As an admin
I need to create cohort customs fields and be able to populate them on cohort creation
Background:
Given the following "custom field categories" exist:
| name | component | area | itemid |
| Category for test | core_cohort | cohort | 0 |
Scenario: Create a new cohort custom field and use the field for a new cohort
When I log in as "admin"
And I navigate to "Users > Accounts > Cohort custom fields" in site administration
And I click on "Add a new custom field" "link"
And I click on "Short text" "link"
And I set the following fields to these values:
| Name | Test field |
| Short name | testfield |
And I click on "Save changes" "button" in the "Adding a new Short text" "dialogue"
Then the following should exist in the "generaltable" table:
| Custom field | Short name | Type |
| Test field | testfield | Short text |
And I navigate to "Users > Accounts > Cohorts" in site administration
And I follow "Add new cohort"
Then I should see "Category for test"
And I should see "Test field"
And I set the following fields to these values:
| Name | My new cohort |
| Context | System |
| Cohort ID | mynewcohort |
| Description | My new cohort description |
| Test field | Custom field text |
And I press "Save changes"
Then the following should exist in the "generaltable" table:
| Name | Cohort ID | Description |
| My new cohort | mynewcohort | My new cohort description |
And I press "Edit" action in the "My new cohort" report row
And the field "Test field" matches value "Custom field text"

View File

@ -0,0 +1,182 @@
<?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_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 <dmitriim@catalys-au.net>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class cohort_handler_test extends advanced_testcase {
/**
* Test custom field handler.
* @var \core_customfield\handler
*/
protected $handler;
/**
* Setup.
*/
public function setUp(): void {
$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() {
$this->assertInstanceOf(context_system::class, $this->handler->get_configuration_context());
}
/**
* Test getting config URL.
*/
public function test_get_configuration_url() {
$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() {
$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() {
$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() {
$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() {
$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));
}
}

View File

@ -19,6 +19,7 @@ namespace core_cohort;
use core_cohort_external;
use core_external\external_api;
use externallib_advanced_testcase;
use core_cohort\customfield\cohort_handler;
defined('MOODLE_INTERNAL') || die();
@ -37,11 +38,34 @@ require_once($CFG->dirroot . '/cohort/externallib.php');
*/
class externallib_test extends externallib_advanced_testcase {
/**
* Create cohort custom fields for testing.
*/
protected function create_custom_fields(): void {
$fieldcategory = self::getDataGenerator()->create_custom_field_category([
'component' => 'core_cohort',
'area' => 'cohort',
'name' => 'Other fields',
]);
self::getDataGenerator()->create_custom_field([
'shortname' => 'testfield1',
'name' => 'Custom field',
'type' => 'text',
'categoryid' => $fieldcategory->get('id'),
]);
self::getDataGenerator()->create_custom_field([
'shortname' => 'testfield2',
'name' => 'Custom field',
'type' => 'text',
'categoryid' => $fieldcategory->get('id'),
]);
}
/**
* Test create_cohorts
*/
public function test_create_cohorts() {
global $USER, $CFG, $DB;
global $DB;
$this->resetAfterTest(true);
@ -50,6 +74,9 @@ class externallib_test extends externallib_advanced_testcase {
$contextid = \context_system::instance()->id;
$category = $this->getDataGenerator()->create_category();
// Custom fields.
$this->create_custom_fields();
$cohort1 = array(
'categorytype' => array('type' => 'id', 'value' => $category->id),
'name' => 'cohort test 1',
@ -82,6 +109,23 @@ class externallib_test extends externallib_advanced_testcase {
'theme' => 'classic'
);
$cohort5 = array(
'categorytype' => array('type' => 'id', 'value' => $category->id),
'name' => 'cohort test 5 (with custom fields)',
'idnumber' => 'cohorttest5',
'description' => 'This is a description for cohorttest5',
'customfields' => array(
array(
'shortname' => 'testfield1',
'value' => 'Test value 1',
),
array(
'shortname' => 'testfield2',
'value' => 'Test value 2',
),
),
);
// Call the external function.
$this->setCurrentTimeStart();
$createdcohorts = core_cohort_external::create_cohorts(array($cohort1, $cohort2));
@ -115,6 +159,21 @@ class externallib_test extends externallib_advanced_testcase {
$this->assertTimeCurrent($dbcohort->timemodified);
}
$createdcohorts = core_cohort_external::create_cohorts(array($cohort5));
$createdcohorts = external_api::clean_returnvalue(core_cohort_external::create_cohorts_returns(), $createdcohorts);
$this->assertCount(1, $createdcohorts);
$createdcohort = reset($createdcohorts);
$dbcohort = $DB->get_record('cohort', array('id' => $createdcohort['id']));
$this->assertEquals($cohort5['name'], $dbcohort->name);
$this->assertEquals($cohort5['description'], $dbcohort->description);
$this->assertEquals(1, $dbcohort->visible);
$this->assertEquals('', $dbcohort->theme);
$data = cohort_handler::create()->export_instance_data_object($createdcohort['id'], true);
$this->assertEquals('Test value 1', $data->testfield1);
$this->assertEquals('Test value 2', $data->testfield2);
// Call when $CFG->allowcohortthemes is disabled.
set_config('allowcohortthemes', 0);
$createdcohorts = core_cohort_external::create_cohorts(array($cohort4));
@ -174,10 +233,11 @@ class externallib_test extends externallib_advanced_testcase {
* Test get_cohorts
*/
public function test_get_cohorts() {
global $USER, $CFG;
$this->resetAfterTest(true);
// Custom fields.
$this->create_custom_fields();
set_config('allowcohortthemes', 1);
$cohort1 = array(
@ -185,8 +245,14 @@ class externallib_test extends externallib_advanced_testcase {
'name' => 'cohortnametest1',
'idnumber' => 'idnumbertest1',
'description' => 'This is a description for cohort 1',
'theme' => 'classic'
);
'theme' => 'classic',
'customfield_testfield1' => 'Test value 1',
'customfield_testfield2' => 'Test value 2',
);
// We need a site admin to be able to populate cohorts custom fields.
$this->setAdminUser();
$cohort1 = self::getDataGenerator()->create_cohort($cohort1);
$cohort2 = self::getDataGenerator()->create_cohort();
@ -207,6 +273,19 @@ class externallib_test extends externallib_advanced_testcase {
$this->assertEquals($cohort1->description, $enrolledcohort['description']);
$this->assertEquals($cohort1->visible, $enrolledcohort['visible']);
$this->assertEquals($cohort1->theme, $enrolledcohort['theme']);
$this->assertIsArray($enrolledcohort['customfields']);
$this->assertCount(2, $enrolledcohort['customfields']);
$actual = [];
foreach ($enrolledcohort['customfields'] as $customfield) {
$this->assertArrayHasKey('name', $customfield);
$this->assertArrayHasKey('shortname', $customfield);
$this->assertArrayHasKey('type', $customfield);
$this->assertArrayHasKey('valueraw', $customfield);
$this->assertArrayHasKey('value', $customfield);
$actual[$customfield['shortname']] = $customfield;
}
$this->assertEquals('Test value 1', $actual['testfield1']['value']);
$this->assertEquals('Test value 2', $actual['testfield2']['value']);
}
}
@ -237,22 +316,39 @@ class externallib_test extends externallib_advanced_testcase {
* Test update_cohorts
*/
public function test_update_cohorts() {
global $USER, $CFG, $DB;
global $DB;
$this->resetAfterTest(true);
// Custom fields.
$this->create_custom_fields();
set_config('allowcohortthemes', 0);
$cohort1 = self::getDataGenerator()->create_cohort(array('visible' => 0));
$data = cohort_handler::create()->export_instance_data_object($cohort1->id, true);
$this->assertNull($data->testfield1);
$this->assertNull($data->testfield2);
$cohort1 = array(
'id' => $cohort1->id,
'categorytype' => array('type' => 'id', 'value' => '1'),
'name' => 'cohortnametest1',
'idnumber' => 'idnumbertest1',
'description' => 'This is a description for cohort 1',
'theme' => 'classic'
);
'theme' => 'classic',
'customfields' => array(
array(
'shortname' => 'testfield1',
'value' => 'Test value 1',
),
array(
'shortname' => 'testfield2',
'value' => 'Test value 2',
),
),
);
$context = \context_system::instance();
$roleid = $this->assignUserCapability('moodle/cohort:manage', $context->id);
@ -269,6 +365,9 @@ class externallib_test extends externallib_advanced_testcase {
$this->assertEquals($dbcohort->description, $cohort1['description']);
$this->assertEquals($dbcohort->visible, 0);
$this->assertEmpty($dbcohort->theme);
$data = cohort_handler::create()->export_instance_data_object($cohort1['id'], true);
$this->assertEquals('Test value 1', $data->testfield1);
$this->assertEquals('Test value 2', $data->testfield2);
// Since field 'visible' was added in 2.8, make sure that update works correctly with and without this parameter.
core_cohort_external::update_cohorts(array($cohort1 + array('visible' => 1)));
@ -290,6 +389,22 @@ class externallib_test extends externallib_advanced_testcase {
$dbcohort = $DB->get_record('cohort', array('id' => $cohort1['id']));
$this->assertEquals('classic', $dbcohort->theme);
// Updating custom fields.
$cohort1['customfields'] = array(
array(
'shortname' => 'testfield1',
'value' => 'Test value 1 updated',
),
array(
'shortname' => 'testfield2',
'value' => 'Test value 2 updated',
),
);
core_cohort_external::update_cohorts(array($cohort1));
$data = cohort_handler::create()->export_instance_data_object($cohort1['id'], true);
$this->assertEquals('Test value 1 updated', $data->testfield1);
$this->assertEquals('Test value 2 updated', $data->testfield2);
// Call without required capability.
$this->unassignUserCapability('moodle/cohort:manage', $context->id, $roleid);
$this->expectException(\required_capability_exception::class);
@ -523,6 +638,7 @@ class externallib_test extends externallib_advanced_testcase {
global $DB, $CFG;
$this->resetAfterTest(true);
$this->create_custom_fields();
$creator = $this->getDataGenerator()->create_user();
$user = $this->getDataGenerator()->create_user();
$catuser = $this->getDataGenerator()->create_user();
@ -562,10 +678,19 @@ class externallib_test extends externallib_advanced_testcase {
$catcontext = array('contextid' => \context_coursecat::instance($category->id)->id);
$othercatcontext = array('contextid' => \context_coursecat::instance($othercategory->id)->id);
$coursecontext = array('contextid' => \context_course::instance($course->id)->id);
$customfields = array(
'contextid' => \context_system::instance()->id,
'customfield_testfield1' => 'Test value 1',
'customfield_testfield2' => 'Test value 2',
);
// We need a site admin to be able to populate cohorts custom fields.
$this->setAdminUser();
$cohort1 = $this->getDataGenerator()->create_cohort(array_merge($syscontext, array('name' => 'Cohortsearch 1')));
$cohort2 = $this->getDataGenerator()->create_cohort(array_merge($catcontext, array('name' => 'Cohortsearch 2')));
$cohort3 = $this->getDataGenerator()->create_cohort(array_merge($othercatcontext, array('name' => 'Cohortsearch 3')));
$cohort4 = $this->getDataGenerator()->create_cohort(array_merge($customfields, array('name' => 'Cohortsearch 4')));
// A user without permission in the system.
$this->setUser($user);
@ -587,14 +712,31 @@ class externallib_test extends externallib_advanced_testcase {
// A user with permissions in the system.
$this->setUser($creator);
$result = core_cohort_external::search_cohorts("Cohortsearch", $syscontext, 'parents');
$this->assertEquals(1, count($result['cohorts']));
$this->assertEquals('Cohortsearch 1', $result['cohorts'][$cohort1->id]->name);
$result = core_cohort_external::search_cohorts("Cohortsearch 4", $syscontext, 'parents');
$this->assertCount(1, $result['cohorts']);
$this->assertEquals('Cohortsearch 4', $result['cohorts'][$cohort4->id]->name);
$result = core_cohort_external::search_cohorts("Cohortsearch 4", $syscontext, 'parents');
$this->assertCount(1, $result['cohorts']);
$this->assertEquals('Cohortsearch 4', $result['cohorts'][$cohort4->id]->name);
$this->assertIsArray($result['cohorts'][$cohort4->id]->customfields);
$this->assertCount(2, $result['cohorts'][$cohort4->id]->customfields);
$actual = [];
foreach ($result['cohorts'][$cohort4->id]->customfields as $customfield) {
$this->assertArrayHasKey('name', $customfield);
$this->assertArrayHasKey('shortname', $customfield);
$this->assertArrayHasKey('type', $customfield);
$this->assertArrayHasKey('valueraw', $customfield);
$this->assertArrayHasKey('value', $customfield);
$actual[$customfield['shortname']] = $customfield;
}
$this->assertEquals('Test value 1', $actual['testfield1']['value']);
$this->assertEquals('Test value 2', $actual['testfield2']['value']);
// A user with permissions in the category.
$this->setUser($catcreator);
$result = core_cohort_external::search_cohorts("Cohortsearch", $catcontext, 'parents');
$this->assertEquals(2, count($result['cohorts']));
$this->assertCount(3, $result['cohorts']);
$cohorts = array();
foreach ($result['cohorts'] as $cohort) {
$cohorts[] = $cohort->name;
@ -604,18 +746,18 @@ class externallib_test extends externallib_advanced_testcase {
// Check for parameter $includes = 'self'.
$this->setUser($creator);
$result = core_cohort_external::search_cohorts("Cohortsearch", $othercatcontext, 'self');
$this->assertEquals(1, count($result['cohorts']));
$this->assertCount(1, $result['cohorts']);
$this->assertEquals('Cohortsearch 3', $result['cohorts'][$cohort3->id]->name);
// Check for parameter $includes = 'all'.
$this->setUser($creator);
$result = core_cohort_external::search_cohorts("Cohortsearch", $syscontext, 'all');
$this->assertEquals(3, count($result['cohorts']));
$this->assertCount(4, $result['cohorts']);
// A user in the course context with the system cohort:view capability. Check that all the system cohorts are returned.
$this->setUser($courseuser);
$result = core_cohort_external::search_cohorts("Cohortsearch", $coursecontext, 'all');
$this->assertEquals(1, count($result['cohorts']));
$this->assertCount(2, $result['cohorts']);
$this->assertEquals('Cohortsearch 1', $result['cohorts'][$cohort1->id]->name);
// Detect invalid parameter $includes.

View File

@ -16,6 +16,9 @@
namespace core_cohort;
use core_cohort\customfield\cohort_handler;
use core_customfield\data_controller;
defined('MOODLE_INTERNAL') || die();
global $CFG;
@ -32,10 +35,33 @@ require_once("$CFG->dirroot/cohort/lib.php");
*/
class lib_test extends \advanced_testcase {
/**
* Create Cohort custom field for testing.
*
* @return \core_customfield\field_controller
*/
protected function create_cohort_custom_field(): \core_customfield\field_controller {
$fieldcategory = self::getDataGenerator()->create_custom_field_category([
'component' => 'core_cohort',
'area' => 'cohort',
'name' => 'Other fields',
]);
return self::getDataGenerator()->create_custom_field([
'shortname' => 'testfield1',
'name' => 'Custom field',
'type' => 'text',
'categoryid' => $fieldcategory->get('id'),
]);
}
public function test_cohort_add_cohort() {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$this->create_cohort_custom_field();
$cohort = new \stdClass();
$cohort->contextid = \context_system::instance()->id;
@ -43,6 +69,7 @@ class lib_test extends \advanced_testcase {
$cohort->idnumber = 'testid';
$cohort->description = 'test cohort desc';
$cohort->descriptionformat = FORMAT_HTML;
$cohort->customfield_testfield1 = 'Test value 1';
$id = cohort_add_cohort($cohort);
$this->assertNotEmpty($id);
@ -56,6 +83,10 @@ class lib_test extends \advanced_testcase {
$this->assertSame($newcohort->component, '');
$this->assertSame($newcohort->theme, '');
$this->assertSame($newcohort->timecreated, $newcohort->timemodified);
$handler = cohort_handler::create();
$customfieldsdata = $handler->export_instance_data_object($id);
$this->assertEquals('Test value 1', $customfieldsdata->testfield1);
}
public function test_cohort_add_cohort_missing_name() {
@ -109,6 +140,9 @@ class lib_test extends \advanced_testcase {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$this->create_cohort_custom_field();
$cohort = new \stdClass();
$cohort->contextid = \context_system::instance()->id;
@ -116,6 +150,8 @@ class lib_test extends \advanced_testcase {
$cohort->idnumber = 'testid';
$cohort->description = 'test cohort desc';
$cohort->descriptionformat = FORMAT_HTML;
$cohort->customfield_testfield1 = 'Test value 1';
$id = cohort_add_cohort($cohort);
$this->assertNotEmpty($id);
$DB->set_field('cohort', 'timecreated', $cohort->timecreated - 10, array('id'=>$id));
@ -123,6 +159,8 @@ class lib_test extends \advanced_testcase {
$cohort = $DB->get_record('cohort', array('id'=>$id));
$cohort->name = 'test cohort 2';
$cohort->customfield_testfield1 = 'Test value updated';
cohort_update_cohort($cohort);
$newcohort = $DB->get_record('cohort', array('id'=>$id));
@ -136,6 +174,10 @@ class lib_test extends \advanced_testcase {
$this->assertSame($newcohort->theme, '');
$this->assertGreaterThan($newcohort->timecreated, $newcohort->timemodified);
$this->assertLessThanOrEqual(time(), $newcohort->timemodified);
$handler = cohort_handler::create();
$customfieldsdata = $handler->export_instance_data_object($id);
$this->assertEquals('Test value updated', $customfieldsdata->testfield1);
}
public function test_cohort_update_cohort_event() {
@ -185,12 +227,17 @@ class lib_test extends \advanced_testcase {
global $DB;
$this->resetAfterTest();
$this->setAdminUser();
$cohort = $this->getDataGenerator()->create_cohort();
$field = $this->create_cohort_custom_field();
$cohort = $this->getDataGenerator()->create_cohort(['customfield_testfield1' => 'Test value 1']);
$this->assertTrue($DB->record_exists('customfield_data', ['instanceid' => $cohort->id, 'fieldid' => $field->get('id')]));
cohort_delete_cohort($cohort);
$this->assertFalse($DB->record_exists('cohort', array('id'=>$cohort->id)));
$this->assertFalse($DB->record_exists('customfield_data', ['instanceid' => $cohort->id, 'fieldid' => $field->get('id')]));
}
public function test_cohort_delete_cohort_event() {
@ -643,6 +690,142 @@ class lib_test extends \advanced_testcase {
$this->assertEquals(array($cohort1->id, $cohort2->id, $cohort4->id), array_keys($result));
}
/**
* Test that all get functions return custom fields data.
*
* @covers \cohort_get_cohort, \cohort_get_cohorts, \cohort_get_all_cohorts
* @covers \cohort_get_available_cohorts, \cohort_get_user_cohorts
*/
public function test_get_functions_return_custom_fields() {
$this->resetAfterTest();
$this->setAdminUser();
$user = self::getDataGenerator()->create_user();
$course = self::getDataGenerator()->create_course();
$coursectx = \context_course::instance(($course->id));
$this->create_cohort_custom_field();
$cohort1 = $this->getDataGenerator()->create_cohort(['customfield_testfield1' => 'Test value 1']);
$cohort2 = $this->getDataGenerator()->create_cohort();
// Test cohort_get_cohort.
$result = cohort_get_cohort($cohort1->id, \context_system::instance(), true);
$this->assertObjectHasAttribute('customfields', $result);
$this->assertCount(1, $result->customfields);
$field = reset($result->customfields);
$this->assertInstanceOf(data_controller::class, $field);
$this->assertEquals('testfield1', $field->get_field()->get('shortname'));
$this->assertEquals('Test value 1', $field->get_value());
// Test custom fields are not returned if not needed.
$result = cohort_get_cohort($cohort1->id, \context_system::instance());
$this->assertObjectNotHasAttribute('customfields', $result);
// Test cohort_get_cohorts.
$result = cohort_get_cohorts(\context_system::instance()->id, 0, 25, '', true);
$this->assertEquals(2, $result['totalcohorts']);
$this->assertEquals(2, $result['allcohorts']);
foreach ($result['cohorts'] as $cohort) {
$this->assertObjectHasAttribute('customfields', $cohort);
$this->assertCount(1, $cohort->customfields);
$field = reset($cohort->customfields);
$this->assertInstanceOf(data_controller::class, $field);
$this->assertEquals('testfield1', $field->get_field()->get('shortname'));
if ($cohort->id == $cohort1->id ) {
$this->assertEquals('Test value 1', $field->get_value());
} else {
$this->assertEquals('', $field->get_value());
}
}
// Test custom fields are not returned if not needed.
$result = cohort_get_cohorts(\context_system::instance()->id, 0, 25, '');
$this->assertEquals(2, $result['totalcohorts']);
$this->assertEquals(2, $result['allcohorts']);
foreach ($result['cohorts'] as $cohort) {
$this->assertObjectNotHasAttribute('customfields', $cohort);
}
// Test test_cohort_get_all_cohorts.
$result = cohort_get_all_cohorts(0, 100, '', true);
$this->assertEquals(2, $result['totalcohorts']);
$this->assertEquals(2, $result['allcohorts']);
foreach ($result['cohorts'] as $cohort) {
$this->assertObjectHasAttribute('customfields', $cohort);
$this->assertCount(1, $cohort->customfields);
$field = reset($cohort->customfields);
$this->assertInstanceOf(data_controller::class, $field);
$this->assertEquals('testfield1', $field->get_field()->get('shortname'));
if ($cohort->id == $cohort1->id ) {
$this->assertEquals('Test value 1', $field->get_value());
} else {
$this->assertEquals('', $field->get_value());
}
}
// Test custom fields are not returned if not needed.
$result = cohort_get_all_cohorts(0, 100, '');
$this->assertEquals(2, $result['totalcohorts']);
$this->assertEquals(2, $result['allcohorts']);
foreach ($result['cohorts'] as $cohort) {
$this->assertObjectNotHasAttribute('customfields', $cohort);
}
// Test cohort_get_available_cohorts.
$result = cohort_get_available_cohorts($coursectx, COHORT_ALL, 0, 25, '', true);
$this->assertCount(2, $result);
foreach ($result as $cohort) {
$this->assertObjectHasAttribute('customfields', $cohort);
$this->assertCount(1, $cohort->customfields);
$field = reset($cohort->customfields);
$this->assertInstanceOf(data_controller::class, $field);
$this->assertEquals('testfield1', $field->get_field()->get('shortname'));
if ($cohort->id == $cohort1->id ) {
$this->assertEquals('Test value 1', $field->get_value());
} else {
$this->assertEquals('', $field->get_value());
}
}
// Test custom fields are not returned if not needed.
$result = cohort_get_available_cohorts($coursectx, COHORT_ALL, 0, 25, '');
$this->assertCount(2, $result);
foreach ($result as $cohort) {
$this->assertObjectNotHasAttribute('customfields', $cohort);
}
// Test cohort_get_user_cohorts.
cohort_add_member($cohort1->id, $user->id);
cohort_add_member($cohort2->id, $user->id);
$result = cohort_get_user_cohorts($user->id, true);
$this->assertCount(2, $result);
foreach ($result as $cohort) {
$this->assertObjectHasAttribute('customfields', $cohort);
$this->assertCount(1, $cohort->customfields);
$field = reset($cohort->customfields);
$this->assertInstanceOf(data_controller::class, $field);
$this->assertEquals('testfield1', $field->get_field()->get('shortname'));
if ($cohort->id == $cohort1->id ) {
$this->assertEquals('Test value 1', $field->get_value());
} else {
$this->assertEquals('', $field->get_value());
}
}
// Test that there is no custom fields returned if not required.
$result = cohort_get_user_cohorts($user->id);
$this->assertCount(2, $result);
foreach ($result as $cohort) {
$this->assertObjectNotHasAttribute('customfields', $cohort);
}
}
/**
* Create a cohort with allowcohortthemes enabled/disabled.
*/
@ -725,4 +908,35 @@ class lib_test extends \advanced_testcase {
$this->assertNotEmpty($updatedcohort->theme);
$this->assertSame($cohort1->theme, $updatedcohort->theme);
}
/**
* Test that lib function returns custom field data for a cohorts.
*
* @covers \cohort_get_custom_fields_data
*/
public function test_cohort_get_custom_fields_data() {
$this->resetAfterTest();
$this->setAdminUser();
$this->create_cohort_custom_field();
$cohort1 = $this->getDataGenerator()->create_cohort(['customfield_testfield1' => 'Test value 1']);
$cohort2 = $this->getDataGenerator()->create_cohort();
$result = cohort_get_custom_fields_data([$cohort1->id, $cohort2->id, 777]);
$this->assertArrayHasKey($cohort1->id, $result);
$this->assertArrayHasKey($cohort2->id, $result);
$this->assertArrayHasKey(777, $result);
foreach ($result as $cohortid => $fieldcontrollers) {
foreach ($fieldcontrollers as $fieldcontroller) {
$this->assertInstanceOf(data_controller::class, $fieldcontroller);
if ($cohortid == $cohort1->id) {
$this->assertSame('Test value 1', $fieldcontroller->export_value());
} else {
$this->assertNull($fieldcontroller->export_value());
}
}
}
}
}

View File

@ -1,6 +1,9 @@
This files describes API changes in /cohort/ information provided here is intended
especially for developers.
=== 4.2 ===
* Added cohort custom fields.
=== 3.1 ===
* The Webservice core_cohort_get_cohorts now has the added functionality of getting all cohorts
by not passing any parameters

View File

@ -146,6 +146,7 @@ $string['cliupgradenoneed'] = 'No upgrade needed for the installed version {$a}.
$string['cliupgradepending'] = 'An upgrade is pending';
$string['cliyesnoprompt'] = 'type y (means yes) or n (means no)';
$string['close'] = 'Close';
$string['cohort_customfield'] = 'Cohort custom fields';
$string['commentsperpage'] = 'Comments displayed per page';
$string['commonactivitysettings'] = 'Common activity settings';
$string['commonfiltersettings'] = 'Common filter settings';

View File

@ -107,6 +107,7 @@ $string['category:visibility'] = 'See hidden categories';
$string['cohort:assign'] = 'Add and remove cohort members';
$string['cohort:view'] = 'View site-wide cohorts';
$string['cohort:manage'] = 'Create, delete and move cohorts';
$string['cohort:configurecustomfields'] = 'Configure cohort custom fields';
$string['comment:delete'] = 'Delete comments';
$string['comment:post'] = 'Post comments';
$string['comment:view'] = 'View comments';

View File

@ -781,6 +781,13 @@ $capabilities = array(
)
),
'moodle/cohort:configurecustomfields' => array(
'riskbitmask' => RISK_SPAM,
'captype' => 'write',
'contextlevel' => CONTEXT_SYSTEM,
'clonepermissionsfrom' => 'moodle/site:config'
),
'moodle/course:create' => array(
'riskbitmask' => RISK_XSS,

View File

@ -258,6 +258,9 @@ class phpunit_util extends testing_util {
if (class_exists('\core_reportbuilder\manager')) {
\core_reportbuilder\manager::reset_caches();
}
if (class_exists('\core_cohort\customfield\cohort_handler')) {
\core_cohort\customfield\cohort_handler::reset_caches();
}
// Clear static cache within restore.
if (class_exists('restore_section_structure_step')) {

View File

@ -29,7 +29,7 @@
defined('MOODLE_INTERNAL') || die();
$version = 2023040400.00; // YYYYMMDD = weekly release date of this DEV branch.
$version = 2023040400.01; // YYYYMMDD = weekly release date of this DEV branch.
// RR = release increments - 00 in DEV branches.
// .XX = incremental changes.
$release = '4.2dev+ (Build: 20230401)'; // Human-friendly version name