diff --git a/admin/apiretries.php b/admin/apiretries.php index eb0a4ebe84b..5d3f4e0b70f 100644 --- a/admin/apiretries.php +++ b/admin/apiretries.php @@ -26,6 +26,7 @@ use enrol_arlo\api; use enrol_arlo\local\tablesql\apiretries; use enrol_arlo\adminsettings\configarlostatus; +use enrol_arlo\form\syncold; require_once(__DIR__ . '/../../../config.php'); require_once($CFG->libdir . '/adminlib.php'); @@ -36,6 +37,7 @@ $action = optional_param('action', null, PARAM_ALPHA); $course = optional_param('course', null, PARAM_INT); $regid = optional_param('regid', null, PARAM_INT); +$message = optional_param('message', null, PARAM_TEXT); echo $OUTPUT->header(); echo $OUTPUT->heading(get_string('apiretries', 'enrol_arlo')); @@ -50,6 +52,10 @@ echo $OUTPUT->single_button(new moodle_url($PAGE->url, ['action' => 'enablecommunication']), get_string('enablecommunication', 'enrol_arlo')); } +if (!enrol_arlo_sync_adhoc_queued()) { + echo $OUTPUT->single_button('', get_string('synoldreg', 'enrol_arlo'), '', ['data-action' => 'syncold']); +} + if (!empty($pluginconfig->get('redirectcount'))) { echo get_string('apifails', 'enrol_arlo') . $pluginconfig->get('redirectcount'); echo $OUTPUT->single_button(new moodle_url($PAGE->url, ['action' => 'resetredirects']), get_string('resetredirects', 'enrol_arlo')); @@ -72,6 +78,10 @@ } $report = new apiretries('enrolsettingsarloapiretries'); +if ($message) { + echo $OUTPUT->notification(get_string($message, 'enrol_arlo'), \core\output\notification::NOTIFY_INFO); +} $report->out(apiretries::PAGINATION_MAX_LIMIT, false); +$PAGE->requires->js_call_amd('enrol_arlo/syncold', 'init', ['[data-action="syncold"]', syncold::class]); echo $OUTPUT->footer(); \ No newline at end of file diff --git a/amd/build/syncold.min.js b/amd/build/syncold.min.js new file mode 100644 index 00000000000..c3b0dbe0e7f --- /dev/null +++ b/amd/build/syncold.min.js @@ -0,0 +1,3 @@ +define("enrol_arlo/syncold",["exports","core_form/modalform","core/config","core/str"],(function(_exports,_modalform,_config,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_modalform=_interopRequireDefault(_modalform),_config=_interopRequireDefault(_config);_exports.init=(linkSelector,formClass)=>{document.querySelector(linkSelector).addEventListener("click",(async e=>{e.preventDefault();const form=new _modalform.default({formClass:formClass,args:{},modalConfig:{title:await(0,_str.get_string)("dateselector","enrol_arlo")},saveButtonText:await(0,_str.get_string)("synchronize","enrol_arlo"),returnFocus:e.currentTarget});form.addEventListener(form.events.FORM_SUBMITTED,(e=>{const response=e.detail;let redirect="".concat(_config.default.wwwroot,"/enrol/arlo/admin/apiretries.php?"),first=!1;for(let key in response)first?first=!1:redirect+="&",redirect+="".concat(key,"=").concat(response[key]);window.location.assign(redirect)})),form.show()}))}})); + +//# sourceMappingURL=syncold.min.js.map \ No newline at end of file diff --git a/amd/build/syncold.min.js.map b/amd/build/syncold.min.js.map new file mode 100644 index 00000000000..f509b4093fa --- /dev/null +++ b/amd/build/syncold.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"syncold.min.js","sources":["../src/syncold.js"],"sourcesContent":["import ModalForm from 'core_form/modalform';\nimport Config from 'core/config';\nimport {get_string as getString} from 'core/str';\n\nexport const init = (linkSelector, formClass) => {\n let syncbutton = document.querySelector(linkSelector);\n\n syncbutton.addEventListener('click', async(e) => {\n e.preventDefault();\n\n const form = new ModalForm(({\n formClass,\n args: {},\n modalConfig: {\n title: await getString('dateselector', 'enrol_arlo'),\n },\n saveButtonText: await getString('synchronize', 'enrol_arlo'),\n returnFocus: e.currentTarget\n }));\n\n form.addEventListener(form.events.FORM_SUBMITTED, (e) => {\n const response = e.detail;\n let redirect = `${Config.wwwroot}/enrol/arlo/admin/apiretries.php?`;\n let first = false;\n for (let key in response) {\n if (first) {\n first = false;\n } else {\n redirect = redirect + '&';\n }\n redirect = redirect + `${key}=${response[key]}`;\n }\n window.location.assign(redirect);\n });\n\n form.show();\n });\n\n};\n"],"names":["linkSelector","formClass","document","querySelector","addEventListener","async","e","preventDefault","form","ModalForm","args","modalConfig","title","saveButtonText","returnFocus","currentTarget","events","FORM_SUBMITTED","response","detail","redirect","Config","wwwroot","first","key","window","location","assign","show"],"mappings":"sYAIoB,CAACA,aAAcC,aACdC,SAASC,cAAcH,cAE7BI,iBAAiB,SAASC,MAAAA,IACjCC,EAAEC,uBAEIC,KAAO,IAAIC,mBAAW,CACxBR,UAAAA,UACAS,KAAM,GACNC,YAAa,CACTC,YAAa,mBAAU,eAAgB,eAE3CC,qBAAsB,mBAAU,cAAe,cAC/CC,YAAaR,EAAES,gBAGnBP,KAAKJ,iBAAiBI,KAAKQ,OAAOC,gBAAiBX,UACzCY,SAAWZ,EAAEa,WACfC,mBAAcC,gBAAOC,6CACrBC,OAAQ,MACP,IAAIC,OAAON,SACRK,MACAA,OAAQ,EAERH,UAAsB,IAE1BA,oBAAyBI,gBAAON,SAASM,MAE7CC,OAAOC,SAASC,OAAOP,aAG3BZ,KAAKoB"} \ No newline at end of file diff --git a/amd/src/syncold.js b/amd/src/syncold.js new file mode 100644 index 00000000000..95a24a0bfc7 --- /dev/null +++ b/amd/src/syncold.js @@ -0,0 +1,39 @@ +import ModalForm from 'core_form/modalform'; +import Config from 'core/config'; +import {get_string as getString} from 'core/str'; + +export const init = (linkSelector, formClass) => { + let syncbutton = document.querySelector(linkSelector); + + syncbutton.addEventListener('click', async(e) => { + e.preventDefault(); + + const form = new ModalForm(({ + formClass, + args: {}, + modalConfig: { + title: await getString('dateselector', 'enrol_arlo'), + }, + saveButtonText: await getString('synchronize', 'enrol_arlo'), + returnFocus: e.currentTarget + })); + + form.addEventListener(form.events.FORM_SUBMITTED, (e) => { + const response = e.detail; + let redirect = `${Config.wwwroot}/enrol/arlo/admin/apiretries.php?`; + let first = false; + for (let key in response) { + if (first) { + first = false; + } else { + redirect = redirect + '&'; + } + redirect = redirect + `${key}=${response[key]}`; + } + window.location.assign(redirect); + }); + + form.show(); + }); + +}; diff --git a/classes/api.php b/classes/api.php index 13d731af12b..d679bcf308e 100644 --- a/classes/api.php +++ b/classes/api.php @@ -453,7 +453,6 @@ public static function run_instance_jobs($instanceid, $full = false, $trace = nu } } - if (!empty($outcomesjobpersistent)) { $outcomesjob = \enrol_arlo\local\factory\job_factory::create_from_persistent($outcomesjobpersistent); $outcomestatus = $outcomesjob->run(); diff --git a/classes/form/syncold.php b/classes/form/syncold.php new file mode 100644 index 00000000000..f2dafa99f28 --- /dev/null +++ b/classes/form/syncold.php @@ -0,0 +1,98 @@ +. + +namespace enrol_arlo\form; + + +defined('MOODLE_INTERNAL') || die(); + +require_once($CFG->libdir . '/formslib.php'); +use core_form\dynamic_form; +use enrol_arlo\task\enrolments_adhoc; +use moodle_url; +use stdClass; + +class syncold extends dynamic_form { + + /** + * Get context. + * + * @return \context + * @throws \dml_exception + */ + protected function get_context_for_dynamic_submission(): \context { + return \context_system::instance(); + } + + /** + * Check access. + * + * @return void + * @throws \dml_exception + * @throws \required_capability_exception + */ + protected function check_access_for_dynamic_submission(): void { + require_capability('moodle/course:create', \context_system::instance()); + } + + /** + * Process submission. + * + * @return array + */ + public function process_dynamic_submission() { + $data = $this->get_data(); + $task = new enrolments_adhoc(); + $task->set_custom_data($data->startdate); + \core\task\manager::queue_adhoc_task($task); + return ['message' => 'taskqueued']; + } + + /** + * Set form data. + * + * @return void + * @throws Exception No record in persistent table + */ + public function set_data_for_dynamic_submission(): void { + $this->set_data(new stdClass()); + } + + /** + * Get page url. + * + * @return moodle_url + */ + protected function get_page_url_for_dynamic_submission(): moodle_url { + return new moodle_url('/enrol/arlo/admin/apiretries.php'); + } + + public function definition() { + global $DB, $COURSE; + $form = $this->_form; + $form->addElement('date_selector', 'startdate', get_string('syncsince', 'enrol_arlo')); + $form->addHelpButton('startdate', 'syncsince', 'enrol_arlo'); + } + + public function validation($data, $files) { + $errors = parent::validation($data, $files); + $time = time(); + if ($data['startdate'] > $time) { + $errors['startdate'] = get_string('invalidstartdate', 'enrol_arlo'); + } + return $errors; + } +} diff --git a/classes/local/job/contact_merge_requests_job.php b/classes/local/job/contact_merge_requests_job.php index 2e5ba26c569..b3f0b3ac7be 100644 --- a/classes/local/job/contact_merge_requests_job.php +++ b/classes/local/job/contact_merge_requests_job.php @@ -69,8 +69,7 @@ class contact_merge_requests_job extends job { public function run() { $pluginconfig = new arlo_plugin_config(); $jobpersistent = $this->get_job_persistent(); - $disableskip = get_config('enrol_arlo', 'disableskip'); - $lastime = empty($disableskip) ? $jobpersistent->get('lastsourcetimemodified') : 0; + $lastime = $jobpersistent->get('lastsourcetimemodified'); try { $hasnext = true; while ($hasnext) { diff --git a/classes/local/job/memberships_job.php b/classes/local/job/memberships_job.php index a745b97a308..88186c927e9 100644 --- a/classes/local/job/memberships_job.php +++ b/classes/local/job/memberships_job.php @@ -247,7 +247,7 @@ public function sync_resource($resource) { * @return bool * @throws \GuzzleHttp\Exception\GuzzleException */ - public static function sync_memberships($trace) { + public static function sync_memberships($trace, $timetosync = null) { global $DB; $plugin = api::get_enrolment_plugin(); @@ -294,14 +294,13 @@ public static function sync_memberships($trace) { // adjusting and the filter each call so we get all records and don't end up // getting same 250 each call. $hasnext = true; - $disableskip = get_config('enrol_arlo', 'disableskip'); - $lastime = empty($disableskip) ? get_config('enrol_arlo', 'lastregtimemodified') : date('c', 0); - $lastregid = empty($disableskip) ? get_config('enrol_arlo', 'lastregid') : 0; + $lastime = empty($timetosync) ? get_config('enrol_arlo', 'lastregtimemodified') : date('c', $timetosync); + $lastregid = empty($timetosync) ? get_config('enrol_arlo', 'lastregid') : 0; while ($hasnext) { $hasnext = false; // Break paging by default. // Update contact merge requests records every page. $contactmergerequestsjob = job_factory::get_job(['type' => 'contact_merge_requests']); - $contactmergerequestsjob->run(); + $contactmergerequestsjob->run($timetosync); $uri = new RequestUri(); $uri->setHost($pluginconfig->get('platform')); $uri->setResourcePath('registrations/'); diff --git a/classes/task/enrolments_adhoc.php b/classes/task/enrolments_adhoc.php new file mode 100644 index 00000000000..f5206c171f3 --- /dev/null +++ b/classes/task/enrolments_adhoc.php @@ -0,0 +1,73 @@ +. + +namespace enrol_arlo\task; + +use core\task\adhoc_task; +use core\task\scheduled_task; +use enrol_arlo\api; +use enrol_arlo\local\job\memberships_job; +use enrol_arlo\manager; +use null_progress_trace; +use text_progress_trace; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Create Moodle enrolments based off Arlo registrations adhoc. + * + * @package enrol_arlo + * @copyright 2020 LearningWorks Ltd {@link http://www.learningworks.co.nz} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class enrolments_adhoc extends adhoc_task { + + /** + * Get schedule task human readable name. + * + * @return string + * @throws \coding_exception + */ + public function get_name() { + return get_string('enrolmentstaskadhoc', 'enrol_arlo'); + } + + /** + * Execute the task. + * + * @throws \coding_exception + * @throws \dml_exception + * @throws \moodle_exception + */ + public function execute() { + global $CFG; + require_once($CFG->dirroot . '/enrol/arlo/lib.php'); + if (!enrol_is_enabled('arlo')) { + return; + } + $trace = new null_progress_trace(); + if ($CFG->debug == DEBUG_DEVELOPER) { + $trace = new text_progress_trace(); + } + $timetosync = $this->get_custom_data(); + memberships_job::sync_memberships($trace, $timetosync); + + $manager = new manager(); + $manager->process_email_queue(); + return true; + } + +} diff --git a/lang/en/enrol_arlo.php b/lang/en/enrol_arlo.php index c273e22061c..9d5bc2ddbef 100644 --- a/lang/en/enrol_arlo.php +++ b/lang/en/enrol_arlo.php @@ -451,8 +451,6 @@ $string['useadhoctask_desc'] = 'Enable this if you are planning to perform a large synchronisation between Arlo and Moodle (e.g. 100+ records at once).'; $string['onlyactive'] = 'Only active events'; $string['onlyactive_desc'] = 'Only process registrations for active Arlo courses and online activities.'; -$string['disableskip'] = 'Disable registration skip'; -$string['disableskip_desc'] = 'Disables the ability to skip processing old registrations (A sync will run for all registrations even the ones already processed).'; $string['enable_multisync'] = 'Enable multisync'; $string['enable_multisync_desc'] = 'When the webhook is enabled the sync is done only trough the webhooks. This setting allows to run the sync through the scheduled task as well.'; $string['technicalcontact'] = 'Contact email'; @@ -492,4 +490,9 @@ $string['retry_sync'] = 'Retry sync'; $string['connectionstatus'] = 'Connection Status: '; $string['apifails'] = 'Global API fails: '; - +$string['synoldreg'] = 'Sync old registrations'; +$string['dateselector'] = 'Sync date selector'; +$string['syncsince'] = 'Sync since'; +$string['syncsince_help'] = 'Sync registrations since selected date.'; +$string['invalidstartdate'] = 'Date must be in the past'; +$string['taskqueued'] = 'Syncronisation task has been queued.'; diff --git a/locallib.php b/locallib.php index b81886f6173..51b422edd33 100644 --- a/locallib.php +++ b/locallib.php @@ -387,3 +387,14 @@ function enrol_arlo_update_all_course_registrations($courseid) { $DB->update_record('enrol_arlo_registration', $registration); } } + +/** + * Check if there are any adhoc syncs queued. + * + * @return bool + */ +function enrol_arlo_sync_adhoc_queued() { + global $DB; + $sql = "SELECT * FROM {task_adhoc} WHERE classname = '\\enrol_arlo\\task\\enrolments_adhoc'"; + return $DB->record_exists_sql($sql); +} diff --git a/settings.php b/settings.php index bc640f7930e..f103733400d 100644 --- a/settings.php +++ b/settings.php @@ -113,10 +113,6 @@ $name = get_string('onlyactive', 'enrol_arlo'); $settings->add(new admin_setting_configcheckbox('enrol_arlo/onlyactive', $name, $description, 0)); - $description = get_string('disableskip_desc', 'enrol_arlo'); - $name = get_string('disableskip', 'enrol_arlo'); - $settings->add(new admin_setting_configcheckbox('enrol_arlo/disableskip', $name, $description, 0)); - // Only display management category if plugin enabled. if ($enrol->is_enabled()) { $name = get_string('managearlo', 'enrol_arlo');