Skip to content

Commit

Permalink
Failed upload job limiter (#386)
Browse files Browse the repository at this point in the history
* control failed upload try and introducing uploadjob archive mechanism,
fixes #385

* update lang file

* fix code checker issues

* make archived job deletable

* correct the status before deletion

* changes according to request

* adjust langstring keys in js file
  • Loading branch information
ferishili authored Dec 3, 2024
1 parent 2ecc0a4 commit 0adefe5
Show file tree
Hide file tree
Showing 14 changed files with 333 additions and 28 deletions.
2 changes: 1 addition & 1 deletion amd/build/block_index.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion amd/build/block_index.min.js.map

Large diffs are not rendered by default.

58 changes: 56 additions & 2 deletions amd/src/block_index.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ define(['jquery', 'core/modal_factory', 'core/modal_events',
seriesid = tableid.replace('opencast-videos-table-', '');
}
bulkinfodiv = '<div id="bulkinfodiv" class="w-100 mb-1">';
bulkinfodiv += '<p>' + langstrings[9].replace('{$a}', detail.selectedtitles.join('</li><li>')) + '</p>';
bulkinfodiv += '<p>' + langstrings[12].replace('{$a}', detail.selectedtitles.join('</li><li>')) + '</p>';
bulkinfodiv += '</div>';
for (let videoid of detail.selectedids) {
bulkinfodiv += '<input type="hidden" name="videoids[]" value="' + videoid + '">';
Expand Down Expand Up @@ -141,7 +141,7 @@ define(['jquery', 'core/modal_factory', 'core/modal_events',

ModalFactory.create({
type: ModalFactory.types.SAVE_CANCEL,
title: ismassaction ? langstrings[10] : langstrings[5],
title: ismassaction ? langstrings[13] : langstrings[5],
body: body
}, undefined)
.then(function(modal) {
Expand Down Expand Up @@ -489,6 +489,47 @@ define(['jquery', 'core/modal_factory', 'core/modal_events',
}
});
};
/*
* Initalizes the unarchive uploadjob package on button click with modal.
*/
var initUnarchiveUploadJobModal = function(ocinstanceid, langstrings, contextid, liveupdate) {
$('.unarchive-uploadjob').on('click', function(e) {
e.preventDefault();
var targetBtn = $(e.currentTarget);
var uploadjobid = targetBtn.data('id');
ModalFactory.create({
type: ModalFactory.types.SAVE_CANCEL,
title: langstrings[9],
body: langstrings[10]
})
.then(function(modal) {
// Pause the live update if it is running.
pauseLiveUpdate(liveupdate);
modal.setSaveButtonText(langstrings[11]);
var root = modal.getRoot();
root.on(ModalEvents.save, function (e) {
Ajax.call([{
methodname: 'block_opencast_unarchive_uploadjob',
args: {contextid: contextid, ocinstanceid: ocinstanceid, uploadjobid: uploadjobid},
done: function() {
window.location.reload();
},
fail: Notification.exception
}]);
e.preventDefault();
});
root.on(ModalEvents.hidden, function() {
// Resume the live update if it was paused.
resumeLiveUpdate(ocinstanceid, contextid, liveupdate);
// Destroy when hidden/closed.
modal.destroy();
});
modal.show();
return;
})
.catch(Notification.exception);
});
};

/**
* Resets the bulk action select dropdowns.
Expand Down Expand Up @@ -548,6 +589,18 @@ define(['jquery', 'core/modal_factory', 'core/modal_events',
key: 'startworkflow_modal_configpanel_title',
component: 'block_opencast'
},
{
key: 'unarchiveuploadjob',
component: 'block_opencast'
},
{
key: 'unarchiveuploadjobconfirmtext',
component: 'block_opencast'
},
{
key: 'unarchiveuploadjobconfirmbtn_save',
component: 'block_opencast'
},
{
key: 'videostable_massaction_startworkflow_modal_body',
component: 'block_opencast'
Expand All @@ -560,6 +613,7 @@ define(['jquery', 'core/modal_factory', 'core/modal_events',
str.get_strings(strings).then(function(results) {
initWorkflowModal(ocinstanceid, courseid, results, contextid, liveupdate);
initReportModal(ocinstanceid, courseid, results, contextid, liveupdate);
initUnarchiveUploadJobModal(ocinstanceid, results, contextid, liveupdate);
return;
}).catch(Notification.exception);
window.addEventListener('message', function(event) {
Expand Down
5 changes: 5 additions & 0 deletions classes/event/upload_failed.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,13 @@ public static function get_name() {
* @return string
*/
public function get_description() {
$archived = "";
if (isset($this->data['other']['archived']) && $this->data['other']['archived'] === true) {
$archived = " the upload job has now been archived, ";
}
return "The upload of {$this->data['other']['filename']} (Course: {$this->data['courseid']}) " .
"to opencast instance {$this->data['ocinstanceid']} failed {$this->data['other']['countfailed']} times, " .
$archived .
"Reason: {$this->data['other']['errormessage']}";
}

Expand Down
66 changes: 66 additions & 0 deletions classes/external.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
use block_opencast\local\apibridge;
use block_opencast\local\series_form;
use block_opencast\local\liveupdate_helper;
use block_opencast\local\upload_helper;
use tool_opencast\seriesmapping;

defined('MOODLE_INTERNAL') || die;
Expand Down Expand Up @@ -121,6 +122,19 @@ public static function get_liveupdate_info_parameters() {
]);
}

/**
* Returns description of method parameters
*
* @return external_function_parameters
*/
public static function unarchive_uploadjob_parameters() {
return new external_function_parameters([
'contextid' => new external_value(PARAM_INT, 'The context id for the course'),
'ocinstanceid' => new external_value(PARAM_INT, 'The Opencast instance id'),
'uploadjobid' => new external_value(PARAM_INT, 'The upload job id'),
]);
}

/**
* Submits the series form.
*
Expand Down Expand Up @@ -449,6 +463,49 @@ public static function get_liveupdate_info(int $contextid, int $ocinstanceid, st
return json_encode($liveupdateinfo);
}

/**
* Perform unarchiving an uploadjob.
*
* @param int $contextid The context id for the course.
* @param int $ocinstanceid Opencast instance id
* @param int $uploadjobid Uploadjob id
*
* @return string Latest update state info
*/
public static function unarchive_uploadjob(int $contextid, int $ocinstanceid, int $uploadjobid) {
global $USER, $DB;
$params = self::validate_parameters(self::unarchive_uploadjob_parameters(), [
'contextid' => $contextid,
'ocinstanceid' => $ocinstanceid,
'uploadjobid' => $uploadjobid,
]);

$context = context::instance_by_id($params['contextid']);
self::validate_context($context);
require_capability('block/opencast:addvideo', $context);

list($unused, $course, $cm) = get_context_info_array($context->id);

$params = [
'id' => $params['uploadjobid'],
'ocinstanceid' => $params['ocinstanceid'],
'courseid' => $course->id,
'status' => upload_helper::STATUS_ARCHIVED_FAILED_UPLOAD,
];
$uploadjob = $DB->get_record('block_opencast_uploadjob', $params);

if (!empty($uploadjob)) {
$time = time();
$uploadjob->timemodified = $time;
$uploadjob->countfailed = 0;
$uploadjob->status = upload_helper::STATUS_READY_TO_UPLOAD;
$DB->update_record('block_opencast_uploadjob', $uploadjob);
return true;
}

throw new moodle_exception('uploadjobnotfound', 'block_opencast');
}

/**
* Returns description of method result value
*
Expand Down Expand Up @@ -502,4 +559,13 @@ public static function set_default_series_returns() {
public static function get_liveupdate_info_returns() {
return new external_value(PARAM_RAW, 'Json live update info');
}

/**
* Returns description of method result value
*
* @return external_description
*/
public static function unarchive_uploadjob_returns() {
return new external_value(PARAM_BOOL, 'True if successful');
}
}
47 changes: 45 additions & 2 deletions classes/local/eventstatus_notification_helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -236,9 +236,10 @@ public static function notify_users_upload_queue($job, $metadata) {
}
}

$where = 'status <> :status';
$where = 'status NOT IN (:statustransferred, :statusarchived)';
$params = [
'status' => upload_helper::STATUS_TRANSFERRED,
'statustransferred' => upload_helper::STATUS_TRANSFERRED,
'statusarchived' => upload_helper::STATUS_ARCHIVED_FAILED_UPLOAD,
];
$allqueuednum = $DB->count_records_select('block_opencast_uploadjob', $where, $params);
$waitingnum = 0;
Expand All @@ -259,6 +260,48 @@ public static function notify_users_upload_queue($job, $metadata) {
}
}


