PluginProbe
Import WP – CSV & XML Import Export for WordPress / 2.7.7
Import WP – CSV & XML Import Export for WordPress v2.7.7
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.7, at class/Common/Rest/RestManager.php

1,438 lines 50.6 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 Logger::setRequestType('get_importer');
420
421 $id = intval($request->get_param('id'));
422 $importer_data = $this->importer_manager->get_importer($id);
423 $response = $importer_data->data('public');
424 return $this->http->end_rest_success($response);
425 }
426
427 public function save_importer(\WP_REST_Request $request)
428 {
429 Logger::setRequestType('save_importer');
430
431 $post_data = $request->get_body_params();
432 $id = isset($post_data['id']) ? intval($post_data['id']) : null;
433
434 $temp_post_data = [
435 'create' => [],
436 'update' => []
437 ];
438
439 if (isset($post_data['permissions'])) {
440 // TODO: update sanitize method to keep track of hierarchy
441 $temp_post_data['create'] = explode("\n", $post_data['permissions']['create']['fields']);
442 $temp_post_data['update'] = explode("\n", $post_data['permissions']['update']['fields']);
443 }
444
445 $post_data = $this->sanitize($post_data);
446
447 if (isset($post_data['permissions'])) {
448 // TODO: Method to bypass sanitization not needed once sanitize method has been upgraded
449 foreach (['create', 'update'] as $permission_method) {
450 $permission_fields = $temp_post_data[$permission_method];
451 if (!empty($permission_fields)) {
452 $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'))));
453 } else {
454 $post_data['permissions'][$permission_method]['fields'] = [];
455 }
456 }
457 }
458
459
460
461 $importer = new ImporterModel($id, $this->importer_manager->is_debug());
462
463 if (isset($post_data['datasource'])) {
464 $importer->setDatasource($post_data['datasource']);
465 }
466
467 if (isset($post_data['remote_url'])) {
468 $importer->setDatasourceSetting('remote_url', $post_data['remote_url']);
469 }
470
471 if (isset($post_data['local_url'])) {
472 $importer->setDatasourceSetting('local_url', $post_data['local_url']);
473 }
474
475 if (isset($post_data['existing_id'])) {
476 $importer->setFileId(intval($post_data['existing_id']));
477 }
478
479 if (isset($post_data['template'], $post_data['template_type'])) {
480 $importer->setTemplate($post_data['template'], $post_data['template_type']);
481
482 // Get default template options
483 $template_class = $this->importer_manager->get_template($post_data['template']);
484
485 /**
486 * @var Template $template
487 */
488 $template = $this->template_manager->load_template($template_class);
489 $template_options = $template->get_default_template_options();
490
491 if (isset($post_data['template_options'])) {
492 $template_options = array_merge($template_options, $post_data['template_options']);
493 }
494
495 foreach ($template_options as $key => $val) {
496 $importer->setSetting($key, $val);
497 }
498 }
499
500 if (isset($post_data['name'])) {
501 $importer->setName($post_data['name']);
502 }
503
504 if (isset($post_data['setting_start_row'])) {
505 $importer->setStartRow($post_data['setting_start_row']);
506 }
507
508 if (isset($post_data['setting_max_row'])) {
509 $importer->setMaxRow($post_data['setting_max_row']);
510 }
511
512 // save settings
513 foreach ($post_data as $key => $value) {
514 if (1 === preg_match('/^setting_(?<key>.*)/', $key, $matches)) {
515
516 $value = $this->sanitize_setting($value);
517 $importer->setSetting($matches['key'], $value);
518 }
519 }
520
521 $parser = $importer->getParser();
522
523 if (isset($post_data['file_settings_encoding'])) {
524 $importer->setFileSetting('file_encoding', $post_data['file_settings_encoding']);
525 }
526
527 if ($parser === 'csv') {
528 if (isset($post_data['file_settings_delimiter'])) {
529 $importer->setFileSetting('delimiter', $post_data['file_settings_delimiter']);
530 }
531 if (isset($post_data['file_settings_enclosure'])) {
532 $importer->setFileSetting('enclosure', $post_data['file_settings_enclosure']);
533 }
534 if (isset($post_data['file_settings_show_headings'])) {
535 $importer->setFileSetting('show_headings', $post_data['file_settings_show_headings'] === 'true' || $post_data['file_settings_show_headings'] === true ? true : false);
536 }
537 } elseif ($parser === 'xml') {
538 if (isset($post_data['file_settings_base_path'])) {
539 $importer->setFileSetting('base_path', $post_data['file_settings_base_path']);
540 }
541 }
542
543 if (isset($post_data['file_settings_setup'])) {
544 $importer->setFileSetting('setup', $post_data['file_settings_setup'] === 'true' ? true : false);
545 }
546
547 if (isset($post_data['map']) && is_array($post_data['map'])) {
548 foreach ($post_data['map'] as $key => $value) {
549
550 if (1 === preg_match('/\._index$/', $key)) {
551 $value = intval($value);
552 }
553
554 $importer->setMap($key, $value);
555 }
556 }
557
558 if (isset($post_data['enabled']) && is_array($post_data['enabled'])) {
559 foreach ($post_data['enabled'] as $key => $value) {
560 if ($value === 'true') {
561 $importer->setEnabled($key);
562 } else {
563 $importer->setEnabled($key, false);
564 }
565 }
566 }
567
568 if (isset($post_data['permissions']) && is_array($post_data['permissions'])) {
569
570 // create
571 if (isset($post_data['permissions']['create'])) {
572 $create = $post_data['permissions']['create'];
573 $importer->setPermission('create', [
574 'enabled' => isset($create['enabled']) && $create['enabled'] === 'true' ? true : false,
575 'type' => isset($create['type']) && in_array($create['type'], ['include', 'exclude'], true) ? $create['type'] : null,
576 'fields' => isset($create['fields']) ? $create['fields'] : [],
577 ]);
578 }
579
580 // update
581 if (isset($post_data['permissions']['update'])) {
582 $update = $post_data['permissions']['update'];
583 $importer->setPermission('update', [
584 'enabled' => isset($update['enabled']) && $update['enabled'] === 'true' ? true : false,
585 'type' => isset($update['type']) && in_array($update['type'], ['include', 'exclude'], true) ? $update['type'] : null,
586 'fields' => isset($update['fields']) ? $update['fields'] : [],
587 ]);
588 }
589
590 // remove
591 if (isset($post_data['permissions']['remove'])) {
592 $importer->setPermission('remove', [
593 'enabled' => $post_data['permissions']['remove']['enabled'] === 'true',
594 'trash' => $post_data['permissions']['remove']['trash'] === 'true',
595 ]);
596 }
597 }
598
599 $result = $importer->save();
600 if (is_wp_error($result)) {
601 return $this->http->end_rest_error($result->get_error_message());
602 }
603 return $this->http->end_rest_success($importer->data());
604 }
605
606 private function sanitize_setting($value)
607 {
608 if (is_array($value)) {
609 foreach ($value as &$tmp) {
610 $tmp = $this->sanitize_setting($tmp);
611 }
612 return $value;
613 } else {
614 if (in_array($value, ['true', 'false'], true)) {
615 if ($value === 'true') {
616 $value = true;
617 } else {
618 $value = false;
619 }
620 }
621 }
622
623 return $value;
624 }
625
626 public function get_status(\WP_REST_Request $request)
627 {
628 $this->http->set_stream_headers();
629
630 Logger::disable();
631
632 $importer_ids = $request->get_param('ids');
633
634 $result = [];
635
636 $query_data = array(
637 'post_type' => IWP_POST_TYPE,
638 'posts_per_page' => -1,
639 'fields' => 'ids'
640 );
641 if (!empty($importer_ids)) {
642 $query_data['post__in'] = $importer_ids;
643 }
644
645 $query = new \WP_Query($query_data);
646
647 foreach ($query->posts as $importer_id) {
648
649 $importer_model = $this->importer_manager->get_importer($importer_id);
650
651 $output = ImporterState::get_state($importer_id);
652 $output['version'] = 2;
653 $output['message'] = $this->generate_status_message($output);
654 $output['importer'] = $importer_id;
655
656 $result[] = $this->event_handler->run('iwp/importer/status/output', [$output, $importer_model]);
657 }
658
659 echo json_encode($result) . "\n";
660 die();
661 }
662
663 /**
664 * @param array $data
665 * @return string
666 */
667 protected function generate_status_message($data)
668 {
669 $output = '';
670
671 if (!$data || !isset($data['status']) || is_null($data['status']) || empty($data['status'])) {
672 return '';
673 }
674
675 if (isset($data['status'])) {
676 switch ($data['status']) {
677 case 'cancelled':
678 $output .= 'Import cancelled';
679 break;
680 case 'complete':
681 $output .= 'Import complete';
682 break;
683 case 'error':
684 $output = $data['message'];
685 return $output;
686 break;
687 }
688 }
689
690 if (isset($data['status']) && $data['status'] === 'running' && isset($data['section'])) {
691 switch ($data['section']) {
692 case 'import':
693 case 'delete':
694 $output = $data['section'] === 'import' ? 'Importing: ' : 'Deleting: ';
695 $output .= $data['progress'][$data['section']]['current_row'] . ' / ' . ($data['progress'][$data['section']]['end'] - $data['progress'][$data['section']]['start']);
696
697 break;
698 }
699 }
700
701 if (isset($data['stats'])) {
702 if ($data['stats']['inserts'] > 0) {
703 $output .= sprintf(', Inserts: %d', $data['stats']['inserts']);
704 }
705 if ($data['stats']['updates'] > 0) {
706 $output .= sprintf(', Updates: %d', $data['stats']['updates']);
707 }
708 if ($data['stats']['deletes'] > 0) {
709 $output .= sprintf(', Deletes: %d', $data['stats']['deletes']);
710 }
711 if ($data['stats']['skips'] > 0) {
712 $output .= sprintf(', Skips: %d', $data['stats']['skips']);
713 }
714 if ($data['stats']['errors'] > 0) {
715 $output .= sprintf(', Errors: %d', $data['stats']['errors']);
716 }
717 }
718
719 if (isset($data['timestamp'], $data['updated'])) {
720 /**
721 * @var Util $util
722 */
723 $util = Container::getInstance()->get('util');
724 $output .= ', Run Time: ' . $util->format_time($data['updated'] - $data['timestamp']);
725 } elseif (isset($data['duration'])) {
726 /**
727 * @var Util $util
728 */
729 $util = Container::getInstance()->get('util');
730 $output .= ', Run Time: ' . $util->format_time($data['duration']);
731 }
732
733 return $output;
734 }
735
736 public function delete_importer(\WP_REST_Request $request)
737 {
738 Logger::setRequestType('delete_importer');
739
740 $id = intval($request->get_param('id'));
741 $this->importer_manager->delete_importer($id);
742 return $this->http->end_rest_success(true);
743 }
744
745 public function attach_file(\WP_REST_Request $request)
746 {
747 $id = intval($request->get_param('id'));
748 $post_data = $this->sanitize($request->get_body_params());
749
750 $action = $post_data['action'];
751
752 $importer = $this->importer_manager->get_importer($id);
753
754 // TODO: Remove duplicate code, found in cron manager
755
756 switch ($action) {
757 case 'file_upload':
758 $attachment_id = $this->importer_manager->upload_file($importer, $_FILES['file']);
759 break;
760 case 'file_remote':
761 $raw_source = $post_data['remote_url'];
762 $source = apply_filters('iwp/importer/datasource', $raw_source, $raw_source, $importer);
763 $source = apply_filters('iwp/importer/datasource/remote', $source, $raw_source, $importer);
764
765 $filetype = $importer->getParser();
766 if (is_null($filetype)) {
767 $filetype = $post_data['filetype'];
768 }
769
770 $attachment_id = $this->importer_manager->remote_file($importer, $source, $filetype, null, $importer->getId() . '-');
771 break;
772 case 'file_local':
773 $raw_source = $post_data['local_url'];
774 $source = apply_filters('iwp/importer/datasource', $raw_source, $raw_source, $importer);
775 $source = apply_filters('iwp/importer/datasource/local', $source, $raw_source, $importer);
776 $attachment_id = $this->importer_manager->local_file($importer, $source);
777 break;
778 default:
779 $attachment_id = new \WP_Error('IWP_RM_1', 'Invalid form action');
780 break;
781 }
782
783 if (is_wp_error($attachment_id)) {
784 return $this->http->end_rest_error($attachment_id->get_error_message());
785 }
786
787 return $this->http->end_rest_success($importer->data());
788 }
789
790 public function get_file_process(\WP_REST_Request $request)
791 {
792 try {
793 $id = intval($request->get_param('id'));
794 $post_data = $this->sanitize($request->get_body_params());
795
796 $importer = $this->importer_manager->get_importer($id);
797 if (!$importer) {
798 return $this->http->end_rest_error('Invalid importer');
799 }
800
801 $this->importer_manager->clear_config_files($id, true);
802 $parser = $importer->getParser();
803
804 if ('xml' === $parser) {
805
806 $nodes = $this->importer_manager->process_xml_file($id, true);
807 $importer->setFileSetting('nodes', $nodes);
808 } elseif ('csv' === $parser) {
809
810 $delimiter = isset($post_data['delimiter']) ? $post_data['delimiter'] : null;
811 if (is_null($delimiter)) {
812 $delimiter = ',';
813 }
814
815 $enclosure = isset($post_data['enclosure']) ? $post_data['enclosure'] : null;
816 if (is_null($enclosure)) {
817 $enclosure = '"';
818 }
819
820 $count = $this->importer_manager->process_csv_file($id, $delimiter, $enclosure, true);
821
822 // Need fresh importer, due to process_csv_file importer modifications might get overwritten.
823 $importer = $this->importer_manager->get_importer($id);
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 Logger::setRequestType('get_template');
1158
1159 $importer_id = $request->get_param('id');
1160 $importer_model = $this->importer_manager->get_importer($importer_id);
1161 $importer_template = $importer_model->getTemplate();
1162
1163 $templates = $this->importer_manager->get_templates();
1164
1165 if (!isset($templates[$importer_template])) {
1166 return $this->http->end_rest_error("Invalid template \"" . $importer_template . "\"");
1167 }
1168
1169 $template_id = $templates[$importer_template];
1170 $template_class = $this->template_manager->load_template($template_id);
1171
1172 $output = [
1173 'id' => $template_id,
1174 'label' => $template_class->get_name(),
1175 'map' => $template_class->get_fields($importer_model),
1176 'settings' => $template_class->register_settings(),
1177 'options' => $template_class->register_options(),
1178 ];
1179 return $this->http->end_rest_success($output);
1180 }
1181
1182 public function export_importers(\WP_REST_Request $request = null)
1183 {
1184 Logger::setRequestType('export_importers');
1185
1186 $importer_ids = $request->get_param('ids');
1187
1188 $sql_ids = array_map(function ($v) {
1189 return "'" . esc_sql($v) . "'";
1190 }, $importer_ids);
1191 $sql_ids = implode(',', $sql_ids);
1192
1193 $output = [];
1194
1195 /**
1196 * @var \WPDB $wpdb
1197 */
1198 global $wpdb;
1199 $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);
1200 foreach ($results as $result) {
1201
1202 $data = unserialize($result['post_content']);
1203
1204 unset($data['file']['id']);
1205 unset($data['file']['settings']['count']);
1206 unset($data['file']['settings']['processed']);
1207
1208
1209 $row = [
1210 'name' => $result['post_title'],
1211 'data' => $data
1212 ];
1213
1214 if ($this->importer_manager->is_debug()) {
1215 $row['raw'] = base64_encode($result['post_content']);
1216 }
1217
1218 $output[] = $row;
1219 }
1220
1221 $json = json_encode($output);
1222
1223 header('Content-disposition: attachment; filename="ImportWP-export-' . date('Y-m-d') . '.json"');
1224 header('Content-type: "application/json"; charset="utf8"');
1225 header('Expires: 0');
1226 header('Cache-Control: must-revalidate');
1227 header('Pragma: public');
1228 header('Content-Length: ' . strlen($json));
1229
1230 echo $json;
1231 die();
1232 }
1233
1234 public function import_exporters(\WP_REST_Request $request = null)
1235 {
1236 Logger::setRequestType('import_exporters');
1237
1238 $upload = $this->filesystem->upload_file($_FILES['file']);
1239 if (is_wp_error($upload)) {
1240 return $this->http->end_rest_error($upload->get_error_message());
1241 }
1242
1243 $json_contents = file_get_contents($upload['dest']);
1244 @unlink($upload['dest']);
1245
1246 $contents = json_decode($json_contents, true);
1247 $counter = 0;
1248 $errors = [];
1249 if (!empty($contents)) {
1250 foreach ($contents as $importer) {
1251
1252 $result = wp_insert_post([
1253 'post_type' => IWP_POST_TYPE,
1254 'post_title' => $importer['name'],
1255 'post_status' => 'publish',
1256 'post_author' => get_current_user_id(),
1257 'post_content' => serialize($importer['data'])
1258 ], true);
1259
1260 if (is_wp_error($result)) {
1261 $errors[] = $result->get_error_message();
1262 continue;
1263 }
1264
1265 $counter++;
1266 }
1267 }
1268
1269 if (empty($counter)) {
1270 return $this->http->end_rest_error('No Importers found.');
1271 }
1272
1273 return $this->http->end_rest_success("Import Complete, {$counter} Importer" . ($counter > 1 ? 's' : '') . '.');
1274 }
1275
1276 public function save_exporter(\WP_REST_Request $request = null)
1277 {
1278 Logger::setRequestType('save_exporter');
1279
1280 $post_data = $request->get_body_params();
1281 $id = isset($post_data['id']) ? intval($post_data['id']) : null;
1282
1283
1284 $exporter = new ExporterModel($id, $this->importer_manager->is_debug());
1285
1286 if (isset($post_data['name'])) {
1287 $exporter->setName($post_data['name']);
1288 }
1289
1290 if (isset($post_data['type'])) {
1291 $exporter->setType($post_data['type']);
1292 }
1293
1294 if (isset($post_data['file_type'])) {
1295 $exporter->setFileType($post_data['file_type']);
1296 }
1297
1298 if (isset($post_data['fields']) || $id > 0) {
1299 $exporter->setFields(isset($post_data['fields']) ? $post_data['fields'] : []);
1300 }
1301
1302 if (isset($post_data['filters']) || $id > 0) {
1303 $exporter->setFilters(isset($post_data['filters']) ? $post_data['filters'] : []);
1304 }
1305
1306 if (isset($post_data['unique_identifier'])) {
1307 $exporter->setUniqueIdentifier($post_data['unique_identifier']);
1308 }
1309
1310 if (isset($post_data['export_method'])) {
1311 $exporter->setExportMethod($post_data['export_method']);
1312 }
1313
1314 if (isset($post_data['cron'])) {
1315
1316 // TODO: Save cron settings
1317
1318 $cron = $this->sanitize_setting($post_data['cron']);
1319 $exporter->setCron($cron);
1320 }
1321
1322 $result = $exporter->save();
1323 if (is_wp_error($result)) {
1324 return $this->http->end_rest_error($result->get_error_message());
1325 }
1326 return $this->http->end_rest_success($exporter->data());
1327 }
1328
1329 public function get_exporters(\WP_REST_Request $request = null)
1330 {
1331 Logger::setRequestType('get_exporters');
1332
1333 $exporters = $this->exporter_manager->get_exporters();
1334 $result = [];
1335
1336 foreach ($exporters as $exporter) {
1337 $result[] = $exporter->data();
1338 }
1339
1340 return $this->http->end_rest_success($result);
1341 }
1342
1343 public function get_exporter(\WP_REST_Request $request = null)
1344 {
1345 Logger::setRequestType('get_exporter');
1346
1347 $id = intval($request->get_param('id'));
1348 $exporter_data = $this->exporter_manager->get_exporter($id);
1349 $response = $exporter_data->data('public');
1350 return $this->http->end_rest_success($response);
1351 }
1352
1353 public function delete_exporter(\WP_REST_Request $request = null)
1354 {
1355 Logger::setRequestType('delete_exporter');
1356
1357 $id = intval($request->get_param('id'));
1358 $this->exporter_manager->delete_exporter($id);
1359 return $this->http->end_rest_success(true);
1360 }
1361
1362 public function run_exporter(\WP_REST_Request $request)
1363 {
1364 Logger::setRequestType('run_exporter');
1365
1366 $this->http->set_stream_headers();
1367
1368 $id = intval($request->get_param('id'));
1369 $session = $request->get_param('session');
1370
1371 $exporter_data = $this->exporter_manager->get_exporter($id);
1372
1373 $status = $this->exporter_manager->export($exporter_data, $session);
1374 echo json_encode($status);
1375 // Logger::write(__CLASS__ . '::run_import -import=end -status=' . $status->get_status(), $id);
1376
1377 // if (!empty($this->output_cache)) {
1378 // echo $this->output_cache;
1379 // $this->output_cache = '';
1380 // }
1381
1382 // $output = $status->output();
1383 // $output['message'] = $this->generate_exporter_status_message($status);
1384 // echo json_encode($output) . "\n";
1385 die();
1386 }
1387
1388 public function get_exporter_status(\WP_REST_Request $request)
1389 {
1390 Logger::setRequestType('get_exporter_status');
1391
1392 $exporter_ids = $request->get_param('ids');
1393 $result = array();
1394 $query_data = array(
1395 'post_type' => EWP_POST_TYPE,
1396 'posts_per_page' => -1,
1397 'fields' => 'ids'
1398 );
1399
1400 if (!empty($exporter_ids)) {
1401 $query_data['post__in'] = $exporter_ids;
1402 }
1403
1404 $query = new \WP_Query($query_data);
1405
1406 if (!empty($query->posts)) {
1407 foreach ($query->posts as $post_id) {
1408
1409 $exporter = $this->exporter_manager->get_exporter($post_id);
1410 $status = $exporter->get_status();
1411 $status['id'] = $post_id;
1412 $status['version'] = 2;
1413
1414 $output = '';
1415
1416 switch ($status['status']) {
1417 case 'cancelled':
1418 $output .= 'Export cancelled';
1419 break;
1420 case 'complete':
1421 $output .= 'Export complete';
1422 break;
1423 case 'running':
1424 $output .= 'Exporting: ' . $status['count'] . '/' . $status['total'];
1425 break;
1426 }
1427
1428 $status['message'] = $output;
1429
1430 $result[] = $this->event_handler->run('iwp/exporter/status/output', [$status, $exporter]);
1431 }
1432 }
1433
1434 echo json_encode($result) . "\n";
1435 die();
1436 }
1437 }
1438