mirror of
https://github.com/moodle/moodle.git
synced 2025-04-21 00:12:56 +02:00
Merge branch 'MDL-77130-master-v2' of https://github.com/dmitriim/moodle
This commit is contained in:
commit
ac7f9b45a3
@ -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.
|
||||
|
||||
|
124
cohort/classes/customfield/cohort_handler.php
Normal file
124
cohort/classes/customfield/cohort_handler.php
Normal 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
40
cohort/customfield.php
Normal 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();
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
114
cohort/lib.php
114
cohort/lib.php
@ -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;
|
||||
}
|
||||
|
39
cohort/tests/behat/customfields.feature
Normal file
39
cohort/tests/behat/customfields.feature
Normal 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"
|
182
cohort/tests/customfield/cohort_handler_test.php
Normal file
182
cohort/tests/customfield/cohort_handler_test.php
Normal 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));
|
||||
}
|
||||
}
|
@ -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.
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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';
|
||||
|
@ -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';
|
||||
|
@ -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,
|
||||
|
@ -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')) {
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user