/**
* Notify users about the failed upload being archived.
*
* @param object $job represents the upload job.
* @param string $title event title or filename.
*
*/
public static function notify_users_archived_upload($job, $title) {
global $DB;
// Initialize the user list as an empty array.
$usertolist = [];
// Add uploader user object to the user list.
$usertolist[] = $DB->get_record('user', ['id' => $job->userid]);

// Get admin config to check if all teachers of the course should be notified as well.
$notifyteachers = get_config('block_opencast', 'eventstatusnotifyteachers_' . $job->ocinstanceid);
if ($notifyteachers) {
// Get the role of teachers.
$role = $DB->get_record('role', ['shortname' => 'editingteacher']);
// Get the course context.
$context = context_course::instance($job->courseid);
// Get the teachers based on their role in the course context.
$teachers = get_role_users($role->id, $context);

// If teachers array list is not empty, we add them to the user list.
if (!empty($teachers)) {
foreach ($teachers as $teacher) {
// We need to make sure that the uploader is not in the teachers list.
if ($teacher->id != $job->userid) {
$usertolist[] = $DB->get_record('user', ['id' => $teacher->id]);
}
}
}
}

// Notify users one by one.
foreach ($usertolist as $userto) {
notifications::notify_archived_upload($job->courseid, $userto, $title);
}
}

