Skip to content

Commit

Permalink
MDL-70444 my: Improved robustness of bulk dashboard reset
Browse files Browse the repository at this point in the history
  • Loading branch information
Peterburnett committed Jan 25, 2021
1 parent fd840ab commit 4e72d59
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 28 deletions.
2 changes: 2 additions & 0 deletions lang/en/moodle.php
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@
$string['commentsrequirelogin'] = 'You need to log in to view the comments.';
$string['comparelanguage'] = 'Compare and edit current language';
$string['complete'] = 'Complete';
$string['completed'] = 'Completed';
$string['completereport'] = 'Complete report';
$string['configuration'] = 'Configuration';
$string['confirm'] = 'Confirm';
Expand Down Expand Up @@ -1115,6 +1116,7 @@
$string['indicator:userforumstracking'] = 'User is tracking forums';
$string['indicator:userforumstracking_help'] = 'This indicator represents whether or not the student has tracking turned on in the forums.';
$string['info'] = 'Information';
$string['inprogress'] = 'In progress';
$string['institution'] = 'Institution';
$string['instudentview'] = 'in student view';
$string['interests'] = 'Interests';
Expand Down
1 change: 1 addition & 0 deletions lang/en/my.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
$string['defaultprofilepage'] = 'Default profile page';
$string['addpage'] = 'Add page';
$string['alldashboardswerereset'] = 'All Dashboard pages have been reset to default.';
$string['resettingdashboards'] = 'Resetting user dashboards to default...';
$string['allprofileswerereset'] = 'All profile pages have been reset to default.';
$string['delpage'] = 'Delete page';
$string['managepages'] = 'Manage pages';
Expand Down
21 changes: 17 additions & 4 deletions my/indexsys.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,32 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

define('NO_OUTPUT_BUFFERING', true);
require_once(__DIR__ . '/../config.php');
require_once($CFG->dirroot . '/my/lib.php');
require_once($CFG->libdir.'/adminlib.php');

$resetall = optional_param('resetall', null, PARAM_BOOL);
$resetall = optional_param('resetall', false, PARAM_BOOL);

$header = "$SITE->shortname: ".get_string('myhome')." (".get_string('mypage', 'admin').")";

$PAGE->set_blocks_editing_capability('moodle/my:configsyspages');
admin_externalpage_setup('mypage', '', null, '', array('pagelayout' => 'mydashboard'));

// If we are resetting all, just output a progress bar.
if ($resetall && confirm_sesskey()) {
my_reset_page_for_all_users(MY_PAGE_PRIVATE, 'my-index');
redirect($PAGE->url, get_string('alldashboardswerereset', 'my'));
echo $OUTPUT->header($header);
echo $OUTPUT->heading(get_string('resettingdashboards', 'my'), 3);

$progressbar = new progress_bar();
$progressbar->create();

\core\session\manager::write_close();
my_reset_page_for_all_users(MY_PAGE_PRIVATE, 'my-index', $progressbar);
core\notification::success(get_string('alldashboardswerereset', 'my'));
echo $OUTPUT->continue_button($PAGE->url);
echo $OUTPUT->footer();
die();
}

// Override pagetype to show blocks properly.
Expand All @@ -65,7 +77,8 @@
$PAGE->set_subpage($currentpage->id);

// Display a button to reset everyone's dashboard.
$url = new moodle_url($PAGE->url, array('resetall' => 1));
$url = $PAGE->url;
$url->params(['resetall' => true, 'sesskey' => sesskey()]);
$button = $OUTPUT->single_button($url, get_string('reseteveryonesdashboard', 'my'));
$PAGE->set_button($button . $PAGE->button);

