MDL-67186 group: add custom fields
This commit is contained in:
@@ -263,6 +263,27 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
$CFG->wwwroot . '/course/pending.php', array('moodle/site:approvecourse')));
|
||||
}
|
||||
|
||||
// Add a category for the Groups.
|
||||
$ADMIN->add('courses', new admin_category('groups', new lang_string('groups')));
|
||||
$ADMIN->add(
|
||||
'groups',
|
||||
new admin_externalpage(
|
||||
'group_customfield',
|
||||
new lang_string('group_customfield', 'admin'),
|
||||
$CFG->wwwroot . '/group/customfield.php',
|
||||
['moodle/group:configurecustomfields']
|
||||
)
|
||||
);
|
||||
$ADMIN->add(
|
||||
'groups',
|
||||
new admin_externalpage(
|
||||
'grouping_customfield',
|
||||
new lang_string('grouping_customfield', 'admin'),
|
||||
$CFG->wwwroot . '/group/grouping_customfield.php',
|
||||
['moodle/group:configurecustomfields']
|
||||
)
|
||||
);
|
||||
|
||||
// Add a category for the Activity Chooser.
|
||||
$ADMIN->add('courses', new admin_category('activitychooser', new lang_string('activitychoosercategory', 'course')));
|
||||
$temp = new admin_settingpage('activitychoosersettings', new lang_string('activitychoosersettings', 'course'));
|
||||
|
||||
@@ -1354,6 +1354,10 @@ class backup_groups_structure_step extends backup_structure_step {
|
||||
'name', 'idnumber', 'description', 'descriptionformat', 'enrolmentkey',
|
||||
'picture', 'visibility', 'participation', 'timecreated', 'timemodified'));
|
||||
|
||||
$groupcustomfields = new backup_nested_element('groupcustomfields');
|
||||
$groupcustomfield = new backup_nested_element('groupcustomfield', ['id'], [
|
||||
'shortname', 'type', 'value', 'valueformat', 'groupid']);
|
||||
|
||||
$members = new backup_nested_element('group_members');
|
||||
|
||||
$member = new backup_nested_element('group_member', array('id'), array(
|
||||
@@ -1365,6 +1369,10 @@ class backup_groups_structure_step extends backup_structure_step {
|
||||
'name', 'idnumber', 'description', 'descriptionformat', 'configdata',
|
||||
'timecreated', 'timemodified'));
|
||||
|
||||
$groupingcustomfields = new backup_nested_element('groupingcustomfields');
|
||||
$groupingcustomfield = new backup_nested_element('groupingcustomfield', ['id'], [
|
||||
'shortname', 'type', 'value', 'valueformat', 'groupingid']);
|
||||
|
||||
$groupinggroups = new backup_nested_element('grouping_groups');
|
||||
|
||||
$groupinggroup = new backup_nested_element('grouping_group', array('id'), array(
|
||||
@@ -1373,12 +1381,16 @@ class backup_groups_structure_step extends backup_structure_step {
|
||||
// Build the tree
|
||||
|
||||
$groups->add_child($group);
|
||||
$groups->add_child($groupcustomfields);
|
||||
$groupcustomfields->add_child($groupcustomfield);
|
||||
$groups->add_child($groupings);
|
||||
|
||||
$group->add_child($members);
|
||||
$members->add_child($member);
|
||||
|
||||
$groupings->add_child($grouping);
|
||||
$groupings->add_child($groupingcustomfields);
|
||||
$groupingcustomfields->add_child($groupingcustomfield);
|
||||
$grouping->add_child($groupinggroups);
|
||||
$groupinggroups->add_child($groupinggroup);
|
||||
|
||||
@@ -1405,6 +1417,10 @@ class backup_groups_structure_step extends backup_structure_step {
|
||||
if ($userinfo) {
|
||||
$member->set_source_table('groups_members', array('groupid' => backup::VAR_PARENTID));
|
||||
}
|
||||
|
||||
$courseid = $this->task->get_courseid();
|
||||
$groupcustomfield->set_source_array($this->get_group_custom_fields_for_backup($courseid));
|
||||
$groupingcustomfield->set_source_array($this->get_grouping_custom_fields_for_backup($courseid));
|
||||
}
|
||||
|
||||
// Define id annotations (as final)
|
||||
@@ -1420,6 +1436,40 @@ class backup_groups_structure_step extends backup_structure_step {
|
||||
// Return the root element (groups)
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom fields array for group
|
||||
* @param int $courseid
|
||||
* @return array
|
||||
*/
|
||||
protected function get_group_custom_fields_for_backup(int $courseid): array {
|
||||
global $DB;
|
||||
$handler = \core_group\customfield\group_handler::create();
|
||||
$fieldsforbackup = [];
|
||||
if ($groups = $DB->get_records('groups', ['courseid' => $courseid], '', 'id')) {
|
||||
foreach ($groups as $group) {
|
||||
$fieldsforbackup = array_merge($fieldsforbackup, $handler->get_instance_data_for_backup($group->id));
|
||||
}
|
||||
}
|
||||
return $fieldsforbackup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get custom fields array for grouping
|
||||
* @param int $courseid
|
||||
* @return array
|
||||
*/
|
||||
protected function get_grouping_custom_fields_for_backup(int $courseid): array {
|
||||
global $DB;
|
||||
$handler = \core_group\customfield\grouping_handler::create();
|
||||
$fieldsforbackup = [];
|
||||
if ($groupings = $DB->get_records('groupings', ['courseid' => $courseid], '', 'id')) {
|
||||
foreach ($groupings as $grouping) {
|
||||
$fieldsforbackup = array_merge($fieldsforbackup, $handler->get_instance_data_for_backup($grouping->id));
|
||||
}
|
||||
}
|
||||
return $fieldsforbackup;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1159,7 +1159,10 @@ class restore_groups_structure_step extends restore_structure_step {
|
||||
$groupinfo = $this->get_setting_value('groups');
|
||||
if ($groupinfo) {
|
||||
$paths[] = new restore_path_element('group', '/groups/group');
|
||||
$paths[] = new restore_path_element('groupcustomfield', '/groups/groupcustomfields/groupcustomfield');
|
||||
$paths[] = new restore_path_element('grouping', '/groups/groupings/grouping');
|
||||
$paths[] = new restore_path_element('groupingcustomfield',
|
||||
'/groups/groupings/groupingcustomfields/groupingcustomfield');
|
||||
$paths[] = new restore_path_element('grouping_group', '/groups/groupings/grouping/grouping_groups/grouping_group');
|
||||
}
|
||||
return $paths;
|
||||
@@ -1225,6 +1228,18 @@ class restore_groups_structure_step extends restore_structure_step {
|
||||
cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($data->courseid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore group custom field values.
|
||||
* @param array $data data for group custom field
|
||||
* @return void
|
||||
*/
|
||||
public function process_groupcustomfield($data) {
|
||||
$newgroup = $this->get_mapping('group', $data['groupid']);
|
||||
$data['groupid'] = $newgroup->newitemid;
|
||||
$handler = \core_group\customfield\group_handler::create();
|
||||
$handler->restore_instance_data_from_backup($this->task, $data);
|
||||
}
|
||||
|
||||
public function process_grouping($data) {
|
||||
global $DB;
|
||||
|
||||
@@ -1270,6 +1285,18 @@ class restore_groups_structure_step extends restore_structure_step {
|
||||
cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($data->courseid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore grouping custom field values.
|
||||
* @param array $data data for grouping custom field
|
||||
* @return void
|
||||
*/
|
||||
public function process_groupingcustomfield($data) {
|
||||
$newgroup = $this->get_mapping('grouping', $data['groupingid']);
|
||||
$data['groupingid'] = $newgroup->newitemid;
|
||||
$handler = \core_group\customfield\grouping_handler::create();
|
||||
$handler->restore_instance_data_from_backup($this->task, $data);
|
||||
}
|
||||
|
||||
public function process_grouping_group($data) {
|
||||
global $CFG;
|
||||
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
<?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_backup;
|
||||
|
||||
use core_backup_backup_restore_base_testcase;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once('backup_restore_base_testcase.php');
|
||||
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
|
||||
require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
|
||||
|
||||
/**
|
||||
* Backup restore permission tests.
|
||||
*
|
||||
* @package core_backup
|
||||
* @author Tomo Tsuyuki <[email protected]>
|
||||
* @copyright 2023 Catalyst IT Pty Ltd
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class backup_restore_group_test extends core_backup_backup_restore_base_testcase {
|
||||
|
||||
/**
|
||||
* Test for backup/restore with customfields.
|
||||
* @covers \backup_groups_structure_step
|
||||
* @covers \restore_groups_structure_step
|
||||
*/
|
||||
public function test_backup_restore_group_with_customfields(): void {
|
||||
|
||||
$course1 = self::getDataGenerator()->create_course();
|
||||
$course2 = self::getDataGenerator()->create_course();
|
||||
|
||||
$groupfieldcategory = self::getDataGenerator()->create_custom_field_category([
|
||||
'component' => 'core_group',
|
||||
'area' => 'group',
|
||||
]);
|
||||
$groupcustomfield = self::getDataGenerator()->create_custom_field([
|
||||
'shortname' => 'testgroupcustomfield1',
|
||||
'type' => 'text',
|
||||
'categoryid' => $groupfieldcategory->get('id'),
|
||||
]);
|
||||
$groupingfieldcategory = self::getDataGenerator()->create_custom_field_category([
|
||||
'component' => 'core_group',
|
||||
'area' => 'grouping',
|
||||
]);
|
||||
$groupingcustomfield = self::getDataGenerator()->create_custom_field([
|
||||
'shortname' => 'testgroupingcustomfield1',
|
||||
'type' => 'text',
|
||||
'categoryid' => $groupingfieldcategory->get('id'),
|
||||
]);
|
||||
|
||||
$group1 = self::getDataGenerator()->create_group([
|
||||
'courseid' => $course1->id,
|
||||
'name' => 'Test group 1',
|
||||
'customfield_testgroupcustomfield1' => 'Custom input for group1',
|
||||
]);
|
||||
$grouping1 = self::getDataGenerator()->create_grouping([
|
||||
'courseid' => $course1->id,
|
||||
'name' => 'Test grouping 1',
|
||||
'customfield_testgroupingcustomfield1' => 'Custom input for grouping1',
|
||||
]);
|
||||
|
||||
// Perform backup and restore.
|
||||
$backupid = $this->perform_backup($course1);
|
||||
$this->perform_restore($backupid, $course2);
|
||||
|
||||
// Test group.
|
||||
$groups = groups_get_all_groups($course2->id);
|
||||
$this->assertCount(1, $groups);
|
||||
$group = reset($groups);
|
||||
|
||||
// Confirm the group is not same group as original one.
|
||||
$this->assertNotEquals($group1->id, $group->id);
|
||||
$this->assertEquals($group1->name, $group->name);
|
||||
|
||||
// Confirm custom field is restored in the new group.
|
||||
$grouphandler = \core_group\customfield\group_handler::create();
|
||||
$data = $grouphandler->export_instance_data_object($group->id);
|
||||
$this->assertSame('Custom input for group1', $data->testgroupcustomfield1);
|
||||
|
||||
// Test grouping.
|
||||
$groupings = groups_get_all_groupings($course2->id);
|
||||
$this->assertCount(1, $groupings);
|
||||
$grouping = reset($groupings);
|
||||
|
||||
// Confirm this is not same grouping as original one.
|
||||
$this->assertNotEquals($grouping1->id, $grouping->id);
|
||||
|
||||
// Confirm custom field is restored in the new grouping.
|
||||
$groupinghandler = \core_group\customfield\grouping_handler::create();
|
||||
$data = $groupinghandler->export_instance_data_object($grouping->id);
|
||||
$this->assertSame('Custom input for grouping1', $data->testgroupingcustomfield1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
<?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_group\customfield;
|
||||
|
||||
use context;
|
||||
use context_course;
|
||||
use context_system;
|
||||
use core_customfield\api;
|
||||
use core_customfield\handler;
|
||||
use core_customfield\field_controller;
|
||||
use moodle_url;
|
||||
use restore_task;
|
||||
|
||||
/**
|
||||
* Group handler for custom fields.
|
||||
*
|
||||
* @package core_group
|
||||
* @author Tomo Tsuyuki <[email protected]>
|
||||
* @copyright 2023 Catalyst IT Pty Ltd
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class group_handler extends handler {
|
||||
|
||||
/**
|
||||
* @var group_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/group:configurecustomfields', $this->get_configuration_context());
|
||||
}
|
||||
|
||||
/**
|
||||
* The current user can edit custom fields on the given group.
|
||||
*
|
||||
* @param field_controller $field
|
||||
* @param int $instanceid id of the group 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/course:managegroups', $this->get_instance_context($instanceid));
|
||||
}
|
||||
|
||||
/**
|
||||
* The current user can view custom fields on the given group.
|
||||
*
|
||||
* @param field_controller $field
|
||||
* @param int $instanceid id of the group 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/course:managegroups', 'moodle/course: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('/group/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 $COURSE, $DB;
|
||||
|
||||
if ($instanceid > 0) {
|
||||
$group = $DB->get_record('groups', ['id' => $instanceid], '*', MUST_EXIST);
|
||||
return context_course::instance($group->courseid);
|
||||
} else if (!empty($COURSE->id)) {
|
||||
return context_course::instance($COURSE->id);
|
||||
} else {
|
||||
return context_system::instance();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get raw data associated with all fields current user can view or edit
|
||||
*
|
||||
* @param int $instanceid
|
||||
* @return array
|
||||
*/
|
||||
public function get_instance_data_for_backup(int $instanceid): array {
|
||||
$finalfields = [];
|
||||
$instancedata = $this->get_instance_data($instanceid, true);
|
||||
foreach ($instancedata as $data) {
|
||||
if ($data->get('id') && $this->can_backup($data->get_field(), $instanceid)) {
|
||||
$finalfields[] = [
|
||||
'id' => $data->get('id'),
|
||||
'shortname' => $data->get_field()->get('shortname'),
|
||||
'type' => $data->get_field()->get('type'),
|
||||
'value' => $data->get_value(),
|
||||
'valueformat' => $data->get('valueformat'),
|
||||
'groupid' => $data->get('instanceid'),
|
||||
];
|
||||
}
|
||||
}
|
||||
return $finalfields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or updates custom field data.
|
||||
*
|
||||
* @param restore_task $task
|
||||
* @param array $data
|
||||
*/
|
||||
public function restore_instance_data_from_backup(restore_task $task, array $data) {
|
||||
$instanceid = $data['groupid'];
|
||||
$context = $this->get_instance_context($instanceid);
|
||||
$editablefields = $this->get_editable_fields($instanceid);
|
||||
$records = api::get_instance_fields_data($editablefields, $instanceid);
|
||||
|
||||
foreach ($records as $d) {
|
||||
$field = $d->get_field();
|
||||
if ($field->get('shortname') === $data['shortname'] && $field->get('type') === $data['type']) {
|
||||
if (!$d->get('id')) {
|
||||
$d->set($d->datafield(), $data['value']);
|
||||
$d->set('value', $data['value']);
|
||||
$d->set('valueformat', $data['valueformat']);
|
||||
$d->set('contextid', $context->id);
|
||||
$d->save();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
<?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_group\customfield;
|
||||
|
||||
use context;
|
||||
use context_course;
|
||||
use context_system;
|
||||
use core_customfield\api;
|
||||
use core_customfield\handler;
|
||||
use core_customfield\field_controller;
|
||||
use moodle_url;
|
||||
use restore_task;
|
||||
|
||||
/**
|
||||
* Grouping handler for custom fields.
|
||||
*
|
||||
* @package core_group
|
||||
* @author Tomo Tsuyuki <[email protected]>
|
||||
* @copyright 2023 Catalyst IT Pty Ltd
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class grouping_handler extends handler {
|
||||
|
||||
/**
|
||||
* @var grouping_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/group:configurecustomfields', $this->get_configuration_context());
|
||||
}
|
||||
|
||||
/**
|
||||
* The current user can edit custom fields on the given group.
|
||||
*
|
||||
* @param field_controller $field
|
||||
* @param int $instanceid id of the group 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/course:managegroups', $this->get_instance_context($instanceid));
|
||||
}
|
||||
|
||||
/**
|
||||
* The current user can view custom fields on the given group.
|
||||
*
|
||||
* @param field_controller $field
|
||||
* @param int $instanceid id of the group 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/course:managegroups', 'moodle/course: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('/group/grouping_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 $COURSE, $DB;
|
||||
if ($instanceid > 0) {
|
||||
$grouping = $DB->get_record('groupings', ['id' => $instanceid], '*', MUST_EXIST);
|
||||
return context_course::instance($grouping->courseid);
|
||||
} else if (!empty($COURSE->id)) {
|
||||
return context_course::instance($COURSE->id);
|
||||
} else {
|
||||
return context_system::instance();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get raw data associated with all fields current user can view or edit
|
||||
*
|
||||
* @param int $instanceid
|
||||
* @return array
|
||||
*/
|
||||
public function get_instance_data_for_backup(int $instanceid): array {
|
||||
$finalfields = [];
|
||||
$instancedata = $this->get_instance_data($instanceid, true);
|
||||
foreach ($instancedata as $data) {
|
||||
if ($data->get('id') && $this->can_backup($data->get_field(), $instanceid)) {
|
||||
$finalfields[] = [
|
||||
'id' => $data->get('id'),
|
||||
'shortname' => $data->get_field()->get('shortname'),
|
||||
'type' => $data->get_field()->get('type'),
|
||||
'value' => $data->get_value(),
|
||||
'valueformat' => $data->get('valueformat'),
|
||||
'groupingid' => $data->get('instanceid'),
|
||||
];
|
||||
}
|
||||
}
|
||||
return $finalfields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or updates custom field data for a instanceid from backup data.
|
||||
*
|
||||
* The handlers have to override it if they support backup
|
||||
*
|
||||
* @param restore_task $task
|
||||
* @param array $data
|
||||
*/
|
||||
public function restore_instance_data_from_backup(restore_task $task, array $data) {
|
||||
$instanceid = $data['groupingid'];
|
||||
$context = $this->get_instance_context($instanceid);
|
||||
$editablefields = $this->get_editable_fields($instanceid);
|
||||
$records = api::get_instance_fields_data($editablefields, $instanceid);
|
||||
|
||||
foreach ($records as $d) {
|
||||
$field = $d->get_field();
|
||||
if ($field->get('shortname') === $data['shortname'] && $field->get('type') === $data['type']) {
|
||||
if (!$d->get('id')) {
|
||||
$d->set($d->datafield(), $data['value']);
|
||||
$d->set('value', $data['value']);
|
||||
$d->set('valueformat', $data['valueformat']);
|
||||
$d->set('contextid', $context->id);
|
||||
$d->save();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?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 group custom fields
|
||||
*
|
||||
* @package core_group
|
||||
* @author Tomo Tsuyuki <[email protected]>
|
||||
* @copyright 2023 Catalyst IT Pty Ltd
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use core_group\customfield\group_handler;
|
||||
use core_customfield\output\management;
|
||||
|
||||
require_once('../config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
admin_externalpage_setup('group_customfield');
|
||||
|
||||
$output = $PAGE->get_renderer('core_customfield');
|
||||
$handler = group_handler::create();
|
||||
$outputpage = new management($handler);
|
||||
|
||||
echo $output->header(),
|
||||
$output->heading(new lang_string('group_customfield', 'admin')),
|
||||
$output->render($outputpage),
|
||||
$output->footer();
|
||||
+102
-4
@@ -24,6 +24,10 @@ use core_external\external_warnings;
|
||||
use core_external\util;
|
||||
use core_group\visibility;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/group/lib.php');
|
||||
|
||||
/**
|
||||
* Group external functions
|
||||
*
|
||||
@@ -80,6 +84,7 @@ class core_group_external extends external_api {
|
||||
'participation' => new external_value(PARAM_BOOL,
|
||||
'activity participation enabled? Only for "all" and "members" visibility. Default true.',
|
||||
VALUE_DEFAULT, true),
|
||||
'customfields' => self::build_custom_fields_parameters_structure(),
|
||||
)
|
||||
), 'List of group object. A group has a courseid, a name, a description and an enrolment key.'
|
||||
)
|
||||
@@ -132,6 +137,14 @@ class core_group_external extends external_api {
|
||||
// Validate visibility.
|
||||
self::validate_visibility($group->visibility);
|
||||
|
||||
// Custom fields.
|
||||
if (!empty($group->customfields)) {
|
||||
foreach ($group->customfields as $field) {
|
||||
$fieldname = self::build_custom_field_name($field['shortname']);
|
||||
$group->{$fieldname} = $field['value'];
|
||||
}
|
||||
}
|
||||
|
||||
// finally create the group
|
||||
$group->id = groups_create_group($group, false);
|
||||
if (!isset($group->enrolmentkey)) {
|
||||
@@ -170,6 +183,7 @@ class core_group_external extends external_api {
|
||||
'group visibility mode. 0 = Visible to all. 1 = Visible to members. 2 = See own membership. '
|
||||
. '3 = Membership is hidden.'),
|
||||
'participation' => new external_value(PARAM_BOOL, 'participation mode'),
|
||||
'customfields' => self::build_custom_fields_parameters_structure(),
|
||||
)
|
||||
), 'List of group object. A group has an id, a courseid, a name, a description and an enrolment key.'
|
||||
);
|
||||
@@ -201,6 +215,7 @@ class core_group_external extends external_api {
|
||||
$params = self::validate_parameters(self::get_groups_parameters(), array('groupids'=>$groupids));
|
||||
|
||||
$groups = array();
|
||||
$customfieldsdata = get_group_custom_fields_data($groupids);
|
||||
foreach ($params['groupids'] as $groupid) {
|
||||
// validate params
|
||||
$group = groups_get_group($groupid, 'id, courseid, name, idnumber, description, descriptionformat, enrolmentkey, '
|
||||
@@ -223,6 +238,7 @@ class core_group_external extends external_api {
|
||||
\core_external\util::format_text($group->description, $group->descriptionformat,
|
||||
$context, 'group', 'description', $group->id);
|
||||
|
||||
$group->customfields = $customfieldsdata[$group->id] ?? [];
|
||||
$groups[] = (array)$group;
|
||||
}
|
||||
|
||||
@@ -250,6 +266,7 @@ class core_group_external extends external_api {
|
||||
'group visibility mode. 0 = Visible to all. 1 = Visible to members. 2 = See own membership. '
|
||||
. '3 = Membership is hidden.'),
|
||||
'participation' => new external_value(PARAM_BOOL, 'participation mode'),
|
||||
'customfields' => self::build_custom_fields_returns_structure(),
|
||||
)
|
||||
)
|
||||
);
|
||||
@@ -633,7 +650,8 @@ class core_group_external extends external_api {
|
||||
'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'),
|
||||
'description' => new external_value(PARAM_RAW, 'grouping description text'),
|
||||
'descriptionformat' => new external_format_value('description', VALUE_DEFAULT),
|
||||
'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL)
|
||||
'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL),
|
||||
'customfields' => self::build_custom_fields_parameters_structure(),
|
||||
)
|
||||
), 'List of grouping object. A grouping has a courseid, a name and a description.'
|
||||
)
|
||||
@@ -682,6 +700,14 @@ class core_group_external extends external_api {
|
||||
|
||||
$grouping->descriptionformat = util::validate_format($grouping->descriptionformat);
|
||||
|
||||
// Custom fields.
|
||||
if (!empty($grouping->customfields)) {
|
||||
foreach ($grouping->customfields as $field) {
|
||||
$fieldname = self::build_custom_field_name($field['shortname']);
|
||||
$grouping->{$fieldname} = $field['value'];
|
||||
}
|
||||
}
|
||||
|
||||
// Finally create the grouping.
|
||||
$grouping->id = groups_create_grouping($grouping);
|
||||
$groupings[] = (array)$grouping;
|
||||
@@ -707,7 +733,8 @@ class core_group_external extends external_api {
|
||||
'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'),
|
||||
'description' => new external_value(PARAM_RAW, 'grouping description text'),
|
||||
'descriptionformat' => new external_format_value('description'),
|
||||
'idnumber' => new external_value(PARAM_RAW, 'id number')
|
||||
'idnumber' => new external_value(PARAM_RAW, 'id number'),
|
||||
'customfields' => self::build_custom_fields_parameters_structure(),
|
||||
)
|
||||
), 'List of grouping object. A grouping has an id, a courseid, a name and a description.'
|
||||
);
|
||||
@@ -729,7 +756,8 @@ class core_group_external extends external_api {
|
||||
'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'),
|
||||
'description' => new external_value(PARAM_RAW, 'grouping description text'),
|
||||
'descriptionformat' => new external_format_value('description', VALUE_DEFAULT),
|
||||
'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL)
|
||||
'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL),
|
||||
'customfields' => self::build_custom_fields_parameters_structure(),
|
||||
)
|
||||
), 'List of grouping object. A grouping has a courseid, a name and a description.'
|
||||
)
|
||||
@@ -786,6 +814,14 @@ class core_group_external extends external_api {
|
||||
// We must force allways FORMAT_HTML.
|
||||
$grouping->descriptionformat = util::validate_format($grouping->descriptionformat);
|
||||
|
||||
// Custom fields.
|
||||
if (!empty($grouping->customfields)) {
|
||||
foreach ($grouping->customfields as $field) {
|
||||
$fieldname = self::build_custom_field_name($field['shortname']);
|
||||
$grouping->{$fieldname} = $field['value'];
|
||||
}
|
||||
}
|
||||
|
||||
// Finally update the grouping.
|
||||
groups_update_grouping($grouping);
|
||||
}
|
||||
@@ -839,6 +875,7 @@ class core_group_external extends external_api {
|
||||
'returngroups' => $returngroups));
|
||||
|
||||
$groupings = array();
|
||||
$groupingcustomfieldsdata = get_grouping_custom_fields_data($groupingids);
|
||||
foreach ($params['groupingids'] as $groupingid) {
|
||||
// Validate params.
|
||||
$grouping = groups_get_grouping($groupingid, '*', MUST_EXIST);
|
||||
@@ -859,6 +896,7 @@ class core_group_external extends external_api {
|
||||
\core_external\util::format_text($grouping->description, $grouping->descriptionformat,
|
||||
$context, 'grouping', 'description', $grouping->id);
|
||||
|
||||
$grouping->customfields = $groupingcustomfieldsdata[$grouping->id] ?? [];
|
||||
$groupingarray = (array)$grouping;
|
||||
|
||||
if ($params['returngroups']) {
|
||||
@@ -867,6 +905,7 @@ class core_group_external extends external_api {
|
||||
"ORDER BY groupid", array($groupingid));
|
||||
if ($grouprecords) {
|
||||
$groups = array();
|
||||
$groupids = [];
|
||||
foreach ($grouprecords as $grouprecord) {
|
||||
list($grouprecord->description, $grouprecord->descriptionformat) =
|
||||
\core_external\util::format_text($grouprecord->description, $grouprecord->descriptionformat,
|
||||
@@ -879,6 +918,11 @@ class core_group_external extends external_api {
|
||||
'enrolmentkey' => $grouprecord->enrolmentkey,
|
||||
'courseid' => $grouprecord->courseid
|
||||
);
|
||||
$groupids[] = $grouprecord->groupid;
|
||||
}
|
||||
$groupcustomfieldsdata = get_group_custom_fields_data($groupids);
|
||||
foreach ($groups as $i => $group) {
|
||||
$groups[$i]['customfields'] = $groupcustomfieldsdata[$group['id']] ?? [];
|
||||
}
|
||||
$groupingarray['groups'] = $groups;
|
||||
}
|
||||
@@ -905,6 +949,7 @@ class core_group_external extends external_api {
|
||||
'description' => new external_value(PARAM_RAW, 'grouping description text'),
|
||||
'descriptionformat' => new external_format_value('description'),
|
||||
'idnumber' => new external_value(PARAM_RAW, 'id number'),
|
||||
'customfields' => self::build_custom_fields_returns_structure(),
|
||||
'groups' => new external_multiple_structure(
|
||||
new external_single_structure(
|
||||
array(
|
||||
@@ -914,7 +959,8 @@ class core_group_external extends external_api {
|
||||
'description' => new external_value(PARAM_RAW, 'group description text'),
|
||||
'descriptionformat' => new external_format_value('description'),
|
||||
'enrolmentkey' => new external_value(PARAM_RAW, 'group enrol secret phrase'),
|
||||
'idnumber' => new external_value(PARAM_RAW, 'id number')
|
||||
'idnumber' => new external_value(PARAM_RAW, 'id number'),
|
||||
'customfields' => self::build_custom_fields_returns_structure(),
|
||||
)
|
||||
),
|
||||
'optional groups', VALUE_OPTIONAL)
|
||||
@@ -1554,6 +1600,7 @@ class core_group_external extends external_api {
|
||||
. '2 = See own membership. 3 = Membership is hidden.', VALUE_OPTIONAL),
|
||||
'participation' => new external_value(PARAM_BOOL,
|
||||
'activity participation enabled? Only for "all" and "members" visibility', VALUE_OPTIONAL),
|
||||
'customfields' => self::build_custom_fields_parameters_structure(),
|
||||
)
|
||||
), 'List of group objects. A group is found by the id, then all other details provided will be updated.'
|
||||
)
|
||||
@@ -1629,6 +1676,14 @@ class core_group_external extends external_api {
|
||||
$group->descriptionformat = util::validate_format($group->descriptionformat);
|
||||
}
|
||||
|
||||
// Custom fields.
|
||||
if (!empty($group->customfields)) {
|
||||
foreach ($group->customfields as $field) {
|
||||
$fieldname = self::build_custom_field_name($field['shortname']);
|
||||
$group->{$fieldname} = $field['value'];
|
||||
}
|
||||
}
|
||||
|
||||
groups_update_group($group);
|
||||
}
|
||||
|
||||
@@ -1646,4 +1701,47 @@ class core_group_external extends external_api {
|
||||
public static function update_groups_returns() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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([
|
||||
'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', 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([
|
||||
'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
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -93,7 +93,7 @@ if (!empty($group->id)) {
|
||||
}
|
||||
|
||||
/// First create the form
|
||||
$editform = new group_form(null, array('editoroptions'=>$editoroptions));
|
||||
$editform = new group_form(null, array('editoroptions' => $editoroptions, 'group' => $group));
|
||||
$editform->set_data($group);
|
||||
|
||||
if ($editform->is_cancelled()) {
|
||||
|
||||
@@ -47,6 +47,7 @@ class group_form extends moodleform {
|
||||
|
||||
$mform =& $this->_form;
|
||||
$editoroptions = $this->_customdata['editoroptions'];
|
||||
$group = $this->_customdata['group'];
|
||||
|
||||
$mform->addElement('header', 'general', get_string('general', 'form'));
|
||||
|
||||
@@ -99,6 +100,10 @@ class group_form extends moodleform {
|
||||
$mform->addElement('filepicker', 'imagefile', get_string('newpicture', 'group'));
|
||||
$mform->addHelpButton('imagefile', 'newpicture', 'group');
|
||||
|
||||
$handler = \core_group\customfield\group_handler::create();
|
||||
$handler->instance_form_definition($mform, empty($group->id) ? 0 : $group->id);
|
||||
$handler->instance_form_before_set_data($group);
|
||||
|
||||
$mform->addElement('hidden','id');
|
||||
$mform->setType('id', PARAM_INT);
|
||||
|
||||
@@ -153,6 +158,8 @@ class group_form extends moodleform {
|
||||
$participation->freeze();
|
||||
}
|
||||
|
||||
$handler = core_group\customfield\group_handler::create();
|
||||
$handler->instance_form_definition_after_data($this->_form, empty($groupid) ? 0 : $groupid);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,6 +223,9 @@ class group_form extends moodleform {
|
||||
}
|
||||
}
|
||||
|
||||
$handler = \core_group\customfield\group_handler::create();
|
||||
$errors = array_merge($errors, $handler->instance_form_validation($data, $files));
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -108,7 +108,7 @@ if (!empty($grouping->id)) {
|
||||
}
|
||||
|
||||
/// First create the form
|
||||
$editform = new grouping_form(null, compact('editoroptions'));
|
||||
$editform = new grouping_form(null, compact('editoroptions', 'grouping'));
|
||||
$editform->set_data($grouping);
|
||||
|
||||
if ($editform->is_cancelled()) {
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
<?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 grouping custom fields
|
||||
*
|
||||
* @package core_group
|
||||
* @author Tomo Tsuyuki <[email protected]>
|
||||
* @copyright 2023 Catalyst IT Pty Ltd
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use core_group\customfield\grouping_handler;
|
||||
use core_customfield\output\management;
|
||||
|
||||
require_once('../config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
admin_externalpage_setup('grouping_customfield');
|
||||
|
||||
$output = $PAGE->get_renderer('core_customfield');
|
||||
$handler = grouping_handler::create();
|
||||
$outputpage = new management($handler);
|
||||
|
||||
echo $output->header(),
|
||||
$output->heading(new lang_string('grouping_customfield', 'admin')),
|
||||
$output->render($outputpage),
|
||||
$output->footer();
|
||||
@@ -47,6 +47,7 @@ class grouping_form extends moodleform {
|
||||
|
||||
$mform =& $this->_form;
|
||||
$editoroptions = $this->_customdata['editoroptions'];
|
||||
$grouping = $this->_customdata['grouping'];
|
||||
|
||||
$mform->addElement('header', 'general', get_string('general', 'form'));
|
||||
|
||||
@@ -64,6 +65,10 @@ class grouping_form extends moodleform {
|
||||
$mform->addElement('editor', 'description_editor', get_string('groupingdescription', 'group'), null, $editoroptions);
|
||||
$mform->setType('description_editor', PARAM_RAW);
|
||||
|
||||
$handler = \core_group\customfield\grouping_handler::create();
|
||||
$handler->instance_form_definition($mform, empty($grouping->id) ? 0 : $grouping->id);
|
||||
$handler->instance_form_before_set_data($grouping);
|
||||
|
||||
$mform->addElement('hidden','id');
|
||||
$mform->setType('id', PARAM_INT);
|
||||
|
||||
@@ -109,7 +114,18 @@ class grouping_form extends moodleform {
|
||||
$errors['idnumber']= get_string('idnumbertaken');
|
||||
}
|
||||
|
||||
$handler = \core_group\customfield\grouping_handler::create();
|
||||
$errors = array_merge($errors, $handler->instance_form_validation($data, $files));
|
||||
|
||||
return $errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a logic after data is set.
|
||||
*/
|
||||
public function definition_after_data() {
|
||||
$groupid = $this->_form->getElementValue('id');
|
||||
$handler = \core_group\customfield\grouping_handler::create();
|
||||
$handler->instance_form_definition_after_data($this->_form, empty($groupid) ? 0 : $groupid);
|
||||
}
|
||||
}
|
||||
|
||||
+30
-7
@@ -82,7 +82,7 @@ if ($importform->is_cancelled()) {
|
||||
|
||||
// make arrays of valid fields for error checking
|
||||
$required = array("groupname" => 1);
|
||||
$optionalDefaults = array("lang" => 1);
|
||||
$optionaldefaults = array("lang" => 1);
|
||||
$optional = array("coursename" => 1,
|
||||
"idnumber" => 1,
|
||||
"groupidnumber" => 1,
|
||||
@@ -91,17 +91,34 @@ if ($importform->is_cancelled()) {
|
||||
"groupingname" => 1,
|
||||
"enablemessaging" => 1,
|
||||
);
|
||||
// Check custom fields from group and grouping.
|
||||
$customfields = \core_group\customfield\group_handler::create()->get_fields();
|
||||
$customfieldnames = [];
|
||||
foreach ($customfields as $customfield) {
|
||||
$controller = \core_customfield\data_controller::create(0, null, $customfield);
|
||||
$customfieldnames['customfield_' . $customfield->get('shortname')] = 1;
|
||||
}
|
||||
$customfields = \core_group\customfield\grouping_handler::create()->get_fields();
|
||||
$groupingcustomfields = [];
|
||||
foreach ($customfields as $customfield) {
|
||||
$controller = \core_customfield\data_controller::create(0, null, $customfield);
|
||||
$groupingcustomfieldname = 'grouping_customfield_' . $customfield->get('shortname');
|
||||
$customfieldnames[$groupingcustomfieldname] = 1;
|
||||
$groupingcustomfields[$groupingcustomfieldname] = 'customfield_' . $customfield->get('shortname');
|
||||
}
|
||||
|
||||
// --- get header (field names) ---
|
||||
// Using get_columns() ensures the Byte Order Mark is removed.
|
||||
$header = $csvimport->get_columns();
|
||||
|
||||
// check for valid field names
|
||||
// Check for valid field names.
|
||||
foreach ($header as $i => $h) {
|
||||
$h = trim($h); $header[$i] = $h; // remove whitespace
|
||||
if (!(isset($required[$h]) or isset($optionalDefaults[$h]) or isset($optional[$h]))) {
|
||||
throw new \moodle_exception('invalidfieldname', 'error', $PAGE->url, $h);
|
||||
}
|
||||
// Remove whitespace.
|
||||
$h = trim($h);
|
||||
$header[$i] = $h;
|
||||
if (!isset($required[$h]) && !isset($optionaldefaults[$h]) && !isset($optional[$h]) && !isset($customfieldnames[$h])) {
|
||||
throw new \moodle_exception('invalidfieldname', 'error', $PAGE->url, $h);
|
||||
}
|
||||
if (isset($required[$h])) {
|
||||
$required[$h] = 2;
|
||||
}
|
||||
@@ -117,7 +134,7 @@ if ($importform->is_cancelled()) {
|
||||
while ($line = $csvimport->next()) {
|
||||
|
||||
$newgroup = new stdClass();//to make Martin happy
|
||||
foreach ($optionalDefaults as $key => $value) {
|
||||
foreach ($optionaldefaults as $key => $value) {
|
||||
$newgroup->$key = current_language(); //defaults to current language
|
||||
}
|
||||
foreach ($line as $key => $value) {
|
||||
@@ -211,6 +228,12 @@ if ($importform->is_cancelled()) {
|
||||
$data = new stdClass();
|
||||
$data->courseid = $newgroup->courseid;
|
||||
$data->name = $groupingname;
|
||||
// Add customfield if exists.
|
||||
foreach ($header as $fieldname) {
|
||||
if (isset($customfieldnames[$fieldname]) && isset($newgroup->$fieldname)) {
|
||||
$data->{$groupingcustomfields[$groupingcustomfieldname]} = $newgroup->$fieldname;
|
||||
}
|
||||
}
|
||||
if ($groupingid = groups_create_grouping($data)) {
|
||||
echo $OUTPUT->notification(get_string('groupingaddedsuccesfully', 'group', $groupingname), 'notifysuccess');
|
||||
} else {
|
||||
|
||||
@@ -275,6 +275,9 @@ function groups_create_group($data, $editform = false, $editoroptions = false) {
|
||||
|
||||
$data->id = $DB->insert_record('groups', $data);
|
||||
|
||||
$handler = \core_group\customfield\group_handler::create();
|
||||
$handler->instance_form_save($data, true);
|
||||
|
||||
if ($editform and $editoroptions) {
|
||||
// Update description from editor with fixed files
|
||||
$data = file_postupdate_standard_editor($data, 'description', $editoroptions, $context, 'group', 'description', $data->id);
|
||||
@@ -352,6 +355,9 @@ function groups_create_grouping($data, $editoroptions=null) {
|
||||
$id = $DB->insert_record('groupings', $data);
|
||||
$data->id = $id;
|
||||
|
||||
$handler = \core_group\customfield\grouping_handler::create();
|
||||
$handler->instance_form_save($data, true);
|
||||
|
||||
if ($editoroptions !== null) {
|
||||
$description = new stdClass;
|
||||
$description->id = $data->id;
|
||||
@@ -445,6 +451,9 @@ function groups_update_group($data, $editform = false, $editoroptions = false) {
|
||||
|
||||
$DB->update_record('groups', $data);
|
||||
|
||||
$handler = \core_group\customfield\group_handler::create();
|
||||
$handler->instance_form_save($data);
|
||||
|
||||
// Invalidate the group data.
|
||||
cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($data->courseid));
|
||||
// Rebuild the coursehiddengroups cache for the course.
|
||||
@@ -529,6 +538,9 @@ function groups_update_grouping($data, $editoroptions=null) {
|
||||
}
|
||||
$DB->update_record('groupings', $data);
|
||||
|
||||
$handler = \core_group\customfield\grouping_handler::create();
|
||||
$handler->instance_form_save($data);
|
||||
|
||||
// Invalidate the group data.
|
||||
cache_helper::invalidate_by_definition('core', 'groupdata', array(), array($data->courseid));
|
||||
|
||||
@@ -1222,3 +1234,61 @@ function set_groups_messaging(array $groupids, bool $enabled): void {
|
||||
groups_update_group($data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns custom fields data for provided groups.
|
||||
*
|
||||
* @param array $groupids a list of group IDs to provide data for.
|
||||
* @return \core_customfield\data_controller[]
|
||||
*/
|
||||
function get_group_custom_fields_data(array $groupids): array {
|
||||
$result = [];
|
||||
|
||||
if (!empty($groupids)) {
|
||||
$handler = \core_group\customfield\group_handler::create();
|
||||
$customfieldsdata = $handler->get_instances_data($groupids, true);
|
||||
|
||||
foreach ($customfieldsdata as $groupid => $fieldcontrollers) {
|
||||
foreach ($fieldcontrollers as $fieldcontroller) {
|
||||
$result[$groupid][] = [
|
||||
'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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns custom fields data for provided groupings.
|
||||
*
|
||||
* @param array $groupingids a list of group IDs to provide data for.
|
||||
* @return \core_customfield\data_controller[]
|
||||
*/
|
||||
function get_grouping_custom_fields_data(array $groupingids): array {
|
||||
$result = [];
|
||||
|
||||
if (!empty($groupingids)) {
|
||||
$handler = \core_group\customfield\grouping_handler::create();
|
||||
$customfieldsdata = $handler->get_instances_data($groupingids, true);
|
||||
|
||||
foreach ($customfieldsdata as $groupingid => $fieldcontrollers) {
|
||||
foreach ($fieldcontrollers as $fieldcontroller) {
|
||||
$result[$groupingid][] = [
|
||||
'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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
@core @core_group @core_customfield @javascript
|
||||
Feature: Add and use group custom fields
|
||||
In order to store an extra information about groups
|
||||
As an admin
|
||||
I need to create group customs fields and be able to populate them on group creation
|
||||
|
||||
Background:
|
||||
Given the following "custom field categories" exist:
|
||||
| name | component | area | itemid |
|
||||
| Category for group1 | core_group | group | 0 |
|
||||
| Category for grouping1 | core_group | grouping | 0 |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
|
||||
Scenario: Create a new group custom field and use the field for a new group
|
||||
When I log in as "admin"
|
||||
And I navigate to "Courses > Groups > Group custom fields" in site administration
|
||||
Then I should see "Category for group1"
|
||||
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 |
|
||||
Then I log in as "teacher1"
|
||||
And I am on the "Course 1" "groups" page
|
||||
And I press "Create group"
|
||||
Then I should see "Category for group1"
|
||||
And I should see "Test field"
|
||||
And I set the following fields to these values:
|
||||
| Group name | My new group |
|
||||
| Test field | Custom field text |
|
||||
And I press "Save changes"
|
||||
Then the "groups" select box should contain "My new group (0)"
|
||||
And I set the field "groups" to "My new group (0)"
|
||||
And I press "Edit group settings"
|
||||
And the field "Test field" matches value "Custom field text"
|
||||
|
||||
Scenario: Create a new grouping custom field and use the field for a new grouping
|
||||
When I log in as "admin"
|
||||
And I navigate to "Courses > Groups > Grouping custom fields" in site administration
|
||||
Then I should see "Category for grouping1"
|
||||
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 |
|
||||
Then I log in as "teacher1"
|
||||
And I am on the "Course 1" "groupings" page
|
||||
And I press "Create grouping"
|
||||
Then I should see "Category for grouping1"
|
||||
And I should see "Test field"
|
||||
And I set the following fields to these values:
|
||||
| Grouping name | My new grouping |
|
||||
| Test field | Custom field text |
|
||||
And I press "Save changes"
|
||||
Then I should see "My new grouping"
|
||||
And I click on "Edit" "link" in the "My new grouping" "table_row"
|
||||
And the field "Test field" matches value "Custom field text"
|
||||
@@ -146,3 +146,35 @@ Feature: Importing of groups and groupings
|
||||
And I should not see "group8"
|
||||
And I should not see "group10"
|
||||
And I log out
|
||||
|
||||
@javascript
|
||||
Scenario: Import groups with custom field
|
||||
Given the following "custom field categories" exist:
|
||||
| name | component | area | itemid |
|
||||
| Category for group1 | core_group | group | 0 |
|
||||
| Category for grouping1 | core_group | grouping | 0 |
|
||||
And the following "custom fields" exist:
|
||||
| name | category | type | shortname |
|
||||
| Test Field1 | Category for group1 | text | groupfield1 |
|
||||
| Test Field2 | Category for grouping1 | text | groupingfield1 |
|
||||
And I log in as "teacher1"
|
||||
And I am on the "Course 1" "groups" page
|
||||
And I press "Import groups"
|
||||
When I upload "group/tests/fixtures/groups_import_with_customfield.csv" file to "Import" filemanager
|
||||
And I press "Import groups"
|
||||
Then I should see "Group Group1 added successfully"
|
||||
And I should see "Group Group2 added successfully"
|
||||
And I should see "Grouping Grouping1 added successfully"
|
||||
And I press "Continue"
|
||||
And I set the field "groups" to "Group1 (0)"
|
||||
And I press "Edit group settings"
|
||||
And the field "Test Field1" matches value "Group1-Custom"
|
||||
And I press "Cancel"
|
||||
And I set the field "groups" to "Group2 (0)"
|
||||
And I press "Edit group settings"
|
||||
And the field "Test Field1" matches value "Group2-Custom"
|
||||
And I press "Cancel"
|
||||
And I am on the "Course 1" "groupings" page
|
||||
Then I should see "Grouping1"
|
||||
And I click on "Edit" "link" in the "Grouping1" "table_row"
|
||||
And the field "Test Field2" matches value "Grouping1-Custom"
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
<?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_group\customfield;
|
||||
|
||||
use advanced_testcase;
|
||||
use context_course;
|
||||
use context_system;
|
||||
use moodle_url;
|
||||
use core_customfield\field_controller;
|
||||
|
||||
/**
|
||||
* Unit tests for group custom field handler.
|
||||
*
|
||||
* @package core_group
|
||||
* @covers \core_group\customfield\group_handler
|
||||
* @author Tomo Tsuyuki <[email protected]>
|
||||
* @copyright 2023 Catalyst IT Pty Ltd
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class group_handler_test extends advanced_testcase {
|
||||
/**
|
||||
* Test custom field handler.
|
||||
* @var group_handler
|
||||
*/
|
||||
protected $handler;
|
||||
|
||||
/**
|
||||
* Setup.
|
||||
*/
|
||||
public function setUp(): void {
|
||||
$this->handler = group_handler::create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create group custom field for testing.
|
||||
*
|
||||
* @return field_controller
|
||||
*/
|
||||
protected function create_group_custom_field(): field_controller {
|
||||
$fieldcategory = self::getDataGenerator()->create_custom_field_category([
|
||||
'component' => 'core_group',
|
||||
'area' => 'group',
|
||||
]);
|
||||
|
||||
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('/group/customfield.php', $this->handler->get_configuration_url()->out_as_local_url());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting instance context.
|
||||
*/
|
||||
public function test_get_instance_context() {
|
||||
global $COURSE;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$group = self::getDataGenerator()->create_group(['courseid' => $course->id]);
|
||||
|
||||
$this->assertInstanceOf(context_course::class, $this->handler->get_instance_context());
|
||||
$this->assertSame(context_course::instance($COURSE->id), $this->handler->get_instance_context());
|
||||
|
||||
$this->assertInstanceOf(context_course::class, $this->handler->get_instance_context($group->id));
|
||||
$this->assertSame(context_course::instance($course->id), $this->handler->get_instance_context($group->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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/group: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 can edit functionality.
|
||||
*/
|
||||
public function test_can_edit() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$contextid = context_course::instance($course->id)->id;
|
||||
$group = self::getDataGenerator()->create_group(['courseid' => $course->id]);
|
||||
$roleid = self::getDataGenerator()->create_role();
|
||||
assign_capability('moodle/course:managegroups', CAP_ALLOW, $roleid, $contextid, true);
|
||||
|
||||
$field = $this->create_group_custom_field();
|
||||
|
||||
$user = self::getDataGenerator()->create_user();
|
||||
self::setUser($user);
|
||||
|
||||
$this->assertFalse($this->handler->can_edit($field, $group->id));
|
||||
|
||||
role_assign($roleid, $user->id, $contextid);
|
||||
$this->assertTrue($this->handler->can_edit($field, $group->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test can view functionality.
|
||||
*/
|
||||
public function test_can_view() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$contextid = context_course::instance($course->id)->id;
|
||||
$group = self::getDataGenerator()->create_group(['courseid' => $course->id]);
|
||||
$manageroleid = self::getDataGenerator()->create_role();
|
||||
assign_capability('moodle/course:managegroups', CAP_ALLOW, $manageroleid, $contextid, true);
|
||||
|
||||
$viewroleid = self::getDataGenerator()->create_role();
|
||||
assign_capability('moodle/course:view', CAP_ALLOW, $viewroleid, $contextid, true);
|
||||
|
||||
$viewandmanageroleid = self::getDataGenerator()->create_role();
|
||||
assign_capability('moodle/course:managegroups', CAP_ALLOW, $viewandmanageroleid, $contextid, true);
|
||||
assign_capability('moodle/course:view', CAP_ALLOW, $viewandmanageroleid, $contextid, true);
|
||||
|
||||
$field = $this->create_group_custom_field();
|
||||
|
||||
$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, $group->id));
|
||||
|
||||
self::setUser($user2);
|
||||
$this->assertFalse($this->handler->can_view($field, $group->id));
|
||||
|
||||
self::setUser($user3);
|
||||
$this->assertFalse($this->handler->can_view($field, $group->id));
|
||||
|
||||
role_assign($manageroleid, $user1->id, $contextid);
|
||||
role_assign($viewroleid, $user2->id, $contextid);
|
||||
role_assign($viewandmanageroleid, $user3->id, $contextid);
|
||||
|
||||
self::setUser($user1);
|
||||
$this->assertTrue($this->handler->can_view($field, $group->id));
|
||||
|
||||
self::setUser($user2);
|
||||
$this->assertTrue($this->handler->can_view($field, $group->id));
|
||||
|
||||
self::setUser($user3);
|
||||
$this->assertTrue($this->handler->can_view($field, $group->id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
<?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_group\customfield;
|
||||
|
||||
use advanced_testcase;
|
||||
use context_course;
|
||||
use context_system;
|
||||
use moodle_url;
|
||||
use core_customfield\field_controller;
|
||||
|
||||
/**
|
||||
* Unit tests for grouping custom field handler.
|
||||
*
|
||||
* @package core_group
|
||||
* @covers \core_group\customfield\group_handler
|
||||
* @author Tomo Tsuyuki <[email protected]>
|
||||
* @copyright 2023 Catalyst IT Pty Ltd
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class grouping_handler_test extends advanced_testcase {
|
||||
/**
|
||||
* Test custom field handler.
|
||||
* @var \core_customfield\handler
|
||||
*/
|
||||
protected $handler;
|
||||
|
||||
/**
|
||||
* Setup.
|
||||
*/
|
||||
public function setUp(): void {
|
||||
$this->handler = grouping_handler::create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create grouping custom field for testing.
|
||||
*
|
||||
* @return field_controller
|
||||
*/
|
||||
protected function create_grouping_custom_field(): field_controller {
|
||||
$fieldcategory = self::getDataGenerator()->create_custom_field_category([
|
||||
'component' => 'core_group',
|
||||
'area' => 'grouping',
|
||||
]);
|
||||
|
||||
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('/group/grouping_customfield.php', $this->handler->get_configuration_url()->out_as_local_url());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting instance context.
|
||||
*/
|
||||
public function test_get_instance_context() {
|
||||
global $COURSE;
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$grouping = self::getDataGenerator()->create_grouping(['courseid' => $course->id]);
|
||||
|
||||
$this->assertInstanceOf(context_course::class, $this->handler->get_instance_context());
|
||||
$this->assertSame(context_course::instance($COURSE->id), $this->handler->get_instance_context());
|
||||
|
||||
$this->assertInstanceOf(context_course::class, $this->handler->get_instance_context($grouping->id));
|
||||
$this->assertSame(context_course::instance($course->id), $this->handler->get_instance_context($grouping->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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/group: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 can edit functionality.
|
||||
*/
|
||||
public function test_can_edit() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$contextid = context_course::instance($course->id)->id;
|
||||
$grouping = self::getDataGenerator()->create_grouping(['courseid' => $course->id]);
|
||||
$roleid = self::getDataGenerator()->create_role();
|
||||
assign_capability('moodle/course:managegroups', CAP_ALLOW, $roleid, $contextid, true);
|
||||
|
||||
$field = $this->create_grouping_custom_field();
|
||||
|
||||
$user = self::getDataGenerator()->create_user();
|
||||
self::setUser($user);
|
||||
|
||||
$this->assertFalse($this->handler->can_edit($field, $grouping->id));
|
||||
|
||||
role_assign($roleid, $user->id, $contextid);
|
||||
$this->assertTrue($this->handler->can_edit($field, $grouping->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test can view functionality.
|
||||
*/
|
||||
public function test_can_view() {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$contextid = context_course::instance($course->id)->id;
|
||||
$grouping = self::getDataGenerator()->create_grouping(['courseid' => $course->id]);
|
||||
$manageroleid = self::getDataGenerator()->create_role();
|
||||
assign_capability('moodle/course:managegroups', CAP_ALLOW, $manageroleid, $contextid, true);
|
||||
|
||||
$viewroleid = self::getDataGenerator()->create_role();
|
||||
assign_capability('moodle/course:view', CAP_ALLOW, $viewroleid, $contextid, true);
|
||||
|
||||
$viewandmanageroleid = self::getDataGenerator()->create_role();
|
||||
assign_capability('moodle/course:managegroups', CAP_ALLOW, $viewandmanageroleid, $contextid, true);
|
||||
assign_capability('moodle/course:view', CAP_ALLOW, $viewandmanageroleid, $contextid, true);
|
||||
|
||||
$field = $this->create_grouping_custom_field();
|
||||
|
||||
$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, $grouping->id));
|
||||
|
||||
self::setUser($user2);
|
||||
$this->assertFalse($this->handler->can_view($field, $grouping->id));
|
||||
|
||||
self::setUser($user3);
|
||||
$this->assertFalse($this->handler->can_view($field, $grouping->id));
|
||||
|
||||
role_assign($manageroleid, $user1->id, $contextid);
|
||||
role_assign($viewroleid, $user2->id, $contextid);
|
||||
role_assign($viewandmanageroleid, $user3->id, $contextid);
|
||||
|
||||
self::setUser($user1);
|
||||
$this->assertTrue($this->handler->can_view($field, $grouping->id));
|
||||
|
||||
self::setUser($user2);
|
||||
$this->assertTrue($this->handler->can_view($field, $grouping->id));
|
||||
|
||||
self::setUser($user3);
|
||||
$this->assertTrue($this->handler->can_view($field, $grouping->id));
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,10 @@
|
||||
|
||||
namespace core_group;
|
||||
|
||||
use core_customfield\field_controller;
|
||||
use core_external\external_api;
|
||||
use core_group\customfield\group_handler;
|
||||
use core_group\customfield\grouping_handler;
|
||||
use core_group_external;
|
||||
use externallib_advanced_testcase;
|
||||
|
||||
@@ -36,9 +39,45 @@ require_once($CFG->dirroot . '/group/lib.php');
|
||||
* @copyright 2012 Jerome Mouneyrac
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @since Moodle 2.4
|
||||
* @covers \core_group_external
|
||||
*/
|
||||
class externallib_test extends externallib_advanced_testcase {
|
||||
|
||||
/**
|
||||
* Create group custom field for testing.
|
||||
*
|
||||
* @return field_controller
|
||||
*/
|
||||
protected function create_group_custom_field(): field_controller {
|
||||
$fieldcategory = self::getDataGenerator()->create_custom_field_category([
|
||||
'component' => 'core_group',
|
||||
'area' => 'group',
|
||||
]);
|
||||
|
||||
return self::getDataGenerator()->create_custom_field([
|
||||
'shortname' => 'testgroupcustomfield1',
|
||||
'type' => 'text',
|
||||
'categoryid' => $fieldcategory->get('id'),
|
||||
]);
|
||||
}
|
||||
/**
|
||||
* Create grouping custom field for testing.
|
||||
*
|
||||
* @return field_controller
|
||||
*/
|
||||
protected function create_grouping_custom_field(): field_controller {
|
||||
$fieldcategory = self::getDataGenerator()->create_custom_field_category([
|
||||
'component' => 'core_group',
|
||||
'area' => 'grouping',
|
||||
]);
|
||||
|
||||
return self::getDataGenerator()->create_custom_field([
|
||||
'shortname' => 'testgroupingcustomfield1',
|
||||
'type' => 'text',
|
||||
'categoryid' => $fieldcategory->get('id'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test create_groups
|
||||
*/
|
||||
@@ -129,6 +168,41 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$froups = core_group_external::create_groups(array($group4));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test create_groups with custom fields.
|
||||
*/
|
||||
public function test_create_groups_with_customfields() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$this->create_group_custom_field();
|
||||
$group = [
|
||||
'courseid' => $course->id,
|
||||
'name' => 'Create groups test (with custom fields)',
|
||||
'description' => 'Description for create groups test with custom fields',
|
||||
'customfields' => [
|
||||
[
|
||||
'shortname' => 'testgroupcustomfield1',
|
||||
'value' => 'Test group value 1',
|
||||
],
|
||||
],
|
||||
];
|
||||
$createdgroups = core_group_external::create_groups([$group]);
|
||||
$createdgroups = external_api::clean_returnvalue(core_group_external::create_groups_returns(), $createdgroups);
|
||||
|
||||
$this->assertCount(1, $createdgroups);
|
||||
$createdgroup = reset($createdgroups);
|
||||
$dbgroup = $DB->get_record('groups', ['id' => $createdgroup['id']], '*', MUST_EXIST);
|
||||
$this->assertEquals($group['name'], $dbgroup->name);
|
||||
$this->assertEquals($group['description'], $dbgroup->description);
|
||||
|
||||
$data = group_handler::create()->export_instance_data_object($createdgroup['id'], true);
|
||||
$this->assertEquals('Test group value 1', $data->testgroupcustomfield1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that creating a group with an invalid visibility value throws an exception.
|
||||
*
|
||||
@@ -240,6 +314,35 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$groups = core_group_external::update_groups(array($group1data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test update_groups with custom fields.
|
||||
*/
|
||||
public function test_update_groups_with_customfields() {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$this->create_group_custom_field();
|
||||
$group = self::getDataGenerator()->create_group(['courseid' => $course->id]);
|
||||
|
||||
$data = group_handler::create()->export_instance_data_object($group->id, true);
|
||||
$this->assertNull($data->testgroupcustomfield1);
|
||||
|
||||
$updategroup = [
|
||||
'id' => $group->id,
|
||||
'name' => $group->name,
|
||||
'customfields' => [
|
||||
[
|
||||
'shortname' => 'testgroupcustomfield1',
|
||||
'value' => 'Test value 1',
|
||||
],
|
||||
],
|
||||
];
|
||||
core_group_external::update_groups([$updategroup]);
|
||||
$data = group_handler::create()->export_instance_data_object($group->id, true);
|
||||
$this->assertEquals('Test value 1', $data->testgroupcustomfield1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test an exception is thrown when an invalid visibility value is passed in an update.
|
||||
*
|
||||
@@ -411,6 +514,33 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
$groups = core_group_external::get_groups(array($group1->id, $group2->id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_groups with customfields.
|
||||
*/
|
||||
public function test_get_groups_with_customfields() {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$this->create_group_custom_field();
|
||||
$group = self::getDataGenerator()->create_group([
|
||||
'courseid' => $course->id,
|
||||
'customfield_testgroupcustomfield1' => 'Test group value 1',
|
||||
]);
|
||||
|
||||
// Call the external function.
|
||||
$groups = core_group_external::get_groups([$group->id]);
|
||||
// We need to execute the return values cleaning process to simulate the web service server.
|
||||
$groups = external_api::clean_returnvalue(core_group_external::get_groups_returns(), $groups);
|
||||
|
||||
$this->assertEquals(1, count($groups));
|
||||
$groupresult = reset($groups);
|
||||
$this->assertEquals(1, count($groupresult['customfields']));
|
||||
$customfield = reset($groupresult['customfields']);
|
||||
$this->assertEquals('testgroupcustomfield1', $customfield['shortname']);
|
||||
$this->assertEquals('Test group value 1', $customfield['value']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test delete_groups
|
||||
*/
|
||||
@@ -519,6 +649,73 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test create_groupings with custom fields.
|
||||
*/
|
||||
public function test_create_groupings_with_customfields() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$this->create_grouping_custom_field();
|
||||
$grouping = [
|
||||
'courseid' => $course->id,
|
||||
'name' => 'Create groupings test (with custom fields)',
|
||||
'description' => 'Description for create groupings test with custom fields',
|
||||
'idnumber' => 'groupingidnumber1',
|
||||
'customfields' => [
|
||||
[
|
||||
'shortname' => 'testgroupingcustomfield1',
|
||||
'value' => 'Test grouping value 1',
|
||||
],
|
||||
],
|
||||
];
|
||||
$createdgroupings = core_group_external::create_groupings([$grouping]);
|
||||
$createdgroupings = external_api::clean_returnvalue(core_group_external::create_groupings_returns(), $createdgroupings);
|
||||
|
||||
$this->assertCount(1, $createdgroupings);
|
||||
$createdgrouping = reset($createdgroupings);
|
||||
$dbgroup = $DB->get_record('groupings', ['id' => $createdgrouping['id']], '*', MUST_EXIST);
|
||||
$this->assertEquals($grouping['name'], $dbgroup->name);
|
||||
$this->assertEquals($grouping['description'], $dbgroup->description);
|
||||
$this->assertEquals($grouping['idnumber'], $dbgroup->idnumber);
|
||||
|
||||
$data = grouping_handler::create()->export_instance_data_object($createdgrouping['id'], true);
|
||||
$this->assertEquals('Test grouping value 1', $data->testgroupingcustomfield1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test update_groups with custom fields.
|
||||
*/
|
||||
public function test_update_groupings_with_customfields() {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$this->create_grouping_custom_field();
|
||||
$grouping = self::getDataGenerator()->create_grouping(['courseid' => $course->id]);
|
||||
|
||||
$data = grouping_handler::create()->export_instance_data_object($grouping->id, true);
|
||||
$this->assertNull($data->testgroupingcustomfield1);
|
||||
|
||||
$updategroup = [
|
||||
'id' => $grouping->id,
|
||||
'name' => $grouping->name,
|
||||
'description' => $grouping->description,
|
||||
'customfields' => [
|
||||
[
|
||||
'shortname' => 'testgroupingcustomfield1',
|
||||
'value' => 'Test grouping value 1',
|
||||
],
|
||||
],
|
||||
];
|
||||
core_group_external::update_groupings([$updategroup]);
|
||||
$data = grouping_handler::create()->export_instance_data_object($grouping->id, true);
|
||||
$this->assertEquals('Test grouping value 1', $data->testgroupingcustomfield1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_groupings
|
||||
*/
|
||||
@@ -596,6 +793,56 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test get_groupings with customfields.
|
||||
*/
|
||||
public function test_get_groupings_with_customfields() {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$this->create_grouping_custom_field();
|
||||
$grouping = self::getDataGenerator()->create_grouping([
|
||||
'courseid' => $course->id,
|
||||
'customfield_testgroupingcustomfield1' => 'Test grouping value 1',
|
||||
]);
|
||||
$this->create_group_custom_field();
|
||||
$group = self::getDataGenerator()->create_group([
|
||||
'courseid' => $course->id,
|
||||
'customfield_testgroupcustomfield1' => 'Test group value 1',
|
||||
]);
|
||||
groups_assign_grouping($grouping->id, $group->id);
|
||||
|
||||
// Call the external function.
|
||||
$groupings = core_group_external::get_groupings([$grouping->id]);
|
||||
// We need to execute the return values cleaning process to simulate the web service server.
|
||||
$groupings = external_api::clean_returnvalue(core_group_external::get_groupings_returns(), $groupings);
|
||||
|
||||
$this->assertEquals(1, count($groupings));
|
||||
$groupingresult = reset($groupings);
|
||||
$this->assertEquals(1, count($groupingresult['customfields']));
|
||||
$customfield = reset($groupingresult['customfields']);
|
||||
$this->assertEquals('testgroupingcustomfield1', $customfield['shortname']);
|
||||
$this->assertEquals('Test grouping value 1', $customfield['value']);
|
||||
$this->assertArrayNotHasKey('groups', $groupingresult);
|
||||
|
||||
// Call the external function with return group parameter.
|
||||
$groupings = core_group_external::get_groupings([$grouping->id], true);
|
||||
// We need to execute the return values cleaning process to simulate the web service server.
|
||||
$groupings = external_api::clean_returnvalue(core_group_external::get_groupings_returns(), $groupings);
|
||||
|
||||
$this->assertEquals(1, count($groupings));
|
||||
$groupingresult = reset($groupings);
|
||||
$this->assertEquals(1, count($groupingresult['customfields']));
|
||||
$this->assertArrayHasKey('groups', $groupingresult);
|
||||
$this->assertEquals(1, count($groupingresult['groups']));
|
||||
$groupresult = reset($groupingresult['groups']);
|
||||
$this->assertEquals(1, count($groupresult['customfields']));
|
||||
$customfield = reset($groupresult['customfields']);
|
||||
$this->assertEquals('testgroupcustomfield1', $customfield['shortname']);
|
||||
$this->assertEquals('Test group value 1', $customfield['value']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test delete_groupings.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
groupname, description, groupidnumber, groupingname, customfield_groupfield1, grouping_customfield_groupingfield1
|
||||
Group1, Group1-Desc, group-id1, Grouping1, Group1-Custom, Grouping1-Custom
|
||||
Group2, Group1-Desc, group-id2, Grouping1, Group2-Custom, Grouping1-Custom
|
||||
|
@@ -27,6 +27,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/group/lib.php');
|
||||
require_once($CFG->dirroot . '/lib/grouplib.php');
|
||||
|
||||
/**
|
||||
* Group lib testcase.
|
||||
@@ -439,6 +440,95 @@ class lib_test extends \advanced_testcase {
|
||||
$this->assertFalse($DB->record_exists('groupings_groups', array('groupid' => $group1->id, 'groupingid' => $grouping1->id)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test custom field for group.
|
||||
* @covers ::groups_create_group
|
||||
* @covers ::groups_get_group
|
||||
*/
|
||||
public function test_groups_with_customfield() {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
|
||||
$course1 = self::getDataGenerator()->create_course();
|
||||
$course2 = self::getDataGenerator()->create_course();
|
||||
|
||||
$groupfieldcategory = self::getDataGenerator()->create_custom_field_category([
|
||||
'component' => 'core_group',
|
||||
'area' => 'group',
|
||||
]);
|
||||
$groupcustomfield = self::getDataGenerator()->create_custom_field([
|
||||
'shortname' => 'testgroupcustomfield1',
|
||||
'type' => 'text',
|
||||
'categoryid' => $groupfieldcategory->get('id'),
|
||||
]);
|
||||
$groupingfieldcategory = self::getDataGenerator()->create_custom_field_category([
|
||||
'component' => 'core_group',
|
||||
'area' => 'grouping',
|
||||
]);
|
||||
$groupingcustomfield = self::getDataGenerator()->create_custom_field([
|
||||
'shortname' => 'testgroupingcustomfield1',
|
||||
'type' => 'text',
|
||||
'categoryid' => $groupingfieldcategory->get('id'),
|
||||
]);
|
||||
|
||||
$group1 = self::getDataGenerator()->create_group([
|
||||
'courseid' => $course1->id,
|
||||
'customfield_testgroupcustomfield1' => 'Custom input for group1',
|
||||
]);
|
||||
$group2 = self::getDataGenerator()->create_group([
|
||||
'courseid' => $course2->id,
|
||||
'customfield_testgroupcustomfield1' => 'Custom input for group2',
|
||||
]);
|
||||
$grouping1 = self::getDataGenerator()->create_grouping([
|
||||
'courseid' => $course1->id,
|
||||
'customfield_testgroupingcustomfield1' => 'Custom input for grouping1',
|
||||
]);
|
||||
$grouping2 = self::getDataGenerator()->create_grouping([
|
||||
'courseid' => $course2->id,
|
||||
'customfield_testgroupingcustomfield1' => 'Custom input for grouping2',
|
||||
]);
|
||||
|
||||
$grouphandler = \core_group\customfield\group_handler::create();
|
||||
$data = $grouphandler->export_instance_data_object($group1->id);
|
||||
$this->assertSame('Custom input for group1', $data->testgroupcustomfield1);
|
||||
$data = $grouphandler->export_instance_data_object($group2->id);
|
||||
$this->assertSame('Custom input for group2', $data->testgroupcustomfield1);
|
||||
|
||||
$groupinghandler = \core_group\customfield\grouping_handler::create();
|
||||
$data = $groupinghandler->export_instance_data_object($grouping1->id);
|
||||
$this->assertSame('Custom input for grouping1', $data->testgroupingcustomfield1);
|
||||
$data = $groupinghandler->export_instance_data_object($grouping2->id);
|
||||
$this->assertSame('Custom input for grouping2', $data->testgroupingcustomfield1);
|
||||
|
||||
$group1->customfield_testgroupcustomfield1 = 'Updated input for group1';
|
||||
$group2->customfield_testgroupcustomfield1 = 'Updated input for group2';
|
||||
groups_update_group($group1);
|
||||
groups_update_group($group2);
|
||||
$data = $grouphandler->export_instance_data_object($group1->id);
|
||||
$this->assertSame('Updated input for group1', $data->testgroupcustomfield1);
|
||||
$data = $grouphandler->export_instance_data_object($group2->id);
|
||||
$this->assertSame('Updated input for group2', $data->testgroupcustomfield1);
|
||||
|
||||
$group = groups_get_group($group1->id, '*', IGNORE_MISSING, true);
|
||||
$this->assertCount(1, $group->customfields);
|
||||
$customfield = reset($group->customfields);
|
||||
$this->assertSame('Updated input for group1', $customfield['value']);
|
||||
|
||||
$grouping1->customfield_testgroupingcustomfield1 = 'Updated input for grouping1';
|
||||
$grouping2->customfield_testgroupingcustomfield1 = 'Updated input for grouping2';
|
||||
groups_update_grouping($grouping1);
|
||||
groups_update_grouping($grouping2);
|
||||
$data = $groupinghandler->export_instance_data_object($grouping1->id);
|
||||
$this->assertSame('Updated input for grouping1', $data->testgroupingcustomfield1);
|
||||
$data = $groupinghandler->export_instance_data_object($grouping2->id);
|
||||
$this->assertSame('Updated input for grouping2', $data->testgroupingcustomfield1);
|
||||
|
||||
$grouping = groups_get_grouping($grouping1->id, '*', IGNORE_MISSING, true);
|
||||
$this->assertCount(1, $grouping->customfields);
|
||||
$customfield = reset($grouping->customfields);
|
||||
$this->assertSame('Updated input for grouping1', $customfield['value']);
|
||||
}
|
||||
|
||||
public function test_groups_create_autogroups () {
|
||||
global $DB;
|
||||
$this->resetAfterTest();
|
||||
|
||||
@@ -17,6 +17,7 @@ information provided here is intended especially for developers.
|
||||
'/',
|
||||
'group.svg'
|
||||
);
|
||||
* Added group/grouping custom fields.
|
||||
|
||||
=== 4.2 ===
|
||||
* `\core_group\visibility` class added to support new `visibility` field in group records. This holds the visibility constants
|
||||
|
||||
@@ -697,6 +697,8 @@ $string['globalsearch'] = 'Global search';
|
||||
$string['globalsearchmanage'] = 'Manage global search';
|
||||
$string['groupenrolmentkeypolicy'] = 'Group enrolment key policy';
|
||||
$string['groupenrolmentkeypolicy_desc'] = 'If enabled, group enrolment keys will be checked against the password policy as specified in the settings above.';
|
||||
$string['grouping_customfield'] = 'Grouping custom fields';
|
||||
$string['group_customfield'] = 'Group custom fields';
|
||||
$string['googlemapkey3'] = 'Google Maps API V3 key';
|
||||
$string['googlemapkey3_help'] = 'You need to enter a special key to use Google Maps for IP address lookup visualization. You can obtain the key free of charge at <a href="https://developers.google.com/maps/documentation/javascript/tutorial#api_key" target="_blank">https://developers.google.com/maps/documentation/javascript/tutorial#api_key</a>';
|
||||
$string['gotofirst'] = 'Go to first missing string';
|
||||
|
||||
@@ -280,6 +280,7 @@ $string['grade:unlock'] = 'Unlock grades or items';
|
||||
$string['grade:view'] = 'View own grades';
|
||||
$string['grade:viewall'] = 'View grades of other users';
|
||||
$string['grade:viewhidden'] = 'View hidden grades for owner';
|
||||
$string['group:configurecustomfields'] = 'Configure group/grouping custom fields';
|
||||
$string['h5p:deploy'] = 'Deploy H5P content';
|
||||
$string['h5p:updatelibraries'] = 'Manage H5P content types';
|
||||
$string['h5p:setdisplayoptions'] = 'Set H5P display options';
|
||||
|
||||
@@ -788,6 +788,13 @@ $capabilities = array(
|
||||
'clonepermissionsfrom' => 'moodle/site:config'
|
||||
),
|
||||
|
||||
'moodle/group:configurecustomfields' => array(
|
||||
'riskbitmask' => RISK_SPAM,
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_SYSTEM,
|
||||
'clonepermissionsfrom' => 'moodle/site:config'
|
||||
),
|
||||
|
||||
'moodle/course:create' => array(
|
||||
|
||||
'riskbitmask' => RISK_XSS,
|
||||
|
||||
+14
-4
@@ -211,9 +211,14 @@ function groups_get_grouping_by_idnumber($courseid, $idnumber) {
|
||||
* @return bool|stdClass group object or false if not found
|
||||
* @throws dml_exception
|
||||
*/
|
||||
function groups_get_group($groupid, $fields='*', $strictness=IGNORE_MISSING) {
|
||||
function groups_get_group($groupid, $fields = '*', $strictness = IGNORE_MISSING, $withcustomfields = false) {
|
||||
global $DB;
|
||||
return $DB->get_record('groups', array('id'=>$groupid), $fields, $strictness);
|
||||
$group = $DB->get_record('groups', ['id' => $groupid], $fields, $strictness);
|
||||
if ($withcustomfields) {
|
||||
$customfieldsdata = get_group_custom_fields_data([$groupid]);
|
||||
$group->customfields = $customfieldsdata[$groupid] ?? [];
|
||||
}
|
||||
return $group;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -225,9 +230,14 @@ function groups_get_group($groupid, $fields='*', $strictness=IGNORE_MISSING) {
|
||||
* @param int $strictness (IGNORE_MISSING - default)
|
||||
* @return stdClass group object
|
||||
*/
|
||||
function groups_get_grouping($groupingid, $fields='*', $strictness=IGNORE_MISSING) {
|
||||
function groups_get_grouping($groupingid, $fields='*', $strictness=IGNORE_MISSING, $withcustomfields = false) {
|
||||
global $DB;
|
||||
return $DB->get_record('groupings', array('id'=>$groupingid), $fields, $strictness);
|
||||
$grouping = $DB->get_record('groupings', ['id' => $groupingid], $fields, $strictness);
|
||||
if ($withcustomfields) {
|
||||
$customfieldsdata = get_grouping_custom_fields_data([$groupingid]);
|
||||
$grouping->customfields = $customfieldsdata[$groupingid] ?? [];
|
||||
}
|
||||
return $grouping;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -261,6 +261,12 @@ class phpunit_util extends testing_util {
|
||||
if (class_exists('\core_cohort\customfield\cohort_handler')) {
|
||||
\core_cohort\customfield\cohort_handler::reset_caches();
|
||||
}
|
||||
if (class_exists('\core_group\customfield\group_handler')) {
|
||||
\core_group\customfield\group_handler::reset_caches();
|
||||
}
|
||||
if (class_exists('\core_group\customfield\grouping_handler')) {
|
||||
\core_group\customfield\grouping_handler::reset_caches();
|
||||
}
|
||||
|
||||
// Clear static cache within restore.
|
||||
if (class_exists('restore_section_structure_step')) {
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$version = 2023080400.00; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
$version = 2023080400.01; // YYYYMMDD = weekly release date of this DEV branch.
|
||||
// RR = release increments - 00 in DEV branches.
|
||||
// .XX = incremental changes.
|
||||
$release = '4.3dev (Build: 20230804)'; // Human-friendly version name
|
||||
|
||||
Reference in New Issue
Block a user