Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/sync on category #8

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## Requirements

- Moodle 3.5.3 or later.
- Moodle 3.6 or later.

## Installation

Expand All @@ -15,10 +15,10 @@ Once installed, you should see a new option in your site administration:
## Usage

1. Create system-level cohort(s).
2. Create system-level assignable role(s) - optional, you can also use existing roles.
2. Create system-level or category-level assignable role(s) - optional, you can also use existing roles.
3. Visit Cohort role synchronization page.
4. Create new link between cohort and role.
5. Users will automatically be (un)assigned to the role according to their membership of selected cohort.
4. Create new link between cohort and role on system context or a specific course category.
5. Users will automatically be (un)assigned to the role within the specified context according to their membership of selected cohort.

## Author

Expand Down
41 changes: 35 additions & 6 deletions classes/form/edit.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ class edit extends \core\form\persistent {
/** @var string Persistent class name. */
protected static $persistentclass = persistent::class;

/** @var array Fields to remove when getting the final data. */
protected static $fieldstoremove = array('submitbutton', 'modeid');

/**
* Form definition
*
Expand All @@ -41,16 +44,26 @@ class edit extends \core\form\persistent {
protected function definition() {
$mform = $this->_form;

$mode = $this->_customdata['modeid'];

$mform->addElement('hidden', 'modeid', $mode);
$mform->setType('modeid', PARAM_INT);

$mform->addElement('select', 'cohortid', get_string('cohort', 'local_cohortrole'), self::get_cohorts());
$mform->addRule('cohortid', get_string('required'), 'required', null, 'client');
$mform->setType('cohortid', PARAM_INT);
$mform->addHelpButton('cohortid', 'cohort', 'local_cohortrole');

$mform->addElement('select', 'roleid', get_string('role', 'local_cohortrole'), self::get_roles());
$mform->addElement('select', 'roleid', get_string('role', 'local_cohortrole'), self::get_roles($mode));
$mform->addRule('roleid', get_string('required'), 'required', null, 'client');
$mform->setType('roleid', PARAM_INT);
$mform->addHelpButton('roleid', 'role', 'local_cohortrole');

$mform->addElement('select', 'categoryid', get_string('category', 'local_cohortrole'), self::get_categories());
$mform->setType('categoryid', PARAM_INT);
$mform->addHelpButton('categoryid', 'category', 'local_cohortrole');
$mform->hideIf('categoryid', 'modeid', 'eq', 0);

$this->add_action_buttons();
}

Expand All @@ -63,8 +76,8 @@ protected function definition() {
* @return array
*/
public function extra_validation($data, $files, array &$errors) {
if ($this->get_persistent()->record_exists_select('cohortid = :cohortid AND roleid = :roleid',
['cohortid' => $data->cohortid, 'roleid' => $data->roleid])) {
if ($this->get_persistent()->record_exists_select('cohortid = :cohortid AND roleid = :roleid AND categoryid = :categoryid',
['cohortid' => $data->cohortid, 'roleid' => $data->roleid, 'categoryid' => $data->categoryid])) {

$errors['cohortid'] = get_string('errorexists', 'local_cohortrole');
}
Expand All @@ -89,15 +102,31 @@ protected static function get_cohorts() {
}

/**
* Get roles that are assignable in the system context
* Get roles that are assignable in the system or course category context
*
* @param string $modeid The selected modeid (0 = System, 1 = Category)
* @return array
*/
protected static function get_roles() {
$roles = get_assignable_roles(\context_system::instance(), ROLENAME_ALIAS);
protected static function get_roles($modeid) {
$context = local_cohortrole_get_context($modeid);

$roles = get_assignable_roles($context, ROLENAME_ALIAS);

\core_collator::asort($roles, \core_collator::SORT_STRING);

return $roles;
}

/**
* Get categories from the system
*
* @return array
*/
protected static function get_categories() {
$categories = [0 => get_string('choosedots')] + \core_course_category::make_categories_list();

\core_collator::asort($categories, \core_collator::SORT_STRING);

return $categories;
}
}
32 changes: 25 additions & 7 deletions classes/observers.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,10 @@ public static function cohort_deleted(\core\event\cohort_deleted $event) {
$cohort = $event->get_record_snapshot('cohort', $event->objectid);

$instances = persistent::get_records(['cohortid' => $cohort->id]);
if (count($instances) > 0) {
local_cohortrole_unsynchronize($cohort->id);
foreach ($instances as $instance) {
local_cohortrole_unsynchronize($cohort->id, $instance->get('roleid'), $instance->get('categoryid'));

foreach ($instances as $instance) {
$instance->delete();
}
$instance->delete();
}
}
}
Expand All @@ -64,7 +62,8 @@ public static function cohort_member_added(\core\event\cohort_member_added $even
$user = \core_user::get_user($event->relateduserid, '*', MUST_EXIST);

foreach ($instances as $instance) {
local_cohortrole_role_assign($instance->get('cohortid'), $instance->get('roleid'), [$user->id]);
local_cohortrole_role_assign($instance->get('cohortid'), $instance->get('roleid'), $instance->get('categoryid'),
[$user->id]);
}
}
}
Expand All @@ -85,7 +84,8 @@ public static function cohort_member_removed(\core\event\cohort_member_removed $
$user = \core_user::get_user($event->relateduserid, '*', MUST_EXIST);

foreach ($instances as $instance) {
local_cohortrole_role_unassign($instance->get('cohortid'), $instance->get('roleid'), [$user->id]);
local_cohortrole_role_unassign($instance->get('cohortid'), $instance->get('roleid'),
$instance->get('categoryid'), [$user->id]);
}
}
}
Expand All @@ -107,4 +107,22 @@ public static function role_deleted(\core\event\role_deleted $event) {
}
}
}

