UNPKG

@crowdin/app-project-module

Version:

Module that generates for you all common endpoints for serving standalone Crowdin App

636 lines (635 loc) 33.6 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.runJob = runJob; exports.runUpdateProviderJob = runUpdateProviderJob; exports.filesCron = filesCron; exports.filterFilesFromIntegrationRequest = filterFilesFromIntegrationRequest; exports.createOrUpdateSyncSettings = createOrUpdateSyncSettings; exports.removeFinishedJobs = removeFinishedJobs; const storage_1 = require("../../../storage"); const token_1 = require("../../../util/app-functions/token"); const connection_1 = require("../../../util/connection"); const logger_1 = require("../../../util/logger"); const subscription_1 = require("../../../util/subscription"); const types_1 = require("../types"); const defaults_1 = require("./defaults"); const files_1 = require("./files"); const job_1 = require("./job"); const snapshot_1 = require("./snapshot"); const types_2 = require("./types"); function runJob(_a) { return __awaiter(this, arguments, void 0, function* ({ config, integration, job, }) { (0, logger_1.log)(`Starting cron job with expression [${job.expression}]`); const crowdinCredentialsList = yield (0, storage_1.getStorage)().getAllCrowdinCredentials(); yield Promise.all(crowdinCredentialsList.map((crowdinCredentials) => __awaiter(this, void 0, void 0, function* () { const { token, client: crowdinClient } = yield (0, connection_1.prepareCrowdinClient)({ config, credentials: crowdinCredentials, autoRenew: true, }); const { expired } = yield (0, subscription_1.checkSubscription)({ config, token, organization: crowdinCredentials.id, accountType: crowdinCredentials.type, }); if (expired) { (0, logger_1.log)(`Subscription expired. Skipping job [${job.expression}] for organization ${crowdinCredentials.id}`); return; } const integrationCredentialsList = yield (0, storage_1.getStorage)().getAllIntegrationCredentials(crowdinCredentials.id); const allIntegrationConfigs = yield (0, storage_1.getStorage)().getAllIntegrationConfigs(crowdinCredentials.id); for (const integrationCredentials of integrationCredentialsList) { const integrationConfig = allIntegrationConfigs.find(({ integrationId }) => integrationId === integrationCredentials.id); const projectId = (0, token_1.getProjectId)(integrationCredentials.id); const credentials = yield (0, connection_1.prepareIntegrationCredentials)(config, integration, integrationCredentials); const rootFolder = yield (0, defaults_1.getRootFolder)(config, integration, crowdinClient, projectId); const intConfig = (integrationConfig === null || integrationConfig === void 0 ? void 0 : integrationConfig.config) ? JSON.parse(integrationConfig.config) : undefined; (0, logger_1.log)(`Executing task for cron job with expression [${job.expression}] for project ${projectId}`); yield job.task({ projectId, client: crowdinClient, credentials, rootFolder, settings: intConfig, }); (0, logger_1.log)(`Task for cron job with expression [${job.expression}] for project ${projectId} completed`); } }))); (0, logger_1.log)(`Cron job with expression [${job.expression}] completed`); }); } function runUpdateProviderJob(_a) { return __awaiter(this, arguments, void 0, function* ({ integrationId, crowdinId, type, title, payload, jobType, projectId, client, integration, context, credentials, rootFolder, settings, reRunJobId, initiatedBy, }) { try { yield (0, job_1.runAsJob)({ integrationId, crowdinId, type, title, payload, jobType, projectId, client, reRunJobId, initiatedBy, jobStoreType: integration.jobStoreType, jobCallback: (job) => __awaiter(this, void 0, void 0, function* () { if (type === types_2.JobType.UPDATE_TO_CROWDIN) { yield integration.updateCrowdin({ projectId, client, credentials, request: payload, rootFolder, settings, job, }); try { yield (0, files_1.updateSyncedData)(integrationId, crowdinId, payload, types_1.Provider.INTEGRATION); } catch (e) { (0, logger_1.logError)(e, context); } } else if (type === types_2.JobType.UPDATE_TO_INTEGRATION) { yield integration.updateIntegration({ projectId, client, credentials, request: payload, rootFolder, settings, job, }); } }), }); } catch (e) { const action = type === types_2.JobType.UPDATE_TO_CROWDIN ? 'Auto sync files to Crowdin' : 'Auto sync files to External Service'; yield (0, logger_1.handleUserError)({ action, error: e, crowdinId: crowdinId, clientId: integrationId, }); (0, logger_1.logError)(e, context); throw e; } }); } function filesCron(_a) { return __awaiter(this, arguments, void 0, function* ({ config, integration, period, }) { (0, logger_1.log)(`Starting files cron job with period [${period}]`); const syncSettingsList = yield (0, storage_1.getStorage)().getSyncSettingsBySchedule('schedule', period); const crowdinSyncSettings = syncSettingsList.filter((syncSettings) => syncSettings.provider === types_1.Provider.CROWDIN); const integrationSyncSettings = syncSettingsList.filter((syncSettings) => syncSettings.provider === types_1.Provider.INTEGRATION); const crowdinResults = yield Promise.allSettled(crowdinSyncSettings.map((syncSettings) => processSyncSettings({ config, integration, period, syncSettings }))); crowdinResults.forEach((result) => { if (result.status === 'rejected') { (0, logger_1.logError)(result.reason); } }); const integrationResults = yield Promise.allSettled(integrationSyncSettings.map((syncSettings) => processSyncSettings({ config, integration, period, syncSettings }))); integrationResults.forEach((result) => { if (result.status === 'rejected') { (0, logger_1.logError)(result.reason); } }); (0, logger_1.log)(`Files cron job with period [${period}] completed`); }); } function processSyncSettings(_a) { return __awaiter(this, arguments, void 0, function* ({ config, integration, period, syncSettings, }) { var _b, _c, _d, _e; let projectData; let crowdinClient; let token; let files = (0, files_1.prepareSyncFiles)(JSON.parse(syncSettings.files)); let newFiles = []; const crowdinCredentials = yield (0, storage_1.getStorage)().getCrowdinCredentials(syncSettings.crowdinId); const integrationCredentials = yield (0, storage_1.getStorage)().getIntegrationCredentials(syncSettings.integrationId); const integrationConfig = yield (0, storage_1.getStorage)().getIntegrationConfig(syncSettings.integrationId); if (!crowdinCredentials || !integrationCredentials) { return; } const intConfig = (integrationConfig === null || integrationConfig === void 0 ? void 0 : integrationConfig.config) ? JSON.parse(integrationConfig.config) : { schedule: '0', condition: '0' }; if (period !== intConfig.schedule) { return; } const projectId = (0, token_1.getProjectId)(integrationCredentials.id); const context = { jwtPayload: { context: { project_id: projectId, organization_id: crowdinCredentials.organizationId, organization_domain: crowdinCredentials.domain, user_id: crowdinCredentials.userId, }, }, crowdinId: crowdinCredentials.id, clientId: integrationCredentials.id, }; const logInfo = (0, logger_1.withContext)(context); try { const preparedCrowdinClient = yield (0, connection_1.prepareCrowdinClient)({ config, credentials: crowdinCredentials, autoRenew: true, context, }); token = preparedCrowdinClient.token; crowdinClient = preparedCrowdinClient.client; } catch (e) { intConfig.schedule = '0'; yield (0, storage_1.getStorage)().updateIntegrationConfig(syncSettings.integrationId, JSON.stringify(intConfig)); logInfo(`Auto-sync has been disabled for organization '${crowdinCredentials.id}'.`); (0, logger_1.logError)(e, context); return; } const { expired } = yield (0, subscription_1.checkSubscription)({ config, token, organization: crowdinCredentials.id, accountType: crowdinCredentials.type, }); if (expired) { (0, logger_1.log)(`Subscription expired. Skipping job [${period}] for organization ${crowdinCredentials.id}`); return; } try { projectData = (yield crowdinClient.projectsGroupsApi.getProject(projectId)) .data; } catch (e) { (0, logger_1.logError)(e, context); return; } context.jwtPayload.context.project_identifier = projectData.identifier; const rootFolder = yield (0, defaults_1.getRootFolder)(config, integration, crowdinClient, projectId); const credentials = yield (0, connection_1.prepareIntegrationCredentials)(config, integration, integrationCredentials); let currentFileSnapshot = []; let needsSnapshotForNewFiles = !integration.webhooks && ((_b = integration.syncNewElements) === null || _b === void 0 ? void 0 : _b[syncSettings.provider]) && (intConfig[`new-${syncSettings.provider}-files`] || (0, files_1.hasFolders)(files)); if (!needsSnapshotForNewFiles && !integration.webhooks && ((_c = integration.syncNewElements) === null || _c === void 0 ? void 0 : _c[syncSettings.provider]) && syncSettings.provider === types_1.Provider.CROWDIN) { currentFileSnapshot = yield (0, snapshot_1.getCrowdinSnapshot)(config, integration, crowdinClient, projectData.id, intConfig); const syncedFileIds = Object.keys(files); const hasSyncedFolders = currentFileSnapshot.some((file) => !('type' in file) && syncedFileIds.includes(String(file.id))); if (hasSyncedFolders) { needsSnapshotForNewFiles = true; } } const needsIntegrationSnapshot = needsSnapshotForNewFiles && syncSettings.provider !== types_1.Provider.CROWDIN; const needsCrowdinSnapshot = needsSnapshotForNewFiles && syncSettings.provider === types_1.Provider.CROWDIN && currentFileSnapshot.length === 0; if (needsIntegrationSnapshot) { currentFileSnapshot = yield (0, snapshot_1.getIntegrationSnapshot)({ integration, integrationCredentials: credentials, integrationSettings: intConfig, client: crowdinClient, projectId: projectData.id, }); } else if (needsCrowdinSnapshot) { currentFileSnapshot = yield (0, snapshot_1.getCrowdinSnapshot)(config, integration, crowdinClient, projectData.id, intConfig); } if (needsSnapshotForNewFiles) { try { newFiles = yield getAllNewFiles({ crowdinId: crowdinCredentials.id, integrationId: integrationCredentials.id, projectData, integrationSettings: intConfig, syncSettings, currentFileSnapshot, }); } catch (e) { (0, logger_1.logError)(e, context); return; } } if (integration.webhooks) { const webhooks = yield (0, storage_1.getStorage)().getAllWebhooks(syncSettings.integrationId, syncSettings.crowdinId, syncSettings.provider); const webhooksFileIds = (webhooks || []).map((webhook) => webhook.fileId); if (syncSettings.provider === types_1.Provider.CROWDIN) { files = webhooksFileIds.reduce((acc, fileId) => { if (files[fileId]) { acc[fileId] = files[fileId]; } return acc; }, {}); } else { files = files.filter((file) => webhooksFileIds.includes(file.id)); } yield (0, storage_1.getStorage)().deleteWebhooks(webhooksFileIds, syncSettings.integrationId, syncSettings.crowdinId, syncSettings.provider); } if (syncSettings.provider === types_1.Provider.CROWDIN) { const crowdinFiles = yield filterFilesFromIntegrationRequest({ config, integration, projectId, crowdinFiles: Object.assign(Object.assign({}, files), newFiles), crowdinClient, }); const onlyTranslated = +intConfig.condition === types_1.SyncCondition.TRANSLATED; const onlyApproved = +intConfig.condition === types_1.SyncCondition.APPROVED; const all = +intConfig.condition === types_1.SyncCondition.ALL || intConfig.condition === undefined; let filesToProcess; let deletedFileIds = []; if (all) { filesToProcess = crowdinFiles; } else { const result = yield getOnlyTranslatedOrApprovedFiles({ projectId, crowdinFiles, crowdinClient, onlyApproved, onlyTranslated, context, integration, }); filesToProcess = result.filteredFiles; deletedFileIds = result.deletedFiles; } if (deletedFileIds.length > 0) { (0, logger_1.log)(`Removing ${deletedFileIds.length} deleted files from sync settings`); const updatedFiles = Object.assign({}, files); for (const fileId of deletedFileIds) { delete updatedFiles[fileId]; } yield (0, storage_1.getStorage)().updateSyncSettings(JSON.stringify(updatedFiles), syncSettings.integrationId, syncSettings.crowdinId, 'schedule', types_1.Provider.CROWDIN); files = updatedFiles; } if (Object.keys(filesToProcess).length <= 0) { return; } (0, logger_1.log)(`Executing updateIntegration task for files cron job with period [${period}] for project ${projectId}.Files ${Object.keys(filesToProcess).length}`); if (!all) { if (Object.keys(filesToProcess).length === 0) { (0, logger_1.log)(`There is no ${onlyApproved ? 'approved' : 'translated'} file`); return; } } const credentials = yield (0, connection_1.prepareIntegrationCredentials)(config, integration, integrationCredentials); if (!(intConfig === null || intConfig === void 0 ? void 0 : intConfig.inContext)) { removeInContextLanguage(filesToProcess, projectData); } try { yield runUpdateProviderJob({ integrationId: syncSettings.integrationId, crowdinId: syncSettings.crowdinId, type: types_2.JobType.UPDATE_TO_INTEGRATION, title: `Sync files to ${config.name} [scheduled]`, payload: filesToProcess, jobType: types_2.JobClientType.CRON, projectId: projectId, client: crowdinClient, integration, context, credentials, rootFolder, settings: intConfig, initiatedBy: 'autosync', }); } catch (e) { return; } if (Object.keys(newFiles).length) { yield (0, storage_1.getStorage)().updateSyncSettings(JSON.stringify(Object.assign(Object.assign({}, files), newFiles)), syncSettings.integrationId, syncSettings.crowdinId, 'schedule', syncSettings.provider); const currentFileSnapshot = yield (0, snapshot_1.getCrowdinSnapshot)(config, integration, crowdinClient, projectId, intConfig); yield (0, storage_1.getStorage)().updateFilesSnapshot(JSON.stringify(currentFileSnapshot), syncSettings.integrationId, syncSettings.crowdinId, syncSettings.provider); } (0, logger_1.log)(`updateIntegration task for files cron job with period [${period}] for project ${projectId} completed`); } else { const allIntFiles = [...files, ...newFiles].map((file) => (Object.assign({ id: file.id, name: file.name, parentId: file.parent_id || file.parentId, parent_id: file.parent_id || file.parentId, node_type: file.nodeType || file.node_type }, (file.type ? { type: file.type } : {})))); let intFiles = allIntFiles.filter((file) => 'type' in file); if (integration.forcePushSources === true && currentFileSnapshot.length > 0) { const snapshotMap = new Map(currentFileSnapshot.map((f) => [f.id, f])); intFiles = intFiles.map((file) => { const snapshotFile = snapshotMap.get(file.id); if (snapshotFile) { return Object.assign(Object.assign({}, file), { updatedAt: snapshotFile.updatedAt, createdAt: snapshotFile.createdAt }); } return file; }); intFiles = yield (0, files_1.attachFileStatus)(intFiles, syncSettings.integrationId, syncSettings.crowdinId, integration); intFiles = intFiles.filter((file) => file.isUpdated !== false); } if (intFiles.length <= 0) { return; } (0, logger_1.log)(`Executing updateCrowdin task for files cron job with period [${period}] for project ${projectId}. Files ${intFiles.length}`); const credentials = yield (0, connection_1.prepareIntegrationCredentials)(config, integration, integrationCredentials); if (integration.filterByPathIntegrationFiles) { const includePatterns = (_d = intConfig === null || intConfig === void 0 ? void 0 : intConfig.includeByFilePath) === null || _d === void 0 ? void 0 : _d.split('\n').filter(Boolean); const excludePatterns = (_e = intConfig === null || intConfig === void 0 ? void 0 : intConfig.excludeByFilePath) === null || _e === void 0 ? void 0 : _e.split('\n').filter(Boolean); try { const fullTreeResult = yield integration.getIntegrationFiles({ credentials, client: crowdinClient, projectId: projectId, settings: intConfig, }); const fullTree = (0, files_1.isExtendedResultType)(fullTreeResult) ? fullTreeResult.data || [] : fullTreeResult; const filteredFiles = (0, files_1.filterFilesByPath)(fullTree, includePatterns, excludePatterns); const filteredFileIds = new Set(filteredFiles.map((f) => f.id)); const filteredIntFiles = intFiles.filter((file) => filteredFileIds.has(file.id)); (0, logger_1.log)(`Path filtering applied: ${intFiles.length} -> ${filteredIntFiles.length} files`); if (filteredIntFiles.length === 0) { (0, logger_1.log)('No files passed path filtering, skipping sync'); return; } intFiles = filteredIntFiles; } catch (e) { (0, logger_1.logError)(e, context); } } try { yield runUpdateProviderJob({ integrationId: syncSettings.integrationId, crowdinId: syncSettings.crowdinId, type: types_2.JobType.UPDATE_TO_CROWDIN, title: 'Sync files to Crowdin [scheduled]', payload: intFiles, jobType: types_2.JobClientType.CRON, projectId: projectId, client: crowdinClient, integration, context, credentials, rootFolder, settings: intConfig, initiatedBy: 'autosync', }); } catch (e) { return; } if (Object.keys(newFiles).length) { const newSyncSettingsFields = allIntFiles.map((file) => (Object.assign(Object.assign({}, file), { schedule: true, sync: false }))); yield (0, storage_1.getStorage)().updateSyncSettings(JSON.stringify(newSyncSettingsFields), syncSettings.integrationId, syncSettings.crowdinId, 'schedule', syncSettings.provider); const currentFileSnapshot = yield (0, snapshot_1.getIntegrationSnapshot)({ integration, integrationCredentials: credentials, integrationSettings: intConfig, client: crowdinClient, projectId, }); yield (0, storage_1.getStorage)().updateFilesSnapshot(JSON.stringify(currentFileSnapshot), syncSettings.integrationId, syncSettings.crowdinId, syncSettings.provider); } (0, logger_1.log)(`updateCrowdin task for files cron job with period [${period}] for project ${projectId} completed`); } }); } function getFileDiff(currentFiles, savedFiles) { return currentFiles.filter((x) => !savedFiles.some((x2) => x2.id === x.id)); } function getAllNewFiles(_a) { return __awaiter(this, arguments, void 0, function* ({ crowdinId, integrationId, projectData, integrationSettings, syncSettings, currentFileSnapshot, }) { const fileSnapshotData = yield (0, storage_1.getStorage)().getFilesSnapshot(integrationId, crowdinId, syncSettings.provider); const snapshotFiles = (fileSnapshotData === null || fileSnapshotData === void 0 ? void 0 : fileSnapshotData.files) ? JSON.parse(fileSnapshotData.files) : []; const difference = getFileDiff(currentFileSnapshot, snapshotFiles); const onlyFiles = difference.filter((file) => 'type' in file); const synFiles = (0, files_1.prepareSyncFiles)(JSON.parse(syncSettings.files)); if (syncSettings.provider === types_1.Provider.INTEGRATION) { if (integrationSettings[`new-${syncSettings.provider}-files`]) { return onlyFiles; } const syncFolders = synFiles.filter((file) => !('type' in file)); return getNewFoldersFile(syncFolders, difference); } else { const files = {}; const targetLanguages = projectData.targetLanguageIds; if (projectData.inContext) { targetLanguages.push(projectData.inContextPseudoLanguageId); } if (integrationSettings[`new-${syncSettings.provider}-files`]) { for (const file of onlyFiles) { files[file.id] = targetLanguages; } } else { const syncFolders = currentFileSnapshot.filter((file) => !('type' in file) && Object.keys(synFiles).includes(file.id)); const newFiles = getNewFoldersFile(syncFolders, difference); for (const file of newFiles) { files[file.id] = targetLanguages; } } return files; } }); } function getNewFoldersFile(folders, snapshotFiles) { let files = []; for (const folder of folders) { const folderFiles = snapshotFiles.filter((file) => Number(file.parentId) === Number(folder.id)); if (folderFiles.length) { files = files.concat(folderFiles); } } files = files.filter((file) => 'type' in file); return files; } function getOnlyTranslatedOrApprovedFiles(_a) { return __awaiter(this, arguments, void 0, function* ({ projectId, crowdinFiles, crowdinClient, onlyApproved, onlyTranslated, context, integration, }) { const deletedFiles = []; (0, logger_1.log)(`Filtering files to process only ${onlyApproved ? 'approved' : 'translated'} files`); const filesInfo = yield Promise.all(Object.keys(crowdinFiles).map((fileId) => __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d, _e; try { let info; if (integration.getFileProgress) { const progress = yield integration.getFileProgress({ projectId, client: crowdinClient, fileId: Number(fileId), }); info = (_b = (_a = progress[Number(fileId)]) !== null && _a !== void 0 ? _a : progress[fileId]) !== null && _b !== void 0 ? _b : []; } else { const res = yield crowdinClient.translationStatusApi .withFetchAll() .getFileProgress(projectId, Number(fileId)); info = res.data.map((e) => e.data); } return { id: fileId, info, }; } catch (e) { delete crowdinFiles[fileId]; const status = (_e = (_d = (_c = e === null || e === void 0 ? void 0 : e.response) === null || _c === void 0 ? void 0 : _c.status) !== null && _d !== void 0 ? _d : e === null || e === void 0 ? void 0 : e.status) !== null && _e !== void 0 ? _e : e === null || e === void 0 ? void 0 : e.code; if (status === 404) { (0, logger_1.log)(`File ${fileId} not found in Crowdin (404), marking for removal from sync settings`); deletedFiles.push(Number(fileId)); } else { (0, logger_1.logError)(e, context); } } }))); const filteredFiles = {}; Object.keys(crowdinFiles).forEach((fileId) => { const fileInfo = filesInfo.find((info) => (info === null || info === void 0 ? void 0 : info.id) === fileId); if (!fileInfo) { return; } const languages = crowdinFiles[fileId]; languages.forEach((language) => { const languageInfo = fileInfo.info.find((info) => info.languageId === language); if (!languageInfo) { return; } if (onlyTranslated) { if (languageInfo.translationProgress === 100) { (0, logger_1.log)(`File ${fileId} is fully translated for language ${language}`); if (!filteredFiles[fileId]) { filteredFiles[fileId] = []; } filteredFiles[fileId].push(language); } else { (0, logger_1.log)(`File ${fileId} is not fully translated for language ${language}, progress ${languageInfo.translationProgress}`); } } if (onlyApproved) { if (languageInfo.approvalProgress === 100) { (0, logger_1.log)(`File ${fileId} is fully approved for language ${language}`); if (!filteredFiles[fileId]) { filteredFiles[fileId] = []; } filteredFiles[fileId].push(language); } else { (0, logger_1.log)(`File ${fileId} is not fully approved for language ${language}, progress ${languageInfo.approvalProgress}`); } } }); }); return { filteredFiles, deletedFiles }; }); } function filterFilesFromIntegrationRequest(_a) { return __awaiter(this, arguments, void 0, function* ({ config, integration, projectId, crowdinClient, crowdinFiles, }) { var _b; if (integration.skipAutoSyncFoldersFilter) { return crowdinFiles; } let folders; if ((_b = config.projectIntegration) === null || _b === void 0 ? void 0 : _b.withRootFolder) { const rootFolder = yield (0, defaults_1.getRootFolder)(config, integration, crowdinClient, projectId); if (rootFolder) { folders = (yield crowdinClient.sourceFilesApi.withFetchAll().listProjectDirectories(projectId, { directoryId: rootFolder.id, recursion: 'true', })).data; } } else { folders = (yield crowdinClient.sourceFilesApi.withFetchAll().listProjectDirectories(projectId, { recursion: 'true' })).data; } if (folders) { for (const fileId of Object.keys(crowdinFiles)) { if (folders.find((folder) => folder.data.id === +fileId)) { delete crowdinFiles[fileId]; } } } return crowdinFiles; }); } function createOrUpdateSyncSettings(_a) { return __awaiter(this, arguments, void 0, function* ({ req, files, provider, onlyCreate = false, }) { const existingSettings = yield (0, storage_1.getStorage)().getSyncSettings(req.crowdinContext.clientId, req.crowdinContext.crowdinId, 'schedule', provider); if (!existingSettings) { (0, logger_1.log)(`Saving sync settings for type schedule and provider ${provider} ${JSON.stringify(files, null, 2)}`); yield (0, storage_1.getStorage)().saveSyncSettings(JSON.stringify(files), req.crowdinContext.clientId, req.crowdinContext.crowdinId, 'schedule', provider); } else if (!onlyCreate) { (0, logger_1.log)(`Updating sync settings for type schedule and provider ${provider} ${JSON.stringify(files, null, 2)}`); yield (0, storage_1.getStorage)().updateSyncSettings(JSON.stringify(files), req.crowdinContext.clientId, req.crowdinContext.crowdinId, 'schedule', provider); } }); } function removeFinishedJobs() { return __awaiter(this, void 0, void 0, function* () { (0, logger_1.log)('Removing all finished jobs'); yield (0, storage_1.getStorage)().deleteFinishedJobs(); (0, logger_1.log)('Removed all finished jobs'); }); } function removeInContextLanguage(filesToProcess, projectData) { (0, logger_1.log)('Removing in-context language from files to process'); if (!projectData.inContext) { return; } for (const fileId in filesToProcess) { filesToProcess[fileId] = filesToProcess[fileId].filter((language) => language !== projectData.inContextPseudoLanguageId); } (0, logger_1.log)('In-context language(' + projectData.inContextPseudoLanguageId + ') removed from files to process'); }