Merge branch 'MDL-31973-master-6' of git://git.luns.net.uk/moodle

Conflicts:
	lib/db/upgrade.php
This commit is contained in:
Eloy Lafuente (stronk7) 2012-08-29 00:42:43 +02:00
commit 238f7761af
14 changed files with 161 additions and 7 deletions

View file

@ -1005,7 +1005,7 @@ class backup_groups_structure_step extends backup_structure_step {
$members = new backup_nested_element('group_members'); $members = new backup_nested_element('group_members');
$member = new backup_nested_element('group_member', array('id'), array( $member = new backup_nested_element('group_member', array('id'), array(
'userid', 'timeadded')); 'userid', 'timeadded', 'component', 'itemid'));
$groupings = new backup_nested_element('groupings'); $groupings = new backup_nested_element('groupings');

View file

@ -780,6 +780,17 @@ class restore_groups_structure_step extends restore_structure_step {
// map user newitemid and insert if not member already // map user newitemid and insert if not member already
if ($data->userid = $this->get_mappingid('user', $data->userid)) { if ($data->userid = $this->get_mappingid('user', $data->userid)) {
if (!$DB->record_exists('groups_members', array('groupid' => $data->groupid, 'userid' => $data->userid))) { if (!$DB->record_exists('groups_members', array('groupid' => $data->groupid, 'userid' => $data->userid))) {
// Check the componment, if any, exists
if (!empty($data->component)) {
$dir = get_component_directory($data->component);
if (!$dir || !is_dir($dir)) {
// Component does not exist on restored system; clear
// component and itemid
unset($data->component);
unset($data->itemid);
}
}
$DB->insert_record('groups_members', $data); $DB->insert_record('groups_members', $data);
} }
} }

View file

@ -702,7 +702,8 @@ function process_membership_tag($tagcontents){
} }
// Add the user-to-group association if it doesn't already exist // Add the user-to-group association if it doesn't already exist
if($member->groupid) { if($member->groupid) {
groups_add_member($member->groupid, $memberstoreobj->userid); groups_add_member($member->groupid, $memberstoreobj->userid,
'enrol_imsenterprise', $einstance->id);
} }
} // End of group-enrolment (from member.role.extension.cohort tag) } // End of group-enrolment (from member.role.extension.cohort tag)
@ -793,6 +794,19 @@ function load_role_mappings() {
} }
} }
/**
* Called whenever anybody tries (from the normal interface) to remove a group
* member which is registered as being created by this component. (Not called
* when deleting an entire group or course at once.)
* @param int $itemid Item ID that was stored in the group_members entry
* @param int $groupid Group ID
* @param int $userid User ID being removed from group
* @return bool True if the remove is permitted, false to give an error
*/
function enrol_imsenterprise_allow_group_member_remove($itemid, $groupid, $userid) {
return false;
}
} // end of class } // end of class

View file

@ -545,6 +545,9 @@ class core_group_external extends external_api {
} }
require_capability('moodle/course:managegroups', $context); require_capability('moodle/course:managegroups', $context);
if (!groups_remove_member_allowed($group, $user)) {
throw new moodle_exception('errorremovenotpermitted', 'group', '', fullname($user));
}
groups_remove_member($group, $user); groups_remove_member($group, $user);
} }

View file

