',body='";ModalFactory.create({type:ModalFactory.types.SAVE_CANCEL,title:ismassaction?langstrings[13]:langstrings[5],body:body},void 0).then((function(modal){pauseLiveUpdate(liveupdate),modal.setSaveButtonText(langstrings[5]);var root=modal.getRoot();root.on(ModalEvents.save,(function(e){$("#config-frame").is(":visible")?(document.getElementById("config-frame").contentWindow.postMessage("getdata","*"),e.preventDefault()):$("#startWorkflowForm").submit()})),root.on(ModalEvents.hidden,(function(){resumeLiveUpdate(ocinstanceid,contextid,liveupdate),modal.destroy(),resetVideosTableBulkActions(massactioncontainer)})),modal.show().then((function(){const workflowselect=$("#workflowselect");let workflowid=workflowselect.val();displayWorkflowDescription(workflows[workflowid]),displayWorkflowConfigPanel(ocinstanceid,courseid,workflowid),displayWorkflowPrivacyNotice(privacyworkflows,workflowid),workflowselect.change((function(){let workflowid=$(this).val();displayWorkflowDescription(workflows[workflowid]),displayWorkflowConfigPanel(ocinstanceid,courseid,workflowid),displayWorkflowPrivacyNotice(privacyworkflows,workflowid)}))})).catch(Notification.exception)})).catch(Notification.exception)}))}}(ocinstanceid,courseid,results,contextid,liveupdate),function(ocinstanceid,courseid,langstrings,contextid,liveupdate){$(".report-problem").on("click",(function(e){e.preventDefault();var clickedVideo=$(e.currentTarget);ModalFactory.create({type:ModalFactory.types.SAVE_CANCEL,title:langstrings[0],body:'"}).then((function(modal){pauseLiveUpdate(liveupdate),modal.setSaveButtonText(langstrings[4]);var root=modal.getRoot();root.on(ModalEvents.save,(function(e){$("#inputMessage").val()?$("#reportProblemForm").submit():($("#inputMessage").addClass("is-invalid"),$("#messageValidation").removeClass("d-none")),e.preventDefault()})),root.on(ModalEvents.hidden,(function(){resumeLiveUpdate(ocinstanceid,contextid,liveupdate),modal.destroy()})),modal.show()})).catch(Notification.exception)}))}(ocinstanceid,courseid,results,contextid,liveupdate),function(ocinstanceid,langstrings,contextid,liveupdate){$(".unarchive-uploadjob").on("click",(function(e){e.preventDefault();var uploadjobid=$(e.currentTarget).data("id");ModalFactory.create({type:ModalFactory.types.SAVE_CANCEL,title:langstrings[9],body:langstrings[10]}).then((function(modal){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(){resumeLiveUpdate(ocinstanceid,contextid,liveupdate),modal.destroy()})),modal.show()})).catch(Notification.exception)}))}(ocinstanceid,results,contextid,liveupdate)})).catch(Notification.exception),window.addEventListener("message",(function(event){"null"===event.origin&&(event.data===parseInt(event.data)?$("#config-frame").height(event.data):($("#configparams").val(event.data),$("#startWorkflowForm").submit()))})),liveupdate.enabled&&initLiveUpdate(ocinstanceid,contextid,liveupdate.timeout),$(".access-link-copytoclipboard").on("click",(function(e){e.preventDefault();var link=e.currentTarget.getAttribute("href");link?navigator.clipboard?navigator.clipboard.writeText(link).then((()=>{str.get_string("directaccess_copy_success","block_opencast").done((function(result){Toast.add(result)})).fail(Notification.exception)})).catch():str.get_string("directaccess_copytoclipboard_unavialable","block_opencast").done((function(result){Toast.add(result,{type:"danger",autohide:!1,closeButton:!0})})).fail(Notification.exception):str.get_string("directaccess_copy_no_link","block_opencast").done((function(result){Toast.add(result,{type:"warning"})})).fail(Notification.exception)}))}}}));
//# sourceMappingURL=block_index.min.js.map
\ No newline at end of file
diff --git a/amd/build/block_index.min.js.map b/amd/build/block_index.min.js.map
index c41f4324..406d7511 100644
--- a/amd/build/block_index.min.js.map
+++ b/amd/build/block_index.min.js.map
@@ -1 +1 @@
-{"version":3,"file":"block_index.min.js","sources":["../src/block_index.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Javascript to initialise the opencast block.\n *\n * @module block_opencast\n * @copyright 2021 Tamara Gunkel, University of Münster\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(['jquery', 'core/modal_factory', 'core/modal_events',\n 'core/str', 'core/url', 'core/notification', 'core/toast', 'core/ajax'],\n function($, ModalFactory, ModalEvents, str, url, Notification, Toast, Ajax) {\n /**\n * Instantiate the window variable in order to work with Intervals\n *\n */\n window.liveUpdateInterval = null;\n window.liveUpdateItemsWithError = [];\n window.liveUpdateState = null;\n\n var pauseLiveUpdate = function(liveupdate) {\n if (!liveupdate.enabled) {\n return;\n }\n if (window.liveUpdateInterval !== null) {\n clearInterval(window.liveUpdateInterval);\n window.liveUpdateState = 'paused';\n }\n };\n\n var resumeLiveUpdate = function(ocinstanceid, contextid, liveupdate) {\n if (!liveupdate.enabled) {\n return;\n }\n if (window.liveUpdateState == 'paused') {\n initLiveUpdate(ocinstanceid, contextid, liveupdate.timeout);\n window.liveUpdateState = 'resumed';\n }\n };\n\n var initWorkflowModal = function(ocinstanceid, courseid, langstrings, contextid, liveupdate) {\n if (document.getElementById('workflowsjson')) {\n var workflows = JSON.parse($('#workflowsjson').text());\n var privacyinfohtml = null;\n var privacytitle = null;\n var privacyworkflows = null;\n var hasprivacyinfo = false;\n if (document.getElementById('workflowprivacynotice')) {\n hasprivacyinfo = true;\n privacyinfohtml = $('#swprivacynoticeinfotext').html();\n privacytitle = $('#swprivacynoticetitle').text();\n privacyworkflows = JSON.parse($('#swprivacynoticewfds').text());\n }\n\n $('.start-workflow').on('click', function(e) {\n e.preventDefault();\n const detail = e?.detail || {};\n\n var clickedVideo = $(e.currentTarget);\n var actionurl = url.relativeUrl('blocks/opencast/startworkflow.php', {\n 'ocinstanceid': ocinstanceid,\n 'courseid': courseid,\n 'videoid': clickedVideo.data('id')\n });\n var ismassaction = false;\n var bulkinfodiv = '';\n var massactioncontainer = null;\n if (detail?.type === 'bulk' && detail?.selectedids && detail?.container) {\n ismassaction = true;\n massactioncontainer = detail.container;\n const table = massactioncontainer.querySelector('table.opencast-videos-table');\n const tableid = table?.id;\n let seriesid = '';\n if (tableid) {\n seriesid = tableid.replace('opencast-videos-table-', '');\n }\n bulkinfodiv = '
';\n\n var body = '';\n\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n title: ismassaction ? langstrings[10] : langstrings[5],\n body: body\n }, undefined)\n .then(function(modal) {\n // Pause the live update if it is running.\n pauseLiveUpdate(liveupdate);\n modal.setSaveButtonText(langstrings[5]);\n var root = modal.getRoot();\n root.on(ModalEvents.save, function(e) {\n // Handle form submission after receiving data, if the workflow has config panel.\n if ($('#config-frame').is(':visible')) {\n document.getElementById('config-frame').contentWindow.postMessage('getdata', '*');\n e.preventDefault();\n } else {\n // If the workflow has no config panel, we submit it directly.\n $('#startWorkflowForm').submit();\n }\n });\n root.on(ModalEvents.hidden, function() {\n // Resume the live update if it was paused.\n resumeLiveUpdate(ocinstanceid, contextid, liveupdate);\n // Destroy when hidden/closed.\n modal.destroy();\n // Change the bulk action select back to choose...\n resetVideosTableBulkActions(massactioncontainer);\n });\n\n // Show description for initial value.\n modal.show().then(function() {\n const workflowselect = $('#workflowselect');\n let workflowid = workflowselect.val();\n displayWorkflowDescription(workflows[workflowid]);\n displayWorkflowConfigPanel(ocinstanceid, courseid, workflowid);\n // The first time to check if the privacy notice must be displayed.\n displayWorkflowPrivacyNotice(privacyworkflows, workflowid);\n\n // Show workflow description when selected.\n workflowselect.change(function() {\n let workflowid = $(this).val();\n displayWorkflowDescription(workflows[workflowid]);\n displayWorkflowConfigPanel(ocinstanceid, courseid, workflowid);\n // After each change, check if the selected workflow has to be displayed.\n displayWorkflowPrivacyNotice(privacyworkflows, workflowid);\n });\n return;\n }).catch(Notification.exception);\n return;\n }).catch(Notification.exception);\n });\n }\n };\n\n /**\n * Helper function to display the privacy notice in workflow modal dialog.\n * @param {Array} privacyworkflows an array list of workflows to display privacy notice for.\n * @param {string} workflowid workflow def id\n */\n var displayWorkflowPrivacyNotice = function(privacyworkflows, workflowid) {\n if (Array.isArray(privacyworkflows) && (privacyworkflows.length === 0 || privacyworkflows.includes(workflowid))) {\n $('#privacynoticediv').removeClass('d-none');\n } else {\n $('#privacynoticediv').addClass('d-none');\n }\n };\n\n /**\n * Helper function to display the description of the workflow.\n * @param {Object} workflowobj the workflow object\n */\n var displayWorkflowDescription = function(workflowobj) {\n if (workflowobj?.description) {\n $('#workflowdescdiv').removeClass('d-none');\n $('#workflowdesc').html(workflowobj.description);\n } else {\n $('#workflowdescdiv').addClass('d-none');\n }\n };\n\n /**\n * Helper function to display Workflow configurration panel.\n * @param {string} ocinstanceid oc instance id\n * @param {string} courseid course id\n * @param {string} workflowid workflow def id\n */\n var displayWorkflowConfigPanel = function(ocinstanceid, courseid, workflowid) {\n $('#workflowconfigpaneldiv').addClass('d-none');\n $('#workflowconfigpanelloading').removeClass('d-none');\n $('#config-frame').attr('src', '');\n var configpanelsrc = url.relativeUrl('blocks/opencast/serveworkflowconfigpanel.php', {\n 'ocinstanceid': ocinstanceid,\n 'courseid': courseid,\n 'workflowid': workflowid\n });\n $.ajax({\n url: configpanelsrc,\n success: (data) => {\n if (data.trim() !== '') {\n $('#workflowconfigpaneldiv').removeClass('d-none');\n $('#config-frame').attr('src', configpanelsrc);\n }\n },\n async: false\n });\n };\n\n var initReportModal = function(ocinstanceid, courseid, langstrings, contextid, liveupdate) {\n $('.report-problem').on('click', function(e) {\n e.preventDefault();\n var clickedVideo = $(e.currentTarget);\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n title: langstrings[0],\n body: ''\n })\n .then(function(modal) {\n // Pause the live update if it is running.\n pauseLiveUpdate(liveupdate);\n modal.setSaveButtonText(langstrings[4]);\n var root = modal.getRoot();\n root.on(ModalEvents.save, function(e) {\n if ($('#inputMessage').val()) {\n $('#reportProblemForm').submit();\n } else {\n $('#inputMessage').addClass('is-invalid');\n $('#messageValidation').removeClass('d-none');\n }\n e.preventDefault();\n });\n root.on(ModalEvents.hidden, function() {\n // Resume the live update if it was paused.\n resumeLiveUpdate(ocinstanceid, contextid, liveupdate);\n // Destroy when hidden/closed.\n modal.destroy();\n });\n modal.show();\n return;\n }).catch(Notification.exception);\n });\n };\n\n /*\n * Initialise the status live update in the overview page.\n */\n var initLiveUpdate = function(ocinstanceid, contextid, reloadtimeout) {\n if (window.liveUpdateInterval !== null) {\n clearInterval(window.liveUpdateInterval);\n }\n window.liveUpdateItemsWithError = [];\n var items = getLiveUpdateItems();\n if (items.length) {\n window.liveUpdateInterval = setInterval(function() {\n // Adding the state checker here, in order to pause the live update from other js modules like block_massaction.\n if (window.liveUpdateState === 'paused') {\n return;\n }\n var processingItems = getLiveUpdateProcessingItems();\n var uploadingItems = getLiveUpdateUploadingItems();\n if (processingItems.length == 0 && uploadingItems.length == 0) {\n clearInterval(window.liveUpdateInterval);\n if (window.liveUpdateItemsWithError.length > 0) {\n var titles = window.liveUpdateItemsWithError.join('
');\n str.get_string('liveupdate_fail_notification_message', 'block_opencast', titles)\n .done(function(result) {\n Notification.addNotification({\n message: result,\n type: 'error'\n });\n })\n .fail(Notification.exception);\n }\n return;\n }\n for (var processingItem of processingItems) {\n liveUpdatePerformAjax('processing', ocinstanceid, contextid, processingItem, reloadtimeout);\n }\n for (var uploadingItem of uploadingItems) {\n liveUpdatePerformAjax('uploading', ocinstanceid, contextid, uploadingItem, reloadtimeout);\n }\n }, 5000, ocinstanceid, contextid, url, reloadtimeout);\n }\n };\n\n /*\n * Gets all status live updates items (flags).\n */\n var getLiveUpdateItems = function() {\n var processingItems = getLiveUpdateProcessingItems();\n var uploadingItems = getLiveUpdateUploadingItems();\n return processingItems.concat(uploadingItems);\n };\n\n /*\n * Gets all status live updates items for Processing states.\n */\n var getLiveUpdateProcessingItems = function() {\n var itemsNodeList = document.getElementsByName('liveupdate_processing_item');\n return Array.from(itemsNodeList);\n };\n\n /*\n * Gets all status live updates items for uploading status.\n */\n var getLiveUpdateUploadingItems = function() {\n var itemsNodeList = document.getElementsByName('liveupdate_uploading_item');\n return Array.from(itemsNodeList);\n };\n\n /*\n * Perform status live update Ajax call to the backend to get the related info.\n */\n var liveUpdatePerformAjax = function(type, ocinstanceid, contextid, item, reloadtimeout) {\n var identifier = item.value;\n var title = item?.dataset?.title ? item.dataset.title : '';\n if (identifier == undefined || title == '') {\n window.liveUpdateItemsWithError.push(title);\n item.remove();\n return;\n }\n Ajax.call([{\n methodname: 'block_opencast_get_liveupdate_info',\n args: {contextid: contextid, ocinstanceid: ocinstanceid, type: type, identifier: identifier},\n done: function(status) {\n if (status == '') {\n window.liveUpdateItemsWithError.push(title);\n item.remove();\n return;\n }\n var statusObject = JSON.parse(status);\n if (statusObject.replace != '') {\n replaceLiveUpdateInfo(item, statusObject.replace);\n }\n if (statusObject.remove == true) {\n item.remove();\n var stringparams = {\n timeout: reloadtimeout,\n title: title\n };\n str.get_string('liveupdate_toast_notification', 'block_opencast', stringparams)\n .done(function(result) {\n Toast.add(result);\n })\n .fail(Notification.exception);\n setTimeout(function() {\n window.location.reload();\n }, reloadtimeout * 1000);\n }\n },\n fail: function() {\n window.liveUpdateItemsWithError.push(title);\n item.remove();\n }\n }]);\n };\n\n /*\n * Replace the new live update status with the current one for both text and DOM element.\n */\n var replaceLiveUpdateInfo = function(item, replace) {\n if (item == undefined || replace == '' || typeof replace != 'string') {\n return;\n }\n var newDiv = document.createElement('div');\n newDiv.innerHTML = replace.trim();\n var replaceElm = newDiv.firstChild;\n if (replaceElm.nodeName == '#text') {\n var prevText = item.parentNode.firstChild;\n prevText.remove();\n var newText = document.createTextNode(replace.trim());\n item.parentNode.insertBefore(newText, item);\n } else if (item.previousElementSibling) {\n var prevElm = item.previousElementSibling;\n newDiv.innerHTML = replace.trim();\n if (!areElementsEqual(replaceElm, prevElm)) {\n prevElm.remove();\n item.parentNode.insertBefore(replaceElm, item);\n }\n }\n };\n\n /*\n * Checks if the liev update DOM elements (new vs old) are equal.\n */\n var areElementsEqual = function(baseElm, checkElm) {\n var isEqual = true;\n var attributes = baseElm.getAttributeNames();\n for (var attributeName of attributes) {\n var baseAttributeValue = baseElm.getAttribute(attributeName).trim();\n var checkAttributeValue = '';\n if (checkElm.hasAttribute(attributeName)) {\n checkAttributeValue = checkElm.getAttribute(attributeName).trim();\n }\n if (checkAttributeValue == '') {\n continue;\n }\n if (checkAttributeValue != baseAttributeValue) {\n isEqual = false;\n }\n }\n return isEqual;\n };\n\n /*\n * Copies the direct access link into the clipboard.\n */\n var initCopyAccessLinkToClipboard = function() {\n $('.access-link-copytoclipboard').on('click', function(e) {\n e.preventDefault();\n var element = e.currentTarget;\n var link = element.getAttribute('href');\n if (!link) {\n str.get_string('directaccess_copy_no_link', 'block_opencast')\n .done(function(result) {\n Toast.add(result, {type: 'warning'});\n })\n .fail(Notification.exception);\n return;\n }\n\n if (navigator.clipboard) {\n navigator.clipboard.writeText(link)\n .then(() => {\n str.get_string('directaccess_copy_success', 'block_opencast')\n .done(function(result) {\n Toast.add(result);\n })\n .fail(Notification.exception);\n return;\n }).catch();\n return;\n } else {\n str.get_string('directaccess_copytoclipboard_unavialable', 'block_opencast')\n .done(function(result) {\n Toast.add(result, {type: 'danger', autohide: false, closeButton: true});\n })\n .fail(Notification.exception);\n }\n });\n };\n\n /**\n * Resets the bulk action select dropdowns.\n * @param {object} container The wrapper container which contains the dropdowns, table and selection items of massaction.\n * @param {boolean} disabled a flag to set the dropdown attribute upon using the function (default to false).\n */\n var resetVideosTableBulkActions = function (container, disabled = false) {\n if (!container) {\n return;\n }\n const dropdowns = [...container.querySelectorAll('.opencast-videos-table-massactions')];\n dropdowns.forEach(dropdown => {\n dropdown.value = '';\n dropdown.disabled = disabled;\n });\n };\n\n /*\n * Initialise all of the modules for the opencast block.\n */\n var init = function(courseid, ocinstanceid, contextid, liveupdate) {\n // Load strings\n var strings = [\n {\n key: 'reportproblem_modal_title',\n component: 'block_opencast'\n },\n {\n key: 'reportproblem_modal_body',\n component: 'block_opencast'\n },\n {\n key: 'reportproblem_modal_placeholder',\n component: 'block_opencast'\n },\n {\n key: 'reportproblem_modal_required',\n component: 'block_opencast'\n },\n {\n key: 'reportproblem_modal_submit',\n component: 'block_opencast'\n },\n {\n key: 'startworkflow',\n component: 'block_opencast'\n },\n {\n key: 'startworkflow_modal_body',\n component: 'block_opencast'\n },\n {\n key: 'startworkflow_modal_description_title',\n component: 'block_opencast'\n },\n {\n key: 'startworkflow_modal_configpanel_title',\n component: 'block_opencast'\n },\n {\n key: 'videostable_massaction_startworkflow_modal_body',\n component: 'block_opencast'\n },\n {\n key: 'videostable_massaction_startworkflow_modal_title',\n component: 'block_opencast'\n }\n ];\n str.get_strings(strings).then(function(results) {\n initWorkflowModal(ocinstanceid, courseid, results, contextid, liveupdate);\n initReportModal(ocinstanceid, courseid, results, contextid, liveupdate);\n return;\n }).catch(Notification.exception);\n window.addEventListener('message', function(event) {\n if (event.origin !== \"null\") {\n return;\n }\n\n if (event.data === parseInt(event.data)) {\n $('#config-frame').height(event.data);\n } else {\n $('#configparams').val(event.data);\n $('#startWorkflowForm').submit();\n }\n });\n if (liveupdate.enabled) {\n initLiveUpdate(ocinstanceid, contextid, liveupdate.timeout);\n }\n initCopyAccessLinkToClipboard();\n };\n\n return {\n init: init\n };\n });\n\n"],"names":["define","$","ModalFactory","ModalEvents","str","url","Notification","Toast","Ajax","window","liveUpdateInterval","liveUpdateItemsWithError","liveUpdateState","pauseLiveUpdate","liveupdate","enabled","clearInterval","resumeLiveUpdate","ocinstanceid","contextid","initLiveUpdate","timeout","displayWorkflowPrivacyNotice","privacyworkflows","workflowid","Array","isArray","length","includes","removeClass","addClass","displayWorkflowDescription","workflowobj","description","html","displayWorkflowConfigPanel","courseid","attr","configpanelsrc","relativeUrl","ajax","success","data","trim","async","reloadtimeout","getLiveUpdateItems","setInterval","processingItems","getLiveUpdateProcessingItems","uploadingItems","getLiveUpdateUploadingItems","processingItem","liveUpdatePerformAjax","uploadingItem","titles","join","get_string","done","result","addNotification","message","type","fail","exception","concat","itemsNodeList","document","getElementsByName","from","item","identifier","value","title","dataset","undefined","push","remove","call","methodname","args","status","statusObject","JSON","parse","replace","replaceLiveUpdateInfo","stringparams","add","setTimeout","location","reload","newDiv","createElement","innerHTML","replaceElm","firstChild","nodeName","parentNode","newText","createTextNode","insertBefore","previousElementSibling","prevElm","areElementsEqual","baseElm","checkElm","isEqual","attributes","getAttributeNames","attributeName","baseAttributeValue","getAttribute","checkAttributeValue","hasAttribute","resetVideosTableBulkActions","container","disabled","dropdowns","querySelectorAll","forEach","dropdown","init","get_strings","key","component","then","results","langstrings","getElementById","workflows","text","privacyinfohtml","privacytitle","hasprivacyinfo","on","e","preventDefault","detail","clickedVideo","currentTarget","actionurl","ismassaction","bulkinfodiv","massactioncontainer","selectedids","table","querySelector","tableid","id","seriesid","selectedtitles","videoid","select","workflow","privacynoticediv","workflowdescdiv","workflowconfigpaneldiv","body","create","types","SAVE_CANCEL","modal","setSaveButtonText","root","getRoot","save","is","contentWindow","postMessage","submit","hidden","destroy","show","workflowselect","val","change","this","catch","initWorkflowModal","initReportModal","addEventListener","event","origin","parseInt","height","link","navigator","clipboard","writeText","autohide","closeButton"],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"block_index.min.js","sources":["../src/block_index.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Javascript to initialise the opencast block.\n *\n * @module block_opencast\n * @copyright 2021 Tamara Gunkel, University of Münster\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\ndefine(['jquery', 'core/modal_factory', 'core/modal_events',\n 'core/str', 'core/url', 'core/notification', 'core/toast', 'core/ajax'],\n function($, ModalFactory, ModalEvents, str, url, Notification, Toast, Ajax) {\n /**\n * Instantiate the window variable in order to work with Intervals\n *\n */\n window.liveUpdateInterval = null;\n window.liveUpdateItemsWithError = [];\n window.liveUpdateState = null;\n\n var pauseLiveUpdate = function(liveupdate) {\n if (!liveupdate.enabled) {\n return;\n }\n if (window.liveUpdateInterval !== null) {\n clearInterval(window.liveUpdateInterval);\n window.liveUpdateState = 'paused';\n }\n };\n\n var resumeLiveUpdate = function(ocinstanceid, contextid, liveupdate) {\n if (!liveupdate.enabled) {\n return;\n }\n if (window.liveUpdateState == 'paused') {\n initLiveUpdate(ocinstanceid, contextid, liveupdate.timeout);\n window.liveUpdateState = 'resumed';\n }\n };\n\n var initWorkflowModal = function(ocinstanceid, courseid, langstrings, contextid, liveupdate) {\n if (document.getElementById('workflowsjson')) {\n var workflows = JSON.parse($('#workflowsjson').text());\n var privacyinfohtml = null;\n var privacytitle = null;\n var privacyworkflows = null;\n var hasprivacyinfo = false;\n if (document.getElementById('workflowprivacynotice')) {\n hasprivacyinfo = true;\n privacyinfohtml = $('#swprivacynoticeinfotext').html();\n privacytitle = $('#swprivacynoticetitle').text();\n privacyworkflows = JSON.parse($('#swprivacynoticewfds').text());\n }\n\n $('.start-workflow').on('click', function(e) {\n e.preventDefault();\n const detail = e?.detail || {};\n\n var clickedVideo = $(e.currentTarget);\n var actionurl = url.relativeUrl('blocks/opencast/startworkflow.php', {\n 'ocinstanceid': ocinstanceid,\n 'courseid': courseid,\n 'videoid': clickedVideo.data('id')\n });\n var ismassaction = false;\n var bulkinfodiv = '';\n var massactioncontainer = null;\n if (detail?.type === 'bulk' && detail?.selectedids && detail?.container) {\n ismassaction = true;\n massactioncontainer = detail.container;\n const table = massactioncontainer.querySelector('table.opencast-videos-table');\n const tableid = table?.id;\n let seriesid = '';\n if (tableid) {\n seriesid = tableid.replace('opencast-videos-table-', '');\n }\n bulkinfodiv = '
';\n\n var body = '';\n\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n title: ismassaction ? langstrings[13] : langstrings[5],\n body: body\n }, undefined)\n .then(function(modal) {\n // Pause the live update if it is running.\n pauseLiveUpdate(liveupdate);\n modal.setSaveButtonText(langstrings[5]);\n var root = modal.getRoot();\n root.on(ModalEvents.save, function(e) {\n // Handle form submission after receiving data, if the workflow has config panel.\n if ($('#config-frame').is(':visible')) {\n document.getElementById('config-frame').contentWindow.postMessage('getdata', '*');\n e.preventDefault();\n } else {\n // If the workflow has no config panel, we submit it directly.\n $('#startWorkflowForm').submit();\n }\n });\n root.on(ModalEvents.hidden, function() {\n // Resume the live update if it was paused.\n resumeLiveUpdate(ocinstanceid, contextid, liveupdate);\n // Destroy when hidden/closed.\n modal.destroy();\n // Change the bulk action select back to choose...\n resetVideosTableBulkActions(massactioncontainer);\n });\n\n // Show description for initial value.\n modal.show().then(function() {\n const workflowselect = $('#workflowselect');\n let workflowid = workflowselect.val();\n displayWorkflowDescription(workflows[workflowid]);\n displayWorkflowConfigPanel(ocinstanceid, courseid, workflowid);\n // The first time to check if the privacy notice must be displayed.\n displayWorkflowPrivacyNotice(privacyworkflows, workflowid);\n\n // Show workflow description when selected.\n workflowselect.change(function() {\n let workflowid = $(this).val();\n displayWorkflowDescription(workflows[workflowid]);\n displayWorkflowConfigPanel(ocinstanceid, courseid, workflowid);\n // After each change, check if the selected workflow has to be displayed.\n displayWorkflowPrivacyNotice(privacyworkflows, workflowid);\n });\n return;\n }).catch(Notification.exception);\n return;\n }).catch(Notification.exception);\n });\n }\n };\n\n /**\n * Helper function to display the privacy notice in workflow modal dialog.\n * @param {Array} privacyworkflows an array list of workflows to display privacy notice for.\n * @param {string} workflowid workflow def id\n */\n var displayWorkflowPrivacyNotice = function(privacyworkflows, workflowid) {\n if (Array.isArray(privacyworkflows) && (privacyworkflows.length === 0 || privacyworkflows.includes(workflowid))) {\n $('#privacynoticediv').removeClass('d-none');\n } else {\n $('#privacynoticediv').addClass('d-none');\n }\n };\n\n /**\n * Helper function to display the description of the workflow.\n * @param {Object} workflowobj the workflow object\n */\n var displayWorkflowDescription = function(workflowobj) {\n if (workflowobj?.description) {\n $('#workflowdescdiv').removeClass('d-none');\n $('#workflowdesc').html(workflowobj.description);\n } else {\n $('#workflowdescdiv').addClass('d-none');\n }\n };\n\n /**\n * Helper function to display Workflow configurration panel.\n * @param {string} ocinstanceid oc instance id\n * @param {string} courseid course id\n * @param {string} workflowid workflow def id\n */\n var displayWorkflowConfigPanel = function(ocinstanceid, courseid, workflowid) {\n $('#workflowconfigpaneldiv').addClass('d-none');\n $('#workflowconfigpanelloading').removeClass('d-none');\n $('#config-frame').attr('src', '');\n var configpanelsrc = url.relativeUrl('blocks/opencast/serveworkflowconfigpanel.php', {\n 'ocinstanceid': ocinstanceid,\n 'courseid': courseid,\n 'workflowid': workflowid\n });\n $.ajax({\n url: configpanelsrc,\n success: (data) => {\n if (data.trim() !== '') {\n $('#workflowconfigpaneldiv').removeClass('d-none');\n $('#config-frame').attr('src', configpanelsrc);\n }\n },\n async: false\n });\n };\n\n var initReportModal = function(ocinstanceid, courseid, langstrings, contextid, liveupdate) {\n $('.report-problem').on('click', function(e) {\n e.preventDefault();\n var clickedVideo = $(e.currentTarget);\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n title: langstrings[0],\n body: ''\n })\n .then(function(modal) {\n // Pause the live update if it is running.\n pauseLiveUpdate(liveupdate);\n modal.setSaveButtonText(langstrings[4]);\n var root = modal.getRoot();\n root.on(ModalEvents.save, function(e) {\n if ($('#inputMessage').val()) {\n $('#reportProblemForm').submit();\n } else {\n $('#inputMessage').addClass('is-invalid');\n $('#messageValidation').removeClass('d-none');\n }\n e.preventDefault();\n });\n root.on(ModalEvents.hidden, function() {\n // Resume the live update if it was paused.\n resumeLiveUpdate(ocinstanceid, contextid, liveupdate);\n // Destroy when hidden/closed.\n modal.destroy();\n });\n modal.show();\n return;\n }).catch(Notification.exception);\n });\n };\n\n /*\n * Initialise the status live update in the overview page.\n */\n var initLiveUpdate = function(ocinstanceid, contextid, reloadtimeout) {\n if (window.liveUpdateInterval !== null) {\n clearInterval(window.liveUpdateInterval);\n }\n window.liveUpdateItemsWithError = [];\n var items = getLiveUpdateItems();\n if (items.length) {\n window.liveUpdateInterval = setInterval(function() {\n // Adding the state checker here, in order to pause the live update from other js modules like block_massaction.\n if (window.liveUpdateState === 'paused') {\n return;\n }\n var processingItems = getLiveUpdateProcessingItems();\n var uploadingItems = getLiveUpdateUploadingItems();\n if (processingItems.length == 0 && uploadingItems.length == 0) {\n clearInterval(window.liveUpdateInterval);\n if (window.liveUpdateItemsWithError.length > 0) {\n var titles = window.liveUpdateItemsWithError.join('
');\n str.get_string('liveupdate_fail_notification_message', 'block_opencast', titles)\n .done(function(result) {\n Notification.addNotification({\n message: result,\n type: 'error'\n });\n })\n .fail(Notification.exception);\n }\n return;\n }\n for (var processingItem of processingItems) {\n liveUpdatePerformAjax('processing', ocinstanceid, contextid, processingItem, reloadtimeout);\n }\n for (var uploadingItem of uploadingItems) {\n liveUpdatePerformAjax('uploading', ocinstanceid, contextid, uploadingItem, reloadtimeout);\n }\n }, 5000, ocinstanceid, contextid, url, reloadtimeout);\n }\n };\n\n /*\n * Gets all status live updates items (flags).\n */\n var getLiveUpdateItems = function() {\n var processingItems = getLiveUpdateProcessingItems();\n var uploadingItems = getLiveUpdateUploadingItems();\n return processingItems.concat(uploadingItems);\n };\n\n /*\n * Gets all status live updates items for Processing states.\n */\n var getLiveUpdateProcessingItems = function() {\n var itemsNodeList = document.getElementsByName('liveupdate_processing_item');\n return Array.from(itemsNodeList);\n };\n\n /*\n * Gets all status live updates items for uploading status.\n */\n var getLiveUpdateUploadingItems = function() {\n var itemsNodeList = document.getElementsByName('liveupdate_uploading_item');\n return Array.from(itemsNodeList);\n };\n\n /*\n * Perform status live update Ajax call to the backend to get the related info.\n */\n var liveUpdatePerformAjax = function(type, ocinstanceid, contextid, item, reloadtimeout) {\n var identifier = item.value;\n var title = item?.dataset?.title ? item.dataset.title : '';\n if (identifier == undefined || title == '') {\n window.liveUpdateItemsWithError.push(title);\n item.remove();\n return;\n }\n Ajax.call([{\n methodname: 'block_opencast_get_liveupdate_info',\n args: {contextid: contextid, ocinstanceid: ocinstanceid, type: type, identifier: identifier},\n done: function(status) {\n if (status == '') {\n window.liveUpdateItemsWithError.push(title);\n item.remove();\n return;\n }\n var statusObject = JSON.parse(status);\n if (statusObject.replace != '') {\n replaceLiveUpdateInfo(item, statusObject.replace);\n }\n if (statusObject.remove == true) {\n item.remove();\n var stringparams = {\n timeout: reloadtimeout,\n title: title\n };\n str.get_string('liveupdate_toast_notification', 'block_opencast', stringparams)\n .done(function(result) {\n Toast.add(result);\n })\n .fail(Notification.exception);\n setTimeout(function() {\n window.location.reload();\n }, reloadtimeout * 1000);\n }\n },\n fail: function() {\n window.liveUpdateItemsWithError.push(title);\n item.remove();\n }\n }]);\n };\n\n /*\n * Replace the new live update status with the current one for both text and DOM element.\n */\n var replaceLiveUpdateInfo = function(item, replace) {\n if (item == undefined || replace == '' || typeof replace != 'string') {\n return;\n }\n var newDiv = document.createElement('div');\n newDiv.innerHTML = replace.trim();\n var replaceElm = newDiv.firstChild;\n if (replaceElm.nodeName == '#text') {\n var prevText = item.parentNode.firstChild;\n prevText.remove();\n var newText = document.createTextNode(replace.trim());\n item.parentNode.insertBefore(newText, item);\n } else if (item.previousElementSibling) {\n var prevElm = item.previousElementSibling;\n newDiv.innerHTML = replace.trim();\n if (!areElementsEqual(replaceElm, prevElm)) {\n prevElm.remove();\n item.parentNode.insertBefore(replaceElm, item);\n }\n }\n };\n\n /*\n * Checks if the liev update DOM elements (new vs old) are equal.\n */\n var areElementsEqual = function(baseElm, checkElm) {\n var isEqual = true;\n var attributes = baseElm.getAttributeNames();\n for (var attributeName of attributes) {\n var baseAttributeValue = baseElm.getAttribute(attributeName).trim();\n var checkAttributeValue = '';\n if (checkElm.hasAttribute(attributeName)) {\n checkAttributeValue = checkElm.getAttribute(attributeName).trim();\n }\n if (checkAttributeValue == '') {\n continue;\n }\n if (checkAttributeValue != baseAttributeValue) {\n isEqual = false;\n }\n }\n return isEqual;\n };\n\n /*\n * Copies the direct access link into the clipboard.\n */\n var initCopyAccessLinkToClipboard = function() {\n $('.access-link-copytoclipboard').on('click', function(e) {\n e.preventDefault();\n var element = e.currentTarget;\n var link = element.getAttribute('href');\n if (!link) {\n str.get_string('directaccess_copy_no_link', 'block_opencast')\n .done(function(result) {\n Toast.add(result, {type: 'warning'});\n })\n .fail(Notification.exception);\n return;\n }\n\n if (navigator.clipboard) {\n navigator.clipboard.writeText(link)\n .then(() => {\n str.get_string('directaccess_copy_success', 'block_opencast')\n .done(function(result) {\n Toast.add(result);\n })\n .fail(Notification.exception);\n return;\n }).catch();\n return;\n } else {\n str.get_string('directaccess_copytoclipboard_unavialable', 'block_opencast')\n .done(function(result) {\n Toast.add(result, {type: 'danger', autohide: false, closeButton: true});\n })\n .fail(Notification.exception);\n }\n });\n };\n /*\n * Initalizes the unarchive uploadjob package on button click with modal.\n */\n var initUnarchiveUploadJobModal = function(ocinstanceid, langstrings, contextid, liveupdate) {\n $('.unarchive-uploadjob').on('click', function(e) {\n e.preventDefault();\n var targetBtn = $(e.currentTarget);\n var uploadjobid = targetBtn.data('id');\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n title: langstrings[9],\n body: langstrings[10]\n })\n .then(function(modal) {\n // Pause the live update if it is running.\n pauseLiveUpdate(liveupdate);\n modal.setSaveButtonText(langstrings[11]);\n var root = modal.getRoot();\n root.on(ModalEvents.save, function (e) {\n Ajax.call([{\n methodname: 'block_opencast_unarchive_uploadjob',\n args: {contextid: contextid, ocinstanceid: ocinstanceid, uploadjobid: uploadjobid},\n done: function() {\n window.location.reload();\n },\n fail: Notification.exception\n }]);\n e.preventDefault();\n });\n root.on(ModalEvents.hidden, function() {\n // Resume the live update if it was paused.\n resumeLiveUpdate(ocinstanceid, contextid, liveupdate);\n // Destroy when hidden/closed.\n modal.destroy();\n });\n modal.show();\n return;\n })\n .catch(Notification.exception);\n });\n };\n\n /**\n * Resets the bulk action select dropdowns.\n * @param {object} container The wrapper container which contains the dropdowns, table and selection items of massaction.\n * @param {boolean} disabled a flag to set the dropdown attribute upon using the function (default to false).\n */\n var resetVideosTableBulkActions = function (container, disabled = false) {\n if (!container) {\n return;\n }\n const dropdowns = [...container.querySelectorAll('.opencast-videos-table-massactions')];\n dropdowns.forEach(dropdown => {\n dropdown.value = '';\n dropdown.disabled = disabled;\n });\n };\n\n /*\n * Initialise all of the modules for the opencast block.\n */\n var init = function(courseid, ocinstanceid, contextid, liveupdate) {\n // Load strings\n var strings = [\n {\n key: 'reportproblem_modal_title',\n component: 'block_opencast'\n },\n {\n key: 'reportproblem_modal_body',\n component: 'block_opencast'\n },\n {\n key: 'reportproblem_modal_placeholder',\n component: 'block_opencast'\n },\n {\n key: 'reportproblem_modal_required',\n component: 'block_opencast'\n },\n {\n key: 'reportproblem_modal_submit',\n component: 'block_opencast'\n },\n {\n key: 'startworkflow',\n component: 'block_opencast'\n },\n {\n key: 'startworkflow_modal_body',\n component: 'block_opencast'\n },\n {\n key: 'startworkflow_modal_description_title',\n component: 'block_opencast'\n },\n {\n key: 'startworkflow_modal_configpanel_title',\n component: 'block_opencast'\n },\n {\n key: 'unarchiveuploadjob',\n component: 'block_opencast'\n },\n {\n key: 'unarchiveuploadjobconfirmtext',\n component: 'block_opencast'\n },\n {\n key: 'unarchiveuploadjobconfirmbtn_save',\n component: 'block_opencast'\n },\n {\n key: 'videostable_massaction_startworkflow_modal_body',\n component: 'block_opencast'\n },\n {\n key: 'videostable_massaction_startworkflow_modal_title',\n component: 'block_opencast'\n }\n ];\n str.get_strings(strings).then(function(results) {\n initWorkflowModal(ocinstanceid, courseid, results, contextid, liveupdate);\n initReportModal(ocinstanceid, courseid, results, contextid, liveupdate);\n initUnarchiveUploadJobModal(ocinstanceid, results, contextid, liveupdate);\n return;\n }).catch(Notification.exception);\n window.addEventListener('message', function(event) {\n if (event.origin !== \"null\") {\n return;\n }\n\n if (event.data === parseInt(event.data)) {\n $('#config-frame').height(event.data);\n } else {\n $('#configparams').val(event.data);\n $('#startWorkflowForm').submit();\n }\n });\n if (liveupdate.enabled) {\n initLiveUpdate(ocinstanceid, contextid, liveupdate.timeout);\n }\n initCopyAccessLinkToClipboard();\n };\n\n return {\n init: init\n };\n });\n\n"],"names":["define","$","ModalFactory","ModalEvents","str","url","Notification","Toast","Ajax","window","liveUpdateInterval","liveUpdateItemsWithError","liveUpdateState","pauseLiveUpdate","liveupdate","enabled","clearInterval","resumeLiveUpdate","ocinstanceid","contextid","initLiveUpdate","timeout","displayWorkflowPrivacyNotice","privacyworkflows","workflowid","Array","isArray","length","includes","removeClass","addClass","displayWorkflowDescription","workflowobj","description","html","displayWorkflowConfigPanel","courseid","attr","configpanelsrc","relativeUrl","ajax","success","data","trim","async","reloadtimeout","getLiveUpdateItems","setInterval","processingItems","getLiveUpdateProcessingItems","uploadingItems","getLiveUpdateUploadingItems","processingItem","liveUpdatePerformAjax","uploadingItem","titles","join","get_string","done","result","addNotification","message","type","fail","exception","concat","itemsNodeList","document","getElementsByName","from","item","identifier","value","title","dataset","undefined","push","remove","call","methodname","args","status","statusObject","JSON","parse","replace","replaceLiveUpdateInfo","stringparams","add","setTimeout","location","reload","newDiv","createElement","innerHTML","replaceElm","firstChild","nodeName","parentNode","newText","createTextNode","insertBefore","previousElementSibling","prevElm","areElementsEqual","baseElm","checkElm","isEqual","attributes","getAttributeNames","attributeName","baseAttributeValue","getAttribute","checkAttributeValue","hasAttribute","resetVideosTableBulkActions","container","disabled","dropdowns","querySelectorAll","forEach","dropdown","init","get_strings","key","component","then","results","langstrings","getElementById","workflows","text","privacyinfohtml","privacytitle","hasprivacyinfo","on","e","preventDefault","detail","clickedVideo","currentTarget","actionurl","ismassaction","bulkinfodiv","massactioncontainer","selectedids","table","querySelector","tableid","id","seriesid","selectedtitles","videoid","select","workflow","privacynoticediv","workflowdescdiv","workflowconfigpaneldiv","body","create","types","SAVE_CANCEL","modal","setSaveButtonText","root","getRoot","save","is","contentWindow","postMessage","submit","hidden","destroy","show","workflowselect","val","change","this","catch","initWorkflowModal","initReportModal","uploadjobid","initUnarchiveUploadJobModal","addEventListener","event","origin","parseInt","height","link","navigator","clipboard","writeText","autohide","closeButton"],"mappings":"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"}
\ No newline at end of file
diff --git a/amd/src/block_index.js b/amd/src/block_index.js
index 93bfea43..0aeaa727 100644
--- a/amd/src/block_index.js
+++ b/amd/src/block_index.js
@@ -89,7 +89,7 @@ define(['jquery', 'core/modal_factory', 'core/modal_events',
seriesid = tableid.replace('opencast-videos-table-', '');
}
bulkinfodiv = '
';
for (let videoid of detail.selectedids) {
bulkinfodiv += '';
@@ -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) {
@@ -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.
@@ -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'
@@ -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) {
diff --git a/classes/event/upload_failed.php b/classes/event/upload_failed.php
index 67e4e522..3df22b27 100644
--- a/classes/event/upload_failed.php
+++ b/classes/event/upload_failed.php
@@ -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']}";
}
diff --git a/classes/external.php b/classes/external.php
index f78fc109..14edd35d 100644
--- a/classes/external.php
+++ b/classes/external.php
@@ -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;
@@ -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.
*
@@ -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
*
@@ -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');
+ }
}
diff --git a/classes/local/eventstatus_notification_helper.php b/classes/local/eventstatus_notification_helper.php
index 7002e93b..fa2bf1cf 100644
--- a/classes/local/eventstatus_notification_helper.php
+++ b/classes/local/eventstatus_notification_helper.php
@@ -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;
@@ -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.
*
diff --git a/classes/local/liveupdate_helper.php b/classes/local/liveupdate_helper.php
index dbb0e813..5034ea61 100644
--- a/classes/local/liveupdate_helper.php
+++ b/classes/local/liveupdate_helper.php
@@ -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;
}
diff --git a/classes/local/notifications.php b/classes/local/notifications.php
index a6b44678..e4dcbe5c 100644
--- a/classes/local/notifications.php
+++ b/classes/local/notifications.php
@@ -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);
+ }
}
diff --git a/classes/local/upload_helper.php b/classes/local/upload_helper.php
index e179e962..7eefd340 100644
--- a/classes/local/upload_helper.php
+++ b/classes/local/upload_helper.php
@@ -72,6 +72,9 @@ class upload_helper {
/** @var int Video is successfully transferred to Opencast. */
const STATUS_TRANSFERRED = 40;
+ /** @var int Upload job is archived due to limited failed attempts */
+ const STATUS_ARCHIVED_FAILED_UPLOAD = 11;
+
/**
* Get explaination string for status code
* @param int $statuscode Status code
@@ -92,6 +95,8 @@ public static function get_status_string($statuscode) {
return get_string('mstateuploaded', 'block_opencast');
case self::STATUS_TRANSFERRED :
return get_string('mstatetransferred', 'block_opencast');
+ case self::STATUS_ARCHIVED_FAILED_UPLOAD :
+ return get_string('mstatearchived', 'block_opencast');
default :
return '';
}
@@ -304,10 +309,14 @@ public static function save_upload_jobs($ocinstanceid, $courseid, $options, $vis
*/
public static function delete_video_draft($jobtodelete) {
global $DB;
- // Check again shortly before deletion if the status is still STATUS_READY_TO_UPLOAD.
- if ($DB->record_exists('block_opencast_uploadjob',
- ['id' => $jobtodelete->id, 'status' => self::STATUS_READY_TO_UPLOAD])) {
-
+ // Check again shortly before deletion if the status is still STATUS_READY_TO_UPLOAD or STATUS_ARCHIVED_FAILED_UPLOAD.
+ $selectwhere = "id = :id AND status IN (:statustransferred, :statusarchived)";
+ $params = [
+ 'id' => $jobtodelete->id,
+ 'statustransferred' => self::STATUS_READY_TO_UPLOAD,
+ 'statusarchived' => self::STATUS_ARCHIVED_FAILED_UPLOAD,
+ ];
+ if ($DB->record_exists_select('block_opencast_uploadjob', $selectwhere, $params)) {
$DB->delete_records('block_opencast_uploadjob', ['id' => $jobtodelete->id]);
$DB->delete_records('block_opencast_metadata', ['uploadjobid' => $jobtodelete->id]);
// Delete from files table.
@@ -427,7 +436,16 @@ protected function upload_failed($job, $errormessage) {
// Update the job to enqueue again.
$job->countfailed++;
$job->timemodified = time();
- $job->status = self::STATUS_READY_TO_UPLOAD;
+
+ $failedretrylimit = (int) get_config('block_opencast', 'faileduploadretrylimit');
+ $isarchived = false;
+ $status = self::STATUS_READY_TO_UPLOAD;
+ if ($failedretrylimit > 0 && $job->countfailed >= $failedretrylimit) {
+ $status = self::STATUS_ARCHIVED_FAILED_UPLOAD;
+ $isarchived = true;
+ }
+
+ $job->status = $status;
$DB->update_record('block_opencast_uploadjob', $job);
@@ -455,11 +473,26 @@ protected function upload_failed($job, $errormessage) {
'errormessage' => $errormessage,
'countfailed' => $job->countfailed,
'ocinstanceid' => $job->ocinstanceid,
+ 'archived' => $isarchived,
],
]
);
$event->trigger();
+
+ // Notify users about archived upload job.
+ $notificationenabled = get_config('block_opencast', 'eventstatusnotificationenabled_' . $job->ocinstanceid);
+ if ($notificationenabled && $isarchived) {
+ // Prepare title with default filename.
+ $title = implode(' & ', $filenames);
+ if (isset($job->metadata)) {
+ $metadata = json_decode($job->metadata);
+ $title = $metadata[array_search('title', array_column($metadata, 'id'))]->value;
+ }
+
+ // Notify user about putting the upload into archive status.
+ eventstatus_notification_helper::notify_users_archived_upload($job, $title);
+ }
}
/**
@@ -695,7 +728,8 @@ public function cron() {
$ocinstances = settings_api::get_ocinstances();
foreach ($ocinstances as $ocinstance) {
// Get all waiting jobs.
- $sql = "SELECT * FROM {block_opencast_uploadjob} WHERE status < ? AND ocinstanceid = ? ORDER BY timemodified ASC ";
+ $sql = "SELECT * FROM {block_opencast_uploadjob}" .
+ " WHERE status < ? AND status <> ? AND ocinstanceid = ? ORDER BY timemodified ASC ";
$limituploadjobs = get_config('block_opencast', 'limituploadjobs_' . $ocinstance->id);
@@ -703,7 +737,13 @@ public function cron() {
$limituploadjobs = 0;
}
- $jobs = $DB->get_records_sql($sql, [self::STATUS_TRANSFERRED, $ocinstance->id], 0, $limituploadjobs);
+ $params = [
+ self::STATUS_TRANSFERRED,
+ self::STATUS_ARCHIVED_FAILED_UPLOAD,
+ $ocinstance->id,
+ ];
+
+ $jobs = $DB->get_records_sql($sql, $params, 0, $limituploadjobs);
if (!$jobs) {
mtrace('...no jobs to proceed for instance "' . $ocinstance->name . '"');
diff --git a/db/services.php b/db/services.php
index 0059ddfb..bf0c0e95 100644
--- a/db/services.php
+++ b/db/services.php
@@ -79,4 +79,13 @@
'ajax' => true,
'capabilities' => 'block/opencast:viewunpublishedvideos',
],
+ 'block_opencast_unarchive_uploadjob' => [
+ 'classname' => 'block_opencast_external',
+ 'methodname' => 'unarchive_uploadjob',
+ 'classpath' => 'block/opencast/classes/external.php',
+ 'description' => 'Perform unarchiving an upload job',
+ 'type' => 'write',
+ 'ajax' => true,
+ 'capabilities' => 'block/opencast:addvideo',
+ ],
];
diff --git a/deletedraft.php b/deletedraft.php
index 06d9daeb..3563e477 100644
--- a/deletedraft.php
+++ b/deletedraft.php
@@ -76,7 +76,11 @@
$message = get_string('videodraftnotfound', 'block_opencast');
redirect($redirecturl, $message, null, notification::NOTIFY_WARNING);
}
-if ($jobtodelete->status != upload_helper::STATUS_READY_TO_UPLOAD) {
+$allowedstatuses = [
+ upload_helper::STATUS_READY_TO_UPLOAD,
+ upload_helper::STATUS_ARCHIVED_FAILED_UPLOAD,
+];
+if (!in_array($jobtodelete->status, $allowedstatuses)) {
$message = get_string('videodraftnotdeletable', 'block_opencast',
upload_helper::get_status_string($jobtodelete->status));
redirect($redirecturl, $message, null, notification::NOTIFY_WARNING);
diff --git a/lang/en/block_opencast.php b/lang/en/block_opencast.php
index dd005cf4..5f774bbf 100644
--- a/lang/en/block_opencast.php
+++ b/lang/en/block_opencast.php
@@ -17,9 +17,9 @@
/**
* Strings for component 'block_opencast', language 'en'
*
- * @package block_opencast
- * @copyright 2017 Andreas Wagner, SYNERGY LEARNING
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @package block_opencast
+ * @copyright 2017 Andreas Wagner, SYNERGY LEARNING
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
$string['accesspolicies'] = 'Access Policies';
@@ -389,6 +389,8 @@
$string['expirydate'] = 'Expiry Date';
$string['failedtogetvideo'] = 'Cannot get event data from Opencast.';
$string['failedtransferattempts'] = 'Failed transfer attempts: {$a}';
+$string['faileduploadretrylimit'] = 'Limit failed upload attempts';
+$string['faileduploadretrylimitdesc'] = 'Each upload job will be archived once the maximum number of failed attempts is reached. When a job is archived, teachers must decide whether to delete it or manually re-queue it. The uploader will always be notified. If the "event status notification" option ("eventstatusnotificationenabled") is enabled, other teachers in the course will also be informed about the archived status. NOTE: A value of 0 (default) or leaving the field empty means there is no limit.';
$string['filetypes'] = 'Accepted file types';
$string['form_seriesid'] = 'Series ID';
$string['form_seriestitle'] = 'Series title';
@@ -589,6 +591,7 @@
$string['missingtranscriptionuploadparams'] = 'Required parameters to upload transcription are missing.';
$string['morethanonedefaultserieserror'] = 'This course has more than one default series. Please contact your system administrator.';
$string['morevideos'] = 'More videos...';
+$string['mstatearchived'] = 'Archived';
$string['mstatecreatingevent'] = 'Uploading...';
$string['mstatecreatinggroup'] = 'Creating Opencast Group...';
$string['mstatecreatingseries'] = 'Creating Opencast Series...';
@@ -615,6 +618,8 @@
$string['notificationeventstatusteachers'] = 'Notify all course teachers about the event process status';
$string['notificationeventstatusteachers_desc'] = 'With this option, apart from the uploader of the video, all the teachers of the course where the video is uploaded from get notified about the Opencast processing status.';
$string['notifications_settings_header'] = 'Notifications';
+$string['notificationuploadarchived_body'] = 'The upload job for the video titled "{$a->title}" in the course "{$a->coursefullname}" (ID: {$a->courseid}) has been archived due to reaching the limit of failed attempts. Your action is now required to either delete the job or manually put the job back into the queue. Please contact your system administrator to ensure the upload problem is resolved.';
+$string['notificationuploadarchived_subj'] = 'Opencast Archived Event Upload Notification';
$string['notificationuploaduqeuestatus_body'] = 'Processing of this video: {$a->videotitle} in the course: {$a->coursefullname} (ID: {$a->courseid}) is queued, but has not yet started. The video is currently waiting behind {$a->waitingnum} other video(s) in the processing queue.';
$string['notificationuploaduqeuestatus_subj'] = 'Opencast Event Upload Notification';
$string['notpublished'] = 'Not published';
@@ -822,6 +827,10 @@
$string['unabletodeletetranscription'] = 'Unable to delete transcription';
$string['unabletodownloadtranscription'] = 'Unable to download transcription';
$string['unabletomanagetranscriptions'] = 'Due to an active processing state or an ongoing workflow, managing the event\'s transcriptions is not possible at the moment.';
+$string['unarchiveuploadjob'] = 'Unarchive video upload job';
+$string['unarchiveuploadjobbtntitle'] = 'Unarchive upload job';
+$string['unarchiveuploadjobconfirmbtn_save'] = 'Proceed';
+$string['unarchiveuploadjobconfirmtext'] = 'You are about to unarchive the video upload job. Please ensure that the upload issue has been resolved. Would you like to proceed?';
$string['unexpected_api_response'] = 'Unexpected API response.';
$string['updatemetadata'] = 'Update metadata for this event';
$string['updatemetadata_massaction'] = 'Update metadata for selected video(s)';
@@ -840,6 +849,7 @@
$string['uploadfilelimit'] = 'Video size limit';
$string['uploadfilelimitdesc'] = 'Limit the file size of uploaded videos through the chunkupload.';
$string['uploadingeventfailed'] = 'Creating of event failed';
+$string['uploadjobnotfound'] = 'The video upload job could not be found.';
$string['uploadjobssaved'] = 'Video upload successful. The video is scheduled to be transferred to Opencast now. You do not need to wait on this page for this transfer to finish.';
$string['uploadprocessingexplanation'] = 'These video files will be processed in Opencast and then made available in this course.';
$string['uploadqueuetoopencast'] = 'Videos scheduled to be transferred to Opencast';
diff --git a/renderer.php b/renderer.php
index 58e533c3..59bff980 100644
--- a/renderer.php
+++ b/renderer.php
@@ -670,12 +670,12 @@ public function render_status($statuscode, $countfailed = 0) {
*
* @param int $ocinstanceid Opencast instance id.
* @param array $uploadjobs array of uploadjob objects
- * @param bool $showdeletebutton shows a delete button in the last column
+ * @param bool $showactionbuttons A flag indicating whether to show action buttons.
* @param string $redirectpage
* @param string $seriesid
* @return string
*/
- public function render_upload_jobs($ocinstanceid, $uploadjobs, $showdeletebutton = true,
+ public function render_upload_jobs($ocinstanceid, $uploadjobs, $showactionbuttons = true,
$redirectpage = null, $seriesid = null) {
// Set if visibility change is enabled.
$canchangescheduledvisibility = false;
@@ -695,7 +695,7 @@ public function render_upload_jobs($ocinstanceid, $uploadjobs, $showdeletebutton
if ($canchangescheduledvisibility) {
$table->head[] = get_string('hscheduledvisibility', 'block_opencast');
}
- if ($showdeletebutton) {
+ if ($showactionbuttons) {
$table->head[] = '';
}
@@ -774,7 +774,8 @@ public function render_upload_jobs($ocinstanceid, $uploadjobs, $showdeletebutton
}
$status = $this->render_status($uploadjob->status, $uploadjob->countfailed);
// Add live update flag item (hidden input) to the upload status column, if it is enabled.
- if (boolval(get_config('block_opencast', 'liveupdateenabled_' . $ocinstanceid))) {
+ if (boolval(get_config('block_opencast', 'liveupdateenabled_' . $ocinstanceid)) &&
+ $uploadjob->status != upload_helper::STATUS_ARCHIVED_FAILED_UPLOAD) {
$status .= liveupdate_helper::get_liveupdate_uploading_hidden_input($uploadjob->id, $title);
}
$row[] = $status;
@@ -782,13 +783,32 @@ public function render_upload_jobs($ocinstanceid, $uploadjobs, $showdeletebutton
if ($canchangescheduledvisibility) {
$row[] = $this->render_scheduled_visibility_icon($uploadjob);
}
- if ($showdeletebutton) {
+ if ($showactionbuttons) {
+ $actionbuttonshtml = '';
$coursecontext = context_course::instance($uploadjob->courseid);
- // The one who is allowed to add the video is also allowed to delete the video before it is uploaded.
- $row[] = ($uploadjob->status == upload_helper::STATUS_READY_TO_UPLOAD &&
- has_capability('block/opencast:addvideo', $coursecontext)) ?
- $this->render_delete_draft_icon($uploadjob->ocinstanceid, $uploadjob->courseid,
- $uploadjob->id, $redirectpage, $seriesid) : '';
+ if (has_capability('block/opencast:addvideo', $coursecontext)) {
+ // Rendering a button to put the upload job back into the queue aka unarchive.
+ if ($uploadjob->status == upload_helper::STATUS_ARCHIVED_FAILED_UPLOAD) {
+ $actionbuttonshtml .= $this->render_unarchive_uploadjob_icon(
+ $uploadjob->ocinstanceid,
+ $uploadjob->courseid,
+ $uploadjob->id,
+ );
+ }
+ // The one who is allowed to add the video is also allowed to delete the video before it is uploaded.
+ if ($uploadjob->status == upload_helper::STATUS_READY_TO_UPLOAD ||
+ $uploadjob->status == upload_helper::STATUS_ARCHIVED_FAILED_UPLOAD) {
+ $actionbuttonshtml .= $this->render_delete_draft_icon(
+ $uploadjob->ocinstanceid,
+ $uploadjob->courseid,
+ $uploadjob->id,
+ $redirectpage,
+ $seriesid
+ );
+ }
+ }
+
+ $row[] = $actionbuttonshtml;
}
$table->data[] = $row;
@@ -1034,6 +1054,28 @@ private function render_delete_draft_icon($ocinstanceid, $courseid, $videoidenti
return html_writer::link($url, $icon);
}
+ /**
+ * Render the link that unarchives the upload job.
+ *
+ * @param int $ocinstanceid Opencast instance id.
+ * @param int $courseid
+ * @param string $uploadjobid
+ * @return string
+ * @throws coding_exception
+ * @throws moodle_exception
+ */
+ private function render_unarchive_uploadjob_icon($ocinstanceid, $courseid, $uploadjobid) {
+ $text = get_string('unarchiveuploadjobbtntitle', 'block_opencast');
+
+ $icon = $this->output->pix_icon(
+ 'i/reload',
+ $text,
+ 'moodle'
+ );
+
+ return html_writer::link(new moodle_url('#'), $icon, ['class' => 'unarchive-uploadjob', 'data-id' => $uploadjobid]);
+ }
+
/**
* Render menu of edit options for a video.
* @param int $ocinstanceid
diff --git a/settings.php b/settings.php
index 48614f58..1e730221 100644
--- a/settings.php
+++ b/settings.php
@@ -115,6 +115,12 @@
get_string('uploadtimeout', 'block_opencast'),
get_string('uploadtimeoutdesc', 'block_opencast'), 60, PARAM_INT));
+ // Failed upload retry limit.
+ $sharedsettings->add(
+ new admin_setting_configtext('block_opencast/faileduploadretrylimit',
+ get_string('faileduploadretrylimit', 'block_opencast'),
+ get_string('faileduploadretrylimitdesc', 'block_opencast'), 0, PARAM_INT));
+
$ADMIN->add('block_opencast', $sharedsettings);
foreach ($ocinstances as $instance) {