Skip to content

Commit 4cdb88d

Browse files
committed
New step to remove a file inside the sftp server
1 parent b2a3c15 commit 4cdb88d

File tree

5 files changed

+199
-11
lines changed

5 files changed

+199
-11
lines changed
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
<?php
2+
// This file is part of Moodle - https://moodle.org/
3+
//
4+
// Moodle is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// Moodle is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16+
17+
namespace tool_dataflows\local\step;
18+
19+
use tool_dataflows\helper;
20+
21+
/**
22+
* SFTP connector step type.
23+
*
24+
* Uses phpseclib. See https://phpseclib.com
25+
*
26+
* @package tool_dataflows
27+
* @author Guillaume Barat <[email protected]>
28+
* @copyright 2025, Catalyst IT
29+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
30+
*/
31+
class connector_sftp_delete_file extends connector_sftp {
32+
use sftp_trait{
33+
sftp_trait::form_define_fields as sftp_form_define_fields;
34+
sftp_trait::form_add_custom_inputs as sftp_form_add_custom_inputs;
35+
sftp_trait::validate_for_run as sftp_validate_for_run;
36+
sftp_trait::validate_config as sftp_validate_config;
37+
38+
39+
}
40+
41+
/**
42+
* Return the definition of the fields available in this form.
43+
*
44+
* @param string $behaviour 'delete' or something else.
45+
* @return array
46+
*/
47+
public static function form_define_fields($behaviour = 'delete'): array {
48+
$fields = self::sftp_form_define_fields('delete');
49+
return $fields;
50+
}
51+
52+
/**
53+
* Custom elements for editing the step.
54+
*
55+
* @param \MoodleQuickForm $mform
56+
* @param string $behaviour default to the step.
57+
*/
58+
public function form_add_custom_inputs(\MoodleQuickForm &$mform, $behaviour = 'delete') {
59+
$this->sftp_form_add_custom_inputs($mform, 'delete');
60+
}
61+
62+
/**
63+
* Executes the step
64+
*
65+
* Performs an SFTP call according to config parameters.
66+
*
67+
* @param mixed|null $input
68+
* @return mixed
69+
*/
70+
public function execute($input = null) {
71+
$stepvars = $this->get_variables();
72+
$config = $stepvars->get('config');
73+
74+
// At this point we need to disconnect once we are finished.
75+
try {
76+
// Skip if it is a dry run.
77+
if ($this->is_dry_run() && $this->has_side_effect()) {
78+
return $input;
79+
}
80+
81+
$sftp = $this->init_sftp($config);
82+
83+
$sourceisremote = helper::path_is_scheme($config->source, self::$sftpprefix);
84+
$sourcepath = $this->resolve_path($config->source);
85+
86+
// Deleting from remote.
87+
if ($sourceisremote) {
88+
$this->delete_from_remote($sftp, $sourcepath);
89+
return $input;
90+
}
91+
} catch (\Throwable $e) {
92+
$this->enginestep->log->error($e->getMessage());
93+
if (isset($sftp)) {
94+
$sftp->disconnect();
95+
}
96+
throw new \moodle_exception($e->getMessage(), 'tool_dataflows');
97+
}
98+
99+
return $input;
100+
}
101+
102+
103+
/**
104+
* Perform any extra validation that is required only for runs.
105+
*
106+
* @param string $behaviour
107+
* @return true|array Will return true or an array of errors.
108+
*/
109+
public function validate_for_run($behaviour = 'copy') {
110+
$sftperrors = $this->sftp_validate_for_run('delete');
111+
if ($sftperrors === true) {
112+
$sftperrors = [];
113+
}
114+
return $sftperrors ?: true;
115+
}
116+
117+
/**
118+
* Validate the configuration settings.
119+
*
120+
* @param object $config
121+
* @return true|\lang_string[] true if valid, an array of errors otherwise
122+
*/
123+
public function validate_config($config, $behaviour = 'delete') {
124+
$errors = $this->sftp_validate_config($config, 'delete');
125+
return $errors ?: true;
126+
}
127+
128+
}

classes/local/step/sftp_trait.php

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ public static function form_define_fields($behaviour = 'copy'): array {
8080
'target' => ['type' => PARAM_TEXT, 'required' => true],
8181
]);
8282
}
83+
if ($behaviour === 'delete') {
84+
$fields = array_merge($fields, [
85+
'source' => ['type' => PARAM_TEXT, 'required' => true],
86+
]);
87+
}
8388

8489
return $fields;
8590
}
@@ -131,6 +136,16 @@ public function form_add_custom_inputs(\MoodleQuickForm &$mform, $behaviour = 'c
131136
)
132137
);
133138
}
139+
if ($behaviour === 'delete') {
140+
$mform->addElement('text', 'config_source', get_string('connector_sftp:source', 'tool_dataflows'));
141+
$mform->addElement('static', 'config_source_desc', '', get_string('connector_sftp:source_desc', 'tool_dataflows').
142+
\html_writer::nonempty_tag(
143+
'pre',
144+
get_string('connector_sftp:path_example', 'tool_dataflows').
145+
get_string('path_help_examples', 'tool_dataflows')
146+
)
147+
);
148+
}
134149
}
135150