/**
* Get the relative status text based on status code.
*
Expand Down
3 changes: 2 additions & 1 deletion classes/local/liveupdate_helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ public static function get_uploading_info($uploadjobid) {
$info['replace'] = $status;
// We pass remove param, to decide whether to continue checking that item or not.
$remove = false;
if ($uploadjob->status == upload_helper::STATUS_TRANSFERRED) {
if ($uploadjob->status == upload_helper::STATUS_TRANSFERRED ||
$uploadjob->status == upload_helper::STATUS_ARCHIVED_FAILED_UPLOAD) {
// We remove the item from live update when the upload is transferred.
$remove = true;
}
Expand Down
25 changes: 25 additions & 0 deletions classes/local/notifications.php
Original file line number Diff line number Diff line change
Expand Up @@ -491,4 +491,29 @@ public static function notify_incompleted_import_mapping_records($courseid, $inc
$admin = get_admin();
self::send_message('error', $admin, $subject, $body);
}

/**
* Notify user about archiving an upload job.
* @param int $courseid Course id
* @param object $touser User to which notification is sent
* @param string $title the title or filename of the video
*/
public static function notify_archived_upload($courseid, $touser, $title) {
global $DB;

$a = (object)[
'courseid' => $courseid,
'coursefullname' => get_string('coursefullnameunknown', 'block_opencast'),
'title' => $title,
];

if ($course = $DB->get_record('course', ['id' => $courseid])) {
$a->coursefullname = $course->fullname;
}

$subject = get_string('notificationuploadarchived_subj', 'block_opencast');
$body = get_string('notificationuploadarchived_body', 'block_opencast', $a);

self::send_message('opencasteventstatus_notification', $touser, $subject, $body);
}
}
Loading

0 comments on commit 0adefe5

Please sign in to comment.