@crowdin/app-project-module 0.63.2 → 0.65.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/index.d.ts +2 -0
- package/out/index.js +4 -2
- package/out/modules/integration/handlers/crowdin-project.js +8 -1
- package/out/modules/integration/handlers/user-errors.js +8 -1
- package/out/modules/integration/index.js +15 -1
- package/out/modules/integration/types.d.ts +4 -0
- package/out/modules/integration/util/cron.d.ts +19 -2
- package/out/modules/integration/util/cron.js +59 -39
- package/out/modules/integration/util/defaults.js +3 -0
- package/out/modules/integration/util/job.d.ts +4 -1
- package/out/modules/integration/util/job.js +155 -29
- package/out/modules/integration/util/types.d.ts +12 -6
- package/out/modules/integration/util/types.js +1 -0
- package/out/storage/index.d.ts +5 -2
- package/out/storage/mysql.d.ts +6 -3
- package/out/storage/mysql.js +42 -4
- package/out/storage/postgre.d.ts +7 -3
- package/out/storage/postgre.js +55 -5
- package/out/storage/sqlite.d.ts +7 -3
- package/out/storage/sqlite.js +42 -4
- package/out/util/credentials-masker.d.ts +1 -1
- package/out/util/credentials-masker.js +34 -32
- package/out/util/index.d.ts +3 -0
- package/out/util/index.js +25 -1
- package/out/util/logger.js +0 -6
- package/out/util/terminus-express.js +4 -2
- package/out/views/main.handlebars +11 -2
- package/package.json +1 -1
package/out/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Express } from 'express';
|
|
2
2
|
import { ClientConfig, Config, CrowdinAppUtilities, CrowdinMetadataStore } from './types';
|
|
3
3
|
import express from './util/terminus-express';
|
|
4
|
+
import { getRequestCredentialsMasker, postRequestCredentialsMasker } from './util/credentials-masker';
|
|
5
|
+
export { getRequestCredentialsMasker, postRequestCredentialsMasker };
|
|
4
6
|
export { ProjectPermissions, Scope, UserPermissions } from './types';
|
|
5
7
|
export { express };
|
|
6
8
|
export declare const metadataStore: CrowdinMetadataStore;
|
package/out/index.js
CHANGED
|
@@ -35,7 +35,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
35
35
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
36
|
};
|
|
37
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
-
exports.addCrowdinEndpoints = exports.createApp = exports.metadataStore = exports.express = exports.UserPermissions = exports.Scope = exports.ProjectPermissions = void 0;
|
|
38
|
+
exports.addCrowdinEndpoints = exports.createApp = exports.metadataStore = exports.express = exports.UserPermissions = exports.Scope = exports.ProjectPermissions = exports.postRequestCredentialsMasker = exports.getRequestCredentialsMasker = void 0;
|
|
39
39
|
const logsFormatter = __importStar(require("@crowdin/logs-formatter"));
|
|
40
40
|
const path_1 = require("path");
|
|
41
41
|
const crowdin_client_1 = __importStar(require("./middlewares/crowdin-client"));
|
|
@@ -57,6 +57,8 @@ const logger_1 = require("./util/logger");
|
|
|
57
57
|
const terminus_express_1 = __importDefault(require("./util/terminus-express"));
|
|
58
58
|
exports.express = terminus_express_1.default;
|
|
59
59
|
const credentials_masker_1 = require("./util/credentials-masker");
|
|
60
|
+
Object.defineProperty(exports, "getRequestCredentialsMasker", { enumerable: true, get: function () { return credentials_masker_1.getRequestCredentialsMasker; } });
|
|
61
|
+
Object.defineProperty(exports, "postRequestCredentialsMasker", { enumerable: true, get: function () { return credentials_masker_1.postRequestCredentialsMasker; } });
|
|
60
62
|
//apps
|
|
61
63
|
const apiApp = __importStar(require("./modules/api"));
|
|
62
64
|
const contextMenuApp = __importStar(require("./modules/context-menu"));
|
|
@@ -109,7 +111,7 @@ function createApp(clientConfig) {
|
|
|
109
111
|
const config = convertClientConfig(clientConfig);
|
|
110
112
|
addCrowdinEndpoints(app, config);
|
|
111
113
|
/* eslint no-console: "off" */
|
|
112
|
-
app.listen(config
|
|
114
|
+
app.listen(config, () => console.log(`App started on port ${config.port}`));
|
|
113
115
|
}
|
|
114
116
|
exports.createApp = createApp;
|
|
115
117
|
function addCrowdinEndpoints(app, clientConfig) {
|
|
@@ -15,8 +15,15 @@ function handle() {
|
|
|
15
15
|
const projectId = req.crowdinContext.jwtPayload.context.project_id;
|
|
16
16
|
req.logInfo(`Loading crowdin project ${projectId}`);
|
|
17
17
|
const project = yield req.crowdinApiClient.projectsGroupsApi.getProject(projectId);
|
|
18
|
+
let projectEditorLink;
|
|
19
|
+
if (req.crowdinContext.jwtPayload.domain) {
|
|
20
|
+
projectEditorLink = `https://${req.crowdinContext.jwtPayload.domain}.crowdin.com/editor/${project.data.id}`;
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
projectEditorLink = `https://crowdin.com/editor/${project.data.identifier}`;
|
|
24
|
+
}
|
|
18
25
|
req.logInfo(`Loaded crowdin project ${projectId}`);
|
|
19
|
-
res.send(project.data);
|
|
26
|
+
res.send(Object.assign(Object.assign({}, project.data), { projectEditorLink }));
|
|
20
27
|
}));
|
|
21
28
|
}
|
|
22
29
|
exports.default = handle;
|
|
@@ -11,6 +11,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
const storage_1 = require("../../../storage");
|
|
13
13
|
const util_1 = require("../../../util");
|
|
14
|
+
const logger_1 = require("../../../util/logger");
|
|
14
15
|
function handle() {
|
|
15
16
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
16
17
|
var _a;
|
|
@@ -20,6 +21,12 @@ function handle() {
|
|
|
20
21
|
}
|
|
21
22
|
req.logInfo(`Loading user errors for crowdinId ${req.crowdinContext.crowdinId} and integrationId ${req.crowdinContext.clientId}`);
|
|
22
23
|
const userErrors = (_a = (yield (0, storage_1.getStorage)().getAllUserErrors(req.crowdinContext.crowdinId, req.crowdinContext.clientId))) === null || _a === void 0 ? void 0 : _a.map((userError) => {
|
|
24
|
+
if (!(0, util_1.isJson)(userError.data)) {
|
|
25
|
+
(0, logger_1.logError)(userError);
|
|
26
|
+
userError.data = JSON.stringify({
|
|
27
|
+
appData: { Warning: 'Invalid response data. Please contact the Crowdin support manager.' },
|
|
28
|
+
});
|
|
29
|
+
}
|
|
23
30
|
const date = new Date(+userError.createdAt);
|
|
24
31
|
// Format the date as 'MMM DD, YYYY HH:mm'
|
|
25
32
|
const formattedDate = new Intl.DateTimeFormat('en-US', {
|
|
@@ -31,7 +38,7 @@ function handle() {
|
|
|
31
38
|
hour12: false,
|
|
32
39
|
timeZone: userTimezone,
|
|
33
40
|
}).format(date);
|
|
34
|
-
return Object.assign(Object.assign({}, userError), {
|
|
41
|
+
return Object.assign(Object.assign({}, userError), { formattedDate });
|
|
35
42
|
});
|
|
36
43
|
req.logInfo(`Returning ${userErrors === null || userErrors === void 0 ? void 0 : userErrors.length} user errors`);
|
|
37
44
|
res.send(userErrors);
|
|
@@ -22,6 +22,15 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
22
22
|
__setModuleDefault(result, mod);
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
25
34
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
35
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
36
|
};
|
|
@@ -56,6 +65,7 @@ const sync_settings_1 = __importDefault(require("./handlers/sync-settings"));
|
|
|
56
65
|
const sync_settings_save_1 = __importDefault(require("./handlers/sync-settings-save"));
|
|
57
66
|
const user_errors_1 = __importDefault(require("./handlers/user-errors"));
|
|
58
67
|
const cron_1 = require("./util/cron");
|
|
68
|
+
const storage_1 = require("../../storage");
|
|
59
69
|
function register({ config, app }) {
|
|
60
70
|
var _a, _b, _c;
|
|
61
71
|
const integrationLogic = config.projectIntegration;
|
|
@@ -96,8 +106,12 @@ function register({ config, app }) {
|
|
|
96
106
|
cron.schedule('0 */3 * * *', () => (0, cron_1.filesCron)({ config, integration: integrationLogic, period: '3' }).catch(console.error));
|
|
97
107
|
cron.schedule('0 */6 * * *', () => (0, cron_1.filesCron)({ config, integration: integrationLogic, period: '6' }).catch(console.error));
|
|
98
108
|
cron.schedule('0 */12 * * *', () => (0, cron_1.filesCron)({ config, integration: integrationLogic, period: '12' }).catch(console.error));
|
|
99
|
-
cron.schedule('0 0 * * *', () => (0, cron_1.filesCron)({ config, integration: integrationLogic, period: '24' }).catch(console.error));
|
|
100
109
|
}
|
|
110
|
+
// remove user errors
|
|
111
|
+
cron.schedule('0 0 * * *', () => __awaiter(this, void 0, void 0, function* () {
|
|
112
|
+
const date = (0, util_1.getPreviousDate)(integrationLogic.userErrorLifetimeDays);
|
|
113
|
+
yield (0, storage_1.getStorage)().deleteAllUsersErrorsOlderThan(`${date.getTime()}`);
|
|
114
|
+
}));
|
|
101
115
|
if (integrationLogic.webhooks) {
|
|
102
116
|
app.post(`${integrationLogic.webhooks.crowdinWebhookUrl
|
|
103
117
|
? integrationLogic.webhooks.crowdinWebhookUrl
|
|
@@ -142,6 +142,10 @@ export interface IntegrationLogic {
|
|
|
142
142
|
asyncProgress?: {
|
|
143
143
|
checkInterval?: number;
|
|
144
144
|
};
|
|
145
|
+
/**
|
|
146
|
+
* The duration for storing user errors, default is 30 days.
|
|
147
|
+
*/
|
|
148
|
+
userErrorLifetimeDays: number;
|
|
145
149
|
}
|
|
146
150
|
export interface LoginForm {
|
|
147
151
|
fields: FormEntity[];
|
|
@@ -1,11 +1,28 @@
|
|
|
1
|
-
import Crowdin from '@crowdin/crowdin-api-client';
|
|
2
|
-
import { Config } from '../../../types';
|
|
1
|
+
import Crowdin, { SourceFilesModel } from '@crowdin/crowdin-api-client';
|
|
2
|
+
import { Config, CrowdinContextInfo } from '../../../types';
|
|
3
3
|
import { CronJob, IntegrationLogic, IntegrationRequest, Provider, UpdateIntegrationRequest } from '../types';
|
|
4
|
+
import { JobClientType, JobType } from './types';
|
|
4
5
|
export declare function runJob({ config, integration, job, }: {
|
|
5
6
|
config: Config;
|
|
6
7
|
integration: IntegrationLogic;
|
|
7
8
|
job: CronJob;
|
|
8
9
|
}): Promise<void>;
|
|
10
|
+
export declare function runUpdateProviderJob({ integrationId, crowdinId, type, title, payload, jobType, projectId, client, integration, context, credentials, rootFolder, appSettings, reRunJobId, }: {
|
|
11
|
+
integrationId: string;
|
|
12
|
+
crowdinId: string;
|
|
13
|
+
type: JobType;
|
|
14
|
+
title?: string;
|
|
15
|
+
payload?: any;
|
|
16
|
+
jobType: JobClientType;
|
|
17
|
+
projectId: number;
|
|
18
|
+
client: Crowdin;
|
|
19
|
+
integration: IntegrationLogic;
|
|
20
|
+
context: CrowdinContextInfo;
|
|
21
|
+
credentials: any;
|
|
22
|
+
rootFolder?: SourceFilesModel.Directory;
|
|
23
|
+
appSettings?: any;
|
|
24
|
+
reRunJobId?: string;
|
|
25
|
+
}): Promise<void>;
|
|
9
26
|
export declare function filesCron({ config, integration, period, }: {
|
|
10
27
|
config: Config;
|
|
11
28
|
integration: IntegrationLogic;
|
|
@@ -32,7 +32,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
32
32
|
});
|
|
33
33
|
};
|
|
34
34
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
-
exports.removeFinishedJobs = exports.createOrUpdateSyncSettings = exports.skipFoldersFromIntegrationRequest = exports.filesCron = exports.runJob = void 0;
|
|
35
|
+
exports.removeFinishedJobs = exports.createOrUpdateSyncSettings = exports.skipFoldersFromIntegrationRequest = exports.filesCron = exports.runUpdateProviderJob = exports.runJob = void 0;
|
|
36
36
|
const crowdinAppFunctions = __importStar(require("@crowdin/crowdin-apps-functions"));
|
|
37
37
|
const storage_1 = require("../../../storage");
|
|
38
38
|
const connection_1 = require("../../../util/connection");
|
|
@@ -80,6 +80,52 @@ function runJob({ config, integration, job, }) {
|
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
exports.runJob = runJob;
|
|
83
|
+
function runUpdateProviderJob({ integrationId, crowdinId, type, title, payload, jobType, projectId, client, integration, context, credentials, rootFolder, appSettings, reRunJobId, }) {
|
|
84
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
85
|
+
try {
|
|
86
|
+
yield (0, job_1.runAsJob)({
|
|
87
|
+
integrationId,
|
|
88
|
+
crowdinId,
|
|
89
|
+
type,
|
|
90
|
+
title,
|
|
91
|
+
payload,
|
|
92
|
+
jobType,
|
|
93
|
+
projectId,
|
|
94
|
+
client,
|
|
95
|
+
reRunJobId,
|
|
96
|
+
jobCallback: (job) => __awaiter(this, void 0, void 0, function* () {
|
|
97
|
+
const updateParams = {
|
|
98
|
+
projectId,
|
|
99
|
+
client,
|
|
100
|
+
credentials,
|
|
101
|
+
request: payload,
|
|
102
|
+
rootFolder,
|
|
103
|
+
appSettings,
|
|
104
|
+
job,
|
|
105
|
+
};
|
|
106
|
+
if (type === types_2.JobType.UPDATE_TO_CROWDIN) {
|
|
107
|
+
yield integration.updateCrowdin(updateParams);
|
|
108
|
+
}
|
|
109
|
+
else if (type === types_2.JobType.UPDATE_TO_INTEGRATION) {
|
|
110
|
+
yield integration.updateIntegration(updateParams);
|
|
111
|
+
}
|
|
112
|
+
}),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
catch (e) {
|
|
116
|
+
const action = type === types_2.JobType.UPDATE_TO_CROWDIN ? 'Auto sync files to Crowdin' : 'Auto sync files to External Service';
|
|
117
|
+
yield (0, logger_1.handleUserError)({
|
|
118
|
+
action,
|
|
119
|
+
error: e,
|
|
120
|
+
crowdinId: crowdinId,
|
|
121
|
+
clientId: integrationId,
|
|
122
|
+
});
|
|
123
|
+
(0, logger_1.logError)(e, context);
|
|
124
|
+
throw e;
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
exports.runUpdateProviderJob = runUpdateProviderJob;
|
|
83
129
|
function filesCron({ config, integration, period, }) {
|
|
84
130
|
return __awaiter(this, void 0, void 0, function* () {
|
|
85
131
|
(0, logger_1.log)(`Starting files cron job with period [${period}]`);
|
|
@@ -237,7 +283,7 @@ function processSyncSettings({ config, integration, period, syncSettings, }) {
|
|
|
237
283
|
removeInContextLanguage(filesToProcess, projectData);
|
|
238
284
|
}
|
|
239
285
|
try {
|
|
240
|
-
yield (
|
|
286
|
+
yield runUpdateProviderJob({
|
|
241
287
|
integrationId: syncSettings.integrationId,
|
|
242
288
|
crowdinId: syncSettings.crowdinId,
|
|
243
289
|
type: types_2.JobType.UPDATE_TO_INTEGRATION,
|
|
@@ -246,27 +292,14 @@ function processSyncSettings({ config, integration, period, syncSettings, }) {
|
|
|
246
292
|
jobType: types_2.JobClientType.CRON,
|
|
247
293
|
projectId: projectId,
|
|
248
294
|
client: crowdinClient,
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
request: filesToProcess,
|
|
255
|
-
rootFolder,
|
|
256
|
-
appSettings: intConfig,
|
|
257
|
-
job,
|
|
258
|
-
});
|
|
259
|
-
}),
|
|
295
|
+
integration,
|
|
296
|
+
context,
|
|
297
|
+
credentials: apiCredentials,
|
|
298
|
+
rootFolder,
|
|
299
|
+
appSettings: intConfig,
|
|
260
300
|
});
|
|
261
301
|
}
|
|
262
302
|
catch (e) {
|
|
263
|
-
yield (0, logger_1.handleUserError)({
|
|
264
|
-
action: 'Auto sync files to External Service',
|
|
265
|
-
error: e,
|
|
266
|
-
crowdinId: syncSettings.crowdinId,
|
|
267
|
-
clientId: syncSettings.integrationId,
|
|
268
|
-
});
|
|
269
|
-
(0, logger_1.logError)(e, context);
|
|
270
303
|
return;
|
|
271
304
|
}
|
|
272
305
|
if (Object.keys(newFiles).length) {
|
|
@@ -289,7 +322,7 @@ function processSyncSettings({ config, integration, period, syncSettings, }) {
|
|
|
289
322
|
(0, logger_1.log)(`Executing updateCrowdin task for files cron job with period [${period}] for project ${projectId}. Files ${intFiles.length}`);
|
|
290
323
|
const apiCredentials = yield (0, connection_1.prepareIntegrationCredentials)(config, integration, integrationCredentials);
|
|
291
324
|
try {
|
|
292
|
-
yield (
|
|
325
|
+
yield runUpdateProviderJob({
|
|
293
326
|
integrationId: syncSettings.integrationId,
|
|
294
327
|
crowdinId: syncSettings.crowdinId,
|
|
295
328
|
type: types_2.JobType.UPDATE_TO_CROWDIN,
|
|
@@ -298,27 +331,14 @@ function processSyncSettings({ config, integration, period, syncSettings, }) {
|
|
|
298
331
|
jobType: types_2.JobClientType.CRON,
|
|
299
332
|
projectId: projectId,
|
|
300
333
|
client: crowdinClient,
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
request: intFiles,
|
|
307
|
-
rootFolder,
|
|
308
|
-
appSettings: intConfig,
|
|
309
|
-
job,
|
|
310
|
-
});
|
|
311
|
-
}),
|
|
334
|
+
integration,
|
|
335
|
+
context,
|
|
336
|
+
credentials: apiCredentials,
|
|
337
|
+
rootFolder,
|
|
338
|
+
appSettings: intConfig,
|
|
312
339
|
});
|
|
313
340
|
}
|
|
314
341
|
catch (e) {
|
|
315
|
-
yield (0, logger_1.handleUserError)({
|
|
316
|
-
action: 'Auto sync files to Crowdin',
|
|
317
|
-
error: e,
|
|
318
|
-
crowdinId: syncSettings.crowdinId,
|
|
319
|
-
clientId: syncSettings.integrationId,
|
|
320
|
-
});
|
|
321
|
-
(0, logger_1.logError)(e, context);
|
|
322
342
|
return;
|
|
323
343
|
}
|
|
324
344
|
if (Object.keys(newFiles).length) {
|
|
@@ -255,6 +255,9 @@ function applyIntegrationModuleDefaults(config, integration) {
|
|
|
255
255
|
if (!((_b = integration.filtering) === null || _b === void 0 ? void 0 : _b.hasOwnProperty('crowdinLanguages'))) {
|
|
256
256
|
integration.filtering = Object.assign(Object.assign({}, (integration.filtering || {})), { crowdinLanguages: true });
|
|
257
257
|
}
|
|
258
|
+
if (!integration.userErrorLifetimeDays) {
|
|
259
|
+
integration.userErrorLifetimeDays = 30;
|
|
260
|
+
}
|
|
258
261
|
}
|
|
259
262
|
exports.applyIntegrationModuleDefaults = applyIntegrationModuleDefaults;
|
|
260
263
|
function constructOauthUrl({ config, integration, clientId, loginForm, }) {
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { JobClient, JobClientType, JobType } from './types';
|
|
2
2
|
import { Response } from 'express';
|
|
3
3
|
import Crowdin from '@crowdin/crowdin-api-client';
|
|
4
|
-
|
|
4
|
+
import { Config } from '../../../types';
|
|
5
|
+
export declare function runAsJob({ integrationId, crowdinId, type, title, payload, res, projectId, client, jobType, jobCallback, onError, reRunJobId, }: {
|
|
5
6
|
integrationId: string;
|
|
6
7
|
crowdinId: string;
|
|
7
8
|
type: JobType;
|
|
@@ -13,4 +14,6 @@ export declare function runAsJob({ integrationId, crowdinId, type, title, payloa
|
|
|
13
14
|
jobType: JobClientType;
|
|
14
15
|
jobCallback: (arg1: JobClient) => Promise<any>;
|
|
15
16
|
onError?: (e: any) => Promise<void>;
|
|
17
|
+
reRunJobId?: string;
|
|
16
18
|
}): Promise<void>;
|
|
19
|
+
export declare function reRunInProgressJobs(config: Config): Promise<void>;
|
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
2
25
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
26
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
27
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
@@ -9,37 +32,48 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
32
|
});
|
|
10
33
|
};
|
|
11
34
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.runAsJob = void 0;
|
|
35
|
+
exports.reRunInProgressJobs = exports.runAsJob = void 0;
|
|
13
36
|
const types_1 = require("./types");
|
|
14
37
|
const storage_1 = require("../../../storage");
|
|
15
38
|
const logger_1 = require("../../../util/logger");
|
|
39
|
+
const crowdinAppFunctions = __importStar(require("@crowdin/crowdin-apps-functions"));
|
|
40
|
+
const connection_1 = require("../../../util/connection");
|
|
41
|
+
const defaults_1 = require("./defaults");
|
|
42
|
+
const cron_1 = require("./cron");
|
|
16
43
|
const blockingJobs = {
|
|
17
44
|
[types_1.JobType.UPDATE_TO_CROWDIN]: [types_1.JobType.UPDATE_TO_CROWDIN, types_1.JobType.UPDATE_TO_INTEGRATION],
|
|
18
45
|
[types_1.JobType.UPDATE_TO_INTEGRATION]: [types_1.JobType.UPDATE_TO_CROWDIN, types_1.JobType.UPDATE_TO_INTEGRATION],
|
|
19
46
|
[types_1.JobType.CROWDIN_SYNC_SETTINGS_SAVE]: [types_1.JobType.CROWDIN_SYNC_SETTINGS_SAVE],
|
|
20
47
|
[types_1.JobType.INTEGRATION_SYNC_SETTINGS_SAVE]: [types_1.JobType.INTEGRATION_SYNC_SETTINGS_SAVE],
|
|
21
48
|
};
|
|
22
|
-
|
|
49
|
+
const maxAttempts = 3;
|
|
50
|
+
function runAsJob({ integrationId, crowdinId, type, title, payload, res, projectId, client, jobType, jobCallback, onError, reRunJobId, }) {
|
|
23
51
|
return __awaiter(this, void 0, void 0, function* () {
|
|
52
|
+
let jobId;
|
|
24
53
|
const storage = (0, storage_1.getStorage)();
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if (
|
|
30
|
-
res
|
|
54
|
+
if (!reRunJobId) {
|
|
55
|
+
const activeJobs = yield storage.getActiveJobs({ integrationId, crowdinId });
|
|
56
|
+
if (activeJobs === null || activeJobs === void 0 ? void 0 : activeJobs.length) {
|
|
57
|
+
const existingJob = activeJobs.find((job) => blockingJobs[type].includes(job.type));
|
|
58
|
+
if (existingJob === null || existingJob === void 0 ? void 0 : existingJob.id) {
|
|
59
|
+
if (res) {
|
|
60
|
+
res.status(202).send({ jobId: existingJob.id, message: 'Another sync is running' });
|
|
61
|
+
}
|
|
62
|
+
(0, logger_1.log)(`Unable to run new job '${type}', with title '${title}', already running jobId ${existingJob.id}.`);
|
|
63
|
+
return;
|
|
31
64
|
}
|
|
32
|
-
(0, logger_1.log)(`Unable to run new job '${type}', with title '${title}', already running jobId ${existingJob.id}.`);
|
|
33
|
-
return;
|
|
34
65
|
}
|
|
66
|
+
jobId = yield storage.createJob({
|
|
67
|
+
integrationId,
|
|
68
|
+
crowdinId,
|
|
69
|
+
type,
|
|
70
|
+
title: title || '',
|
|
71
|
+
payload: JSON.stringify(payload),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
jobId = reRunJobId;
|
|
35
76
|
}
|
|
36
|
-
const jobId = yield storage.createJob({
|
|
37
|
-
integrationId,
|
|
38
|
-
crowdinId,
|
|
39
|
-
type,
|
|
40
|
-
title: title || '',
|
|
41
|
-
payload: JSON.stringify(payload),
|
|
42
|
-
});
|
|
43
77
|
if (res) {
|
|
44
78
|
res.status(202).send({ jobId });
|
|
45
79
|
}
|
|
@@ -49,7 +83,7 @@ function runAsJob({ integrationId, crowdinId, type, title, payload, res, project
|
|
|
49
83
|
return yield storage.getJob({ id: jobId });
|
|
50
84
|
});
|
|
51
85
|
},
|
|
52
|
-
update: function updateProgress({ progress, status, info, data }) {
|
|
86
|
+
update: function updateProgress({ progress, status, info, data, attempt }) {
|
|
53
87
|
return __awaiter(this, void 0, void 0, function* () {
|
|
54
88
|
const prevData = yield this.get();
|
|
55
89
|
if ((prevData === null || prevData === void 0 ? void 0 : prevData.status) === types_1.JobStatus.CANCELED) {
|
|
@@ -61,13 +95,14 @@ function runAsJob({ integrationId, crowdinId, type, title, payload, res, project
|
|
|
61
95
|
status: status || types_1.JobStatus.IN_PROGRESS,
|
|
62
96
|
info,
|
|
63
97
|
data: JSON.stringify(data),
|
|
98
|
+
attempt,
|
|
64
99
|
});
|
|
65
100
|
return { isCanceled: false };
|
|
66
101
|
});
|
|
67
102
|
},
|
|
68
103
|
type: jobType,
|
|
69
104
|
fetchTranslation: ({ fileId, languageId }) => __awaiter(this, void 0, void 0, function* () {
|
|
70
|
-
const translationCache = yield storage.
|
|
105
|
+
const translationCache = yield storage.getFileTranslationCacheByLanguage({
|
|
71
106
|
integrationId,
|
|
72
107
|
crowdinId,
|
|
73
108
|
fileId,
|
|
@@ -89,20 +124,28 @@ function runAsJob({ integrationId, crowdinId, type, title, payload, res, project
|
|
|
89
124
|
}
|
|
90
125
|
return translation;
|
|
91
126
|
}),
|
|
92
|
-
translationUploaded: ({ fileId, languageId, etag }) =>
|
|
93
|
-
|
|
127
|
+
// translationUploaded: async ({ fileId, languageId, etag }) => {
|
|
128
|
+
translationUploaded: ({ fileId, translationParams }) => __awaiter(this, void 0, void 0, function* () {
|
|
129
|
+
const translationCache = (yield storage.getFileTranslationCache({
|
|
94
130
|
integrationId,
|
|
95
131
|
crowdinId,
|
|
96
132
|
fileId,
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
133
|
+
})) || [];
|
|
134
|
+
const cacheMap = new Map(translationCache.map((cache) => [cache.languageId, cache]));
|
|
135
|
+
const updates = [];
|
|
136
|
+
const inserts = [];
|
|
137
|
+
for (const { languageId, etag } of translationParams) {
|
|
138
|
+
const cache = cacheMap.get(languageId);
|
|
139
|
+
if (cache) {
|
|
140
|
+
(0, logger_1.log)(`Updating etag translation for file ${fileId} in language ${languageId}`);
|
|
141
|
+
updates.push(storage.updateTranslationCache({ integrationId, crowdinId, fileId, languageId, etag }));
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
(0, logger_1.log)(`Saving new etag translation for file ${fileId} in language ${languageId}`);
|
|
145
|
+
inserts.push(storage.saveTranslationCache({ integrationId, crowdinId, fileId, languageId, etag }));
|
|
146
|
+
}
|
|
105
147
|
}
|
|
148
|
+
yield Promise.all([...updates, ...inserts]);
|
|
106
149
|
}),
|
|
107
150
|
};
|
|
108
151
|
try {
|
|
@@ -128,3 +171,86 @@ function runAsJob({ integrationId, crowdinId, type, title, payload, res, project
|
|
|
128
171
|
});
|
|
129
172
|
}
|
|
130
173
|
exports.runAsJob = runAsJob;
|
|
174
|
+
function reRunInProgressJobs(config) {
|
|
175
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
176
|
+
const storage = (0, storage_1.getStorage)();
|
|
177
|
+
const inProgressJobs = yield storage.getAllInProgressJobs();
|
|
178
|
+
if (!(inProgressJobs === null || inProgressJobs === void 0 ? void 0 : inProgressJobs.length)) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
yield Promise.all(inProgressJobs.map((activeJob) => __awaiter(this, void 0, void 0, function* () {
|
|
182
|
+
if (activeJob && activeJob.status !== types_1.JobStatus.IN_PROGRESS) {
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
if (activeJob.attempt && activeJob.attempt >= maxAttempts) {
|
|
186
|
+
yield storage.updateJob({ id: activeJob.id, status: types_1.JobStatus.FAILED });
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
const { integrationId, crowdinId, type, title, payload } = activeJob;
|
|
190
|
+
const integration = config.projectIntegration;
|
|
191
|
+
let crowdinClient;
|
|
192
|
+
const integrationCredentials = yield (0, storage_1.getStorage)().getIntegrationCredentials(integrationId);
|
|
193
|
+
const crowdinCredentials = yield (0, storage_1.getStorage)().getCrowdinCredentials(crowdinId);
|
|
194
|
+
const integrationConfig = yield (0, storage_1.getStorage)().getIntegrationConfig(integrationId);
|
|
195
|
+
if (!integrationCredentials || !crowdinCredentials) {
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
const projectId = crowdinAppFunctions.getProjectId(integrationCredentials.id);
|
|
199
|
+
const context = {
|
|
200
|
+
jwtPayload: {
|
|
201
|
+
context: {
|
|
202
|
+
// eslint-disable-next-line @typescript-eslint/camelcase
|
|
203
|
+
project_id: projectId,
|
|
204
|
+
// eslint-disable-next-line @typescript-eslint/camelcase
|
|
205
|
+
organization_id: crowdinCredentials.organizationId,
|
|
206
|
+
// eslint-disable-next-line @typescript-eslint/camelcase
|
|
207
|
+
organization_domain: crowdinCredentials.domain,
|
|
208
|
+
// eslint-disable-next-line @typescript-eslint/camelcase
|
|
209
|
+
user_id: crowdinCredentials.userId,
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
};
|
|
213
|
+
try {
|
|
214
|
+
const preparedCrowdinClient = yield (0, connection_1.prepareCrowdinClient)({
|
|
215
|
+
config,
|
|
216
|
+
credentials: crowdinCredentials,
|
|
217
|
+
autoRenew: true,
|
|
218
|
+
context,
|
|
219
|
+
});
|
|
220
|
+
crowdinClient = preparedCrowdinClient.client;
|
|
221
|
+
}
|
|
222
|
+
catch (e) {
|
|
223
|
+
(0, logger_1.logError)(e);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const rootFolder = yield (0, defaults_1.getRootFolder)(config, integration, crowdinClient, projectId);
|
|
227
|
+
const apiCredentials = yield (0, connection_1.prepareIntegrationCredentials)(config, integration, integrationCredentials);
|
|
228
|
+
const intConfig = (integrationConfig === null || integrationConfig === void 0 ? void 0 : integrationConfig.config)
|
|
229
|
+
? JSON.parse(integrationConfig.config)
|
|
230
|
+
: { schedule: '0', condition: '0' };
|
|
231
|
+
yield storage.updateJob({ attempt: +(activeJob.attempt || 0) + 1, id: activeJob.id });
|
|
232
|
+
if ([types_1.JobType.UPDATE_TO_CROWDIN, types_1.JobType.UPDATE_TO_INTEGRATION].includes(type)) {
|
|
233
|
+
yield (0, cron_1.runUpdateProviderJob)({
|
|
234
|
+
integrationId,
|
|
235
|
+
crowdinId,
|
|
236
|
+
type,
|
|
237
|
+
title,
|
|
238
|
+
payload: JSON.parse(payload),
|
|
239
|
+
jobType: types_1.JobClientType.RERUN,
|
|
240
|
+
projectId,
|
|
241
|
+
client: crowdinClient,
|
|
242
|
+
integration,
|
|
243
|
+
context,
|
|
244
|
+
credentials: apiCredentials,
|
|
245
|
+
rootFolder,
|
|
246
|
+
appSettings: intConfig,
|
|
247
|
+
reRunJobId: activeJob.id,
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
else if ([types_1.JobType.CROWDIN_SYNC_SETTINGS_SAVE, types_1.JobType.INTEGRATION_SYNC_SETTINGS_SAVE].includes(type)) {
|
|
251
|
+
yield storage.updateJob({ status: types_1.JobStatus.CANCELED, id: activeJob.id });
|
|
252
|
+
}
|
|
253
|
+
})));
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
exports.reRunInProgressJobs = reRunInProgressJobs;
|
|
@@ -18,7 +18,8 @@ export declare enum JobStatus {
|
|
|
18
18
|
}
|
|
19
19
|
export declare enum JobClientType {
|
|
20
20
|
CRON = "cron",
|
|
21
|
-
MANUAL = "manual"
|
|
21
|
+
MANUAL = "manual",
|
|
22
|
+
RERUN = "rerun"
|
|
22
23
|
}
|
|
23
24
|
export interface Job {
|
|
24
25
|
id: string;
|
|
@@ -35,6 +36,7 @@ export interface Job {
|
|
|
35
36
|
finishedAt?: number;
|
|
36
37
|
eta?: number;
|
|
37
38
|
info?: string;
|
|
39
|
+
attempt?: number;
|
|
38
40
|
}
|
|
39
41
|
export type GetJobParams = Pick<Job, 'id'>;
|
|
40
42
|
export type GetActiveJobsParams = Pick<Job, 'integrationId' | 'crowdinId'>;
|
|
@@ -45,6 +47,7 @@ export type UpdateJobParams = {
|
|
|
45
47
|
status?: JobStatus;
|
|
46
48
|
info?: string;
|
|
47
49
|
data?: string;
|
|
50
|
+
attempt?: number;
|
|
48
51
|
};
|
|
49
52
|
export type JobClient = {
|
|
50
53
|
get: () => Promise<Job | undefined>;
|
|
@@ -53,7 +56,7 @@ export type JobClient = {
|
|
|
53
56
|
translationUploaded: SaveUploadedFileTranslation;
|
|
54
57
|
fetchTranslation: FetchTranslation;
|
|
55
58
|
};
|
|
56
|
-
export type UpdateJobProgress = ({ progress, status, info, data, }: Omit<UpdateJobParams, 'id'>) => Promise<{
|
|
59
|
+
export type UpdateJobProgress = ({ progress, status, info, data, attempt, }: Omit<UpdateJobParams, 'id'>) => Promise<{
|
|
57
60
|
isCanceled: boolean;
|
|
58
61
|
}>;
|
|
59
62
|
export interface GetAllNewFilesArgs {
|
|
@@ -67,10 +70,12 @@ export interface GetAllNewFilesArgs {
|
|
|
67
70
|
integrationSettings: any;
|
|
68
71
|
syncSettings: IntegrationSyncSettings;
|
|
69
72
|
}
|
|
70
|
-
export type SaveUploadedFileTranslation = ({ fileId,
|
|
73
|
+
export type SaveUploadedFileTranslation = ({ fileId, translationParams, }: {
|
|
71
74
|
fileId: number;
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
translationParams: {
|
|
76
|
+
languageId: string;
|
|
77
|
+
etag: string;
|
|
78
|
+
}[];
|
|
74
79
|
}) => Promise<void>;
|
|
75
80
|
export type FetchTranslation = ({ fileId, languageId, }: {
|
|
76
81
|
fileId: number;
|
|
@@ -83,5 +88,6 @@ export interface TranslationCache {
|
|
|
83
88
|
languageId: string;
|
|
84
89
|
etag?: string;
|
|
85
90
|
}
|
|
86
|
-
export type
|
|
91
|
+
export type GetFileTranslationCache = Pick<TranslationCache, 'integrationId' | 'crowdinId' | 'fileId'>;
|
|
92
|
+
export type GetFileTranslationCacheByLanguageParams = Pick<TranslationCache, 'integrationId' | 'crowdinId' | 'fileId' | 'languageId'>;
|
|
87
93
|
export type UpdateTranslationCacheParams = Pick<TranslationCache, 'integrationId' | 'crowdinId' | 'fileId' | 'languageId' | 'etag'>;
|