@crowdin/app-project-module 0.39.1 → 0.41.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/handlers/integration/crowdin-update.js +36 -17
- package/out/handlers/integration/integration-data.js +2 -0
- package/out/handlers/integration/integration-update.js +35 -17
- package/out/handlers/integration/integration-webhook.js +1 -1
- package/out/handlers/integration/job-cancel.d.ts +3 -0
- package/out/handlers/integration/job-cancel.js +28 -0
- package/out/handlers/integration/job-info.d.ts +3 -0
- package/out/handlers/integration/job-info.js +54 -0
- package/out/handlers/integration/main.js +6 -3
- package/out/handlers/integration/settings-save.js +8 -1
- package/out/handlers/integration/user-errors.d.ts +3 -0
- package/out/handlers/{user-errors.js → integration/user-errors.js} +2 -2
- package/out/handlers/uninstall.js +4 -2
- package/out/index.d.ts +2 -1
- package/out/index.js +35 -27
- package/out/middlewares/crowdin-client.js +1 -0
- package/out/middlewares/integration-credentials.js +3 -2
- package/out/middlewares/ui-module.js +1 -0
- package/out/models/index.d.ts +54 -18
- package/out/models/index.js +1 -0
- package/out/models/job.d.ts +44 -0
- package/out/models/job.js +16 -0
- package/out/static/js/form.js +13 -13
- package/out/static/js/main.js +1 -1
- package/out/storage/index.d.ts +11 -2
- package/out/storage/index.js +3 -0
- package/out/storage/mysql.d.ts +11 -2
- package/out/storage/mysql.js +155 -10
- package/out/storage/postgre.d.ts +11 -2
- package/out/storage/postgre.js +153 -9
- package/out/storage/sqlite.d.ts +14 -3
- package/out/storage/sqlite.js +160 -14
- package/out/util/cron.d.ts +1 -0
- package/out/util/cron.js +53 -6
- package/out/util/defaults.js +4 -11
- package/out/util/file-snapshot.js +2 -0
- package/out/util/files.d.ts +2 -1
- package/out/util/files.js +19 -1
- package/out/util/index.js +3 -1
- package/out/util/job.d.ts +12 -0
- package/out/util/job.js +88 -0
- package/out/util/logger.js +4 -0
- package/out/util/webhooks.js +53 -6
- package/out/views/main.handlebars +153 -5
- package/package.json +16 -15
- package/out/handlers/user-errors.d.ts +0 -3
package/out/storage/sqlite.js
CHANGED
|
@@ -15,6 +15,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
15
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
16
|
exports.SQLiteStorage = void 0;
|
|
17
17
|
const path_1 = require("path");
|
|
18
|
+
const uuid_1 = require("uuid");
|
|
19
|
+
const job_1 = require("../models/job");
|
|
18
20
|
class SQLiteStorage {
|
|
19
21
|
constructor(config) {
|
|
20
22
|
this.dbPromise = new Promise((res, rej) => {
|
|
@@ -92,25 +94,45 @@ class SQLiteStorage {
|
|
|
92
94
|
});
|
|
93
95
|
});
|
|
94
96
|
}
|
|
95
|
-
|
|
97
|
+
removeColumns(column, tableName) {
|
|
98
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
99
|
+
const tableInfo = yield this.each(`PRAGMA table_info(${tableName});`, []);
|
|
100
|
+
const exists = tableInfo.some((columnInfo) => columnInfo.name === column);
|
|
101
|
+
if (exists) {
|
|
102
|
+
yield this.run(`ALTER TABLE ${tableName} DROP COLUMN ${column};`, []);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
addColumns(columns, tableName) {
|
|
96
107
|
return __awaiter(this, void 0, void 0, function* () {
|
|
97
108
|
const tableInfo = yield this.each(`PRAGMA table_info(${tableName});`, []);
|
|
98
109
|
//@ts-ignore
|
|
99
110
|
tableInfo.map((columnInfo) => __awaiter(this, void 0, void 0, function* () {
|
|
100
|
-
const index =
|
|
111
|
+
const index = columns.indexOf(columnInfo.name);
|
|
101
112
|
if (~index) {
|
|
102
|
-
|
|
113
|
+
columns.splice(index, 1);
|
|
103
114
|
}
|
|
104
115
|
}));
|
|
105
|
-
for (const column of
|
|
116
|
+
for (const column of columns) {
|
|
106
117
|
yield this.run(`ALTER TABLE ${tableName} ADD COLUMN ${column} varchar null;`, []);
|
|
107
118
|
}
|
|
108
119
|
});
|
|
109
120
|
}
|
|
110
|
-
|
|
121
|
+
updateTables() {
|
|
111
122
|
return __awaiter(this, void 0, void 0, function* () {
|
|
112
|
-
yield this.
|
|
113
|
-
yield this.
|
|
123
|
+
yield this.addColumns(['app_secret', 'domain', 'user_id', 'organization_id', 'base_url'], 'crowdin_credentials');
|
|
124
|
+
yield this.addColumns(['crowdin_id'], 'app_metadata');
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
moveIntegrationSettings() {
|
|
128
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
129
|
+
const integrationCredentials = yield this.each('SELECT * FROM integration_credentials', []);
|
|
130
|
+
for (const credentials of integrationCredentials) {
|
|
131
|
+
if (credentials.config) {
|
|
132
|
+
yield this.saveIntegrationConfig(credentials.id, credentials.crowdin_id, credentials.config);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
yield this.removeColumns('config', 'integration_credentials');
|
|
114
136
|
});
|
|
115
137
|
}
|
|
116
138
|
migrate() {
|
|
@@ -153,7 +175,6 @@ class SQLiteStorage {
|
|
|
153
175
|
(
|
|
154
176
|
id varchar not null primary key,
|
|
155
177
|
credentials varchar not null,
|
|
156
|
-
config varchar null,
|
|
157
178
|
crowdin_id varchar not null
|
|
158
179
|
);
|
|
159
180
|
`, []);
|
|
@@ -207,10 +228,38 @@ class SQLiteStorage {
|
|
|
207
228
|
crowdin_id varchar not null,
|
|
208
229
|
integration_id varchar null
|
|
209
230
|
);
|
|
231
|
+
`, []);
|
|
232
|
+
yield this._run(`
|
|
233
|
+
create table if not exists integration_settings
|
|
234
|
+
(
|
|
235
|
+
id integer not null primary key autoincrement,
|
|
236
|
+
integration_id varchar not null,
|
|
237
|
+
crowdin_id varchar not null,
|
|
238
|
+
config varchar null
|
|
239
|
+
);
|
|
240
|
+
`, []);
|
|
241
|
+
yield this._run(`
|
|
242
|
+
create table if not exists job
|
|
243
|
+
(
|
|
244
|
+
id varchar not null primary key,
|
|
245
|
+
integration_id varchar not null,
|
|
246
|
+
crowdin_id varchar not null,
|
|
247
|
+
type varchar not null,
|
|
248
|
+
title varchar null,
|
|
249
|
+
progress integer DEFAULT 0,
|
|
250
|
+
status varchar DEFAULT '${job_1.JobStatus.CREATED}',
|
|
251
|
+
payload varchar null,
|
|
252
|
+
info varchar null,
|
|
253
|
+
data varchar null,
|
|
254
|
+
created_at varchar not null,
|
|
255
|
+
updated_at varchar null,
|
|
256
|
+
finished_at varchar null
|
|
257
|
+
);
|
|
210
258
|
`, []);
|
|
211
259
|
this._res && this._res();
|
|
212
260
|
// TODO: temporary code
|
|
213
|
-
yield this.
|
|
261
|
+
yield this.updateTables();
|
|
262
|
+
yield this.moveIntegrationSettings();
|
|
214
263
|
}
|
|
215
264
|
catch (e) {
|
|
216
265
|
this._rej && this._rej(e);
|
|
@@ -264,6 +313,8 @@ class SQLiteStorage {
|
|
|
264
313
|
yield this.run('DELETE FROM files_snapshot WHERE crowdin_id = ?', [id]);
|
|
265
314
|
yield this.run('DELETE FROM webhooks WHERE crowdin_id = ?', [id]);
|
|
266
315
|
yield this.run('DELETE FROM user_errors WHERE crowdin_id = ?', [id]);
|
|
316
|
+
yield this.run('DELETE FROM integration_settings WHERE crowdin_id = ?', [id]);
|
|
317
|
+
yield this.run('DELETE FROM job WHERE crowdin_id = ?', [id]);
|
|
267
318
|
});
|
|
268
319
|
}
|
|
269
320
|
saveIntegrationCredentials(id, credentials, crowdinId) {
|
|
@@ -276,19 +327,16 @@ class SQLiteStorage {
|
|
|
276
327
|
updateIntegrationCredentials(id, credentials) {
|
|
277
328
|
return this.run('UPDATE integration_credentials SET credentials = ? WHERE id = ?', [credentials, id]);
|
|
278
329
|
}
|
|
279
|
-
updateIntegrationConfig(id, config) {
|
|
280
|
-
return this.run('UPDATE integration_credentials SET config = ? WHERE id = ?', [config, id]);
|
|
281
|
-
}
|
|
282
330
|
getIntegrationCredentials(id) {
|
|
283
331
|
return __awaiter(this, void 0, void 0, function* () {
|
|
284
|
-
const row = yield this.get('SELECT id, credentials,
|
|
332
|
+
const row = yield this.get('SELECT id, credentials, crowdin_id as crowdinId FROM integration_credentials WHERE id = ?', [id]);
|
|
285
333
|
if (row) {
|
|
286
334
|
return row;
|
|
287
335
|
}
|
|
288
336
|
});
|
|
289
337
|
}
|
|
290
338
|
getAllIntegrationCredentials(crowdinId) {
|
|
291
|
-
return this.each('SELECT id, credentials,
|
|
339
|
+
return this.each('SELECT id, credentials, crowdin_id as crowdinId FROM integration_credentials WHERE crowdin_id = ?', [crowdinId]);
|
|
292
340
|
}
|
|
293
341
|
deleteIntegrationCredentials(id) {
|
|
294
342
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -296,6 +344,7 @@ class SQLiteStorage {
|
|
|
296
344
|
yield this.run('DELETE FROM sync_settings where integration_id = ?', [id]);
|
|
297
345
|
yield this.run('DELETE FROM files_snapshot where integration_id = ?', [id]);
|
|
298
346
|
yield this.run('DELETE FROM webhooks where integration_id = ?', [id]);
|
|
347
|
+
yield this.run('DELETE FROM job where integration_id = ?', [id]);
|
|
299
348
|
});
|
|
300
349
|
}
|
|
301
350
|
deleteAllIntegrationCredentials(crowdinId) {
|
|
@@ -305,6 +354,7 @@ class SQLiteStorage {
|
|
|
305
354
|
yield this.run('DELETE FROM files_snapshot where crowdin_id = ?', [crowdinId]);
|
|
306
355
|
yield this.run('DELETE FROM webhooks where crowdin_id = ?', [crowdinId]);
|
|
307
356
|
yield this.run('DELETE FROM user_errors where crowdin_id = ?', [crowdinId]);
|
|
357
|
+
yield this.run('DELETE FROM job where crowdin_id = ?', [crowdinId]);
|
|
308
358
|
});
|
|
309
359
|
}
|
|
310
360
|
saveMetadata(id, metadata, crowdinId) {
|
|
@@ -426,5 +476,101 @@ class SQLiteStorage {
|
|
|
426
476
|
return this.run(`DELETE FROM user_errors WHERE created_at < ? AND crowdin_id = ? AND ${whereIntegrationCondition}`, params);
|
|
427
477
|
});
|
|
428
478
|
}
|
|
479
|
+
saveIntegrationConfig(integrationId, crowdinId, config) {
|
|
480
|
+
return this.run('INSERT INTO integration_settings(integration_id, crowdin_id, config) VALUES (?, ?, ?)', [
|
|
481
|
+
integrationId,
|
|
482
|
+
crowdinId,
|
|
483
|
+
config,
|
|
484
|
+
]);
|
|
485
|
+
}
|
|
486
|
+
getAllIntegrationConfigs(crowdinId) {
|
|
487
|
+
return this.each('SELECT config, integration_id as integrationId FROM integration_settings WHERE crowdin_id = ?', [crowdinId]);
|
|
488
|
+
}
|
|
489
|
+
getIntegrationConfig(integrationId) {
|
|
490
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
491
|
+
const row = yield this.get('SELECT config FROM integration_settings WHERE integration_id = ?', [
|
|
492
|
+
integrationId,
|
|
493
|
+
]);
|
|
494
|
+
if (row) {
|
|
495
|
+
return row;
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
updateIntegrationConfig(integrationId, config) {
|
|
500
|
+
return this.run('UPDATE integration_settings SET config = ? WHERE integration_id = ?', [config, integrationId]);
|
|
501
|
+
}
|
|
502
|
+
createJob({ integrationId, crowdinId, type, title, payload }) {
|
|
503
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
504
|
+
const id = (0, uuid_1.v4)();
|
|
505
|
+
yield this.run(`
|
|
506
|
+
INSERT
|
|
507
|
+
INTO job(id, integration_id, crowdin_id, type, payload, title, created_at)
|
|
508
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
509
|
+
`, [id, integrationId, crowdinId, type, payload, title, Date.now().toString()]);
|
|
510
|
+
return id;
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
updateJob({ id, progress, status, info, data }) {
|
|
514
|
+
const updateFields = ['updated_at = ?'];
|
|
515
|
+
const updateParams = [Date.now().toString()];
|
|
516
|
+
if (progress) {
|
|
517
|
+
updateFields.push('progress = ?');
|
|
518
|
+
updateParams.push(Math.round(progress));
|
|
519
|
+
if (progress >= 100) {
|
|
520
|
+
updateFields.push('finished_at = ?');
|
|
521
|
+
updateParams.push(Date.now().toString());
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
if (status) {
|
|
525
|
+
updateFields.push('status = ?');
|
|
526
|
+
updateParams.push(status);
|
|
527
|
+
if (!updateFields.includes('finished_at = ?') && [job_1.JobStatus.FAILED, job_1.JobStatus.CANCELED].includes(status)) {
|
|
528
|
+
updateFields.push('finished_at = ?');
|
|
529
|
+
updateParams.push(Date.now().toString());
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
if (data) {
|
|
533
|
+
updateFields.push('data = ?');
|
|
534
|
+
updateParams.push(data);
|
|
535
|
+
}
|
|
536
|
+
if (info) {
|
|
537
|
+
updateFields.push('info = ?');
|
|
538
|
+
updateParams.push(info);
|
|
539
|
+
}
|
|
540
|
+
updateParams.push(id);
|
|
541
|
+
const query = `
|
|
542
|
+
UPDATE job
|
|
543
|
+
SET ${updateFields.join(', ')}
|
|
544
|
+
WHERE id = ?
|
|
545
|
+
`;
|
|
546
|
+
return this.run(query, updateParams);
|
|
547
|
+
}
|
|
548
|
+
getJob({ id }) {
|
|
549
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
550
|
+
const row = yield this.get(`
|
|
551
|
+
SELECT id, integration_id as integrationId, crowdin_id as crowdinId, type, payload, progress, status,
|
|
552
|
+
title, info, payload, data, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
|
|
553
|
+
FROM job
|
|
554
|
+
WHERE id = ?
|
|
555
|
+
`, [id]);
|
|
556
|
+
if (row) {
|
|
557
|
+
return row;
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
}
|
|
561
|
+
getActiveJobs({ integrationId, crowdinId }) {
|
|
562
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
563
|
+
return this.each(`
|
|
564
|
+
SELECT id, integration_id as integrationId, crowdin_id as crowdinId, type, payload, progress, status, title, info, payload, data, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
|
|
565
|
+
FROM job
|
|
566
|
+
WHERE integration_id = ? AND crowdin_id = ? AND finished_at is NULL
|
|
567
|
+
`, [integrationId, crowdinId]);
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
deleteFinishedJobs() {
|
|
571
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
572
|
+
yield this.run('DELETE FROM job WHERE finished_at is not NULL', []);
|
|
573
|
+
});
|
|
574
|
+
}
|
|
429
575
|
}
|
|
430
576
|
exports.SQLiteStorage = SQLiteStorage;
|
package/out/util/cron.d.ts
CHANGED
|
@@ -4,3 +4,4 @@ export declare function runJob(config: Config, integration: IntegrationLogic, jo
|
|
|
4
4
|
export declare function filesCron(config: Config, integration: IntegrationLogic, period: string): Promise<void>;
|
|
5
5
|
export declare function skipFoldersFromIntegrationRequest(config: Config, integration: IntegrationLogic, projectId: number, crowdinFiles: UpdateIntegrationRequest, crowdinClient: Crowdin): Promise<UpdateIntegrationRequest>;
|
|
6
6
|
export declare function createOrUpdateSyncSettings(config: Config, req: IntegrationRequest, files: any, provider: Provider, onlyCreate?: boolean): Promise<void>;
|
|
7
|
+
export declare function removeFinishedJobs(): Promise<void>;
|
package/out/util/cron.js
CHANGED
|
@@ -32,14 +32,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
32
32
|
});
|
|
33
33
|
};
|
|
34
34
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
35
|
-
exports.createOrUpdateSyncSettings = exports.skipFoldersFromIntegrationRequest = exports.filesCron = exports.runJob = void 0;
|
|
35
|
+
exports.removeFinishedJobs = exports.createOrUpdateSyncSettings = exports.skipFoldersFromIntegrationRequest = exports.filesCron = exports.runJob = void 0;
|
|
36
36
|
const crowdinAppFunctions = __importStar(require("@crowdin/crowdin-apps-functions"));
|
|
37
37
|
const models_1 = require("../models");
|
|
38
|
+
const job_1 = require("../models/job");
|
|
38
39
|
const storage_1 = require("../storage");
|
|
39
40
|
const connection_1 = require("./connection");
|
|
40
41
|
const defaults_1 = require("./defaults");
|
|
41
42
|
const file_snapshot_1 = require("./file-snapshot");
|
|
42
43
|
const logger_1 = require("./logger");
|
|
44
|
+
const job_2 = require("./job");
|
|
43
45
|
function runJob(config, integration, job) {
|
|
44
46
|
return __awaiter(this, void 0, void 0, function* () {
|
|
45
47
|
(0, logger_1.log)(`Starting cron job with expression [${job.expression}]`);
|
|
@@ -61,11 +63,13 @@ function runJob(config, integration, job) {
|
|
|
61
63
|
return;
|
|
62
64
|
}
|
|
63
65
|
const integrationCredentialsList = yield (0, storage_1.getStorage)().getAllIntegrationCredentials(crowdinCredentials.id);
|
|
66
|
+
const allIntegrationConfigs = yield (0, storage_1.getStorage)().getAllIntegrationConfigs(crowdinCredentials.id);
|
|
64
67
|
for (const integrationCredentials of integrationCredentialsList) {
|
|
68
|
+
const integrationConfig = allIntegrationConfigs.find(({ integrationId }) => integrationId === integrationCredentials.id);
|
|
65
69
|
const projectId = crowdinAppFunctions.getProjectId(integrationCredentials.id);
|
|
66
70
|
const apiCredentials = yield (0, connection_1.prepareIntegrationCredentials)(config, integration, integrationCredentials);
|
|
67
71
|
const rootFolder = yield (0, defaults_1.getRootFolder)(config, integration, crowdinClient, projectId);
|
|
68
|
-
const intConfig =
|
|
72
|
+
const intConfig = (integrationConfig === null || integrationConfig === void 0 ? void 0 : integrationConfig.config) ? JSON.parse(integrationConfig.config) : undefined;
|
|
69
73
|
(0, logger_1.log)(`Executing task for cron job with expression [${job.expression}] for project ${projectId}`);
|
|
70
74
|
yield job.task(projectId, crowdinClient, apiCredentials, rootFolder, intConfig);
|
|
71
75
|
(0, logger_1.log)(`Task for cron job with expression [${job.expression}] for project ${projectId} completed`);
|
|
@@ -85,11 +89,12 @@ function filesCron(config, integration, period) {
|
|
|
85
89
|
let newFiles = [];
|
|
86
90
|
const crowdinCredentials = yield (0, storage_1.getStorage)().getCrowdinCredentials(syncSettings.crowdinId);
|
|
87
91
|
const integrationCredentials = yield (0, storage_1.getStorage)().getIntegrationCredentials(syncSettings.integrationId);
|
|
92
|
+
const integrationConfig = yield (0, storage_1.getStorage)().getIntegrationConfig(syncSettings.integrationId);
|
|
88
93
|
if (!crowdinCredentials || !integrationCredentials) {
|
|
89
94
|
return;
|
|
90
95
|
}
|
|
91
|
-
const intConfig =
|
|
92
|
-
? JSON.parse(
|
|
96
|
+
const intConfig = (integrationConfig === null || integrationConfig === void 0 ? void 0 : integrationConfig.config)
|
|
97
|
+
? JSON.parse(integrationConfig.config)
|
|
93
98
|
: { schedule: '0', condition: '0' };
|
|
94
99
|
if (period !== intConfig.schedule) {
|
|
95
100
|
return;
|
|
@@ -175,7 +180,24 @@ function filesCron(config, integration, period) {
|
|
|
175
180
|
}
|
|
176
181
|
const apiCredentials = yield (0, connection_1.prepareIntegrationCredentials)(config, integration, integrationCredentials);
|
|
177
182
|
try {
|
|
178
|
-
yield
|
|
183
|
+
yield (0, job_2.runAsJob)({
|
|
184
|
+
integrationId: syncSettings.integrationId,
|
|
185
|
+
crowdinId: syncSettings.crowdinId,
|
|
186
|
+
type: job_1.JobType.UPDATE_TO_INTEGRATION,
|
|
187
|
+
title: `Sync files to ${config.name} [scheduled]`,
|
|
188
|
+
payload: filesToProcess,
|
|
189
|
+
jobCallback: (job) => __awaiter(this, void 0, void 0, function* () {
|
|
190
|
+
yield integration.updateIntegration({
|
|
191
|
+
projectId,
|
|
192
|
+
client: crowdinClient,
|
|
193
|
+
credentials: apiCredentials,
|
|
194
|
+
request: filesToProcess,
|
|
195
|
+
rootFolder,
|
|
196
|
+
appSettings: intConfig,
|
|
197
|
+
job,
|
|
198
|
+
});
|
|
199
|
+
}),
|
|
200
|
+
});
|
|
179
201
|
}
|
|
180
202
|
catch (e) {
|
|
181
203
|
(0, logger_1.logError)(e, context);
|
|
@@ -198,7 +220,24 @@ function filesCron(config, integration, period) {
|
|
|
198
220
|
(0, logger_1.log)(`Executing updateCrowdin task for files cron job with period [${period}] for project ${projectId}. Files ${intFiles.length}`);
|
|
199
221
|
const apiCredentials = yield (0, connection_1.prepareIntegrationCredentials)(config, integration, integrationCredentials);
|
|
200
222
|
try {
|
|
201
|
-
yield
|
|
223
|
+
yield (0, job_2.runAsJob)({
|
|
224
|
+
integrationId: syncSettings.integrationId,
|
|
225
|
+
crowdinId: syncSettings.crowdinId,
|
|
226
|
+
type: job_1.JobType.UPDATE_TO_CROWDIN,
|
|
227
|
+
title: 'Sync files to Crowdin [scheduled]',
|
|
228
|
+
payload: intFiles,
|
|
229
|
+
jobCallback: (job) => __awaiter(this, void 0, void 0, function* () {
|
|
230
|
+
yield integration.updateCrowdin({
|
|
231
|
+
projectId,
|
|
232
|
+
client: crowdinClient,
|
|
233
|
+
credentials: apiCredentials,
|
|
234
|
+
request: intFiles,
|
|
235
|
+
rootFolder,
|
|
236
|
+
appSettings: intConfig,
|
|
237
|
+
job,
|
|
238
|
+
});
|
|
239
|
+
}),
|
|
240
|
+
});
|
|
202
241
|
}
|
|
203
242
|
catch (e) {
|
|
204
243
|
(0, logger_1.logError)(e, context);
|
|
@@ -311,3 +350,11 @@ function createOrUpdateSyncSettings(config, req, files, provider, onlyCreate = f
|
|
|
311
350
|
});
|
|
312
351
|
}
|
|
313
352
|
exports.createOrUpdateSyncSettings = createOrUpdateSyncSettings;
|
|
353
|
+
function removeFinishedJobs() {
|
|
354
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
355
|
+
(0, logger_1.log)('Removing all finished jobs');
|
|
356
|
+
yield (0, storage_1.getStorage)().deleteFinishedJobs();
|
|
357
|
+
(0, logger_1.log)('Removed all finished jobs');
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
exports.removeFinishedJobs = removeFinishedJobs;
|
package/out/util/defaults.js
CHANGED
|
@@ -149,17 +149,11 @@ function applyIntegrationModuleDefaults(config, integration) {
|
|
|
149
149
|
if (getUserSettings) {
|
|
150
150
|
fields = yield getUserSettings(projectId, crowdinClient, integrationCredentials);
|
|
151
151
|
}
|
|
152
|
-
const defaultSettings = [
|
|
153
|
-
{
|
|
154
|
-
label: 'Background synchronization',
|
|
155
|
-
},
|
|
156
|
-
];
|
|
152
|
+
const defaultSettings = [];
|
|
157
153
|
defaultSettings.push({
|
|
158
154
|
key: 'schedule',
|
|
159
|
-
label: '
|
|
160
|
-
helpText:
|
|
161
|
-
? 'Set the frequency for pushing sources and translations. The source file changes made in integration will be synced with Crowdin continuously.'
|
|
162
|
-
: 'Set the frequency for pushing sources and translations',
|
|
155
|
+
label: 'Auto sync',
|
|
156
|
+
helpText: 'Adjust the update frequency for sources and translations. If enabled, make sure Auto Sync is enabled for your selected directories and files in the dual pane view.',
|
|
163
157
|
type: 'select',
|
|
164
158
|
defaultValue: '0',
|
|
165
159
|
options: [
|
|
@@ -282,11 +276,10 @@ function convertClientConfig(clientConfig) {
|
|
|
282
276
|
const clientSecret = clientConfig.clientSecret || process.env.CROWDIN_CLIENT_SECRET;
|
|
283
277
|
const port = clientConfig.port || process.env.PORT || 3000;
|
|
284
278
|
const { region = process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION, tmpBucketName = process.env.AWS_TMP_BUCKET_NAME, } = clientConfig.awsConfig || {};
|
|
285
|
-
const sentryDsn = clientConfig.sentryDsn || process.env.SENTRY_DSN;
|
|
286
279
|
if (!baseUrl || !clientId || !clientSecret) {
|
|
287
280
|
throw new Error('One of following parameters are not defined [baseUrl, clientId, clientSecret]');
|
|
288
281
|
}
|
|
289
|
-
return Object.assign(Object.assign({}, clientConfig), {
|
|
282
|
+
return Object.assign(Object.assign({}, clientConfig), { baseUrl: baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl, clientId,
|
|
290
283
|
clientSecret, awsConfig: {
|
|
291
284
|
tmpBucketName,
|
|
292
285
|
region,
|
|
@@ -14,6 +14,7 @@ const models_1 = require("../models");
|
|
|
14
14
|
const storage_1 = require("../storage");
|
|
15
15
|
const defaults_1 = require("./defaults");
|
|
16
16
|
const index_1 = require("./index");
|
|
17
|
+
const files_1 = require("./files");
|
|
17
18
|
function getFileDiff(currentFiles, savedFiles) {
|
|
18
19
|
return currentFiles.filter((x) => !savedFiles.some((x2) => x2.id === x.id));
|
|
19
20
|
}
|
|
@@ -117,6 +118,7 @@ function getIntegrationSnapshot(integration, integrationCredentials, integration
|
|
|
117
118
|
if (integration.integrationOneLevelFetching) {
|
|
118
119
|
files = yield getOneLevelFetchingFiles(integration, integrationCredentials, integrationSettings, files);
|
|
119
120
|
}
|
|
121
|
+
files = (0, files_1.skipFilesByRegex)(files, integration.skipIntegrationNodes);
|
|
120
122
|
// trick for compatibility in requests and set files
|
|
121
123
|
files = files.map((file) => (Object.assign(Object.assign({}, file), { parentId: file.parent_id || file.parentId,
|
|
122
124
|
// eslint-disable-next-line @typescript-eslint/camelcase
|
package/out/util/files.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { ProcessFileString } from '../models';
|
|
2
|
+
import { ProcessFileString, SkipIntegrationNodes, TreeItem } from '../models';
|
|
3
3
|
export declare const MAX_BODY_SIZE: number;
|
|
4
4
|
export declare function storeFile(fileContent: Buffer, folder: string): Promise<string>;
|
|
5
5
|
export declare function getFileContent(url: string): Promise<Buffer>;
|
|
6
6
|
export declare function getFileStrings(url: string): Promise<ProcessFileString[]>;
|
|
7
|
+
export declare function skipFilesByRegex(files: TreeItem[] | undefined, skipIntegrationNodes?: SkipIntegrationNodes): TreeItem[];
|
package/out/util/files.js
CHANGED
|
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
12
12
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.getFileStrings = exports.getFileContent = exports.storeFile = exports.MAX_BODY_SIZE = void 0;
|
|
15
|
+
exports.skipFilesByRegex = exports.getFileStrings = exports.getFileContent = exports.storeFile = exports.MAX_BODY_SIZE = void 0;
|
|
16
16
|
const axios_1 = __importDefault(require("axios"));
|
|
17
17
|
const fs_1 = __importDefault(require("fs"));
|
|
18
18
|
const path_1 = __importDefault(require("path"));
|
|
@@ -45,3 +45,21 @@ function getFileStrings(url) {
|
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
47
|
exports.getFileStrings = getFileStrings;
|
|
48
|
+
function skipFilesByRegex(files, skipIntegrationNodes) {
|
|
49
|
+
if (!Array.isArray(files)) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
if (skipIntegrationNodes) {
|
|
53
|
+
files = files.filter((file) => file);
|
|
54
|
+
if (skipIntegrationNodes.fileNamePattern) {
|
|
55
|
+
const regex = new RegExp(skipIntegrationNodes.fileNamePattern);
|
|
56
|
+
files = files.filter((file) => !('type' in file) || !regex.test(file.name));
|
|
57
|
+
}
|
|
58
|
+
if (skipIntegrationNodes.folderNamePattern) {
|
|
59
|
+
const regex = new RegExp(skipIntegrationNodes.folderNamePattern);
|
|
60
|
+
files = files.filter((file) => 'type' in file || !regex.test(file.name));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return files;
|
|
64
|
+
}
|
|
65
|
+
exports.skipFilesByRegex = skipFilesByRegex;
|
package/out/util/index.js
CHANGED
|
@@ -56,7 +56,9 @@ function handleError(err, req, res) {
|
|
|
56
56
|
res.redirect('/');
|
|
57
57
|
return;
|
|
58
58
|
}
|
|
59
|
-
|
|
59
|
+
if (!res.headersSent) {
|
|
60
|
+
res.status(code).send({ message: (0, logger_1.getErrorMessage)(err), code });
|
|
61
|
+
}
|
|
60
62
|
});
|
|
61
63
|
}
|
|
62
64
|
function runAsyncWrapper(callback) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { JobClient, JobType } from '../models/job';
|
|
2
|
+
import { Response } from 'express';
|
|
3
|
+
export declare function runAsJob({ integrationId, crowdinId, type, title, payload, res, jobCallback, onError, }: {
|
|
4
|
+
integrationId: string;
|
|
5
|
+
crowdinId: string;
|
|
6
|
+
type: JobType;
|
|
7
|
+
title?: string;
|
|
8
|
+
payload?: any;
|
|
9
|
+
res?: Response;
|
|
10
|
+
jobCallback: (arg1: JobClient) => Promise<any>;
|
|
11
|
+
onError?: (e: any) => Promise<void>;
|
|
12
|
+
}): Promise<void>;
|
package/out/util/job.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.runAsJob = void 0;
|
|
13
|
+
const job_1 = require("../models/job");
|
|
14
|
+
const storage_1 = require("../storage");
|
|
15
|
+
const logger_1 = require("./logger");
|
|
16
|
+
const blockingJobs = {
|
|
17
|
+
[job_1.JobType.UPDATE_TO_CROWDIN]: [job_1.JobType.UPDATE_TO_CROWDIN, job_1.JobType.UPDATE_TO_INTEGRATION],
|
|
18
|
+
[job_1.JobType.UPDATE_TO_INTEGRATION]: [job_1.JobType.UPDATE_TO_CROWDIN, job_1.JobType.UPDATE_TO_INTEGRATION],
|
|
19
|
+
};
|
|
20
|
+
function runAsJob({ integrationId, crowdinId, type, title, payload, res, jobCallback, onError, }) {
|
|
21
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
22
|
+
const storage = (0, storage_1.getStorage)();
|
|
23
|
+
const activeJobs = yield storage.getActiveJobs({ integrationId, crowdinId });
|
|
24
|
+
if (activeJobs === null || activeJobs === void 0 ? void 0 : activeJobs.length) {
|
|
25
|
+
const existingJob = activeJobs.find((job) => blockingJobs[type].includes(job.type));
|
|
26
|
+
if (existingJob === null || existingJob === void 0 ? void 0 : existingJob.id) {
|
|
27
|
+
if (res) {
|
|
28
|
+
res.status(202).send({ jobId: existingJob.id, message: 'Job is already running' });
|
|
29
|
+
}
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const jobId = yield storage.createJob({
|
|
34
|
+
integrationId,
|
|
35
|
+
crowdinId,
|
|
36
|
+
type,
|
|
37
|
+
title: title || '',
|
|
38
|
+
payload: JSON.stringify(payload),
|
|
39
|
+
});
|
|
40
|
+
if (res) {
|
|
41
|
+
res.status(202).send({ jobId });
|
|
42
|
+
}
|
|
43
|
+
const job = {
|
|
44
|
+
get: function getJob() {
|
|
45
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
+
return yield storage.getJob({ id: jobId });
|
|
47
|
+
});
|
|
48
|
+
},
|
|
49
|
+
update: function updateProgress({ progress, status, info, data }) {
|
|
50
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
51
|
+
const prevData = yield this.get();
|
|
52
|
+
if ((prevData === null || prevData === void 0 ? void 0 : prevData.status) === job_1.JobStatus.CANCELED) {
|
|
53
|
+
return { isCanceled: true };
|
|
54
|
+
}
|
|
55
|
+
yield storage.updateJob({
|
|
56
|
+
id: jobId,
|
|
57
|
+
progress,
|
|
58
|
+
status: status || job_1.JobStatus.IN_PROGRESS,
|
|
59
|
+
info,
|
|
60
|
+
data: JSON.stringify(data),
|
|
61
|
+
});
|
|
62
|
+
return { isCanceled: false };
|
|
63
|
+
});
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
try {
|
|
67
|
+
const data = yield jobCallback(job);
|
|
68
|
+
yield job.update({
|
|
69
|
+
progress: 100,
|
|
70
|
+
status: job_1.JobStatus.FINISHED,
|
|
71
|
+
data,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
yield job.update({
|
|
76
|
+
status: job_1.JobStatus.FAILED,
|
|
77
|
+
info: (0, logger_1.getErrorMessage)(e),
|
|
78
|
+
});
|
|
79
|
+
if (onError) {
|
|
80
|
+
yield onError(e);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
throw e;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
exports.runAsJob = runAsJob;
|
package/out/util/logger.js
CHANGED
|
@@ -67,7 +67,9 @@ function log(message, context) {
|
|
|
67
67
|
else {
|
|
68
68
|
let prefix = `[${new Date().toISOString()}]`;
|
|
69
69
|
if (context) {
|
|
70
|
+
logsFormatter.resetContext();
|
|
70
71
|
logsFormatter.setContext({
|
|
72
|
+
appIdentifier: context.appIdentifier || '',
|
|
71
73
|
project: {
|
|
72
74
|
id: context.jwtPayload.context.project_id,
|
|
73
75
|
identifier: (_a = context.jwtPayload.context.project_identifier) !== null && _a !== void 0 ? _a : '',
|
|
@@ -100,7 +102,9 @@ function logError(e, context) {
|
|
|
100
102
|
}
|
|
101
103
|
else {
|
|
102
104
|
if (context) {
|
|
105
|
+
logsFormatter.resetContext();
|
|
103
106
|
logsFormatter.setContext({
|
|
107
|
+
appIdentifier: context.appIdentifier || '',
|
|
104
108
|
project: {
|
|
105
109
|
id: context.jwtPayload.context.project_id,
|
|
106
110
|
identifier: (_a = context.jwtPayload.context.project_identifier) !== null && _a !== void 0 ? _a : '',
|