303 lines
9.1 KiB
JavaScript
303 lines
9.1 KiB
JavaScript
/**
|
|
* Copyright since 2007 PrestaShop SA and Contributors
|
|
* PrestaShop is an International Registered Trademark & Property of PrestaShop SA
|
|
*
|
|
* NOTICE OF LICENSE
|
|
*
|
|
* This source file is subject to the Open Software License (OSL 3.0)
|
|
* that is bundled with this package in the file LICENSE.md.
|
|
* It is also available through the world-wide-web at this URL:
|
|
* https://opensource.org/licenses/OSL-3.0
|
|
* If you did not receive a copy of the license and are unable to
|
|
* obtain it through the world-wide-web, please send an email
|
|
* to license@prestashop.com so we can send you a copy immediately.
|
|
*
|
|
* DISCLAIMER
|
|
*
|
|
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
|
|
* versions in the future. If you wish to customize PrestaShop for your
|
|
* needs please refer to https://devdocs.prestashop.com/ for more information.
|
|
*
|
|
* @author PrestaShop SA and Contributors <contact@prestashop.com>
|
|
* @copyright Since 2007 PrestaShop SA and Contributors
|
|
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
|
|
*/
|
|
|
|
import ImportProgressModal from './ImportProgressModal';
|
|
import ImportBatchSizeCalculator from './ImportBatchSizeCalculator';
|
|
import PostSizeChecker from './PostSizeChecker';
|
|
|
|
export default class Importer {
|
|
constructor() {
|
|
this.configuration = {};
|
|
this.progressModal = new ImportProgressModal();
|
|
this.batchSizeCalculator = new ImportBatchSizeCalculator();
|
|
this.postSizeChecker = new PostSizeChecker();
|
|
|
|
// Default number of rows in one batch of the import.
|
|
this.defaultBatchSize = 5;
|
|
}
|
|
|
|
/**
|
|
* Process the import.
|
|
*
|
|
* @param {String} importUrl url of the controller, processing the import.
|
|
* @param {Object} configuration import configuration.
|
|
*/
|
|
import(importUrl, configuration) {
|
|
this.mergeConfiguration(configuration);
|
|
this.importUrl = importUrl;
|
|
|
|
// Total number of rows to be imported.
|
|
this.totalRowsCount = 0;
|
|
|
|
// Flags that mark that there were warnings or errors during import.
|
|
this.hasWarnings = false;
|
|
this.hasErrors = false;
|
|
|
|
// Resetting the import progress modal and showing it.
|
|
this.progressModal.reset();
|
|
this.progressModal.show();
|
|
|
|
// Starting the import with default batch size, which is adjusted for next iterations.
|
|
this.ajaxImport(0, this.defaultBatchSize);
|
|
}
|
|
|
|
/**
|
|
* Process the ajax import request.
|
|
*
|
|
* @param {number} offset row number, from which the import job will start processing data.
|
|
* @param {number} batchSize batch size of this import job.
|
|
* @param {boolean} validateOnly whether the data should be only validated, if false - the data will be imported.
|
|
* @param {Object} recurringVariables variables which are recurring between import batch jobs.
|
|
* @private
|
|
*/
|
|
ajaxImport(offset, batchSize, validateOnly = true, recurringVariables = {}) {
|
|
this.mergeConfiguration({
|
|
offset,
|
|
limit: batchSize,
|
|
validateOnly: validateOnly ? 1 : 0,
|
|
crossStepsVars: JSON.stringify(recurringVariables),
|
|
});
|
|
|
|
this.onImportStart();
|
|
|
|
$.post({
|
|
url: this.importUrl,
|
|
dataType: 'json',
|
|
data: this.configuration,
|
|
success: (response) => {
|
|
if (this.importCancelRequested) {
|
|
this.cancelImport();
|
|
return false;
|
|
}
|
|
|
|
const hasErrors = response.errors && response.errors.length;
|
|
const hasWarnings = response.warnings && response.warnings.length;
|
|
const hasNotices = response.notices && response.notices.length;
|
|
|
|
if (response.totalCount !== undefined && response.totalCount) {
|
|
// The total rows count is retrieved only in the first batch response.
|
|
this.totalRowsCount = response.totalCount;
|
|
}
|
|
|
|
// Update import progress.
|
|
this.progressModal.updateProgress(response.doneCount, this.totalRowsCount);
|
|
|
|
if (!validateOnly) {
|
|
// Set the progress label to "Importing".
|
|
this.progressModal.setImportingProgressLabel();
|
|
}
|
|
|
|
// Information messages are not shown during validation.
|
|
if (!validateOnly && hasNotices) {
|
|
this.progressModal.showInfoMessages(response.notices);
|
|
}
|
|
|
|
if (hasErrors) {
|
|
this.hasErrors = true;
|
|
this.progressModal.showErrorMessages(response.errors);
|
|
|
|
// If there are errors and it's not validation step - stop the import.
|
|
// If it's validation step - we will show all errors once it finishes.
|
|
if (!validateOnly) {
|
|
this.onImportStop();
|
|
return false;
|
|
}
|
|
} else if (hasWarnings) {
|
|
this.hasWarnings = true;
|
|
this.progressModal.showWarningMessages(response.warnings);
|
|
}
|
|
|
|
if (!response.isFinished) {
|
|
// Marking the end of import operation.
|
|
this.batchSizeCalculator.markImportEnd();
|
|
|
|
// Calculate next import batch size and offset.
|
|
const nextOffset = offset + batchSize;
|
|
const nextBatchSize = this.batchSizeCalculator.calculateBatchSize(batchSize, this.totalRowsCount);
|
|
|
|
// Showing a warning if post size limit is about to be reached.
|
|
if (this.postSizeChecker.isReachingPostSizeLimit(response.postSizeLimit, response.nextPostSize)) {
|
|
this.progressModal.showPostLimitMessage(
|
|
this.postSizeChecker.getRequiredPostSizeInMegabytes(response.nextPostSize),
|
|
);
|
|
}
|
|
|
|
// Run the import again for the next batch.
|
|
return this.ajaxImport(
|
|
nextOffset,
|
|
nextBatchSize,
|
|
validateOnly,
|
|
response.crossStepsVariables,
|
|
);
|
|
}
|
|
|
|
// All import batches are finished successfully.
|
|
// If it was only validating the import data until this point,
|
|
// we have to run the data import now.
|
|
if (validateOnly) {
|
|
// If errors occurred during validation - stop the import.
|
|
if (this.hasErrors) {
|
|
this.onImportStop();
|
|
return false;
|
|
}
|
|
|
|
if (this.hasWarnings) {
|
|
// Show the button to ignore warnings.
|
|
this.progressModal.showContinueImportButton();
|
|
this.onImportStop();
|
|
return false;
|
|
}
|
|
|
|
// Update the progress bar to 100%.
|
|
this.progressModal.updateProgress(this.totalRowsCount, this.totalRowsCount);
|
|
|
|
// Continue with the data import.
|
|
return this.ajaxImport(0, this.defaultBatchSize, false);
|
|
}
|
|
|
|
// Import is completely finished.
|
|
return this.onImportFinish();
|
|
},
|
|
error: (XMLHttpRequest, textStatus) => {
|
|
let txt = textStatus;
|
|
|
|
if (txt === 'parsererror') {
|
|
txt = 'Technical error: Unexpected response returned by server. Import stopped.';
|
|
}
|
|
|
|
this.onImportStop();
|
|
this.progressModal.showErrorMessages([txt]);
|
|
},
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Continue the import when it was stopped.
|
|
*/
|
|
continueImport() {
|
|
if (!this.configuration) {
|
|
throw new Error('Missing import configuration. Make sure the import had started before continuing.');
|
|
}
|
|
|
|
this.progressModal.hideContinueImportButton();
|
|
this.progressModal.hideCloseModalButton();
|
|
this.progressModal.clearWarningMessages();
|
|
this.ajaxImport(0, this.defaultBatchSize, false);
|
|
}
|
|
|
|
/**
|
|
* Set the import configuration.
|
|
*
|
|
* @param importConfiguration
|
|
*/
|
|
set configuration(importConfiguration) {
|
|
this.importConfiguration = importConfiguration;
|
|
}
|
|
|
|
/**
|
|
* Get the import configuration.
|
|
*
|
|
* @returns {*}
|
|
*/
|
|
get configuration() {
|
|
return this.importConfiguration;
|
|
}
|
|
|
|
/**
|
|
* Set progress modal.
|
|
*
|
|
* @param {ImportProgressModal} modal
|
|
*/
|
|
set progressModal(modal) {
|
|
this.modal = modal;
|
|
}
|
|
|
|
/**
|
|
* Get progress modal.
|
|
*
|
|
* @returns {ImportProgressModal}
|
|
*/
|
|
get progressModal() {
|
|
return this.modal;
|
|
}
|
|
|
|
/**
|
|
* Request import cancellation.
|
|
* Import operation will be cancelled at next iteration when requested.
|
|
*/
|
|
requestCancelImport() {
|
|
this.importCancelRequested = true;
|
|
}
|
|
|
|
/**
|
|
* Merge given configuration into current import configuration.
|
|
*
|
|
* @param {Object} configuration
|
|
* @private
|
|
*/
|
|
mergeConfiguration(configuration) {
|
|
this.importConfiguration = {...this.importConfiguration, ...configuration};
|
|
}
|
|
|
|
/**
|
|
* Cancel the import process.
|
|
* @private
|
|
*/
|
|
cancelImport() {
|
|
this.progressModal.hide();
|
|
this.importCancelRequested = false;
|
|
}
|
|
|
|
/**
|
|
* Additional actions when import is stopped.
|
|
* @private
|
|
*/
|
|
onImportStop() {
|
|
this.progressModal.showCloseModalButton();
|
|
this.progressModal.hideAbortImportButton();
|
|
}
|
|
|
|
/**
|
|
* Additional actions when import is finished.
|
|
* @private
|
|
*/
|
|
onImportFinish() {
|
|
this.onImportStop();
|
|
this.progressModal.showSuccessMessage();
|
|
this.progressModal.setImportedProgressLabel();
|
|
this.progressModal.updateProgress(this.totalRowsCount, this.totalRowsCount);
|
|
}
|
|
|
|
/**
|
|
* Additional actions when import is starting.
|
|
* @private
|
|
*/
|
|
onImportStart() {
|
|
// Marking the start of import operation.
|
|
this.batchSizeCalculator.markImportStart();
|
|
this.progressModal.showAbortImportButton();
|
|
}
|
|
}
|