PluginProbe
Import WP – CSV & XML Import Export for WordPress / 2.7.0
Import WP – CSV & XML Import Export for WordPress v2.7.0
2.15.2 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 All 145 releases
jc-importer / class / Common / Rest / RestManager.php

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

1,391 lines 49.1 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 $importer->setFileSetting('count', $count);
825 } else {
826
827 do_action('iwp/file-process/' . $parser, $importer, $post_data);
828 }
829
830 $importer->setFileSetting('processed', true);
831 $importer->save();
832
833 return $this->http->end_rest_success($importer->data());
834 } catch (\Exception $e) {
835 return $this->http->end_rest_error($e->getMessage());
836 }
837 }
838
839 public function get_file_preview(\WP_REST_Request $request)
840 {
841 try {
842 $id = intval($request->get_param('id'));
843 $post_data = $this->sanitize($request->get_body_params());
844 $importer = $this->importer_manager->get_importer($id);
845
846 $import_file_exists = $this->filesystem->file_exists($importer->getFile());
847 if (is_wp_error($import_file_exists)) {
848 throw new \Exception("Unable to load preview, " . $import_file_exists->get_error_message());
849 }
850
851 $record_index = isset($post_data['record']) ? $post_data['record'] : null;
852 if (is_null($record_index)) {
853 $record_index = 0;
854 }
855
856 // Temp set file_encoding
857 if (isset($post_data['file_encoding'])) {
858 $importer->setFileSetting('file_encoding', $post_data['file_encoding']);
859 }
860
861 if ($importer->getParser() === 'xml') {
862
863 $config = $this->importer_manager->get_config($importer, true);
864 $file = $this->importer_manager->get_xml_file($importer, $config);
865
866 $base_path = $post_data['base_path'];
867 if (!is_null($base_path)) {
868 $file->setRecordPath($base_path);
869 }
870
871 $preview = new XMLPreview($file, $base_path);
872 $result = $preview->data();
873 if (is_wp_error($result)) {
874 return $this->http->end_rest_error($result);
875 }
876
877 return $this->http->end_rest_success($result[0]);
878 } elseif ($importer->getParser() === 'csv') {
879
880 $config = $this->importer_manager->get_config($importer, true);
881 $file = $this->importer_manager->get_csv_file($importer, $config);
882
883 $delimiter = $post_data['delimiter'];
884 if (!is_null($delimiter)) {
885 $file->setDelimiter($delimiter);
886 }
887
888 $enclosure = $post_data['enclosure'];
889 if (!is_null($enclosure)) {
890 $file->setEnclosure($enclosure);
891 }
892
893 // parse bool param from string
894 $show_headings = $post_data['show_headings'];
895 if (in_array($show_headings, ['true', 'false'])) {
896 $show_headings = $show_headings === 'true' ? true : false;
897 }
898
899 if (is_null($show_headings)) {
900 $show_headings = $importer->getFileSetting('show_headings');
901 }
902
903 $preview = new CSVPreview($file);
904 $result = $preview->data($record_index, $show_headings);
905 if (is_wp_error($result)) {
906 return $this->http->end_rest_error($result);
907 }
908
909 return $this->http->end_rest_success($result);
910 } else {
911
912 $result = apply_filters('iwp/file-preview/' . $importer->getParser(), null, $importer);
913 if (is_wp_error($result)) {
914 return $this->http->end_rest_error($result);
915 }
916
917 return $this->http->end_rest_success($result);
918 }
919 } catch (\Exception $error) {
920 return $this->http->end_rest_error($error->getMessage());
921 }
922 }
923
924 public function get_preview(\WP_REST_Request $request)
925 {
926 // if no fields have been posted send all previews
927 try {
928 $id = intval($request->get_param('id'));
929 $importer = $this->importer_manager->get_importer($id);
930 $import_file_exists = $this->filesystem->file_exists($importer->getFile());
931 if (is_wp_error($import_file_exists)) {
932 throw new \Exception("Unable to load preview, " . $import_file_exists->get_error_message());
933 }
934
935 $parser = $importer->getParser();
936
937 $fields = $this->sanitize($request->get_body_params());
938 if (is_null($fields) || empty($fields)) {
939 $fields = $importer->getMap();
940 }
941
942 if ('xml' === $parser) {
943 $result = $this->importer_manager->preview_xml_file($importer, $fields);
944 } elseif ('csv' === $parser) {
945 $row = 0;
946 if ($importer->getFileSetting('show_headings') === true) {
947 $row = 1;
948 }
949 $result = $this->importer_manager->preview_csv_file($importer, $fields, $row);
950 } else {
951
952 $result = apply_filters('iwp/record-preview/' . $parser, [], $importer, $fields);
953 if (is_wp_error($result)) {
954 return $this->http->end_rest_error($result);
955 }
956
957 return $this->http->end_rest_success($result);
958 }
959
960 return $this->http->end_rest_success($result);
961 } catch (\Exception $error) {
962 return $this->http->end_rest_error($error->getMessage());
963 }
964 }
965
966 /**
967 * Trigger a new import.
968 *
969 * @param \WP_REST_Request $request
970 * @return array
971 */
972 public function init_import(\WP_REST_Request $request)
973 {
974 $id = intval($request->get_param('id'));
975
976 Logger::setRequestType('rest::init_import');
977
978 Logger::write('init_import -start', $id);
979
980 $importer_data = $this->importer_manager->get_importer($id);
981
982 // clear existing
983 ImporterState::clear_options($importer_data->getId());
984
985 // This is used for storing version on imported records
986 $session_id = md5($importer_data->getId() . time());
987 update_post_meta($importer_data->getId(), '_iwp_session', $session_id);
988
989 Logger::clearRequestType();
990
991 return $this->http->end_rest_success([
992 'session' => $session_id
993 ]);
994 }
995
996 public function run_import(\WP_REST_Request $request)
997 {
998 $this->http->set_stream_headers();
999
1000 Logger::setRequestType('rest::run_import');
1001
1002 $session = $request->get_param('session');
1003 $user = uniqid('iwp', true);
1004 $id = intval($request->get_param('id'));
1005 Logger::write('run_import -session=' . $session, $id);
1006
1007 $importer_data = $this->importer_manager->get_importer($id);
1008 Logger::write('run_import -import=start', $id);
1009
1010 $state = $this->importer_manager->import($importer_data->getId(), $user, $session);
1011 $state['message'] = $this->generate_status_message($state);
1012
1013 Logger::clearRequestType();
1014
1015 return $this->http->end_rest_success($state);
1016 }
1017
1018 public function pause_import(\WP_REST_Request $request)
1019 {
1020 $id = intval($request->get_param('id'));
1021 $paused = $this->sanitize($request->get_param('paused'), 'paused');
1022
1023 $importer_data = $this->importer_manager->get_importer($id);
1024 $user = uniqid('iwp', true);
1025
1026 $state = ImporterState::wait_for_lock($importer_data->getId(), $user, function () use ($importer_data, $paused) {
1027 $state = ImporterState::get_state($importer_data->getId());
1028
1029
1030 if ($paused === 'no') {
1031 $state['status'] = 'running';
1032 } else {
1033 $state['status'] = 'paused';
1034 }
1035
1036 ImporterState::set_state($importer_data->getId(), $state);
1037 return $state;
1038 });
1039
1040 return $this->http->end_rest_success($state);
1041 }
1042
1043 public function stop_import(\WP_REST_Request $request)
1044 {
1045 $id = intval($request->get_param('id'));
1046
1047 $importer_data = $this->importer_manager->get_importer($id);
1048
1049 $user = uniqid('iwp');
1050
1051 $state = ImporterState::wait_for_lock($importer_data->getId(), $user, function () use ($importer_data) {
1052 $state = ImporterState::get_state($importer_data->getId());
1053 $state['status'] = 'cancelled';
1054 ImporterState::set_state($importer_data->getId(), $state);
1055 return $state;
1056 });
1057
1058 return $this->http->end_rest_success($state);
1059 }
1060
1061 /**
1062 * Get field options for current template
1063 *
1064 * @param \WP_REST_Request $request
1065 * @return void
1066 */
1067 public function get_template_field_options(\WP_REST_Request $request)
1068 {
1069 $id = intval($request->get_param('id'));
1070 $field = $this->sanitize($request->get_param('field'), 'field');
1071
1072 $importer_data = $this->importer_manager->get_importer($id);
1073 $template = $this->importer_manager->get_importer_template($id);
1074
1075 return $this->http->end_rest_success($template->get_field_options($field, $importer_data));
1076 }
1077
1078 public function get_logs(\WP_REST_Request $request)
1079 {
1080 $id = intval($request->get_param('id'));
1081 $importer_data = $this->importer_manager->get_importer($id);
1082 $logs = $this->importer_manager->get_importer_logs($importer_data);
1083 return $this->http->end_rest_success(array_reverse($logs));
1084 }
1085
1086 public function get_log(\WP_REST_Request $request)
1087 {
1088 $id = intval($request->get_param('id'));
1089 $session = $this->sanitize($request->get_param('session'), 'session');
1090 $page = intval($request->get_param('page'));
1091 if ($page < 1) {
1092 $page = 1;
1093 }
1094 $importer_data = $this->importer_manager->get_importer($id);
1095 $log = $this->importer_manager->get_importer_log($importer_data, $session, $page, 500);
1096 $status = $this->importer_manager->get_importer_status_report($importer_data, $session);
1097 return $this->http->end_rest_success(['logs' => $log, 'status' => $status]);
1098 }
1099
1100 public function get_debug_log(\WP_REST_Request $request)
1101 {
1102 $id = intval($request->get_param('id'));
1103 $page = intval($request->get_param('page'));
1104 if ($page < 1) {
1105 $page = 1;
1106 }
1107 $importer_data = $this->importer_manager->get_importer($id);
1108 $log = $this->importer_manager->get_importer_debug_log($importer_data, $page, 100);
1109
1110 $download = Logger::getLogFile($importer_data->getId(), true);
1111 return $this->http->end_rest_success(['log' => $log, 'download' => $download]);
1112 }
1113
1114 public function save_settings(\WP_REST_Request $request)
1115 {
1116 $post_data = $request->get_body_params();
1117 $post_data = $this->sanitize($post_data);
1118
1119 $defaults = $this->properties->_default_settings();
1120
1121 $output = [];
1122
1123 foreach ($defaults as $setting => $default) {
1124 if (isset($post_data[$setting])) {
1125 if ('bool' === $default['type']) {
1126 // Handle Boolean
1127 if (is_bool($post_data[$setting])) {
1128 $output[$setting] = $post_data[$setting];
1129 } elseif (in_array($post_data[$setting], ['true', 'false'])) {
1130 $output[$setting] = $post_data[$setting] === 'true' ? true : false;
1131 } else {
1132 $output[$setting] = boolval($post_data[$setting]);
1133 }
1134 } elseif ('number' === $default['type']) {
1135 $output[$setting] = intval($post_data[$setting]);
1136 } else {
1137 $output[$setting] = $post_data[$setting];
1138 }
1139 } else {
1140 $output[$setting] = $default['value'];
1141 }
1142 }
1143
1144 update_site_option('iwp_settings', $output);
1145
1146 return $this->http->end_rest_success($this->properties->get_settings());
1147 }
1148
1149 public function get_settings(\WP_REST_Request $request = null)
1150 {
1151 $output = $this->properties->get_settings();
1152 return $this->http->end_rest_success($output);
1153 }
1154
1155 public function get_template(\WP_REST_Request $request = null)
1156 {
1157 $importer_id = $request->get_param('id');
1158 $importer_model = $this->importer_manager->get_importer($importer_id);
1159 $importer_template = $importer_model->getTemplate();
1160
1161 $templates = $this->importer_manager->get_templates();
1162
1163 if (!isset($templates[$importer_template])) {
1164 return $this->http->end_rest_error("Invalid template \"" . $importer_template . "\"");
1165 }
1166
1167 $template_id = $templates[$importer_template];
1168 $template_class = $this->template_manager->load_template($template_id);
1169
1170 $output = [
1171 'id' => $template_id,
1172 'label' => $template_class->get_name(),
1173 'map' => $template_class->get_fields($importer_model),
1174 'settings' => $template_class->register_settings(),
1175 'options' => $template_class->register_options(),
1176 ];
1177 return $this->http->end_rest_success($output);
1178 }
1179
1180 public function export_importers(\WP_REST_Request $request = null)
1181 {
1182 $importer_ids = $request->get_param('ids');
1183
1184 $sql_ids = array_map(function ($v) {
1185 return "'" . esc_sql($v) . "'";
1186 }, $importer_ids);
1187 $sql_ids = implode(',', $sql_ids);
1188
1189 $output = [];
1190
1191 /**
1192 * @var \WPDB $wpdb
1193 */
1194 global $wpdb;
1195 $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);
1196 foreach ($results as $result) {
1197
1198 $data = unserialize($result['post_content']);
1199
1200 unset($data['file']['id']);
1201 unset($data['file']['settings']['count']);
1202 unset($data['file']['settings']['processed']);
1203
1204
1205 $row = [
1206 'name' => $result['post_title'],
1207 'data' => $data
1208 ];
1209
1210 if ($this->importer_manager->is_debug()) {
1211 $row['raw'] = base64_encode($result['post_content']);
1212 }
1213
1214 $output[] = $row;
1215 }
1216
1217 $json = json_encode($output);
1218
1219 header('Content-disposition: attachment; filename="ImportWP-export-' . date('Y-m-d') . '.json"');
1220 header('Content-type: "application/json"; charset="utf8"');
1221 header('Expires: 0');
1222 header('Cache-Control: must-revalidate');
1223 header('Pragma: public');
1224 header('Content-Length: ' . strlen($json));
1225
1226 echo $json;
1227 die();
1228 }
1229
1230 public function import_exporters(\WP_REST_Request $request = null)
1231 {
1232 $upload = $this->filesystem->upload_file($_FILES['file']);
1233 if (is_wp_error($upload)) {
1234 return $this->http->end_rest_error($upload->get_error_message());
1235 }
1236
1237 $json_contents = file_get_contents($upload['dest']);
1238 @unlink($upload['dest']);
1239
1240 $contents = json_decode($json_contents, true);
1241 $counter = 0;
1242 $errors = [];
1243 if (!empty($contents)) {
1244 foreach ($contents as $importer) {
1245
1246 $result = wp_insert_post([
1247 'post_type' => IWP_POST_TYPE,
1248 'post_title' => $importer['name'],
1249 'post_status' => 'publish',
1250 'post_author' => get_current_user_id(),
1251 'post_content' => serialize($importer['data'])
1252 ], true);
1253
1254 if (is_wp_error($result)) {
1255 $errors[] = $result->get_error_message();
1256 continue;
1257 }
1258
1259 $counter++;
1260 }
1261 }
1262
1263 if (empty($counter)) {
1264 return $this->http->end_rest_error('No Importers found.');
1265 }
1266
1267 return $this->http->end_rest_success("Import Complete, {$counter} Importer" . ($counter > 1 ? 's' : '') . '.');
1268 }
1269
1270 public function save_exporter(\WP_REST_Request $request = null)
1271 {
1272 $post_data = $request->get_body_params();
1273 $id = isset($post_data['id']) ? intval($post_data['id']) : null;
1274
1275
1276 $exporter = new ExporterModel($id, $this->importer_manager->is_debug());
1277
1278 if (isset($post_data['name'])) {
1279 $exporter->setName($post_data['name']);
1280 }
1281
1282 if (isset($post_data['type'])) {
1283 $exporter->setType($post_data['type']);
1284 }
1285
1286 if (isset($post_data['file_type'])) {
1287 $exporter->setFileType($post_data['file_type']);
1288 }
1289
1290 if (isset($post_data['fields']) || $id > 0) {
1291 $exporter->setFields(isset($post_data['fields']) ? $post_data['fields'] : []);
1292 }
1293
1294 if (isset($post_data['filters']) || $id > 0) {
1295 $exporter->setFilters(isset($post_data['filters']) ? $post_data['filters'] : []);
1296 }
1297
1298 if (isset($post_data['unique_identifier'])) {
1299 $exporter->setUniqueIdentifier($post_data['unique_identifier']);
1300 }
1301
1302 $result = $exporter->save();
1303 if (is_wp_error($result)) {
1304 return $this->http->end_rest_error($result->get_error_message());
1305 }
1306 return $this->http->end_rest_success($exporter->data());
1307 }
1308
1309 public function get_exporters(\WP_REST_Request $request = null)
1310 {
1311 $exporters = $this->exporter_manager->get_exporters();
1312 $result = [];
1313
1314 foreach ($exporters as $exporter) {
1315 $result[] = $exporter->data();
1316 }
1317
1318 return $this->http->end_rest_success($result);
1319 }
1320
1321 public function get_exporter(\WP_REST_Request $request = null)
1322 {
1323 $id = intval($request->get_param('id'));
1324 $exporter_data = $this->exporter_manager->get_exporter($id);
1325 $response = $exporter_data->data('public');
1326 return $this->http->end_rest_success($response);
1327 }
1328
1329 public function delete_exporter(\WP_REST_Request $request = null)
1330 {
1331 $id = intval($request->get_param('id'));
1332 $this->exporter_manager->delete_exporter($id);
1333 return $this->http->end_rest_success(true);
1334 }
1335
1336 public function run_exporter(\WP_REST_Request $request)
1337 {
1338 $this->http->set_stream_headers();
1339
1340 $id = intval($request->get_param('id'));
1341 $session = $request->get_param('session');
1342
1343 $exporter_data = $this->exporter_manager->get_exporter($id);
1344
1345 $status = $this->exporter_manager->export($exporter_data, $session);
1346 echo json_encode($status);
1347 // Logger::write(__CLASS__ . '::run_import -import=end -status=' . $status->get_status(), $id);
1348
1349 // if (!empty($this->output_cache)) {
1350 // echo $this->output_cache;
1351 // $this->output_cache = '';
1352 // }
1353
1354 // $output = $status->output();
1355 // $output['message'] = $this->generate_exporter_status_message($status);
1356 // echo json_encode($output) . "\n";
1357 die();
1358 }
1359
1360 public function get_exporter_status(\WP_REST_Request $request)
1361 {
1362 $exporter_ids = $request->get_param('ids');
1363 $result = array();
1364 $query_data = array(
1365 'post_type' => EWP_POST_TYPE,
1366 'posts_per_page' => -1,
1367 'fields' => 'ids'
1368 );
1369
1370 if (!empty($exporter_ids)) {
1371 $query_data['post__in'] = $exporter_ids;
1372 }
1373
1374 $query = new \WP_Query($query_data);
1375
1376 if (!empty($query->posts)) {
1377 foreach ($query->posts as $post_id) {
1378
1379 $exporter = $this->exporter_manager->get_exporter($post_id);
1380 $status = $exporter->get_status();
1381 $status['id'] = $post_id;
1382
1383 $result[] = $status;
1384 }
1385 }
1386
1387 echo json_encode($result) . "\n";
1388 die();
1389 }
1390 }
1391