@ -33,10 +33,12 @@
* *
* @param mixed $grouporid The group id or group object * @param mixed $grouporid The group id or group object
* @param mixed $userorid The user id or user object * @param mixed $userorid The user id or user object
* @param string $component Optional component name e.g. 'enrol_imsenterprise'
* @param int $itemid Optional itemid associated with component
* @return bool True if user added successfully or the user is already a * @return bool True if user added successfully or the user is already a
* member of the group, false otherwise. * member of the group, false otherwise.
*/ */
function groups_add_member($grouporid, $userorid) { function groups_add_member($grouporid, $userorid, $component=null, $itemid=0) {
global $DB; global $DB;
if (is_object($userorid)) { if (is_object($userorid)) {
@ -68,6 +70,25 @@ function groups_add_member($grouporid, $userorid) {
$member->groupid = $groupid; $member->groupid = $groupid;
$member->userid = $userid; $member->userid = $userid;
$member->timeadded = time(); $member->timeadded = time();
$member->component = '';
$member->itemid = 0;
// Check the component exists if specified
if (!empty($component)) {
$dir = get_component_directory($component);
if ($dir && is_dir($dir)) {
// Component exists and can be used
$member->component = $component;
$member->itemid = $itemid;
} else {
throw new coding_exception('Invalid call to groups_add_member(). An invalid component was specified');
}
}
if ($itemid !== 0 && empty($member->component)) {
// An itemid can only be specified if a valid component was found
throw new coding_exception('Invalid call to groups_add_member(). A component must be specified if an itemid is given');
}
$DB->insert_record('groups_members', $member); $DB->insert_record('groups_members', $member);
@ -78,11 +99,62 @@ function groups_add_member($grouporid, $userorid) {
$eventdata = new stdClass(); $eventdata = new stdClass();
$eventdata->groupid = $groupid; $eventdata->groupid = $groupid;
$eventdata->userid = $userid; $eventdata->userid = $userid;
$eventdata->component = $member->component;
$eventdata->itemid = $member->itemid;
events_trigger('groups_member_added', $eventdata); events_trigger('groups_member_added', $eventdata);
return true; return true;
} }
/**
* Checks whether the current user is permitted (using the normal UI) to
* remove a specific group member, assuming that they have access to remove
* group members in general.
*
* For automatically-created group member entries, this checks with the
* relevant plugin to see whether it is permitted. The default, if the plugin
* doesn't provide a function, is true.
*
* For other entries (and any which have already been deleted/don't exist) it
* just returns true.
*
* @param mixed $grouporid The group id or group object
* @param mixed $userorid The user id or user object
* @return bool True if permitted, false otherwise
*/
function groups_remove_member_allowed($grouporid, $userorid) {
global $DB;
if (is_object($userorid)) {
$userid = $userorid->id;
} else {
$userid = $userorid;
}
if (is_object($grouporid)) {
$groupid = $grouporid->id;
} else {
$groupid = $grouporid;
}
// Get entry
if (!($entry = $DB->get_record('groups_members',
array('groupid' => $groupid, 'userid' => $userid), '*', IGNORE_MISSING))) {
// If the entry does not exist, they are allowed to remove it (this
// is consistent with groups_remove_member below).
return true;
}
// If the entry does not have a component value, they can remove it
if (empty($entry->component)) {
return true;
}
// It has a component value, so we need to call a plugin function (if it
// exists); the default is to allow removal
return component_callback($entry->component, 'allow_group_member_remove',
array($entry->itemid, $entry->groupid, $entry->userid), true);
}
/** /**
* Deletes the link between the specified user and group. * Deletes the link between the specified user and group.
* *

View file

@ -67,6 +67,10 @@ if (optional_param('remove', false, PARAM_BOOL) && confirm_sesskey()) {
$userstoremove = $groupmembersselector->get_selected_users(); $userstoremove = $groupmembersselector->get_selected_users();
if (!empty($userstoremove)) { if (!empty($userstoremove)) {
foreach ($userstoremove as $user) { foreach ($userstoremove as $user) {
if (!groups_remove_member_allowed($groupid, $user->id)) {
print_error('errorremovenotpermitted', 'group', $returnurl,
$user->fullname);
}
if (!groups_remove_member($groupid, $user->id)) { if (!groups_remove_member($groupid, $user->id)) {
print_error('erroraddremoveuser', 'group', $returnurl); print_error('erroraddremoveuser', 'group', $returnurl);
} }

View file

@ -24,6 +24,7 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/ */
$string['addedby'] = 'Added by {$a}';
$string['addgroup'] = 'Add user into group'; $string['addgroup'] = 'Add user into group';
$string['addgroupstogrouping'] = 'Add group to grouping'; $string['addgroupstogrouping'] = 'Add group to grouping';
$string['addgroupstogroupings'] = 'Add/remove groups'; $string['addgroupstogroupings'] = 'Add/remove groups';
@ -62,6 +63,7 @@ $string['erroraddremoveuser'] = 'Error adding/removing user {$a} to group';
$string['erroreditgroup'] = 'Error creating/updating group {$a}'; $string['erroreditgroup'] = 'Error creating/updating group {$a}';
$string['erroreditgrouping'] = 'Error creating/updating grouping {$a}'; $string['erroreditgrouping'] = 'Error creating/updating grouping {$a}';
$string['errorinvalidgroup'] = 'Error, invalid group {$a}'; $string['errorinvalidgroup'] = 'Error, invalid group {$a}';
$string['errorremovenotpermitted'] = 'You do not have permission to remove automatically-added group member {$a}';
$string['errorselectone'] = 'Please select a single group before choosing this option'; $string['errorselectone'] = 'Please select a single group before choosing this option';
$string['errorselectsome'] = 'Please select one or more groups before choosing this option'; $string['errorselectsome'] = 'Please select one or more groups before choosing this option';
$string['evenallocation'] = 'Note: To keep group allocation even, the actual number of members per group differs from the number you specified.'; $string['evenallocation'] = 'Note: To keep group allocation even, the actual number of members per group differs from the number you specified.';

View file

@ -2097,7 +2097,9 @@
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="groupid"/> <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true" NEXT="groupid"/>
<FIELD NAME="groupid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="userid"/> <FIELD NAME="groupid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="id" NEXT="userid"/>
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="groupid" NEXT="timeadded"/> <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="groupid" NEXT="timeadded"/>
<FIELD NAME="timeadded" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="userid"/> <FIELD NAME="timeadded" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="userid" NEXT="component"/>
<FIELD NAME="component" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false" COMMENT="Defines the Moodle component which added this group membership (e.g. 'auth_myplugin'), or blank if it was added manually. (Entries which are created by a Moodle component cannot be removed in the normal user interface.)" PREVIOUS="timeadded" NEXT="itemid"/>
<FIELD NAME="itemid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="If the 'component' field is set, this can be used to define the instance of the component that created the entry. Otherwise should be left as default (0)." PREVIOUS="component"/>
</FIELDS> </FIELDS>
<KEYS> <KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="groupid"/> <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="groupid"/>
@ -2864,4 +2866,4 @@
</KEYS> </KEYS>
</TABLE> </TABLE>
</TABLES> </TABLES>
</XMLDB> </XMLDB>

View file

@ -1162,6 +1162,27 @@ function xmldb_main_upgrade($oldversion) {
upgrade_main_savepoint(true, 2012082300.01); upgrade_main_savepoint(true, 2012082300.01);
} }
if ($oldversion < 2012082300.02) {
// Define field component to be added to groups_members
$table = new xmldb_table('groups_members');
$field = new xmldb_field('component', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, 'timeadded');
// Conditionally launch add field component
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
// Define field itemid to be added to groups_members
$field = new xmldb_field('itemid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'component');
// Conditionally launch add field itemid
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
// Main savepoint reached
upgrade_main_savepoint(true, 2012082300.02);
}
return true; return true;
} }

View file

@ -515,3 +515,7 @@ function page_dndupload_handle($uploadinfo) {
return page_add_instance($data, null); return page_add_instance($data, null);
} }
function mod_page_allow_group_member_remove($itemid, $groupid, $userid) {
return true;
}

View file

@ -40,6 +40,9 @@
.userselector select {width: 100%;} .userselector select {width: 100%;}
.userselector div {margin-top: 0.2em;} .userselector div {margin-top: 0.2em;}
.userselector div label {margin-right: 0.3em;} .userselector div label {margin-right: 0.3em;}
/* Next style does not work in all browsers but looks nicer when it does */
.userselector .userselector-infobelow {font-size: 0.8em;}
#userselector_options {padding:0.3em 0;} #userselector_options {padding:0.3em 0;}
#userselector_options .collapsibleregioncaption {font-weight: bold;} #userselector_options .collapsibleregioncaption {font-weight: bold;}
#userselector_options p {margin:0.2em 0;text-align:left;} #userselector_options p {margin:0.2em 0;text-align:left;}

View file

@ -578,6 +578,12 @@ abstract class user_selector_base {
unset($this->selected[$user->id]); unset($this->selected[$user->id]);
$output .= ' <option' . $attributes . ' value="' . $user->id . '">' . $output .= ' <option' . $attributes . ' value="' . $user->id . '">' .
$this->output_user($user) . "</option>\n"; $this->output_user($user) . "</option>\n";
if (!empty($user->infobelow)) {
// 'Poor man's indent' here is because CSS styles do not work
// in select options, except in Firefox.
$output .= ' <option disabled="disabled" class="userselector-infobelow">' .
'&nbsp;&nbsp;&nbsp;&nbsp;' . s($user->infobelow) . '</option>';
}
} }
} else { } else {
$output = ' <optgroup label="' . htmlspecialchars($groupname) . '">' . "\n"; $output = ' <optgroup label="' . htmlspecialchars($groupname) . '">' . "\n";
@ -712,6 +718,10 @@ abstract class groups_user_selector_base extends user_selector_base {
foreach ($groupedusers[$groupname] as &$user) { foreach ($groupedusers[$groupname] as &$user) {
unset($user->roles); unset($user->roles);
$user->fullname = fullname($user); $user->fullname = fullname($user);
if (!empty($user->component)) {
$user->infobelow = get_string('addedby', 'group',
get_string('pluginname', $user->component));
}
} }
} }
return $groupedusers; return $groupedusers;
@ -726,8 +736,8 @@ class group_members_selector extends groups_user_selector_base {
public function find_users($search) { public function find_users($search) {
list($wherecondition, $params) = $this->search_sql($search, 'u'); list($wherecondition, $params) = $this->search_sql($search, 'u');
$roles = groups_get_members_by_role($this->groupid, $this->courseid, $roles = groups_get_members_by_role($this->groupid, $this->courseid,
$this->required_fields_sql('u'), 'u.lastname, u.firstname', $this->required_fields_sql('u') . ', gm.component',
$wherecondition, $params); 'u.lastname, u.firstname', $wherecondition, $params);
return $this->convert_array_format($roles, $search); return $this->convert_array_format($roles, $search);
} }
} }

View file

@ -240,6 +240,11 @@ M.core_user.init_user_selector = function (Y, name, hash, extrafields, lastsearc
option.set('selected', false); option.set('selected', false);
} }
optgroup.append(option); optgroup.append(option);
if (user.infobelow) {
extraoption = Y.Node.create('<option disabled="disabled" class="userselector-infobelow"/>');
extraoption.appendChild(document.createTextNode(user.infobelow));
optgroup.append(extraoption);
}
count++; count++;
} }

View file

@ -87,6 +87,9 @@ foreach ($users as &$group) {
if (!empty($user->disabled)) { if (!empty($user->disabled)) {
$output->disabled = true; $output->disabled = true;
} }
if (!empty($user->infobelow)) {
$output->infobelow = $user->infobelow;
}
$group[$user->id] = $output; $group[$user->id] = $output;
} }
} }