PluginProbe
Import WP – CSV & XML Import Export for WordPress / 2.7.5
Import WP – CSV & XML Import Export for WordPress v2.7.5
2.15.1 2.15.0 2.14.24 2.14.23 2.7.0 2.7.1 2.7.10 2.7.11 2.7.12 2.7.13 2.7.14 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.8.0 2.8.1 2.8.2 2.8.3 2.9.0 2.9.1 All 144 releases
jc-importer / class / Common / Rest / RestManager.php

RestManager.php in Import WP – CSV & XML Import Export for WordPress 2.7.5, at class/Common/Rest/RestManager.php

1,394 lines 49.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace ImportWP\Common\Rest;
4
5 use ImportWP\Common\Exporter\ExporterManager;
6 use ImportWP\Common\Filesystem\Filesystem;
7 use ImportWP\Common\Http\Http;
8 use ImportWP\Common\Importer\ImporterManager;
9 use ImportWP\Common\Importer\Preview\CSVPreview;
10 use ImportWP\Common\Importer\Preview\XMLPreview;
11 use ImportWP\Common\Importer\State\ImporterState;
12 use ImportWP\Common\Importer\Template\Template;
13 use ImportWP\Common\Importer\Template\TemplateManager;
14 use ImportWP\Common\Migration\Migrations;
15 use ImportWP\Common\Model\ExporterModel;
16 use ImportWP\Common\Model\ImporterModel;
17 use ImportWP\Common\Properties\Properties;
18 use ImportWP\Common\Util\Logger;
19 use ImportWP\Common\Util\Util;
20 use ImportWP\Container;
21 use ImportWP\EventHandler;
22
23 class RestManager extends \WP_REST_Controller
24 {
25 /**
26 * @var Properties
27 */
28 protected $properties;
29
30 /**
31 * @var Http
32 */
33 protected $http;
34
35 /**
36 * @var Filesystem
37 */
38 protected $filesystem;
39
40 /**
41 * @var ImporterManager
42 */
43 protected $importer_manager;
44
45 /**
46 * @var ExporterManager
47 */
48 protected $exporter_manager;
49
50 /**
51 * @var TemplateManager $template_manager
52 */
53 protected $template_manager;
54
55 /**
56 * @var EventHandler
57 */
58 protected $event_handler;
59
60 public function __construct(ImporterManager $importer_manager, ExporterManager $exporter_manager, Properties $properties, Http $http, Filesystem $filesystem, TemplateManager $template_manager, $event_handler)
61 {
62 $this->importer_manager = $importer_manager;
63 $this->exporter_manager = $exporter_manager;
64 $this->properties = $properties;
65 $this->http = $http;
66 $this->filesystem = $filesystem;
67 $this->template_manager = $template_manager;
68 $this->event_handler = $event_handler;
69 }
70
71 public function register()
72 {
73 add_action('rest_api_init', array($this, 'register_routes'));
74 }
75
76 public function register_routes()
77 {
78 $namespace = $this->properties->rest_namespace . '/' . $this->properties->rest_version;
79
80 register_rest_route($namespace, '/system/check', array(
81 array(
82 'methods' => \WP_REST_Server::READABLE,
83 'callback' => array($this, 'check_rest_status'),
84 'permission_callback' => array($this, 'get_permission')
85 )
86 ));
87 register_rest_route($namespace, '/system/migrate', array(
88 array(
89 'methods' => \WP_REST_Server::READABLE,
90 'callback' => array($this, 'migrate'),
91 'permission_callback' => array($this, 'get_permission')
92 )
93 ));
94
95 register_rest_route($namespace, '/importer', array(
96 array(
97 'methods' => \WP_REST_Server::CREATABLE,
98 'callback' => array($this, 'save_importer'),
99 'permission_callback' => array($this, 'get_permission')
100 )
101 ));
102
103 register_rest_route($namespace, '/importers', array(
104 array(
105 'methods' => \WP_REST_Server::READABLE,
106 'callback' => array($this, 'get_importers'),
107 'permission_callback' => array($this, 'get_permission')
108 ),
109 ));
110
111 register_rest_route($namespace, '/status', array(
112 array(
113 'methods' => \WP_REST_Server::READABLE,
114 'callback' => array($this, 'get_status'),
115 'permission_callback' => array($this, 'get_permission')
116 ),
117 ));
118
119 register_rest_route($namespace, '/importer/(?P<id>\d+)', array(
120 array(
121 'methods' => \WP_REST_Server::READABLE,
122 'callback' => array($this, 'get_importer'),
123 'permission_callback' => array($this, 'get_permission')
124 ),
125 array(
126 'methods' => \WP_REST_Server::EDITABLE,
127 'callback' => array($this, 'save_importer'),
128 'permission_callback' => array($this, 'get_permission')
129 ),
130 array(
131 'methods' => \WP_REST_Server::DELETABLE,
132 'callback' => array($this, 'delete_importer'),
133 'permission_callback' => array($this, 'get_permission')
134 ),
135 ));
136
137 register_rest_route($namespace, '/importer/(?P<id>\d+)/upload', array(
138 array(
139 'methods' => \WP_REST_Server::EDITABLE,
140 'callback' => array($this, 'attach_file'),
141 'permission_callback' => array($this, 'get_permission')
142 )
143 ));
144
145 register_rest_route($namespace, '/importer/(?P<id>\d+)/file-process', array(
146 array(
147 'methods' => \WP_REST_Server::CREATABLE,
148 'callback' => array($this, 'get_file_process'),
149 'permission_callback' => array($this, 'get_permission')
150 )
151 ));
152
153 register_rest_route($namespace, '/importer/(?P<id>\d+)/file-preview', array(
154 array(
155 'methods' => \WP_REST_Server::CREATABLE,
156 'callback' => array($this, 'get_file_preview'),
157 'permission_callback' => array($this, 'get_permission')
158 )
159 ));
160
161 register_rest_route($namespace, '/importer/(?P<id>\d+)/preview', array(
162 array(
163 'methods' => \WP_REST_Server::CREATABLE,
164 'callback' => array($this, 'get_preview'),
165 'permission_callback' => array($this, 'get_permission')
166 )
167 ));
168
169 register_rest_route($namespace, '/importer/(?P<id>\d+)/init', array(
170 array(
171 'methods' => \WP_REST_Server::READABLE,
172 'callback' => array($this, 'init_import'),
173 'permission_callback' => array($this, 'get_permission')
174 )
175 ));
176
177 register_rest_route($namespace, '/importer/(?P<id>\d+)/run', array(
178 array(
179 'methods' => \WP_REST_Server::CREATABLE,
180 'callback' => array($this, 'run_import'),
181 'permission_callback' => array($this, 'get_permission')
182 )
183 ));
184
185 register_rest_route($namespace, '/importer/(?P<id>\d+)/pause', array(
186 array(
187 'methods' => \WP_REST_Server::CREATABLE,
188 'callback' => array($this, 'pause_import'),
189 'permission_callback' => array($this, 'get_permission')
190 )
191 ));
192
193 register_rest_route($namespace, '/importer/(?P<id>\d+)/stop', array(
194 array(
195 'methods' => \WP_REST_Server::CREATABLE,
196 'callback' => array($this, 'stop_import'),
197 'permission_callback' => array($this, 'get_permission')
198 )
199 ));
200
201 register_rest_route($namespace, '/importer/(?P<id>\d+)/field', array(
202 array(
203 'methods' => \WP_REST_Server::CREATABLE,
204 'callback' => array($this, 'get_template_field_options'),
205 'permission_callback' => array($this, 'get_permission')
206 )
207 ));
208
209 register_rest_route($namespace, '/importer/(?P<id>\d+)/logs/(?P<session>\S+)', array(
210 array(
211 'methods' => \WP_REST_Server::READABLE,
212 'callback' => array($this, 'get_log'),
213 'permission_callback' => array($this, 'get_permission')
214 )
215 ));
216
217 register_rest_route($namespace, '/importer/(?P<id>\d+)/logs', array(
218 array(
219 'methods' => \WP_REST_Server::READABLE,
220 'callback' => array($this, 'get_logs'),
221 'permission_callback' => array($this, 'get_permission')
222 )
223 ));
224
225 register_rest_route($namespace, '/settings', array(
226 array(
227 'methods' => \WP_REST_Server::CREATABLE,
228 'callback' => array($this, 'save_settings'),
229 'permission_callback' => array($this, 'get_permission')
230 ),
231 array(
232 'methods' => \WP_REST_Server::READABLE,
233 'callback' => array($this, 'get_settings'),
234 'permission_callback' => array($this, 'get_permission')
235 ),
236 ));
237
238 register_rest_route($namespace, '/import-export', array(
239 array(
240 'methods' => \WP_REST_Server::CREATABLE,
241 'callback' => array($this, 'import_exporters'),
242 'permission_callback' => array($this, 'get_permission')
243 ),
244 array(
245 'methods' => \WP_REST_Server::READABLE,
246 'callback' => array($this, 'export_importers'),
247 'permission_callback' => array($this, 'get_permission')
248 ),
249 ));
250
251 register_rest_route($namespace, '/importer/(?P<id>\d+)/debug_log', array(
252 array(
253 'methods' => \WP_REST_Server::READABLE,
254 'callback' => array($this, 'get_debug_log'),
255 'permission_callback' => array($this, 'get_permission')
256 )
257 ));
258
259 register_rest_route($namespace, '/importer/(?P<id>\d+)/template', array(
260 array(
261 'methods' => \WP_REST_Server::READABLE,
262 'callback' => array($this, 'get_template'),
263 'permission_callback' => array($this, 'get_permission')
264 )
265 ));
266
267 // Exporter
268
269 register_rest_route($namespace, '/exporter', array(
270 array(
271 'methods' => \WP_REST_Server::CREATABLE,
272 'callback' => array($this, 'save_exporter'),
273 'permission_callback' => array($this, 'get_permission')
274 )
275 ));
276
277 register_rest_route($namespace, '/exporters', array(
278 array(
279 'methods' => \WP_REST_Server::READABLE,
280 'callback' => array($this, 'get_exporters'),
281 'permission_callback' => array($this, 'get_permission')
282 ),
283 ));
284
285 register_rest_route($namespace, '/exporter/(?P<id>\d+)', array(
286 array(
287 'methods' => \WP_REST_Server::READABLE,
288 'callback' => array($this, 'get_exporter'),
289 'permission_callback' => array($this, 'get_permission')
290 ),
291 array(
292 'methods' => \WP_REST_Server::EDITABLE,
293 'callback' => array($this, 'save_exporter'),
294 'permission_callback' => array($this, 'get_permission')
295 ),
296 array(
297 'methods' => \WP_REST_Server::DELETABLE,
298 'callback' => array($this, 'delete_exporter'),
299 'permission_callback' => array($this, 'get_permission')
300 ),
301 ));
302
303 register_rest_route($namespace, '/exporter/(?P<id>\d+)/run', array(
304 array(
305 'methods' => \WP_REST_Server::CREATABLE,
306 'callback' => array($this, 'run_exporter'),
307 'permission_callback' => array($this, 'get_permission')
308 ),
309 ));
310
311 register_rest_route($namespace, '/exporter/status', array(
312 array(
313 'methods' => \WP_REST_Server::READABLE,
314 'callback' => array($this, 'get_exporter_status'),
315 'permission_callback' => array($this, 'get_permission')
316 ),
317 ));
318 }
319
320 public function get_permission()
321 {
322
323 if (!current_user_can('manage_options')) {
324 return new \WP_Error('rest_forbidden', esc_html__('You do not have permissions.', $this->properties->plugin_domain), array('status' => 401));
325 }
326
327 return true;
328 }
329
330 public function sanitize($data, $name = null, $path = [])
331 {
332 $path[] = $name;
333
334 if (is_array($data)) {
335 foreach ($data as $k => $v) {
336 $data[$k] = $this->sanitize($v, $k, $path);
337 }
338
339 return $data;
340 }
341
342 $full_path = implode('.', array_filter($path));
343 if (!is_null($full_path)) {
344
345 if (preg_match('/^map\.\S+/', $full_path) !== false) {
346 return $data;
347 }
348 }
349
350 if (!is_null($name)) {
351 switch ($name) {
352 case 'id':
353 return intval($data);
354 }
355 }
356
357 return sanitize_text_field($data);
358 }
359
360 public function check_rest_status(\WP_REST_Request $request)
361 {
362 $result = [];
363 // find required php ext: https://github.com/llaville/php-compat-info
364
365 $tmp_writable = wp_is_writable($this->filesystem->get_temp_directory());
366
367
368 $result = [
369 'tmp_writable' => [
370 'status' => $tmp_writable ? 'yes' : 'no',
371 'message' => $tmp_writable ? '' : 'WordPress is unable to write to directory: ' . $this->filesystem->get_temp_directory() . ', make sure this directory is writable.',
372 ],
373 'rest_enabled' => [
374 'status' => 'yes',
375 'message' => '',
376 ],
377 'ext_simplexml' => [
378 'status' => extension_loaded('SimpleXML') ? 'yes' : 'no',
379 'message' => '',
380 ],
381 'ext_mbstring' => [
382 'status' => extension_loaded('mbstring') ? 'yes' : 'no',
383 'message' => '',
384 ],
385 'ext_xmlreader' => [
386 'status' => extension_loaded('xmlreader') ? 'yes' : 'no',
387 'message' => '',
388 ],
389 'php_version' => [
390 'status' => version_compare(phpversion(), '5.5.0') ? 'yes' : 'no',
391 'message' => '',
392 ],
393 ];
394 return $this->http->end_rest_success($result);
395 }
396
397 public function migrate(\WP_REST_Request $request)
398 {
399 $migration = new Migrations();
400 $result = $migration->migrate();
401
402 return $this->http->end_rest_success("Migration Complete.");
403 }
404
405 public function get_importers(\WP_REST_Request $request)
406 {
407 $importers = $this->importer_manager->get_importers();
408 $result = [];
409
410 foreach ($importers as $importer) {
411 $result[] = $importer->data();
412 }
413
414 return $this->http->end_rest_success($result);
415 }
416
417 public function get_importer(\WP_REST_Request $request)
418 {
419 $id = intval($request->get_param('id'));
420 $importer_data = $this->importer_manager->get_importer($id);
421 $response = $importer_data->data('public');
422 return $this->http->end_rest_success($response);
423 }
424
425 public function save_importer(\WP_REST_Request $request)
426 {
427 $post_data = $request->get_body_params();
428 $id = isset($post_data['id']) ? intval($post_data['id']) : null;
429
430 $temp_post_data = [
431 'create' => [],
432 'update' => []
433 ];
434
435 if (isset($post_data['permissions'])) {
436 // TODO: update sanitize method to keep track of hierarchy
437 $temp_post_data['create'] = explode("\n", $post_data['permissions']['create']['fields']);
438 $temp_post_data['update'] = explode("\n", $post_data['permissions']['update']['fields']);
439 }
440
441 $post_data = $this->sanitize($post_data);
442
443 if (isset($post_data['permissions'])) {
444 // TODO: Method to bypass sanitization not needed once sanitize method has been upgraded
445 foreach (['create', 'update'] as $permission_method) {
446 $permission_fields = $temp_post_data[$permission_method];
447 if (!empty($permission_fields)) {
448 $post_data['permissions'][$permission_method]['fields'] = array_values(array_filter(array_map([$this, 'sanitize'], $permission_fields, array_fill(0, count($permission_fields), 'permission_' . $permission_method . '_fields'))));
449 } else {
450 $post_data['permissions'][$permission_method]['fields'] = [];
451 }
452 }
453 }
454
455
456
457 $importer = new ImporterModel($id, $this->importer_manager->is_debug());
458
459 if (isset($post_data['datasource'])) {
460 $importer->setDatasource($post_data['datasource']);
461 }
462
463 if (isset($post_data['remote_url'])) {
464 $importer->setDatasourceSetting('remote_url', $post_data['remote_url']);
465 }
466
467 if (isset($post_data['local_url'])) {
468 $importer->setDatasourceSetting('local_url', $post_data['local_url']);
469 }
470
471 if (isset($post_data['existing_id'])) {
472 $importer->setFileId(intval($post_data['existing_id']));
473 }
474
475 if (isset($post_data['template'], $post_data['template_type'])) {
476 $importer->setTemplate($post_data['template'], $post_data['template_type']);
477
478 // Get default template options
479 $template_class = $this->importer_manager->get_template($post_data['template']);
480
481 /**
482 * @var Template $template
483 */
484 $template = $this->template_manager->load_template($template_class);
485 $template_options = $template->get_default_template_options();
486
487 if (isset($post_data['template_options'])) {
488 $template_options = array_merge($template_options, $post_data['template_options']);
489 }
490
491 foreach ($template_options as $key => $val) {
492 $importer->setSetting($key, $val);
493 }
494 }
495
496 if (isset($post_data['name'])) {
497 $importer->setName($post_data['name']);
498 }
499
500 if (isset($post_data['setting_start_row'])) {
501 $importer->setStartRow($post_data['setting_start_row']);
502 }
503
504 if (isset($post_data['setting_max_row'])) {
505 $importer->setMaxRow($post_data['setting_max_row']);
506 }
507
508 // save settings
509 foreach ($post_data as $key => $value) {
510 if (1 === preg_match('/^setting_(?<key>.*)/', $key, $matches)) {
511
512 $value = $this->sanitize_setting($value);
513 $importer->setSetting($matches['key'], $value);
514 }
515 }
516
517 $parser = $importer->getParser();
518
519 if (isset($post_data['file_settings_encoding'])) {
520 $importer->setFileSetting('file_encoding', $post_data['file_settings_encoding']);
521 }
522
523 if ($parser === 'csv') {
524 if (isset($post_data['file_settings_delimiter'])) {
525 $importer->setFileSetting('delimiter', $post_data['file_settings_delimiter']);
526 }
527 if (isset($post_data['file_settings_enclosure'])) {
528 $importer->setFileSetting('enclosure', $post_data['file_settings_enclosure']);
529 }
530 if (isset($post_data['file_settings_show_headings'])) {
531 $importer->setFileSetting('show_headings', $post_data['file_settings_show_headings'] === 'true' || $post_data['file_settings_show_headings'] === true ? true : false);
532 }
533 } elseif ($parser === 'xml') {
534 if (isset($post_data['file_settings_base_path'])) {
535 $importer->setFileSetting('base_path', $post_data['file_settings_base_path']);
536 }
537 }
538
539 if (isset($post_data['file_settings_setup'])) {
540 $importer->setFileSetting('setup', $post_data['file_settings_setup'] === 'true' ? true : false);
541 }
542
543 if (isset($post_data['map']) && is_array($post_data['map'])) {
544 foreach ($post_data['map'] as $key => $value) {
545
546 if (1 === preg_match('/\._index$/', $key)) {
547 $value = intval($value);
548 }
549
550 $importer->setMap($key, $value);
551 }
552 }
553
554 if (isset($post_data['enabled']) && is_array($post_data['enabled'])) {
555 foreach ($post_data['enabled'] as $key => $value) {
556 if ($value === 'true') {
557 $importer->setEnabled($key);
558 } else {
559 $importer->setEnabled($key, false);
560 }
561 }
562 }
563
564 if (isset($post_data['permissions']) && is_array($post_data['permissions'])) {
565
566 // create
567 if (isset($post_data['permissions']['create'])) {
568 $create = $post_data['permissions']['create'];
569 $importer->setPermission('create', [
570 'enabled' => isset($create['enabled']) && $create['enabled'] === 'true' ? true : false,
571 'type' => isset($create['type']) && in_array($create['type'], ['include', 'exclude'], true) ? $create['type'] : null,
572 'fields' => isset($create['fields']) ? $create['fields'] : [],
573 ]);
574 }
575
576 // update
577 if (isset($post_data['permissions']['update'])) {
578 $update = $post_data['permissions']['update'];
579 $importer->setPermission('update', [
580 'enabled' => isset($update['enabled']) && $update['enabled'] === 'true' ? true : false,
581 'type' => isset($update['type']) && in_array($update['type'], ['include', 'exclude'], true) ? $update['type'] : null,
582 'fields' => isset($update['fields']) ? $update['fields'] : [],
583 ]);
584 }
585
586 // remove
587 if (isset($post_data['permissions']['remove'])) {
588 $importer->setPermission('remove', [
589 'enabled' => $post_data['permissions']['remove']['enabled'] === 'true',
590 'trash' => $post_data['permissions']['remove']['trash'] === 'true',
591 ]);
592 }
593 }
594
595 $result = $importer->save();
596 if (is_wp_error($result)) {
597 return $this->http->end_rest_error($result->get_error_message());
598 }
599 return $this->http->end_rest_success($importer->data());
600 }
601
602 private function sanitize_setting($value)
603 {
604 if (is_array($value)) {
605 foreach ($value as &$tmp) {
606 $tmp = $this->sanitize_setting($tmp);
607 }
608 return $value;
609 } else {
610 if (in_array($value, ['true', 'false'], true)) {
611 if ($value === 'true') {
612 $value = true;
613 } else {
614 $value = false;
615 }
616 }
617 }
618
619 return $value;
620 }
621
622 public function get_status(\WP_REST_Request $request)
623 {
624 $this->http->set_stream_headers();
625
626 Logger::setRequestType('rest::get_status');
627
628 $importer_ids = $request->get_param('ids');
629
630 $result = [];
631
632 $query_data = array(
633 'post_type' => IWP_POST_TYPE,
634 'posts_per_page' => -1,
635 'fields' => 'ids'
636 );
637 if (!empty($importer_ids)) {
638 $query_data['post__in'] = $importer_ids;
639 }
640
641 $query = new \WP_Query($query_data);
642
643 foreach ($query->posts as $importer_id) {
644
645 Logger::write('-start', $importer_id);
646
647 $importer_model = $this->importer_manager->get_importer($importer_id);
648
649 $output = ImporterState::get_state($importer_id);
650 if (!$output) {
651 // TODO: What should happen if there is no state.
652 $output['version'] = 2;
653 }
654 $output['message'] = $this->generate_status_message($output);
655 $output['importer'] = $importer_id;
656
657 $result[] = $this->event_handler->run('iwp/importer/status/output', [$output, $importer_model]);
658
659 Logger::write('-end', $importer_id);
660 }
661
662 Logger::clearRequestType();
663
664 echo json_encode($result) . "\n";
665 die();
666 }
667
668 /**
669 * @param array $data
670 * @return string
671 */
672 protected function generate_status_message($data)
673 {
674 $output = '';
675
676 if (!$data || !isset($data['status']) || is_null($data['status']) || empty($data['status'])) {
677 return '';
678 }
679
680 if (isset($data['status'])) {
681 switch ($data['status']) {
682 case 'cancelled':
683 $output .= 'Import cancelled';
684 break;
685 case 'complete':
686 $output .= 'Import complete';
687 break;
688 case 'error':
689 $output = $data['message'];
690 return $output;
691 break;
692 }
693 }
694
695 if (isset($data['status']) && $data['status'] === 'running' && isset($data['section'])) {
696 switch ($data['section']) {
697 case 'import':
698 case 'delete':
699 $output = $data['section'] === 'import' ? 'Importing: ' : 'Deleting: ';
700 $output .= $data['progress'][$data['section']]['current_row'] . ' / ' . ($data['progress'][$data['section']]['end'] - $data['progress'][$data['section']]['start']);
701
702 break;
703 }
704 }
705
706 if (isset($data['stats'])) {
707 if ($data['stats']['inserts'] > 0) {
708 $output .= sprintf(', Inserts: %d', $data['stats']['inserts']);
709 }
710 if ($data['stats']['updates'] > 0) {
711 $output .= sprintf(', Updates: %d', $data['stats']['updates']);
712 }
713 if ($data['stats']['deletes'] > 0) {
714 $output .= sprintf(', Deletes: %d', $data['stats']['deletes']);
715 }
716 if ($data['stats']['skips'] > 0) {
717 $output .= sprintf(', Skips: %d', $data['stats']['skips']);
718 }
719 if ($data['stats']['errors'] > 0) {
720 $output .= sprintf(', Errors: %d', $data['stats']['errors']);
721 }
722 }
723
724 if (isset($data['timestamp'], $data['updated'])) {
725 /**
726 * @var Util $util
727 */
728 $util = Container::getInstance()->get('util');
729 $output .= ', Run Time: ' . $util->format_time($data['updated'] - $data['timestamp']);
730 } elseif (isset($data['duration'])) {
731 /**
732 * @var Util $util
733 */
734 $util = Container::getInstance()->get('util');
735 $output .= ', Run Time: ' . $util->format_time($data['duration']);
736 }
737
738 return $output;
739 }
740
741 public function delete_importer(\WP_REST_Request $request)
742 {
743 $id = intval($request->get_param('id'));
744 $this->importer_manager->delete_importer($id);
745 return $this->http->end_rest_success(true);
746 }
747
748 public function attach_file(\WP_REST_Request $request)
749 {
750 $id = intval($request->get_param('id'));
751 $post_data = $this->sanitize($request->get_body_params());
752
753 $action = $post_data['action'];
754
755 $importer = $this->importer_manager->get_importer($id);
756
757 // TODO: Remove duplicate code, found in cron manager
758
759 switch ($action) {
760 case 'file_upload':
761 $attachment_id = $this->importer_manager->upload_file($importer, $_FILES['file']);
762 break;
763 case 'file_remote':
764 $raw_source = $post_data['remote_url'];
765 $source = apply_filters('iwp/importer/datasource', $raw_source, $raw_source, $importer);
766 $source = apply_filters('iwp/importer/datasource/remote', $source, $raw_source, $importer);
767
768 $filetype = $importer->getParser();
769 if (is_null($filetype)) {
770 $filetype = $post_data['filetype'];
771 }
772
773 $attachment_id = $this->importer_manager->remote_file($importer, $source, $filetype, null, $importer->getId() . '-');
774 break;
775 case 'file_local':
776 $raw_source = $post_data['local_url'];
777 $source = apply_filters('iwp/importer/datasource', $raw_source, $raw_source, $importer);
778 $source = apply_filters('iwp/importer/datasource/local', $source, $raw_source, $importer);
779 $attachment_id = $this->importer_manager->local_file($importer, $source);
780 break;
781 default:
782 $attachment_id = new \WP_Error('IWP_RM_1', 'Invalid form action');
783 break;
784 }
785
786 if (is_wp_error($attachment_id)) {
787 return $this->http->end_rest_error($attachment_id->get_error_message());
788 }
789
790 return $this->http->end_rest_success($importer->data());
791 }
792
793 public function get_file_process(\WP_REST_Request $request)
794 {
795 try {
796 $id = intval($request->get_param('id'));
797 $post_data = $this->sanitize($request->get_body_params());
798
799 $importer = $this->importer_manager->get_importer($id);
800 if (!$importer) {
801 return $this->http->end_rest_error('Invalid importer');
802 }
803
804 $this->importer_manager->clear_config_files($id, true);
805 $parser = $importer->getParser();
806
807 if ('xml' === $parser) {
808
809 $nodes = $this->importer_manager->process_xml_file($id, true);
810 $importer->setFileSetting('nodes', $nodes);
811 } elseif ('csv' === $parser) {
812
813 $delimiter = isset($post_data['delimiter']) ? $post_data['delimiter'] : null;
814 if (is_null($delimiter)) {
815 $delimiter = ',';
816 }
817
818 $enclosure = isset($post_data['enclosure']) ? $post_data['enclosure'] : null;
819 if (is_null($enclosure)) {
820 $enclosure = '"';
821 }
822
823 $count = $this->importer_manager->process_csv_file($id, $delimiter, $enclosure, true);
824
825 // Need fresh importer, due to process_csv_file importer modifications might get overwritten.
826 $importer = $this->importer_manager->get_importer($id);
827 $importer->setFileSetting('count', $count);
828 } else {
829
830 do_action('iwp/file-process/' . $parser, $importer, $post_data);
831 }
832
833 $importer->setFileSetting('processed', true);
834 $importer->save();
835
836 return $this->http->end_rest_success($importer->data());
837 } catch (\Exception $e) {
838 return $this->http->end_rest_error($e->getMessage());
839 }
840 }
841
842 public function get_file_preview(\WP_REST_Request $request)
843 {
844 try {
845 $id = intval($request->get_param('id'));
846 $post_data = $this->sanitize($request->get_body_params());
847 $importer = $this->importer_manager->get_importer($id);
848
849 $import_file_exists = $this->filesystem->file_exists($importer->getFile());
850 if (is_wp_error($import_file_exists)) {
851 throw new \Exception("Unable to load preview, " . $import_file_exists->get_error_message());
852 }
853
854 $record_index = isset($post_data['record']) ? $post_data['record'] : null;
855 if (is_null($record_index)) {
856 $record_index = 0;
857 }
858
859 // Temp set file_encoding
860 if (isset($post_data['file_encoding'])) {
861 $importer->setFileSetting('file_encoding', $post_data['file_encoding']);
862 }
863
864 if ($importer->getParser() === 'xml') {
865
866 $config = $this->importer_manager->get_config($importer, true);
867 $file = $this->importer_manager->get_xml_file($importer, $config);
868
869 $base_path = $post_data['base_path'];
870 if (!is_null($base_path)) {
871 $file->setRecordPath($base_path);
872 }
873
874 $preview = new XMLPreview($file, $base_path);
875 $result = $preview->data();
876 if (is_wp_error($result)) {
877 return $this->http->end_rest_error($result);
878 }
879
880 return $this->http->end_rest_success($result[0]);
881 } elseif ($importer->getParser() === 'csv') {
882
883 $config = $this->importer_manager->get_config($importer, true);
884 $file = $this->importer_manager->get_csv_file($importer, $config);
885
886 $delimiter = $post_data['delimiter'];
887 if (!is_null($delimiter)) {
888 $file->setDelimiter($delimiter);
889 }
890
891 $enclosure = $post_data['enclosure'];
892 if (!is_null($enclosure)) {
893 $file->setEnclosure($enclosure);
894 }
895
896 // parse bool param from string
897 $show_headings = $post_data['show_headings'];
898 if (in_array($show_headings, ['true', 'false'])) {
899 $show_headings = $show_headings === 'true' ? true : false;
900 }
901
902 if (is_null($show_headings)) {
903 $show_headings = $importer->getFileSetting('show_headings');
904 }
905
906 $preview = new CSVPreview($file);
907 $result = $preview->data($record_index, $show_headings);
908 if (is_wp_error($result)) {
909 return $this->http->end_rest_error($result);
910 }
911
912 return $this->http->end_rest_success($result);
913 } else {
914
915 $result = apply_filters('iwp/file-preview/' . $importer->getParser(), null, $importer);
916 if (is_wp_error($result)) {
917 return $this->http->end_rest_error($result);
918 }
919
920 return $this->http->end_rest_success($result);
921 }
922 } catch (\Exception $error) {
923 return $this->http->end_rest_error($error->getMessage());
924 }
925 }
926
927 public function get_preview(\WP_REST_Request $request)
928 {
929 // if no fields have been posted send all previews
930 try {
931 $id = intval($request->get_param('id'));
932 $importer = $this->importer_manager->get_importer($id);
933 $import_file_exists = $this->filesystem->file_exists($importer->getFile());
934 if (is_wp_error($import_file_exists)) {
935 throw new \Exception("Unable to load preview, " . $import_file_exists->get_error_message());
936 }
937
938 $parser = $importer->getParser();
939
940 $fields = $this->sanitize($request->get_body_params());
941 if (is_null($fields) || empty($fields)) {
942 $fields = $importer->getMap();
943 }
944
945 if ('xml' === $parser) {
946 $result = $this->importer_manager->preview_xml_file($importer, $fields);
947 } elseif ('csv' === $parser) {
948 $row = 0;
949 if ($importer->getFileSetting('show_headings') === true) {
950 $row = 1;
951 }
952 $result = $this->importer_manager->preview_csv_file($importer, $fields, $row);
953 } else {
954
955 $result = apply_filters('iwp/record-preview/' . $parser, [], $importer, $fields);
956 if (is_wp_error($result)) {
957 return $this->http->end_rest_error($result);
958 }
959
960 return $this->http->end_rest_success($result);
961 }
962
963 return $this->http->end_rest_success($result);
964 } catch (\Exception $error) {
965 return $this->http->end_rest_error($error->getMessage());
966 }
967 }
968
969 /**
970 * Trigger a new import.
971 *
972 * @param \WP_REST_Request $request
973 * @return array
974 */
975 public function init_import(\WP_REST_Request $request)
976 {
977 $id = intval($request->get_param('id'));
978
979 Logger::setRequestType('rest::init_import');
980
981 Logger::write('init_import -start', $id);
982
983 $importer_data = $this->importer_manager->get_importer($id);
984
985 // clear existing
986 ImporterState::clear_options($importer_data->getId());
987
988 // This is used for storing version on imported records
989 $session_id = md5($importer_data->getId() . time());
990 update_post_meta($importer_data->getId(), '_iwp_session', $session_id);
991
992 Logger::clearRequestType();
993
994 return $this->http->end_rest_success([
995 'session' => $session_id
996 ]);
997 }
998
999 public function run_import(\WP_REST_Request $request)
1000 {
1001 $this->http->set_stream_headers();
1002
1003 Logger::setRequestType('rest::run_import');
1004
1005 $session = $request->get_param('session');
1006 $user = uniqid('iwp', true);
1007 $id = intval($request->get_param('id'));
1008 Logger::write('run_import -session=' . $session, $id);
1009
1010 $importer_data = $this->importer_manager->get_importer($id);
1011 Logger::write('run_import -import=start', $id);
1012
1013 $state = $this->importer_manager->import($importer_data->getId(), $user, $session);
1014 $state['message'] = $this->generate_status_message($state);
1015
1016 Logger::clearRequestType();
1017
1018 return $this->http->end_rest_success($state);
1019 }
1020
1021 public function pause_import(\WP_REST_Request $request)
1022 {
1023 $id = intval($request->get_param('id'));
1024 $paused = $this->sanitize($request->get_param('paused'), 'paused');
1025
1026 $importer_data = $this->importer_manager->get_importer($id);
1027 $user = uniqid('iwp', true);
1028
1029 $state = ImporterState::wait_for_lock($importer_data->getId(), $user, function () use ($importer_data, $paused) {
1030 $state = ImporterState::get_state($importer_data->getId());
1031
1032
1033 if ($paused === 'no') {
1034 $state['status'] = 'running';
1035 } else {
1036 $state['status'] = 'paused';
1037 }
1038
1039 ImporterState::set_state($importer_data->getId(), $state);
1040 return $state;
1041 });
1042
1043 return $this->http->end_rest_success($state);
1044 }
1045
1046 public function stop_import(\WP_REST_Request $request)
1047 {
1048 $id = intval($request->get_param('id'));
1049
1050 $importer_data = $this->importer_manager->get_importer($id);
1051
1052 $user = uniqid('iwp');
1053
1054 $state = ImporterState::wait_for_lock($importer_data->getId(), $user, function () use ($importer_data) {
1055 $state = ImporterState::get_state($importer_data->getId());
1056 $state['status'] = 'cancelled';
1057 ImporterState::set_state($importer_data->getId(), $state);
1058 return $state;
1059 });
1060
1061 return $this->http->end_rest_success($state);
1062 }
1063
1064 /**
1065 * Get field options for current template
1066 *
1067 * @param \WP_REST_Request $request
1068 * @return void
1069 */
1070 public function get_template_field_options(\WP_REST_Request $request)
1071 {
1072 $id = intval($request->get_param('id'));
1073 $field = $this->sanitize($request->get_param('field'), 'field');
1074
1075 $importer_data = $this->importer_manager->get_importer($id);
1076 $template = $this->importer_manager->get_importer_template($id);
1077
1078 return $this->http->end_rest_success($template->get_field_options($field, $importer_data));
1079 }
1080
1081 public function get_logs(\WP_REST_Request $request)
1082 {
1083 $id = intval($request->get_param('id'));
1084 $importer_data = $this->importer_manager->get_importer($id);
1085 $logs = $this->importer_manager->get_importer_logs($importer_data);
1086 return $this->http->end_rest_success(array_reverse($logs));
1087 }
1088
1089 public function get_log(\WP_REST_Request $request)
1090 {
1091 $id = intval($request->get_param('id'));
1092 $session = $this->sanitize($request->get_param('session'), 'session');
1093 $page = intval($request->get_param('page'));
1094 if ($page < 1) {
1095 $page = 1;
1096 }
1097 $importer_data = $this->importer_manager->get_importer($id);
1098 $log = $this->importer_manager->get_importer_log($importer_data, $session, $page, 500);
1099 $status = $this->importer_manager->get_importer_status_report($importer_data, $session);
1100 return $this->http->end_rest_success(['logs' => $log, 'status' => $status]);
1101 }
1102
1103 public function get_debug_log(\WP_REST_Request $request)
1104 {
1105 $id = intval($request->get_param('id'));
1106 $page = intval($request->get_param('page'));
1107 if ($page < 1) {
1108 $page = 1;
1109 }
1110 $importer_data = $this->importer_manager->get_importer($id);
1111 $log = $this->importer_manager->get_importer_debug_log($importer_data, $page, 100);
1112
1113 $download = Logger::getLogFile($importer_data->getId(), true);
1114 return $this->http->end_rest_success(['log' => $log, 'download' => $download]);
1115 }
1116
1117 public function save_settings(\WP_REST_Request $request)
1118 {
1119 $post_data = $request->get_body_params();
1120 $post_data = $this->sanitize($post_data);
1121
1122 $defaults = $this->properties->_default_settings();
1123
1124 $output = [];
1125
1126 foreach ($defaults as $setting => $default) {
1127 if (isset($post_data[$setting])) {
1128 if ('bool' === $default['type']) {
1129 // Handle Boolean
1130 if (is_bool($post_data[$setting])) {
1131 $output[$setting] = $post_data[$setting];
1132 } elseif (in_array($post_data[$setting], ['true', 'false'])) {
1133 $output[$setting] = $post_data[$setting] === 'true' ? true : false;
1134 } else {
1135 $output[$setting] = boolval($post_data[$setting]);
1136 }
1137 } elseif ('number' === $default['type']) {
1138 $output[$setting] = intval($post_data[$setting]);
1139 } else {
1140 $output[$setting] = $post_data[$setting];
1141 }
1142 } else {
1143 $output[$setting] = $default['value'];
1144 }
1145 }
1146
1147 update_site_option('iwp_settings', $output);
1148
1149 return $this->http->end_rest_success($this->properties->get_settings());
1150 }
1151
1152 public function get_settings(\WP_REST_Request $request = null)
1153 {
1154 $output = $this->properties->get_settings();
1155 return $this->http->end_rest_success($output);
1156 }
1157
1158 public function get_template(\WP_REST_Request $request = null)
1159 {
1160 $importer_id = $request->get_param('id');
1161 $importer_model = $this->importer_manager->get_importer($importer_id);
1162 $importer_template = $importer_model->getTemplate();
1163
1164 $templates = $this->importer_manager->get_templates();
1165
1166 if (!isset($templates[$importer_template])) {
1167 return $this->http->end_rest_error("Invalid template \"" . $importer_template . "\"");
1168 }
1169
1170 $template_id = $templates[$importer_template];
1171 $template_class = $this->template_manager->load_template($template_id);
1172
1173 $output = [
1174 'id' => $template_id,
1175 'label' => $template_class->get_name(),
1176 'map' => $template_class->get_fields($importer_model),
1177 'settings' => $template_class->register_settings(),
1178 'options' => $template_class->register_options(),
1179 ];
1180 return $this->http->end_rest_success($output);
1181 }
1182
1183 public function export_importers(\WP_REST_Request $request = null)
1184 {
1185 $importer_ids = $request->get_param('ids');
1186
1187 $sql_ids = array_map(function ($v) {
1188 return "'" . esc_sql($v) . "'";
1189 }, $importer_ids);
1190 $sql_ids = implode(',', $sql_ids);
1191
1192 $output = [];
1193
1194 /**
1195 * @var \WPDB $wpdb
1196 */
1197 global $wpdb;
1198 $results = $wpdb->get_results("SELECT post_title, post_content from {$wpdb->posts} WHERE post_type='" . IWP_POST_TYPE . "' AND ID IN (" . $sql_ids . ")", ARRAY_A);
1199 foreach ($results as $result) {
1200
1201 $data = unserialize($result['post_content']);
1202
1203 unset($data['file']['id']);
1204 unset($data['file']['settings']['count']);
1205 unset($data['file']['settings']['processed']);
1206
1207
1208 $row = [
1209 'name' => $result['post_title'],
1210 'data' => $data
1211 ];
1212
1213 if ($this->importer_manager->is_debug()) {
1214 $row['raw'] = base64_encode($result['post_content']);
1215 }
1216
1217 $output[] = $row;
1218 }
1219
1220 $json = json_encode($output);
1221
1222 header('Content-disposition: attachment; filename="ImportWP-export-' . date('Y-m-d') . '.json"');
1223 header('Content-type: "application/json"; charset="utf8"');
1224 header('Expires: 0');
1225 header('Cache-Control: must-revalidate');
1226 header('Pragma: public');
1227 header('Content-Length: ' . strlen($json));
1228
1229 echo $json;
1230 die();
1231 }
1232
1233 public function import_exporters(\WP_REST_Request $request = null)
1234 {
1235 $upload = $this->filesystem->upload_file($_FILES['file']);
1236 if (is_wp_error($upload)) {
1237 return $this->http->end_rest_error($upload->get_error_message());
1238 }
1239
1240 $json_contents = file_get_contents($upload['dest']);
1241 @unlink($upload['dest']);
1242
1243 $contents = json_decode($json_contents, true);
1244 $counter = 0;
1245 $errors = [];
1246 if (!empty($contents)) {
1247 foreach ($contents as $importer) {
1248
1249 $result = wp_insert_post([
1250 'post_type' => IWP_POST_TYPE,
1251 'post_title' => $importer['name'],
1252 'post_status' => 'publish',
1253 'post_author' => get_current_user_id(),
1254 'post_content' => serialize($importer['data'])
1255 ], true);
1256
1257 if (is_wp_error($result)) {
1258 $errors[] = $result->get_error_message();
1259 continue;
1260 }
1261
1262 $counter++;
1263 }
1264 }
1265
1266 if (empty($counter)) {
1267 return $this->http->end_rest_error('No Importers found.');
1268 }
1269
1270 return $this->http->end_rest_success("Import Complete, {$counter} Importer" . ($counter > 1 ? 's' : '') . '.');
1271 }
1272
1273 public function save_exporter(\WP_REST_Request $request = null)
1274 {
1275 $post_data = $request->get_body_params();
1276 $id = isset($post_data['id']) ? intval($post_data['id']) : null;
1277
1278
1279 $exporter = new ExporterModel($id, $this->importer_manager->is_debug());
1280
1281 if (isset($post_data['name'])) {
1282 $exporter->setName($post_data['name']);
1283 }
1284
1285 if (isset($post_data['type'])) {
1286 $exporter->setType($post_data['type']);
1287 }
1288
1289 if (isset($post_data['file_type'])) {
1290 $exporter->setFileType($post_data['file_type']);
1291 }
1292
1293 if (isset($post_data['fields']) || $id > 0) {
1294 $exporter->setFields(isset($post_data['fields']) ? $post_data['fields'] : []);
1295 }
1296
1297 if (isset($post_data['filters']) || $id > 0) {
1298 $exporter->setFilters(isset($post_data['filters']) ? $post_data['filters'] : []);
1299 }
1300
1301 if (isset($post_data['unique_identifier'])) {
1302 $exporter->setUniqueIdentifier($post_data['unique_identifier']);
1303 }
1304
1305 $result = $exporter->save();
1306 if (is_wp_error($result)) {
1307 return $this->http->end_rest_error($result->get_error_message());
1308 }
1309 return $this->http->end_rest_success($exporter->data());
1310 }
1311
1312 public function get_exporters(\WP_REST_Request $request = null)
1313 {
1314 $exporters = $this->exporter_manager->get_exporters();
1315 $result = [];
1316
1317 foreach ($exporters as $exporter) {
1318 $result[] = $exporter->data();
1319 }
1320
1321 return $this->http->end_rest_success($result);
1322 }
1323
1324 public function get_exporter(\WP_REST_Request $request = null)
1325 {
1326 $id = intval($request->get_param('id'));
1327 $exporter_data = $this->exporter_manager->get_exporter($id);
1328 $response = $exporter_data->data('public');
1329 return $this->http->end_rest_success($response);
1330 }
1331
1332 public function delete_exporter(\WP_REST_Request $request = null)
1333 {
1334 $id = intval($request->get_param('id'));
1335 $this->exporter_manager->delete_exporter($id);
1336 return $this->http->end_rest_success(true);
1337 }
1338
1339 public function run_exporter(\WP_REST_Request $request)
1340 {
1341 $this->http->set_stream_headers();
1342
1343 $id = intval($request->get_param('id'));
1344 $session = $request->get_param('session');
1345
1346 $exporter_data = $this->exporter_manager->get_exporter($id);
1347
1348 $status = $this->exporter_manager->export($exporter_data, $session);
1349 echo json_encode($status);
1350 // Logger::write(__CLASS__ . '::run_import -import=end -status=' . $status->get_status(), $id);
1351
1352 // if (!empty($this->output_cache)) {
1353 // echo $this->output_cache;
1354 // $this->output_cache = '';
1355 // }
1356
1357 // $output = $status->output();
1358 // $output['message'] = $this->generate_exporter_status_message($status);
1359 // echo json_encode($output) . "\n";
1360 die();
1361 }
1362
1363 public function get_exporter_status(\WP_REST_Request $request)
1364 {
1365 $exporter_ids = $request->get_param('ids');
1366 $result = array();
1367 $query_data = array(
1368 'post_type' => EWP_POST_TYPE,
1369 'posts_per_page' => -1,
1370 'fields' => 'ids'
1371 );
1372
1373 if (!empty($exporter_ids)) {
1374 $query_data['post__in'] = $exporter_ids;
1375 }
1376
1377 $query = new \WP_Query($query_data);
1378
1379 if (!empty($query->posts)) {
1380 foreach ($query->posts as $post_id) {
1381
1382 $exporter = $this->exporter_manager->get_exporter($post_id);
1383 $status = $exporter->get_status();
1384 $status['id'] = $post_id;
1385
1386 $result[] = $status;
1387 }
1388 }
1389
1390 echo json_encode($result) . "\n";
1391 die();
1392 }
1393 }
1394