This script will merge two Moodle user accounts, "user A" and "user B". The intent of the script is to assign all activity & records from user A to user B. This will give the effect of user B seeming to have done everything both users have ever done in Moodle. The basic function of the script is to loop through the tables and update the userid of every record from user A to user B. This works well for most tables. We do however, have a few special cases:
- Special Case #1: The grade_grades table has a compound unique key on userid and itemid. This prevents a simple update statement if the two users have done the same activity. What this script does is determine which activities have been completed by both users and delete the entry for the old user from this table. Data is not lost because a duplicate entry can be found in the grade_grades_history table, which is correctly updated by the regular processing of the script.
- Special Case #2: The user_enrolments table controls which user is enrolled in which course. Rather than unenroll the old user from the course, this script simply updates their access to the course to "2" which makes them completely unable to access the course. To remove these records all together I recomend disabling or deleting the entire old user account once the migration has been successful.
- Special Case #3: There are 4 logging/preference tables (user_lastaccess, user_preferences, user_private_key, my_pages) which exist in Moodle 2.0. This script is simply skipping these tables since there's no legitimate purpose to updating the userid value here. This would lead to duplicate rows for the new user which is silly. Again, if you want to remove these records I would recommend deleting the old user after this script runs sucessfully. my_pages' records will not be deleted, but this is something you find in Moodle, that not all records related to a specific entity are clened up. We need to skip my_pages table too, since that MyMoodle page of the old user have a relation of blocks appearing on it. If we proceed with a normal merging action, resulting with two records with the same userid, the user will not see correctly his/her MyMoodle page.
- Special Case #4: mod/journal plugin has a record per user and journal on journal_entries table. In case there is a record for both users, we delete the record related to the old user. For the rest of cases, this operates as usual.
- Special Case #5: groups_members table has a record per user and group. Updating always the old user id for the new one is incorrect if both users appear in that group. In that case, this plugin deletes the record related to the old user. For the rest of cases, this plugin operates as usual.
- Special Case #6: course_completions table has a record per user and course. Updating always the old user id for the new one is incorrect if both users appear in that group. In that case, this plugin deletes the record related to the old user. For the rest of cases, this plugin operates as usual.
- Special case #7: message_contacts table has a record per user and contact id, which is again a user.id. If replacing the old id by the new one means index conflict, this means actually that the resulting record already exists, so we can securely remove the old record. In addition, this checking is performed for both column names (userid and contactid) looking for matching on both in the same way.
- Special case #8: role_assignments table has a three-field unique index, including context, role and userid. As before, it always updates records to be the new one. If only old id exists, it is updated; if only new id exists, it does nothing; if both ids exist, the record with the old id is removed.
A cli/climerger.php script is added. You can now perform user mergings by command line having their user ids.
You can go further and develop your own CLI script by extending the Gathering interface (see lib/cligathering.php for an example). Ok, but let us explain how to do it step by step:
- Develop a class, namely MyGathering, in lib/mygathering.php, implementing the interface Gathering. Be sure the class name and the filename are the same, but filename all in lowercase ending with ".php". See lib/cligathering for an example.
- Create or edit the file config/config.local.php with at least the following content:
<?php
return array(
// gathering tool
'gathering' => 'MyGathering',
);
- Run as a command line in a form like this: $ time php cli/climerger.php.
Once the merging action is completed, an event 'merging_success' is triggered if it was ok, or an event 'merging_failed' otherwise. The available data on the event are as follows:
- oldid: the user.id of the "user A" to be removed from all his/her activity.
- newid: the user.id of the "user B" which will gather the activity of both users.
- log: string with the list of actions performed.
- timemodified: time in which the event is generated, after the merging action.
The goal of this event triggering is the ability to be detected by other parts of Moodle.
This plugin also manages the 'merging_success' event is trigered, what includes:
- Suspending the user (user.suspended = 1). This prevents the person to log in with the old account.
- Changing the old user's profile picture by the given on pix/suspended.jpg. It is a simple white image with the text "suspended user", which could help to teachers and managers to rapidly detect them.
These are the main steps to do so:
- You should have a replica of your Moodle instance, with a full replica of your Moodle database.
- Run a sufficient amount of user merging to check if anything goes wrong.
- What if...?
- ... all was ok? You are almost secure all will be ok also in your production instance of Moodle. Above all, check if your database type and version supports transcations. If so, no action will actually be committed if something went wrong.
- ... something went wrong? There are several reasons for that:
- Non-core plugins installed on your Moodle and not assumed in this plugin.
- Local database changes on Moodle that may affect to the normal execution of this plugin.
- Some compound index not detected yet.
If in your tests or already in production something went wrong, please, report the error log on the official plugin website on moodle.org. And if you have some PHP skill, you can try to solve it and share both the error and the patch to solve it ;-)
Before running this plugin, it is highly recommended to back up your database. That will help you to restore the state before any merging action was done.
This plugin stores a log for any user merging, with the list of actions done or errors produced. But, there is no provision for automatic rollbacks, so if something were to fail midway through you will end up with a half-updated database. This. Is. Bad. Practice safe script. Always backup first.
- MySQL v5.x or MSSQL or Postgres
- Moodle v2.x
GNU GPL v3 or later. http://www.gnu.org/copyleft/gpl.html
- Based on the mergeusers_v2.php script written by Nicolas Dunand.
- Updated for Moodle 2.0 by Mike Holzer [m.e.holzer AT gmail DOT com]
- Moodle 2.x report by Forrest Gaston
- Updated by Jordi Pujol-Ahulló (at SREd, Universitat Rovira i Virgili) with:
- several compound index on database tables,
- selector for the type of user identification (username, id, idnumber),
- more Moodle-like web and code, including web renderer,
- config.php with current configuration settings, used for merging,
- config.local.php to include local settings on your Moodle instance,
- log of any merging action in database for further reference
- Plugin maintained by Nicolas Dunand [nicolas.dunand AT unil DOT ch]