/**
* Category deleted
*
* @param \core\event\course_category_deleted $event the event
* @return void
*/
public static function course_category_deleted(\core\event\course_category_deleted $event) {
if ($event->contextlevel == CONTEXT_COURSECAT) {
// MDL-71314: Fix the missing record snapshot issue. Workaround using contextinstanceid of event.
//$category = $event->get_record_snapshot('course_categories', $event->objectid);
//$instances = persistent::get_records(['categoryid' => $category->id]);
$instances = persistent::get_records(['categoryid' => $event->contextinstanceid]);
foreach ($instances as $instance) {
$instance->delete();
}
}
}
}
18 changes: 18 additions & 0 deletions classes/output/summary_table.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public function __construct() {
$columns = [
'cohort' => get_string('cohort', 'local_cohortrole'),
'role' => get_string('role', 'local_cohortrole'),
'category' => get_string('category', 'local_cohortrole'),
'timecreated' => get_string('modified'),
'edit' => get_string('edit'),
];
Expand Down Expand Up @@ -124,6 +125,23 @@ public function col_role(\stdClass $record) {
return role_get_name($persistent->get_role(), \context_system::instance(), ROLENAME_ALIAS);
}

/**
* Format record category column
*
* @param stdClass $record
* @return string
*/
public function col_category(\stdClass $record) {
if ($record->categoryid == LOCAL_COHORTROLE_MODE_SYSTEM) {
return '';
}

$persistent = new persistent(0, $record);
$category = \core_course_category::get($persistent->get_category()->id);

return $category->get_nested_name();
}

/**
* Format record time created column
*
Expand Down
36 changes: 36 additions & 0 deletions classes/persistent.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

defined('MOODLE_INTERNAL') || die();

require_once($CFG->dirroot . '/local/cohortrole/locallib.php');

use \local_cohortrole\event\definition_created,
\local_cohortrole\event\definition_deleted;

Expand All @@ -45,6 +47,9 @@ protected static function define_properties() {
'roleid' => array(
'type' => PARAM_INT,
),
'categoryid' => array(
'type' => PARAM_INT,
),
);
}

Expand Down Expand Up @@ -82,6 +87,26 @@ protected function validate_roleid($roleid) {
return true;
}

/**
* Validate category ID
*
* @param int $categoryid
* @return true|lang_string
*/
protected function validate_categoryid($categoryid) {
global $DB;

if ($categoryid == LOCAL_COHORTROLE_MODE_SYSTEM) {
return true;
}

if (! $DB->record_exists('course_categories', ['id' => $categoryid])) {
return new \lang_string('invalidcategoryid', 'error');
}

return true;
}

/**
* Hook to execute after model is created
*
Expand Down Expand Up @@ -122,4 +147,15 @@ public function get_role() {

return $DB->get_record('role', ['id' => $this->get('roleid')], '*', MUST_EXIST);
}

/**
* Returns the category object
*
* @return stdClass
*/
public function get_category() {
global $DB;

return $DB->get_record('course_categories', ['id' => $this->get('categoryid')], '*', MUST_EXIST);
}
}
2 changes: 2 additions & 0 deletions classes/privacy/provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public static function get_metadata(collection $collection) : collection {
$collection->add_database_table('local_cohortrole', [
'cohortid' => 'privacy:metadata:cohortrole:cohortid',
'roleid' => 'privacy:metadata:cohortrole:roleid',
'categoryid' => 'privacy:metadata:cohortrole:categoryid',
'usermodified' => 'privacy:metadata:cohortrole:usermodified',
'timecreated' => 'privacy:metadata:cohortrole:timecreated',

Expand Down Expand Up @@ -112,6 +113,7 @@ public static function export_user_data(approved_contextlist $contextlist) {
$data[] = (object) [
'cohort' => $instance->get_cohort()->name,
'role' => role_get_name($instance->get_role(), $context, ROLENAME_ALIAS),
'category' => $instance->get_category()->name,
'timecreated' => transform::datetime($instance->get('timecreated')),
];
}
Expand Down
4 changes: 4 additions & 0 deletions db/events.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,8 @@
'eventname' => '\core\event\role_deleted',
'callback' => '\local_cohortrole\observers::role_deleted',
),
array(
'eventname' => '\core\event\course_category_deleted',
'callback' => '\local_cohortrole\observers::course_category_deleted',
),
);
4 changes: 3 additions & 1 deletion db/install.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="cohortid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The id of the cohort"/>
<FIELD NAME="roleid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The id of the role"/>
<FIELD NAME="categoryid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="The id of the category"/>
<FIELD NAME="usermodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="The id of the user"/>
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Time the definition was created"/>
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Time the definition was modified"/>
Expand All @@ -17,10 +18,11 @@
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="fk_cohort" TYPE="foreign" FIELDS="cohortid" REFTABLE="cohort" REFFIELDS="id"/>
<KEY NAME="fk_role" TYPE="foreign" FIELDS="roleid" REFTABLE="role" REFFIELDS="id"/>
<KEY NAME="fk_category" TYPE="foreign" FIELDS="categoryid" REFTABLE="course_categories" REFFIELDS="id"/>
<KEY NAME="fk_user" TYPE="foreign" FIELDS="usermodified" REFTABLE="user" REFFIELDS="id"/>
</KEYS>
<INDEXES>
<INDEX NAME="uq_cohort_role" UNIQUE="true" FIELDS="cohortid, roleid" COMMENT="Cohort and role identifiers must be unique"/>
<INDEX NAME="uq_cohort_role" UNIQUE="true" FIELDS="cohortid, roleid, categoryid" COMMENT="Cohort, role and category identifiers must be unique"/>
</INDEXES>
</TABLE>
</TABLES>
Expand Down
28 changes: 28 additions & 0 deletions db/upgrade.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,5 +119,33 @@ function xmldb_local_cohortrole_upgrade($oldversion) {
upgrade_plugin_savepoint(true, 2018121001, 'local', 'cohortrole');
}

if ($oldversion < 2021060801) {
// Define field categoryid to be added to local_cohortrole.
$table = new xmldb_table('local_cohortrole');
$field = new xmldb_field('categoryid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, 0, 'roleid');

// Conditionally launch add field categoryid.
if (! $dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}

// Define key fk_category (foreign) to be added to local_cohortrole.
$key = new xmldb_key('fk_category', XMLDB_KEY_FOREIGN, array('categoryid'), 'course_categories', array('id'));
$dbman->add_key($table, $key);

// Conditionally launch drop and add index 'uq_cohort_role'.
$index = new xmldb_index('uq_cohort_role', XMLDB_INDEX_UNIQUE, array('cohortid', 'roleid'));

if ($dbman->index_exists($table, $index)) {
$dbman->drop_index($table, $index);
}

$index = new xmldb_index('uq_cohort_role', XMLDB_INDEX_UNIQUE, array('cohortid', 'roleid', 'categoryid'));
$dbman->add_index($table, $index);

// Cohortrole savepoint reached.
upgrade_plugin_savepoint(true, 2021060801, 'local', 'cohortrole');
}

return true;
}
15 changes: 8 additions & 7 deletions edit.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,20 @@

use \local_cohortrole\persistent;

$delete = optional_param('delete', 0, PARAM_INT);
$confirm = optional_param('confirm', 0, PARAM_BOOL);
$delete = optional_param('delete', 0, PARAM_INT);
$confirm = optional_param('confirm', 0, PARAM_BOOL);
$mode = optional_param('mode', 0, PARAM_INT);

admin_externalpage_setup('local_cohortrole');

$editurl = new moodle_url('/local/cohortrole/edit.php');
$editurl = new moodle_url('/local/cohortrole/edit.php');
$returnurl = clone($PAGE->url);

if ($delete) {
$persistent = new persistent($delete);

if ($confirm and confirm_sesskey()) {
local_cohortrole_unsynchronize($persistent->get('cohortid'), $persistent->get('roleid'));
local_cohortrole_unsynchronize($persistent->get('cohortid'), $persistent->get('roleid'), $persistent->get('categoryid'));

$persistent->delete();

Expand All @@ -58,14 +59,14 @@
die;
}

$mform = new \local_cohortrole\form\edit($editurl, ['persistent' => null]);
$mform = new \local_cohortrole\form\edit($editurl, ['persistent' => null, 'modeid' => $mode]);

if ($mform->is_cancelled()) {
redirect($returnurl);
} else if ($data = $mform->get_data()) {
$persistent = (new persistent(0, $data))->create();

local_cohortrole_synchronize($persistent->get('cohortid'), $persistent->get('roleid'));
local_cohortrole_synchronize($persistent->get('cohortid'), $persistent->get('roleid'), $persistent->get('categoryid'));

redirect($returnurl, get_string('notificationcreated', 'local_cohortrole'), null,
\core\output\notification::NOTIFY_SUCCESS);
Expand All @@ -74,7 +75,7 @@
$PAGE->navbar->add(get_string('add'));

echo $OUTPUT->header();
echo $OUTPUT->heading(get_string('heading_add', 'local_cohortrole'));
echo $OUTPUT->heading(get_string('heading_add', 'local_cohortrole', local_cohortrole_get_context_name($mode)));

$mform->display();

Expand Down
Loading