From cf751de1a34c2d527898d63e6952b2d402c8d4f5 Mon Sep 17 00:00:00 2001 From: Thomas Winkler Date: Wed, 11 Oct 2023 08:54:17 +0200 Subject: [PATCH] FTPSyncfiles --- classes/event/cron_trigger.php | 67 ++++++ classes/task/cron_trigger.php | 57 +++++ db/events.php | 4 + db/tasks.php | 38 +++ entries_class.php | 4 +- field/file/field_class.php | 11 +- lang/de/datalynx.php | 3 + lang/en/datalynx.php | 3 + .../lang/de/datalynxrule_ftpsyncfiles.php | 32 +++ .../lang/en/datalynxrule_ftpsyncfiles.php | 32 +++ rule/ftpsyncfiles/rule_class.php | 227 ++++++++++++++++++ rule/ftpsyncfiles/rule_form.php | 87 +++++++ rule/ftpsyncfiles/version.php | 27 +++ version.php | 2 +- view/csv/view_form.php | 4 +- 15 files changed, 591 insertions(+), 7 deletions(-) create mode 100644 classes/event/cron_trigger.php create mode 100644 classes/task/cron_trigger.php create mode 100644 db/tasks.php create mode 100644 rule/ftpsyncfiles/lang/de/datalynxrule_ftpsyncfiles.php create mode 100644 rule/ftpsyncfiles/lang/en/datalynxrule_ftpsyncfiles.php create mode 100644 rule/ftpsyncfiles/rule_class.php create mode 100644 rule/ftpsyncfiles/rule_form.php create mode 100644 rule/ftpsyncfiles/version.php diff --git a/classes/event/cron_trigger.php b/classes/event/cron_trigger.php new file mode 100644 index 00000000..e08a8f57 --- /dev/null +++ b/classes/event/cron_trigger.php @@ -0,0 +1,67 @@ +. + +/** + * The mod_datalynx comment created event. + * + * @package mod_datalynx + * @copyright 2023 Thomas Winkler + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_datalynx\event; + +defined('MOODLE_INTERNAL') or die(); + +/** + * The mod_datalynx comment created event class. + * + * @package mod_datalynx + * @since Moodle 4.0 + * @copyright 2023 Thomas Winkler + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class cron_trigger extends \core\event\base { + + /** + * Init method. + * + * @return void + */ + protected function init() { + $this->data['objecttable'] = 'datalynx'; + $this->data['crud'] = 'u'; + $this->data['edulevel'] = self::LEVEL_OTHER; + } + + /** + * Return localised event name. + * + * @return string + */ + public static function get_name() { + return get_string('datalynx_cron_trigger', 'mod_datalynx'); + } + + /** + * Returns description of what happened. + * + * @return string + */ + public function get_description() { + return "Cron Job trigger occured"; + } +} diff --git a/classes/task/cron_trigger.php b/classes/task/cron_trigger.php new file mode 100644 index 00000000..92cc36fe --- /dev/null +++ b/classes/task/cron_trigger.php @@ -0,0 +1,57 @@ +. + +/** + * Trigger an event in a periodic time + * + * @package mod_datalynx + * @copyright 2023 Thomas Winkler + * @author Thomas Winkler + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace mod_datalynx\task; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Trigger an event in a periodic time + * + * @package mod_datalynx + * @copyright 2023 Thomas Winkler + * @author Thomas Winkler + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * + */ +class cron_trigger extends \core\task\scheduled_task { + + public function get_name() { + return get_string('cron_trigger', 'mod_datalynx'); + } + + /** + * + * Close off any overdue attempts. + */ + public function execute() { + global $DB; + $records = $DB->get_records('datalynx_rules', null, '', 'DISTINCT dataid'); + foreach ($records as $record) { + $df = new \mod_datalynx\datalynx($record->dataid); + $event = \mod_datalynx\event\cron_trigger::create(array('context' => $df->context, 'objectid' => $df->id())); + $event->trigger(); + } + } +} diff --git a/db/events.php b/db/events.php index affc505e..11a995c7 100644 --- a/db/events.php +++ b/db/events.php @@ -51,5 +51,9 @@ array('eventname' => 'mod_datalynx\event\team_updated', 'callback' => 'datalynx_rule_manager::trigger_rules', 'includefile' => 'mod/datalynx/rule/rule_manager.php' + ), + array('eventname' => 'mod_datalynx\event\cron_trigger', + 'callback' => 'datalynx_rule_manager::trigger_rules', + 'includefile' => 'mod/datalynx/rule/rule_manager.php' ) ); diff --git a/db/tasks.php b/db/tasks.php new file mode 100644 index 00000000..ae3a4ca3 --- /dev/null +++ b/db/tasks.php @@ -0,0 +1,38 @@ +. + +/** + * Definition of Quiz scheduled tasks. + * + * @package mod _datalynx + * @category task + * @copyright 2023 Thomas Winkler Michael Hughes + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$tasks = [ + [ + 'classname' => 'mod_datalynx\task\cron_trigger', + 'blocking' => 0, + 'minute' => '*', + 'hour' => '*', + 'day' => '*', + 'dayofweek' => '*', + 'month' => '*' + ] +]; diff --git a/entries_class.php b/entries_class.php index 009f4be1..b97d45bf 100644 --- a/entries_class.php +++ b/entries_class.php @@ -507,7 +507,7 @@ public function get_contentinfo(array $fids) { * Process entries when after editing content for saving into db * * @param string $action - * @param string $eids + * @param string||array $eids * @param null $data * @param bool $confirmed * @return array notificationstrings, list of processed ids @@ -515,7 +515,7 @@ public function get_contentinfo(array $fids) { * @throws dml_exception * @throws moodle_exception */ - public function process_entries(string $action, string $eids, $data = null, bool $confirmed = false): array { + public function process_entries(string $action, $eids, $data = null, bool $confirmed = false): array { global $DB, $USER, $OUTPUT, $PAGE; $dl = $this->datalynx; $errorstring = ''; diff --git a/field/file/field_class.php b/field/file/field_class.php index 5badc387..92cc7f8d 100644 --- a/field/file/field_class.php +++ b/field/file/field_class.php @@ -87,7 +87,8 @@ public function update_content(stdClass $entry, array $values = null) { $rec->entryid = $entryid; $rec->content1 = $alttext; - if (count($files) > 1) { + // Hack for update field for ftpsync. + if (count($files) > 1 || $filemanager == 111111) { $rec->content = 1; // We just store a 1 to show there is something, look for files. } else { $rec->content = 0; // In case there is no file, add a 0. @@ -174,11 +175,17 @@ public function prepare_import_content(&$data, $importsettings, $csvrecord = nul $fs = get_file_storage(); $fs->create_file_from_url($filerecord, $fileurl, null, true); } + // If no files, then return false. - if ($filesprocessed == 0) { + if ($filesprocessed == 0 && $data->ftpsyncmode == 0) { return false; } + if ($data->ftpsyncmode) { + $data->{"field_{$fieldid}_{$entryid}"} = 1; + $draftitemid = 111111; + } + // Tell the update script what itemid to look for. $data->{"field_{$fieldid}_{$entryid}_filemanager"} = $draftitemid; diff --git a/lang/de/datalynx.php b/lang/de/datalynx.php index 62c7f362..8d46f859 100644 --- a/lang/de/datalynx.php +++ b/lang/de/datalynx.php @@ -895,3 +895,6 @@ $string['search:entry'] = "Datalynx - Einträge"; $string['noselection'] = "Keine Auswahl"; + +// Task. +$string['datalynx_cron_trigger'] = "DL Cron Job"; diff --git a/lang/en/datalynx.php b/lang/en/datalynx.php index 02087254..d7922f90 100644 --- a/lang/en/datalynx.php +++ b/lang/en/datalynx.php @@ -937,3 +937,6 @@ $string['search:entry'] = "Datalynx - entries"; $string['noselection'] = "Nothing selected"; + +// Task. +$string['datalynx_cron_trigger'] = "DL Cron Job"; diff --git a/rule/ftpsyncfiles/lang/de/datalynxrule_ftpsyncfiles.php b/rule/ftpsyncfiles/lang/de/datalynxrule_ftpsyncfiles.php new file mode 100644 index 00000000..7a36b396 --- /dev/null +++ b/rule/ftpsyncfiles/lang/de/datalynxrule_ftpsyncfiles.php @@ -0,0 +1,32 @@ +. + +/** + * + * @package datalynxrule + * @subpackage ftpsyncfiles + * @copyright 2023 Thomas Winkler + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +$string['event'] = 'Datalynx Ereignis'; +$string['pluginname'] = 'FTP Sync Data'; +$string['triggerspecificevent'] = 'Nur bei markierter Checkbox senden'; + +$string['sftpsettings'] = 'SFTP Settings'; +$string['sftpserver'] = 'STFP Server'; +$string['sftpusername'] = 'STFP Username'; +$string['sftppassword'] = 'STFP Passwort'; +$string['sftppath'] = 'STFP Path'; diff --git a/rule/ftpsyncfiles/lang/en/datalynxrule_ftpsyncfiles.php b/rule/ftpsyncfiles/lang/en/datalynxrule_ftpsyncfiles.php new file mode 100644 index 00000000..70028412 --- /dev/null +++ b/rule/ftpsyncfiles/lang/en/datalynxrule_ftpsyncfiles.php @@ -0,0 +1,32 @@ +. + +/** + * + * @package datalynxrule + * @subpackage ftpsyncfiles + * @copyright 2023 Thomas Winkler + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +$string['event'] = 'Datalynx event'; +$string['pluginname'] = 'FTP Sync Data'; +$string['triggerspecificevent'] = 'Nur bei markierter Checkbox senden'; + +$string['sftpsettings'] = 'SFTP Settings'; +$string['sftpserver'] = 'STFP Server'; +$string['sftpusername'] = 'STFP Username'; +$string['sftppassword'] = 'STFP Password'; +$string['sftppath'] = 'STFP Path'; diff --git a/rule/ftpsyncfiles/rule_class.php b/rule/ftpsyncfiles/rule_class.php new file mode 100644 index 00000000..cbaf675b --- /dev/null +++ b/rule/ftpsyncfiles/rule_class.php @@ -0,0 +1,227 @@ +. + +/** + * + * @package datalynx_rule + * @subpackage ftpsyncfiles + * @copyright 2015 Ivan Šakić + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +defined('MOODLE_INTERNAL') or die(); + +require_once(dirname(__FILE__) . "/../rule_class.php"); + +class datalynx_rule_ftpsyncfiles extends datalynx_rule_base { + + public $type = 'ftpsyncfiles'; + + protected $sftpserver; + + protected $stfpport; + + protected $sftpusername; + + protected $sftppassword; + + protected $sftppath; + + const USERID = 1; + + const USERNAME = 2; + + const USEREMAIL = 3; + + /** + * Class constructor + * + * @param datalynx|int $df datalynx id or class object + * @param stdClass|int $rule rule id or DB record + */ + public function __construct($df = 0, $rule = 0) { + parent::__construct($df, $rule); + $this->sftpserver = $this->rule->param2; + $this->stfpport = $this->rule->param3; + $this->sftpusername = $this->rule->param4; + $this->sftppassword = $this->rule->param5; + $this->sftppath = $this->rule->param6; + } + + public function trigger(\core\event\base $event) { + global $CFG; + require_once("$CFG->dirroot/mod/datalynx/classes/datalynx.php"); + require_once("$CFG->dirroot/mod/datalynx/view/csv/view_class.php"); + require_once($CFG->libdir.'/completionlib.php'); + + $did = $event->get_data()['objectid']; + + // Download Server files. + $dl = $this->download_files($did); + + $instance = new datalynxview_csv($did); + $df = new mod_datalynx\datalynx($did); + + // $file = $CFG->dirroot . '/mod/datalynx/testfile/1_test.csv'; + $fs = get_file_storage(); + + // Scan folder + // $folder = $CFG->dataroot . '/temp/csvimport/moddatalynx/' . $did . '/'; + // $files = scandir($folder); + + // foreach ($files as $file) { + // if ($file !== '.' && $file !== '..') { + // if (preg_match('/^(\d+)_/', $file, $matches)) { + // $prefix = $matches[1]; + // } + // } + // } + + // How + // $filerecord = [ + // 'contextid' => $df->context->id, + // 'component' => 'mod_datalynx', + // 'filearea' => 'content', + // 'itemid' => 204, -> (not entryid datalynx_contents -> id) + // 'filepath' => '/', + // 'filename' => 'test.csv', + // 'timecreated' => time(), + // 'timemodified' => time(), + // 'userid' => $userid, + // ]; + // $fs->create_file_from_pathname($filerecord, $file); + + if (file_exists($file) && is_readable($file)) { + $filecontents = file_get_contents($file); + + if ($filecontents !== false) { + $data = new stdClass(); + $data->eids = array(); + $df = new mod_datalynx\datalynx($did); + $fields = $df->get_fields(); + // Get all the fields and write it into fieldsettings array. Needed for process_csv function. + $fieldsettings = []; + foreach ($fields as $field => $value) { + $fieldsettings[$field] = [$value->field->name => array('name' => $value->field->name)]; + } + // Options array for process_csv + $options = array( + 'settings' => $fieldsettings, + ); + $data->ftpsyncmode = true; + $data = $instance->process_csv($data, $filecontents, $options); + $instance->execute_import($data); + } else { + // handle the case where reading the file failed. + echo 'Error reading the file.'; + } + } else { + // handle the case where the file does not exist or is not readable. + echo 'File does not exist or is not readable.'; + } + + return true; + } + + /** + * Download the files from the server and place it in a temporary folder. + * + * @param integer $did + * + * @return void + */ + private function download_files(int $did) { + global $CFG; + // Initialize cURL. + $c = curl_init("sftp://$this->sftpusername:$this->sftppassword@$this->sftpserver:$this->stfpport/$this->sftppath"); + + // Set cURL options for SFTP. + curl_setopt($c, CURLOPT_RETURNTRANSFER, CURLPROTO_SFTP); + + // Get a list of files in the SFTP folder. + $list = curl_exec($c); + $info = curl_getinfo($c); + + // Close the cURL connection. + curl_close($c); + + // Split the directory listing into an array of file names. + $lines = explode("\n", trim($list)); + + foreach ($lines as $line) { + // Split each line by whitespace and extract the last field as the file name. + $fields = preg_split('/\s+/', trim($line)); + $filename = end($fields); + + // Skip directories and any other non-file entries. + if ($filename && strpos($filename, '.') !== 0) { + $filenames[] = $filename; + } + } + + $datadir = $CFG->dataroot . '/temp/csvimport/moddatalynx/' . $did . '/'; + if (!is_dir($datadir)) { + // Create the directory if it doesn't exist + if (!make_temp_directory('/csvimport/moddatalynx/' .$did .'/')) { + // Handle directory creation error (e.g., display an error message) + throw new Exception('Error creating sapfiles directory'); + } + } + // Loop through the file names and download each file. + foreach ($filenames as $filename) { + // Initialize a new cURL handle to download the file. + $c = curl_init("sftp://$this->sftpusername:$this->sftppassword@$this->sftpserver:$this->stfpport/$this->sftppath/$filename"); + + // Set cURL options for SFTP file transfer. + $destinationpath = $CFG->dataroot . '/temp/csvimport/moddatalynx/' . $did . '/' . $filename; // Replace with your local download path + $fp = fopen($destinationpath, 'w'); + + curl_setopt($c, CURLOPT_FILE, $fp); + curl_setopt($c, CURLOPT_PROTOCOLS, CURLPROTO_SFTP); + + // Execute the cURL request to download the file. + curl_exec($c); + + // Close the cURL handle and the local file pointer. + curl_close($c); + fclose($fp); + return true; + } + } + + /** + * Check how to get the userid based on rule setting + * + * @param string $userinfo + * + * @return void + */ + // private function get_userid(string $userinfo) { + // switch ($this->mode) { + // case self::USERID: + // $userid = 2; // Replace with the actual user ID + // break; + // case self::USERNAME: + // // $userid = + // break; + // case self::USEREMAIL: + + // break; + // default: + // echo "Invalid mode selected."; + // break; + // } + // } +} diff --git a/rule/ftpsyncfiles/rule_form.php b/rule/ftpsyncfiles/rule_form.php new file mode 100644 index 00000000..42353f49 --- /dev/null +++ b/rule/ftpsyncfiles/rule_form.php @@ -0,0 +1,87 @@ +. + +/** + * + * @package datalynx_rule + * @subpackage ftpsyncfiles + * @copyright 2013 onwards edulabs.org and associated programmers + * @copyright based on the work by 2012 Itamar Tzadok + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +defined('MOODLE_INTERNAL') or die(); + +require_once("$CFG->dirroot/mod/datalynx/rule/rule_form.php"); +require_once($CFG->libdir . '/csvlib.class.php'); + +class datalynx_rule_ftpsyncfiles_form extends datalynx_rule_form { + + public function rule_definition() { + $br = html_writer::empty_tag('br'); + $mform = &$this->_form; + + $mform->addElement('header', 'settingshdr', get_string('sftpsettings', 'datalynxrule_ftpsyncfiles')); + $sftpgrp = array(); + $mform->addElement('text', 'param2', get_string('sftpserver', 'datalynxrule_ftpsyncfiles')); + $mform->addElement('text', 'param3', get_string('sftpport', 'datalynxrule_ftpsyncfiles')); + $mform->addElement('text', 'param4', get_string('sftpusername', 'datalynxrule_ftpsyncfiles')); + $mform->addElement('text', 'param5', get_string('sftppassword', 'datalynxrule_ftpsyncfiles')); + $mform->addElement('text', 'param6', get_string('sftppath', 'datalynxrule_ftpsyncfiles')); + // TODO: ADD SELECT for mode. + $mform->addElement('header', 'settingshdr', get_string('settings')); + + // Delimiter. + $delimiters = csv_import_reader::get_delimiter_list(); + $mform->addElement('select', 'delimiter', get_string('csvdelimiter', 'datalynx'), $delimiters); + $mform->setDefault('delimiter', 'comma'); + + // Enclosure. + $mform->addElement('text', 'enclosure', get_string('csvenclosure', 'datalynx'), array('size' => '10')); + $mform->setType('enclosure', PARAM_NOTAGS); + $mform->setDefault('enclosure', '"'); + + // Encoding. + $choices = core_text::get_encodings(); + $mform->addElement('select', 'encoding', get_string('encoding', 'grades'), $choices); + $mform->setDefault('encoding', 'UTF-8'); + + } + + /** + */ + public function data_preprocessing(&$data) { + // CSV settings. + if (!empty($data->param7)) { + list($data->delimiter, $data->enclosure, $data->encoding) = explode(',', $data->param7); + } + } + + /** + */ + public function set_data($data) { + $this->data_preprocessing($data); + parent::set_data($data); + } + + /** + */ + public function get_data($slashed = true) { + if ($data = parent::get_data($slashed)) { + $data->param7 = "$data->delimiter,$data->enclosure,$data->encoding"; + } + return $data; + } +} diff --git a/rule/ftpsyncfiles/version.php b/rule/ftpsyncfiles/version.php new file mode 100644 index 00000000..5939f754 --- /dev/null +++ b/rule/ftpsyncfiles/version.php @@ -0,0 +1,27 @@ +. +/** + * + * @package datalynxrule + * @subpackage ftpsyncfiles + * @copyright 2023 Thomas Winkler + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +defined('MOODLE_INTERNAL') or die(); + +$plugin->component = 'datalynxrule_ftpsyncfiles'; +$plugin->version = 2023101001; +$plugin->requires = 2014051200; \ No newline at end of file diff --git a/version.php b/version.php index c9aa131a..b7e23b13 100644 --- a/version.php +++ b/version.php @@ -22,7 +22,7 @@ */ defined('MOODLE_INTERNAL') or die(); $plugin->component = 'mod_datalynx'; -$plugin->version = 2023082300; +$plugin->version = 2023101000; $plugin->release = 'v3.0-DataIntelligence'; // Data words like data science, data mining. $plugin->requires = 2022112800; $plugin->maturity = MATURITY_STABLE; diff --git a/view/csv/view_form.php b/view/csv/view_form.php index 698e1408..0a20b296 100644 --- a/view/csv/view_form.php +++ b/view/csv/view_form.php @@ -43,7 +43,7 @@ public function view_definition_after_gps() { $mform->addElement('select', 'param3', get_string('outputtype', 'datalynxview_csv'), $options); // Delimiter. - $delimiters = csv_import_reader::get_delimiter_list(); + $delimiters = \csv_import_reader::get_delimiter_list(); $mform->addElement('select', 'delimiter', get_string('csvdelimiter', 'datalynx'), $delimiters); $mform->setDefault('delimiter', 'comma'); @@ -53,7 +53,7 @@ public function view_definition_after_gps() { $mform->setDefault('enclosure', '"'); // Encoding. - $choices = core_text::get_encodings(); + $choices = \core_text::get_encodings(); $mform->addElement('select', 'encoding', get_string('encoding', 'grades'), $choices); $mform->setDefault('encoding', 'UTF-8');