Source: job-manager/sampleFileDownloader.js

Source: job-manager/sampleFileDownloader.js

/**
 * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
 * Licensed under the Universal Permissive License v 1.0 as shown at http://oss.oracle.com/licenses/upl.
 */
/* globals app, module, __dirname */
/* jshint esversion: 6 */
var translationProvider = require('../provider/translationProvider').factory.create(),
    filterApi = require('./translationFilter'),
    persistenceStore = require('./persistenceStore').factory.create(),
    fileImporter = require('./sampleFileImporter'),
    localeMap = require('./localeMap');


/**
 * Download all the translated files.<br/>
 * This involves downloading each file, merging the translated strings with the original file and creating a new file under the locale folder for the file.
 * @constructor
 * @alias SampleFileDownloader
 */
var SampleFileDownloader = function () {};


/**
 * Download the translated file from the Language Service Provider.<br/>
 * <ul>
 *   <li> For each target language: 
 *     <ul>
 *       <li>Download the translation for the targeted language.</li>
 *       <li>Merge the translation with the original file.</li>
 *       <li>Save the combined file under a folder named for the targeted locale.</li>
 *       <li>If the file is a binary file, then download the translated binary file to a folder named for the targeted locale.</li>
 *     </ul>
 *   </li>
 * </ul>
 * @param {SampleJobManager.JobConfig} jobConfig - The configuration of the connector job to run. This information is held as metadata in the connector for the job. 
 * @param {string} jobId - The job identifier that contains this file.
 * @param {SampleJobManager.file} file - Details on the site or assets file to import.
 * @param {('site'|'assets')} fileType - The type of file being imported.
 * @param {string} sourceLanguage - The source language for the file.
 * @param {string[]} targetLanguages - Array of target languages for the file.
 * @returns {Promise} A Promise that is resolved when all translations have been received.
 */
SampleFileDownloader.prototype.downloadFile = function (jobConfig, jobId, file, fileType, jobDetails) {
    var sourceLanguage = jobDetails.sourceLanguage,
        targetLanguages = jobDetails.targetLanguages;

    return new Promise(function (resolve, reject) {
        // ToDo: check if file has already been downloaded

        // get the file metadata
        persistenceStore.getFileMetadata({
            jobId: jobConfig.properties.id,
            fileType: fileType,
            file: file
        }).then(function (fileMetadata) {
            if (fileMetadata.folderPath) {
                // console.log('downloadFile binary file', fileMetadata.name);
                var translatedBinaryFilePromises = [];
                targetLanguages.forEach(function (targetLanguage) {
                    if (fileMetadata.documentId === fileImporter.EMPTY_DOCUMENT_ID) {

                        // See sampleFileImporter.js, importBinaryFile function.
                        console.log('SampleFileDownloader.downloadFile(): use original binary file for file -', file.name);
                        translatedBinaryFilePromises.push(persistenceStore.getBinaryFile({
                            jobId: jobId,
                            fileType: fileType,
                            file: file
                        }));
                    }
                    else {
                        translatedBinaryFilePromises.push(translationProvider.getBinaryTranslation(jobConfig.authToken, fileMetadata.documentId, targetLanguage));
                    }
                });
                Promise.all(translatedBinaryFilePromises).then(function (translatedBinaryFile) {
                    targetLanguages.forEach(function (targetLocale, index) {
                        if (translatedBinaryFile[index] && Object.keys(translatedBinaryFile[index]).length === 0) {
                            console.log('SampleFileDownloader.downloadFile(): no translated binary for file -', fileMetadata.name, 'for locale', targetLocale);
                            resolve();
                        }
                        else {
                            persistenceStore.addBinaryTranslationFile({
                                jobId: jobId,
                                locale: targetLocale,
                                fileType: fileType,
                                fileName: fileMetadata.name,
                                folderPath: fileMetadata.folderPath,
                                fileContent: translatedBinaryFile[index]
                            }).then(function () {
                                resolve();
                            }).catch(function (error) {
                                // failed to download translated file
                                console.log('SampleFileDownloader.downloadFile(): unable to persist binary translation file for file - ' + fileMetadata.name);
                                console.log(error);
                                reject(error);
                            });
                        }
                    });
                });
            }
            else {
                // read in the original file
                persistenceStore.getSourceFile({
                    jobId: jobId,
                    fileType: fileType,
                    filePath: fileMetadata.path
                }).then(function (fileContent) {
                    var originalFile = fileContent && fileContent.length > 0 ? JSON.parse(fileContent) : {};

                    // create promises to get all the translations for all the target languages
                    var translatedDocumentPromises = [];
                    targetLanguages.forEach(function (targetLanguage) {
                        if (targetLanguage === null) {
                            // handle unsupported locales
                            translatedDocumentPromises.push(Promise.resolve({}));
                        } else if (targetLanguage === sourceLanguage) {
                            // handle equivalent locales
                            translatedDocumentPromises.push(Promise.resolve({}));
                        } else if (fileMetadata.documentId === fileImporter.EMPTY_DOCUMENT_ID) {
                            // handle empty files
                            translatedDocumentPromises.push(Promise.resolve({}));
                        } else {
                            // handle translated file
                            translatedDocumentPromises.push(translationProvider.getTranslation(jobConfig.authToken, fileMetadata.documentId, targetLanguage));
                        }
                    });

                    // wait until we have all the translations
                    Promise.all(translatedDocumentPromises).then(function (translatedDocuments) {
                        // re-combine and save the translations
                        targetLanguages.forEach(function (targetLocale, index) {
                            // overwrite properties with the corresponding translations
                            var translation = filterApi.applyTranslation(originalFile, translatedDocuments[index], fileType);

                            // write this translation to all the original languages that map to this target locale
                            jobDetails.origTargetLanguages.forEach(function (origTargetLocale) {
                                var lspTargetLocale = localeMap.getLSPLocale(origTargetLocale);

                                // if this original locale maps to the lsp target locale
                                if (lspTargetLocale === targetLocale) {
                                    // add the file to the zip
                                    persistenceStore.addTranslationFile({
                                        jobId: jobId,
                                        locale: origTargetLocale,
                                        fileType: fileType,
                                        fileName: fileMetadata.path,
                                        fileContent: JSON.stringify(translation)
                                    }).then(function () {
                                        resolve();
                                    }).catch(function (error) {
                                        // failed to download translated file
                                        console.log('SampleFileDownloader.downloadFile(): unable to persist translation file for file - ' + fileMetadata.name);
                                        console.log(e.toString());
                                        reject(e);
                                    });
                                }
                            });
                        });
                    }).catch(function (error) {
                        // failed to download translated file
                        console.log('SampleFileDownloader.downloadFile(): unable to download translation file for file - ' + fileMetadata.name);
                        console.log(error && error.toString());
                        reject(error);
                    });
                }).catch(function (error) {
                    // failed to get original file
                    console.log('SampleFileDownloader.downloadFile(): unable to get original content for file - ' + fileMetadata.name);
                    console.log(error.toString());
                    reject(error);
                });
            }
        }).catch(function (error) {
            // failed to get metadata file
            console.log('SampleFileDownloader.downloadFile(): unable to get metadata for original file - ' + file.name);
            console.log(error && error.toString());
            reject(error);
        });
    });
};