Expand Down
82 changes: 58 additions & 24 deletions my/lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,40 +166,70 @@ function my_reset_page($userid, $private=MY_PAGE_PRIVATE, $pagetype='my-index')
*
* @param int $private Either MY_PAGE_PRIVATE or MY_PAGE_PUBLIC.
* @param string $pagetype Either my-index or user-profile.
* @param progress_bar $progressbar A progress bar to update.
* @return void
*/
function my_reset_page_for_all_users($private = MY_PAGE_PRIVATE, $pagetype = 'my-index') {
function my_reset_page_for_all_users($private = MY_PAGE_PRIVATE, $pagetype = 'my-index', $progressbar = null) {
global $DB;

// This may take a while. Raise the execution time limit.
core_php_time_limit::raise();

// Find all the user pages and all block instances in them.
$sql = "SELECT bi.id
FROM {my_pages} p
JOIN {context} ctx ON ctx.instanceid = p.userid AND ctx.contextlevel = :usercontextlevel
JOIN {block_instances} bi ON bi.parentcontextid = ctx.id AND
bi.pagetypepattern = :pagetypepattern AND
(bi.subpagepattern IS NULL OR bi.subpagepattern = " . $DB->sql_concat("''", 'p.id') . ")
WHERE p.private = :private";
$params = array('private' => $private,
'usercontextlevel' => CONTEXT_USER,
'pagetypepattern' => $pagetype);
$blockids = $DB->get_fieldset_sql($sql, $params);

// Wrap the SQL queries in a transaction.
$transaction = $DB->start_delegated_transaction();

// Delete the block instances.
if (!empty($blockids)) {
blocks_delete_instances($blockids);
$users = $DB->get_fieldset_select(
'my_pages',
'DISTINCT(userid)',
'userid IS NOT NULL AND private = :private',
['private' => $private]
);
$chunks = array_chunk($users, 20);

if (!empty($progressbar) && count($chunks) > 0) {
$count = count($chunks);
$message = get_string('inprogress');
$progressbar->update(0, $count, $message);
}

// Finally delete the pages.
$DB->delete_records_select('my_pages', 'userid IS NOT NULL AND private = :private', ['private' => $private]);
foreach ($chunks as $key => $userchunk) {
list($infragment, $inparams) = $DB->get_in_or_equal($userchunk, SQL_PARAMS_NAMED);
// Find all the user pages and all block instances in them.
$sql = "SELECT bi.id
FROM {my_pages} p
JOIN {context} ctx ON ctx.instanceid = p.userid AND ctx.contextlevel = :usercontextlevel
JOIN {block_instances} bi ON bi.parentcontextid = ctx.id
AND bi.pagetypepattern = :pagetypepattern
AND (bi.subpagepattern IS NULL OR bi.subpagepattern = " . $DB->sql_concat("''", 'p.id') . ")
WHERE p.private = :private
AND p.userid $infragment";

$params = array_merge([
'private' => $private,
'usercontextlevel' => CONTEXT_USER,
'pagetypepattern' => $pagetype
], $inparams);
$blockids = $DB->get_fieldset_sql($sql, $params);

// Wrap the SQL queries in a transaction.
$transaction = $DB->start_delegated_transaction();

// Delete the block instances.
if (!empty($blockids)) {
blocks_delete_instances($blockids);
}

// We should be good to go now.
$transaction->allow_commit();
// Finally delete the pages.
$DB->delete_records_select(
'my_pages',
"userid $infragment AND private = :private",
array_merge(['private' => $private], $inparams)
);

// We should be good to go now.
$transaction->allow_commit();

if (!empty($progressbar)) {
$progressbar->update(((int) $key + 1), $count, $message);
}
}

// Trigger dashboard has been reset event.
$eventparams = array(
Expand All @@ -211,6 +241,10 @@ function my_reset_page_for_all_users($private = MY_PAGE_PRIVATE, $pagetype = 'my
);
$event = \core\event\dashboards_reset::create($eventparams);
$event->trigger();

if (!empty($progressbar)) {
$progressbar->update(1, 1, get_string('completed'));
}
}

class my_syspage_block_manager extends block_manager {
Expand Down

0 comments on commit 4e72d59

Please sign in to comment.