jpahullo / moodle-tool_mergeusers

Merge users script for Moodle
https://moodle.org/plugins/view.php?plugin=tool_mergeusers
22 stars 52 forks source link

Exception thrown when merging: 'Can not find course module". #281

Open Richardvi opened 1 month ago

Richardvi commented 1 month ago

When merging two user accounts, I have gotten this error:

Merge user accounts

  1. Choose users to merge / ► 2. Confirm users to merge / ► 3. Merging results and log

Merged «xxxx0027@hz.nl» (user ID = xxx) into «xxxx0061@hz.nl» (user ID = xxx)

For further reference, these results are recorded in the log id 24. Some error occurred:

Exception thrown when merging: 'Can not find course module".

Trace:

0 /home/learn/public_html/admin/tool/mergeusers/lib/mergeusertool.php(271): MergeUserTool->updateGrades('28320', '23599')

1 /home/learn/public_html/admin/tool/mergeusers/lib/mergeusertool.php(192): MergeUserTool->_merge('28320', '23599')

2 /home/learn/public_html/admin/tool/mergeusers/index.php(135): MergeUserTool->merge('28320', '23599')

3 {main}

Started merging at Monday, 16 September 2024, 10:37 AM Merge took 16 seconds

It seems to have something to do with grades, but how can I find which course module this is concerning? It would be nice to find which course module (or even course ID) the problem has.

One more thing: where are the log files stored?

jpahullo commented 1 month ago

Hi @Richardvi,

Thank you for reporting the issue.

In general, this kind of error is due to some database inconsistence in your Moodle instance. Nothing to do with this tool by itself. Time to time we face this kind of problems and we have to investigate these inconsistencies.

To find it easily, it is best to bring a copy of your Moodle instance locally, somehow, so that you can repeat the process locally and go step by step with xdebug or so, so that you can find which is the database record bringing problems to the user merge.

To find all merge records you can go to the Administration > Users > Merge user accounts > See merging logs, or by URL going to https:/your.moodle/admin/tool/mergeusers/view.php. It is a single page, with no pagination of results yet.

But, basically, the logs are the same as you can see when you merge user from the web administration, just for later reference. There will be no more detail, if you are looking at that.

Thanks for the feedback.

Jordi

Richardvi commented 1 month ago

Hi Jordi!

Thanks for the quick response. Could you explain what you mean with 'bring a copy of your Moodle instance locally' because we are hosting our own Moodle on a server at the University. It has 30k+ courses... I can't really make a copy to my laptop if that's what you mean.

But I have full server access.

Thanks,

Richard. Moodle 4.4 PHP 8.2

Richardvi commented 1 month ago

Can I find more debug information somewhere? What grades are we talking about, or course module, or course ID? I have full access to server and database but unfortunately I have to little info to dive in this problem.

jpahullo commented 1 month ago

Hi,

If you have a local copy of your Moodle code, then, you could import a copy of the whole database locally. There is no need for getting files locally. Some images may fail and something could be shown a bit weird, but your Moodle would work perfectly.

With a local copy of the Moodle code and database, you could use xdebug to debug step by step which is the record that is making the process fail.

If you have whole database access too, you could start making queries (SELECTs) on the Moodle databse to find which records exists on the database relating to grades, using both user ids. You could use the specific queries from this plugin to know which database tables to look into, and then, search iterativelly until finding a something inconsistent. In your case, maybe this is the simplest option.

I cannot help you any further.

Thanks for contacting,

Jordi

luisdev commented 1 month ago

Hi Jordi!

Thanks for the quick response. Could you explain what you mean with 'bring a copy of your Moodle instance locally' because we are hosting our own Moodle on a server at the University. It has 30k+ courses... I can't really make a copy to my laptop if that's what you mean.

Do you have a Moodle DEV or TEST environment where you test new Moodle functions and upgrades? If so, then use that.

Richardvi commented 1 month ago

I do have a test site, but it's not the entire data. Our Moodle is to big to keep an entire test site. Students upload 500-1000 documents a day. We have around 11 Terabyte of data. It's not easily copied.

I will dig into the code myself to add some extra debug info that might point me in the direction of where to look in the database.

Best guess right now is that it is a plugin that we had in the past, it generated grades, but we are no longer using that plugin (or has even be uninstalled).

Richardvi commented 1 month ago

OK, so I update the function updategrades() in mergeusertool.php to this:

private function updateGrades($toid, $fromid) {
    global $DB, $CFG;
    require_once($CFG->libdir.'/gradelib.php');
    $sql = "SELECT DISTINCT gi.id, gi.iteminstance, gi.itemmodule, gi.courseid
            FROM {grade_grades} gg
            INNER JOIN {grade_items} gi on gg.itemid = gi.id
            WHERE itemtype = 'mod' AND (gg.userid = :toid OR gg.userid = :fromid)";
    $iteminstances = $DB->get_records_sql($sql, array('toid' => $toid, 'fromid' => $fromid));
    foreach ($iteminstances as $iteminstance) {
        if (!$activity = $DB->get_record($iteminstance->itemmodule, array('id' => $iteminstance->iteminstance))) {
            throw new \Exception("Can not find $iteminstance->itemmodule activity with id $iteminstance->iteminstance");
        }
        if (!$cm = get_coursemodule_from_instance($iteminstance->itemmodule, $activity->id, $iteminstance->courseid)) {
            throw new \Exception(sprintf(
                'Can not find course module. Debug info: itemmodule=%s, activity_id=%d, courseid=%d',
                $iteminstance->itemmodule,
                $activity->id,
                $iteminstance->courseid
            ));
        }
        $activity->modname    = $iteminstance->itemmodule;
        $activity->cmidnumber = $cm->idnumber;
        grade_update_mod_grades($activity, $toid);
    }
}

In the error, I now understand what the problem is.

Exception thrown when merging: 'Can not find course module. Debug info: itemmodule=quiz, activity_id=10031, courseid=29223".

The problem most likely is a quiz where either the user has been unenrolled or quiz-results have been deleted.

Thanks, you can close this issue now.

jpahullo commented 1 month ago

Good catch! Congrats!

I will leave this issue open just to include your proposal into de code. If you build a PR this change could come from the plugin itself, so you do not have to maintain it at your own side.

Thank you for your feedback, anyway.

Jordi

Richardvi commented 1 month ago

What's a PR? I'm not a programmer, just a quick learner.

I fixed the issue. What happened was that the account that needed to be merged had quiz-results for a quiz that had already been deleted.

When I looked into this table mdl_grade_items I saw that there were quizes present in that table that were no longer in the course. I checked the recyclebin just to be sure, but these quizes were also not in the recycle bin.

I deleted the entry of the 'orphaned' quiz in mdl_grade_items table and then could merge the accounts.

jpahullo commented 1 month ago

Fantastic. Thanks for the report.

PR is a "Pull Request" and is a code contribution to any project. It is possible if you know about git and github. If not, do not worry, I will add this patch as soon as I could.

Thanks,

Jordi