/**
 * Create an array of Promises to download all the translations for all the files in the file list<br/>
 * The promises are chained in a "return p1.then(return p2.then(return p3.then(...)))"" model to avoid overloading the Language Service Provider. 
 * @param {('site'|'assets')} fileType - The type of file being downloaded.
 * @param {SampleJobManager.file} file - Details on the site or assets file to download.
 * @returns {function[]} An array of functions, each of which returns a promise that resolves when all the translations for the file are downloaded. 
 */
SampleFileDownloader.prototype.downloadFileList = function (jobConfig, jobDetails, fileType, files) {
    var self = this;

    // create the array of functions to return the import promises
    return (files || []).map(function (file) {
        return function () {
            return self.downloadFile(jobConfig, jobConfig.properties.id, file, fileType, jobDetails);
        };
    });
};

/**
 * Download all the translations for all the Site & Assets files into the Language Service Provider for this job <br/>
 * The promises are chained in a "return p1.then(return p2.then(return p3.then(...)))"" model to avoid overloading the Language Service Provider. 
 * @param {SampleJobManager.JobConfig} jobConfig - The configuration of the connector job to run. This information is held as metadata in the connector for the job. 
 * @param {SampleJobManager.JobDetails} jobDetails - The details of the combined job.json files.
 * @returns {Promise} A Promise that resolves when all files have been downloaded.
 */
SampleFileDownloader.prototype.downloadFiles = function (jobConfig, jobDetails) {
    var self = this;

    return new Promise(function (resolve, reject) {
        // make sure necessary files are there and then import all the jobJSON files
        if (jobDetails.sourceLanguage && jobDetails.targetLanguages) {
            // create a repository for the translations
            persistenceStore.createTranslationRepository({
                jobId: jobConfig.properties.id,
            }).then(function () {
                // download the files into the translation zip
                var downloadPromises = [];
                if (jobDetails.assets) {
                    downloadPromises = downloadPromises.concat(self.downloadFileList(jobConfig, jobDetails, 'assets', jobDetails.assets && jobDetails.assets.files));
                    downloadPromises = downloadPromises.concat(self.downloadFileList(jobConfig, jobDetails, 'assets', jobDetails.assets && jobDetails.assets.binaryFiles));
                }
                if (jobDetails.site) {
                    downloadPromises = downloadPromises.concat(self.downloadFileList(jobConfig, jobDetails, 'site', jobDetails.site && jobDetails.site.files));
                }

                // now run through and download all the files
                // chain the promises in the array so that they execute as: return p1.then(return p2.then(return p3.then(...)));
                var doDownload = downloadPromises.reduce(function (previousPromise, nextPromise) {
                        return previousPromise.then(function () {
                            // wait for the previous promise to complete and then return a new promise for the next 
                            return nextPromise();
                        });
                    },
                    // Start with a previousPromise value that is a resolved promise 
                    Promise.resolve());

                // once all files are downloaded, can continue
                doDownload.then(function () {
                    console.log('SampleFileDownloader.downloadFiles(): all files downloaded');
                    resolve();
                }).catch(function (e) {
                    console.log('SampleFileDownloader.downloadFiles(): error downloading files');
                    console.log(e);
                    reject(e);
                });
            });
        } else {
            reject('no target language specified in job.json files');
        }
    });
};

module.exports = new SampleFileDownloader();