136151
/**
@@ -190,19 +205,42 @@ public function validate_config($config, $behaviour = 'copy') {
190205
);
191206
}
192207
}
208+
// Delete step checks.
209+
if ($behaviour === 'delete') {
210+
if (empty($config->source)) {
211+
$errors['config_source'] = get_string(
212+
'config_field_missing',
213+
'tool_dataflows',
214+
get_string('connector_sftp:source', 'tool_dataflows'),
215+
true
216+
);
217+
}
218+
}
193219

194220
$hasremote = true;
195221
// Check that at least one file config has an sftp:// scheme.
196-
if (!empty($config->source) && !empty($config->target)) {
197-
// Check if the source or target is an expression, and evaluate it if required.
198-
$sourceremote = helper::path_has_scheme($config->source, self::$sftpprefix);
199-
$targetremote = helper::path_has_scheme($config->target, self::$sftpprefix);
200-
$hasremote = $sourceremote || $targetremote;
201-
}
202-
if (!$hasremote) {
203-
$errormsg = get_string('connector_sftp:missing_remote', 'tool_dataflows', null, true);
204-
$errors['config_source'] = $errors['config_source'] ?? $errormsg;
205-
$errors['config_target'] = $errors['config_target'] ?? $errormsg;
222+
if ($behaviour === 'delete') {
223+
if (!empty($config->source)) {
224+
// Check if the source or target is an expression, and evaluate it if required.
225+
$sourceremote = helper::path_has_scheme($config->source, self::$sftpprefix);
226+
$hasremote = $sourceremote;
227+
}
228+
if (!$hasremote) {
229+
$errormsg = get_string('connector_sftp:missing_remote', 'tool_dataflows', null, true);
230+
$errors['config_source'] = $errors['config_source'] ?? $errormsg;
231+
}
232+
} else {
233+
if (!empty($config->source) && !empty($config->target)) {
234+
// Check if the source or target is an expression, and evaluate it if required.
235+
$sourceremote = helper::path_has_scheme($config->source, self::$sftpprefix);
236+
$targetremote = helper::path_has_scheme($config->target, self::$sftpprefix);
237+
$hasremote = $sourceremote || $targetremote;
238+
}
239+
if (!$hasremote) {
240+
$errormsg = get_string('connector_sftp:missing_remote', 'tool_dataflows', null, true);
241+
$errors['config_source'] = $errors['config_source'] ?? $errormsg;
242+
$errors['config_target'] = $errors['config_target'] ?? $errormsg;
243+
}
206244
}
207245

208246
return empty($errors) ? true : $errors;
@@ -230,6 +268,12 @@ public function validate_for_run($behaviour = 'copy') {
230268
$errors['config_target'] = $error;
231269
}
232270
}
271+
if ($behaviour === 'delete') {
272+
$error = helper::path_validate($config->source);
273+
if ($error !== true) {
274+
$errors['config_source'] = $error;
275+
}
276+
}
233277
if (!empty($config->privkeyfile)) {
234278
$error = helper::path_validate($config->privkeyfile);
235279
if ($error !== true) {
@@ -399,6 +443,19 @@ private function copy_remote_to_remote(SFTP $sftp, string $sourcepath, string $t
399443
$this->upload($sftp, $tmppath, $targetpath);
400444
}
401445

446+
/**
447+
* Delete a file from one remote source
448+
*
449+
* @param SFTP $sftp
450+
* @param string $sourcepath
451+
*/
452+
private function delete_from_remote(SFTP $sftp, string $sourcepath) {
453+
$this->log("Deleting from '$sourcepath'");
454+
if (!$sftp->delete($sourcepath, false)) {
455+
throw new \moodle_exception('connector_sftp:delete_fail', 'tool_dataflows', '', $sftp->getLastSFTPError());
456+
}
457+
}
458+
402459
/**
403460
* Lists files in a directory
404461
*

lang/en/tool_dataflows.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@
158158
$string['step_name_connector_set_variable'] = 'Set variable';
159159
$string['step_name_connector_set_multiple_variables'] = 'Set multiple variables';
160160
$string['step_name_connector_sftp'] = 'SFTP file copy';
161+
$string['step_name_connector_sftp_delete_file'] = 'SFTP file to delete';
161162
$string['step_name_connector_sns_notify'] = 'AWS-SNS Notification';
162163
$string['step_name_connector_wait'] = 'Wait';
163164
$string['step_name_flow_abort'] = 'Abort';
@@ -486,6 +487,7 @@
486487
$string['connector_sftp:hostpubkey'] = 'Host public key';
487488
$string['connector_sftp:hostpubkey_desc'] = 'Public key that must match the one returned by the host. If empty, it will be set on the first connection.';
488489
$string['connector_sftp:copy_fail'] = 'Copy failed: \'{$a}\'.';
490+
$string['connector_sftp:delete_fail'] = 'Delete failed: \'{$a}\'.';
489491
$string['connector_sftp:missing_remote'] = 'At least one of source/target must be remote.';
490492
$string['connector_sftp:pubkeyfile'] = 'Public key file';
491493
$string['connector_sftp:privkeyfile'] = 'Private key file';

lib.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ function tool_dataflows_step_types() {
6969
new step\connector_s3,
7070
new step\connector_set_variable,
7171
new step\connector_sftp,
72+
new step\connector_sftp_delete_file,
7273
new step\connector_sql,
7374
new step\connector_update_user,
7475
new step\connector_sftp_directory_file_list,

version.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
defined('MOODLE_INTERNAL') || die();
2727

28-
$plugin->version = 2024101001;
28+
$plugin->version = 2025033100;
2929
$plugin->release = 2024101001;
3030
$plugin->requires = 2022112800; // Our lowest supported Moodle (3.3.0).
3131
$plugin->supported = [400, 402];

0 commit comments

Comments
 (0)