@crowdin/app-project-module 0.74.0 → 0.75.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/modules/api/api.js +75 -3
- package/out/modules/api/components.d.ts +58 -17
- package/out/modules/api/components.js +58 -17
- package/out/modules/integration/handlers/job-cancel.d.ts +2 -1
- package/out/modules/integration/handlers/job-cancel.js +10 -2
- package/out/modules/integration/handlers/job-info.js +32 -1
- package/out/modules/integration/index.js +1 -1
- package/out/modules/integration/util/webhooks.js +18 -12
- package/out/storage/index.js +93 -1
- package/out/storage/postgre.d.ts +3 -1
- package/out/storage/postgre.js +38 -5
- package/out/storage/sqlite.js +7 -5
- package/out/types.d.ts +9 -0
- package/out/types.js +7 -1
- package/out/util/index.d.ts +1 -0
- package/out/util/index.js +6 -1
- package/out/views/main.handlebars +10 -12
- package/package.json +1 -1
package/out/modules/api/api.js
CHANGED
|
@@ -14,6 +14,8 @@ const crowdin_file_progress_1 = __importDefault(require("../integration/handlers
|
|
|
14
14
|
const crowdin_files_1 = __importDefault(require("../integration/handlers/crowdin-files"));
|
|
15
15
|
const crowdin_update_1 = __importDefault(require("../integration/handlers/crowdin-update"));
|
|
16
16
|
const integration_data_1 = __importDefault(require("../integration/handlers/integration-data"));
|
|
17
|
+
const job_info_1 = __importDefault(require("../integration/handlers/job-info"));
|
|
18
|
+
const job_cancel_1 = __importDefault(require("../integration/handlers/job-cancel"));
|
|
17
19
|
const integration_login_1 = __importDefault(require("../integration/handlers/integration-login"));
|
|
18
20
|
const integration_update_1 = __importDefault(require("../integration/handlers/integration-update"));
|
|
19
21
|
const settings_1 = __importDefault(require("../integration/handlers/settings"));
|
|
@@ -55,7 +57,7 @@ function getDefaultApiEndpointsManifest(config) {
|
|
|
55
57
|
description: 'Get a list of synced files',
|
|
56
58
|
documentationUrl: '/api-docs#tag/Files/operation/crowdin.files',
|
|
57
59
|
}, {
|
|
58
|
-
key: '
|
|
60
|
+
key: 'file-translation-progress-api',
|
|
59
61
|
name: 'File Translation Progress',
|
|
60
62
|
url: '/file-progress',
|
|
61
63
|
method: types_1.RequestMethods.GET,
|
|
@@ -82,6 +84,20 @@ function getDefaultApiEndpointsManifest(config) {
|
|
|
82
84
|
method: types_1.RequestMethods.POST,
|
|
83
85
|
description: 'Update integration data',
|
|
84
86
|
documentationUrl: '/api-docs#tag/Files/operation/integration.update',
|
|
87
|
+
}, {
|
|
88
|
+
key: 'job-get-api',
|
|
89
|
+
name: 'Job Status',
|
|
90
|
+
url: '/jobs',
|
|
91
|
+
method: types_1.RequestMethods.GET,
|
|
92
|
+
description: 'Get Job Info',
|
|
93
|
+
documentationUrl: '/api-docs#tag/Jobs/operation/job.get',
|
|
94
|
+
}, {
|
|
95
|
+
key: 'job-cancel-api',
|
|
96
|
+
name: 'Job Status',
|
|
97
|
+
url: '/jobs',
|
|
98
|
+
method: types_1.RequestMethods.DELETE,
|
|
99
|
+
description: 'Cancel Job',
|
|
100
|
+
documentationUrl: '/api-docs#tag/Jobs/operation/job.cancel',
|
|
85
101
|
}, {
|
|
86
102
|
key: 'settings-api',
|
|
87
103
|
name: 'Get App Settings',
|
|
@@ -191,7 +207,7 @@ function addDefaultApiEndpoints(app, config) {
|
|
|
191
207
|
* name: fileId
|
|
192
208
|
* in: query
|
|
193
209
|
* required: true
|
|
194
|
-
* description: '
|
|
210
|
+
* description: 'Get via [List Crowdin Files](#operation/crowdin.files)'
|
|
195
211
|
* schema:
|
|
196
212
|
* type: integer
|
|
197
213
|
* example: 102
|
|
@@ -294,6 +310,62 @@ function addDefaultApiEndpoints(app, config) {
|
|
|
294
310
|
checkSubscriptionExpiration: true,
|
|
295
311
|
moduleKey: config.projectIntegration.key,
|
|
296
312
|
}), (0, integration_credentials_1.default)(config, config.projectIntegration), (0, integration_update_1.default)(config, config.projectIntegration));
|
|
313
|
+
/**
|
|
314
|
+
* @openapi
|
|
315
|
+
* /jobs:
|
|
316
|
+
* get:
|
|
317
|
+
* tags:
|
|
318
|
+
* - 'Jobs'
|
|
319
|
+
* summary: 'Get Job Info'
|
|
320
|
+
* operationId: job.get
|
|
321
|
+
* parameters:
|
|
322
|
+
* - $ref: '#/components/parameters/ProjectId'
|
|
323
|
+
* - name: jobId
|
|
324
|
+
* in: query
|
|
325
|
+
* required: false
|
|
326
|
+
* schema:
|
|
327
|
+
* type: string
|
|
328
|
+
* example: 067da473-fc0b-43e3-b0a2-09d26af130c1
|
|
329
|
+
* responses:
|
|
330
|
+
* 200:
|
|
331
|
+
* description: 'Job information retrieved successfully'
|
|
332
|
+
* content:
|
|
333
|
+
* application/json:
|
|
334
|
+
* schema:
|
|
335
|
+
* $ref: '#/components/schemas/JobResponse'
|
|
336
|
+
*/
|
|
337
|
+
app.get('/jobs', json_response_1.default, (0, crowdin_client_1.default)({
|
|
338
|
+
config,
|
|
339
|
+
optional: false,
|
|
340
|
+
checkSubscriptionExpiration: true,
|
|
341
|
+
moduleKey: config.projectIntegration.key,
|
|
342
|
+
}), (0, job_info_1.default)(config));
|
|
343
|
+
/**
|
|
344
|
+
* @openapi
|
|
345
|
+
* /jobs:
|
|
346
|
+
* delete:
|
|
347
|
+
* tags:
|
|
348
|
+
* - 'Jobs'
|
|
349
|
+
* summary: 'Cancel Job'
|
|
350
|
+
* operationId: job.cancel
|
|
351
|
+
* parameters:
|
|
352
|
+
* - $ref: '#/components/parameters/ProjectId'
|
|
353
|
+
* - name: jobId
|
|
354
|
+
* in: query
|
|
355
|
+
* required: false
|
|
356
|
+
* schema:
|
|
357
|
+
* type: string
|
|
358
|
+
* example: 067da473-fc0b-43e3-b0a2-09d26af130c1
|
|
359
|
+
* responses:
|
|
360
|
+
* 204:
|
|
361
|
+
* description: 'Job canceled successfully'
|
|
362
|
+
*/
|
|
363
|
+
app.delete('/jobs', json_response_1.default, (0, crowdin_client_1.default)({
|
|
364
|
+
config,
|
|
365
|
+
optional: false,
|
|
366
|
+
checkSubscriptionExpiration: true,
|
|
367
|
+
moduleKey: config.projectIntegration.key,
|
|
368
|
+
}), (0, job_cancel_1.default)(config));
|
|
297
369
|
/**
|
|
298
370
|
* @openapi
|
|
299
371
|
* /settings:
|
|
@@ -413,7 +485,7 @@ function addDefaultApiEndpoints(app, config) {
|
|
|
413
485
|
* operationId: integration.fields
|
|
414
486
|
* responses:
|
|
415
487
|
* 200:
|
|
416
|
-
* description: '
|
|
488
|
+
* description: 'Login Form Fields'
|
|
417
489
|
* content:
|
|
418
490
|
* application/json:
|
|
419
491
|
* schema:
|
|
@@ -70,25 +70,32 @@
|
|
|
70
70
|
* - files
|
|
71
71
|
* properties:
|
|
72
72
|
* projectId:
|
|
73
|
-
* description: 'Project
|
|
73
|
+
* description: 'Project Id. Get via [List Projects](https://developer.crowdin.com/api/v2/#operation/api.projects.getMany)'
|
|
74
74
|
* type: integer
|
|
75
75
|
* example: 12
|
|
76
76
|
* files:
|
|
77
|
+
* example: { 102: ['de', 'fr'], 999: ['uk'] }
|
|
77
78
|
* type: object
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
79
|
+
* description: |
|
|
80
|
+
* - **{fileId}** _(integer)_: Crowdin File Id. Get via [List Crowdin Files](#operation/crowdin.files)
|
|
81
|
+
* - **[{languageCode}]** _(array of strings)_: List Of Language Id. Get via [List Supported Languages](https://support.crowdin.com/developer/api/v2/#tag/Languages/operation/api.languages.getMany)
|
|
82
|
+
*
|
|
83
|
+
* **Example:**
|
|
84
|
+
* ```json
|
|
85
|
+
* {
|
|
86
|
+
* 102: ["de", "fr"],
|
|
87
|
+
* 999: ["uk"]
|
|
88
|
+
* }
|
|
89
|
+
* ```
|
|
84
90
|
* UpdateResponse:
|
|
85
91
|
* type: object
|
|
86
|
-
*
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
+
* properties:
|
|
93
|
+
* jobId:
|
|
94
|
+
* type: string
|
|
95
|
+
* example: '067da473-fc0b-43e3-b0a2-09d26af130c1'
|
|
96
|
+
* message:
|
|
97
|
+
* type: string
|
|
98
|
+
* example: 'Another sync is running'
|
|
92
99
|
* SettingsData:
|
|
93
100
|
* type: object
|
|
94
101
|
* example: {schedule: 0, condition: 0}
|
|
@@ -195,8 +202,17 @@
|
|
|
195
202
|
* type: integer
|
|
196
203
|
* example: 86
|
|
197
204
|
* LoginFieldsResponse:
|
|
198
|
-
*
|
|
199
|
-
*
|
|
205
|
+
* type: array
|
|
206
|
+
* items:
|
|
207
|
+
* type: object
|
|
208
|
+
* properties:
|
|
209
|
+
* key:
|
|
210
|
+
* type: string
|
|
211
|
+
* example: 'apiKey'
|
|
212
|
+
* name:
|
|
213
|
+
* type: string
|
|
214
|
+
* example: 'Service API key'
|
|
215
|
+
* example: [{ key: 'email', name: 'User email' }, { key: 'password', name: 'User password' }]
|
|
200
216
|
* Login:
|
|
201
217
|
* title: 'Login'
|
|
202
218
|
* required:
|
|
@@ -211,9 +227,34 @@
|
|
|
211
227
|
* $ref: '#/components/schemas/LoginData'
|
|
212
228
|
* LoginData:
|
|
213
229
|
* type: object
|
|
230
|
+
* description: 'Login Form Fields. Get via [Integration Login Form Fields](#operation/integration.fields)'
|
|
214
231
|
* example: { email: 'user@crowdin.com', password: 'password' }
|
|
215
|
-
*
|
|
216
|
-
*
|
|
232
|
+
* Job:
|
|
233
|
+
* type: object
|
|
234
|
+
* properties:
|
|
235
|
+
* id:
|
|
236
|
+
* type: string
|
|
237
|
+
* description: 'The Unique Identifier For The Job.'
|
|
238
|
+
* example: '067da473-fc0b-43e3-b0a2-09d26af130c1'
|
|
239
|
+
* progress:
|
|
240
|
+
* type: integer
|
|
241
|
+
* description: 'The Progress Of The Job.'
|
|
242
|
+
* example: 94
|
|
243
|
+
* status:
|
|
244
|
+
* type: string
|
|
245
|
+
* description: 'The Current Status Of The Job.'
|
|
246
|
+
* example: 'inProgress'
|
|
247
|
+
* title:
|
|
248
|
+
* type: string
|
|
249
|
+
* description: 'The Title Of The Job.'
|
|
250
|
+
* example: 'Sync files to Crowdin'
|
|
251
|
+
* JobResponse:
|
|
252
|
+
* type: object
|
|
253
|
+
* properties:
|
|
254
|
+
* data:
|
|
255
|
+
* type: array
|
|
256
|
+
* items:
|
|
257
|
+
* $ref: '#/components/schemas/Job'
|
|
217
258
|
*
|
|
218
259
|
* parameters:
|
|
219
260
|
* ProjectId:
|
|
@@ -71,25 +71,32 @@
|
|
|
71
71
|
* - files
|
|
72
72
|
* properties:
|
|
73
73
|
* projectId:
|
|
74
|
-
* description: 'Project
|
|
74
|
+
* description: 'Project Id. Get via [List Projects](https://developer.crowdin.com/api/v2/#operation/api.projects.getMany)'
|
|
75
75
|
* type: integer
|
|
76
76
|
* example: 12
|
|
77
77
|
* files:
|
|
78
|
+
* example: { 102: ['de', 'fr'], 999: ['uk'] }
|
|
78
79
|
* type: object
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
*
|
|
80
|
+
* description: |
|
|
81
|
+
* - **{fileId}** _(integer)_: Crowdin File Id. Get via [List Crowdin Files](#operation/crowdin.files)
|
|
82
|
+
* - **[{languageCode}]** _(array of strings)_: List Of Language Id. Get via [List Supported Languages](https://support.crowdin.com/developer/api/v2/#tag/Languages/operation/api.languages.getMany)
|
|
83
|
+
*
|
|
84
|
+
* **Example:**
|
|
85
|
+
* ```json
|
|
86
|
+
* {
|
|
87
|
+
* 102: ["de", "fr"],
|
|
88
|
+
* 999: ["uk"]
|
|
89
|
+
* }
|
|
90
|
+
* ```
|
|
85
91
|
* UpdateResponse:
|
|
86
92
|
* type: object
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
+
* properties:
|
|
94
|
+
* jobId:
|
|
95
|
+
* type: string
|
|
96
|
+
* example: '067da473-fc0b-43e3-b0a2-09d26af130c1'
|
|
97
|
+
* message:
|
|
98
|
+
* type: string
|
|
99
|
+
* example: 'Another sync is running'
|
|
93
100
|
* SettingsData:
|
|
94
101
|
* type: object
|
|
95
102
|
* example: {schedule: 0, condition: 0}
|
|
@@ -196,8 +203,17 @@
|
|
|
196
203
|
* type: integer
|
|
197
204
|
* example: 86
|
|
198
205
|
* LoginFieldsResponse:
|
|
199
|
-
*
|
|
200
|
-
*
|
|
206
|
+
* type: array
|
|
207
|
+
* items:
|
|
208
|
+
* type: object
|
|
209
|
+
* properties:
|
|
210
|
+
* key:
|
|
211
|
+
* type: string
|
|
212
|
+
* example: 'apiKey'
|
|
213
|
+
* name:
|
|
214
|
+
* type: string
|
|
215
|
+
* example: 'Service API key'
|
|
216
|
+
* example: [{ key: 'email', name: 'User email' }, { key: 'password', name: 'User password' }]
|
|
201
217
|
* Login:
|
|
202
218
|
* title: 'Login'
|
|
203
219
|
* required:
|
|
@@ -212,9 +228,34 @@
|
|
|
212
228
|
* $ref: '#/components/schemas/LoginData'
|
|
213
229
|
* LoginData:
|
|
214
230
|
* type: object
|
|
231
|
+
* description: 'Login Form Fields. Get via [Integration Login Form Fields](#operation/integration.fields)'
|
|
215
232
|
* example: { email: 'user@crowdin.com', password: 'password' }
|
|
216
|
-
*
|
|
217
|
-
*
|
|
233
|
+
* Job:
|
|
234
|
+
* type: object
|
|
235
|
+
* properties:
|
|
236
|
+
* id:
|
|
237
|
+
* type: string
|
|
238
|
+
* description: 'The Unique Identifier For The Job.'
|
|
239
|
+
* example: '067da473-fc0b-43e3-b0a2-09d26af130c1'
|
|
240
|
+
* progress:
|
|
241
|
+
* type: integer
|
|
242
|
+
* description: 'The Progress Of The Job.'
|
|
243
|
+
* example: 94
|
|
244
|
+
* status:
|
|
245
|
+
* type: string
|
|
246
|
+
* description: 'The Current Status Of The Job.'
|
|
247
|
+
* example: 'inProgress'
|
|
248
|
+
* title:
|
|
249
|
+
* type: string
|
|
250
|
+
* description: 'The Title Of The Job.'
|
|
251
|
+
* example: 'Sync files to Crowdin'
|
|
252
|
+
* JobResponse:
|
|
253
|
+
* type: object
|
|
254
|
+
* properties:
|
|
255
|
+
* data:
|
|
256
|
+
* type: array
|
|
257
|
+
* items:
|
|
258
|
+
* $ref: '#/components/schemas/Job'
|
|
218
259
|
*
|
|
219
260
|
* parameters:
|
|
220
261
|
* ProjectId:
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
/// <reference types="qs" />
|
|
2
2
|
import { Response } from 'express';
|
|
3
|
-
|
|
3
|
+
import { Config } from '../../../types';
|
|
4
|
+
export default function handle(config: Config): (req: import("../../../types").CrowdinClientRequest | import("express").Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: Function) => void;
|
|
@@ -12,9 +12,17 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
const types_1 = require("../util/types");
|
|
13
13
|
const util_1 = require("../../../util");
|
|
14
14
|
const storage_1 = require("../../../storage");
|
|
15
|
-
function handle() {
|
|
15
|
+
function handle(config) {
|
|
16
16
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
17
|
-
|
|
17
|
+
var _a;
|
|
18
|
+
const id = req.query.jobId || req.body.jobId;
|
|
19
|
+
const isApi = (0, util_1.isApiRequest)(req, config);
|
|
20
|
+
if (isApi && !((_a = req.body) === null || _a === void 0 ? void 0 : _a.projectId)) {
|
|
21
|
+
res.send({
|
|
22
|
+
error: 'Project id is require',
|
|
23
|
+
});
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
18
26
|
if (!id) {
|
|
19
27
|
req.logInfo('Job id is absent');
|
|
20
28
|
res.status(400).send('Job id is required');
|
|
@@ -35,13 +35,33 @@ function getHumanETA(ms) {
|
|
|
35
35
|
}
|
|
36
36
|
function handle(config) {
|
|
37
37
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
38
|
-
|
|
38
|
+
var _a;
|
|
39
|
+
const id = req.query.jobId || req.body.jobId;
|
|
40
|
+
const isApi = (0, util_1.isApiRequest)(req, config);
|
|
41
|
+
if (isApi && !((_a = req.body) === null || _a === void 0 ? void 0 : _a.projectId)) {
|
|
42
|
+
res.send({
|
|
43
|
+
error: 'Project id is require',
|
|
44
|
+
});
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
39
47
|
if (!id) {
|
|
40
48
|
req.logInfo('Get active jobs');
|
|
41
49
|
const jobs = yield (0, storage_1.getStorage)().getActiveJobs({
|
|
42
50
|
integrationId: req.crowdinContext.clientId,
|
|
43
51
|
crowdinId: req.crowdinContext.crowdinId,
|
|
44
52
|
});
|
|
53
|
+
if (isApi && jobs) {
|
|
54
|
+
const filteredJobs = jobs.map((job) => ({
|
|
55
|
+
id: job.id,
|
|
56
|
+
progress: job.progress,
|
|
57
|
+
status: job.status,
|
|
58
|
+
title: job.title,
|
|
59
|
+
}));
|
|
60
|
+
req.logInfo(`Returning active filtered jobs info ${JSON.stringify(filteredJobs, null, 2)}`);
|
|
61
|
+
res.send(filteredJobs);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
req.logInfo(`Returning active jobs info ${JSON.stringify(jobs, null, 2)}`);
|
|
45
65
|
res.send(jobs);
|
|
46
66
|
return;
|
|
47
67
|
}
|
|
@@ -51,6 +71,17 @@ function handle(config) {
|
|
|
51
71
|
job.eta = ((Date.now() - job.createdAt) / job.progress) * (100 - job.progress);
|
|
52
72
|
job.info = getHumanETA(job.eta) + (job.info ? `\n${job.info}` : '');
|
|
53
73
|
}
|
|
74
|
+
if (isApi && job) {
|
|
75
|
+
const filteredJob = {
|
|
76
|
+
id: job.id,
|
|
77
|
+
progress: job.progress,
|
|
78
|
+
status: job.status,
|
|
79
|
+
title: job.title,
|
|
80
|
+
};
|
|
81
|
+
req.logInfo(`Returning filtered job info ${JSON.stringify(filteredJob, null, 2)}`);
|
|
82
|
+
res.send([filteredJob]);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
54
85
|
if (job && (job === null || job === void 0 ? void 0 : job.updatedAt) && Date.now() - job.updatedAt >= MINUTES * 60 * 1000) {
|
|
55
86
|
const context = req.crowdinContext;
|
|
56
87
|
const projectId = context.jwtPayload.context.project_id;
|
|
@@ -99,7 +99,7 @@ function register({ config, app }) {
|
|
|
99
99
|
optional: false,
|
|
100
100
|
checkSubscriptionExpiration: true,
|
|
101
101
|
moduleKey: integrationLogic.key,
|
|
102
|
-
}), (0, job_cancel_1.default)());
|
|
102
|
+
}), (0, job_cancel_1.default)(config));
|
|
103
103
|
app.post('/api/settings', (0, crowdin_client_1.default)({
|
|
104
104
|
config,
|
|
105
105
|
optional: false,
|
|
@@ -45,8 +45,8 @@ const connection_1 = require("../../../util/connection");
|
|
|
45
45
|
const defaults_1 = require("./defaults");
|
|
46
46
|
const index_1 = require("../../../util/index");
|
|
47
47
|
const logger_1 = require("../../../util/logger");
|
|
48
|
-
const prefetchCount =
|
|
49
|
-
const forceProcessDelay =
|
|
48
|
+
const prefetchCount = 10;
|
|
49
|
+
const forceProcessDelay = 10000;
|
|
50
50
|
exports.HookEvents = {
|
|
51
51
|
fileAdded: 'file.added',
|
|
52
52
|
fileDeleted: 'file.deleted',
|
|
@@ -407,7 +407,7 @@ function consumer({ channel, config, integration, }) {
|
|
|
407
407
|
webhooksInfo[clientId].data.push(data);
|
|
408
408
|
}
|
|
409
409
|
if (messagesCounter < prefetchCount) {
|
|
410
|
-
// if all messages are not received, wait
|
|
410
|
+
// if all messages are not received, wait 10 seconds to force process messages
|
|
411
411
|
timeoutId = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
|
|
412
412
|
yield processMessages({
|
|
413
413
|
webhooksData,
|
|
@@ -436,16 +436,22 @@ function consumer({ channel, config, integration, }) {
|
|
|
436
436
|
}
|
|
437
437
|
function processMessages({ channel, msg, webhooksData, webhooksInfo, }) {
|
|
438
438
|
return __awaiter(this, void 0, void 0, function* () {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
439
|
+
try {
|
|
440
|
+
yield Promise.all(webhooksData);
|
|
441
|
+
for (const { data, integration, webhookData } of Object.values(webhooksInfo)) {
|
|
442
|
+
if (webhookData && webhookData.crowdinClient) {
|
|
443
|
+
yield updateCrowdinFromWebhookRequest({
|
|
444
|
+
integration: integration,
|
|
445
|
+
webhookData: webhookData,
|
|
446
|
+
req: data,
|
|
447
|
+
});
|
|
448
|
+
}
|
|
447
449
|
}
|
|
450
|
+
channel.ack(msg, true);
|
|
451
|
+
}
|
|
452
|
+
catch (e) {
|
|
453
|
+
(0, logger_1.logError)(e);
|
|
454
|
+
channel.nack(msg, false, false);
|
|
448
455
|
}
|
|
449
|
-
channel.ack(msg, true);
|
|
450
456
|
});
|
|
451
457
|
}
|
package/out/storage/index.js
CHANGED
|
@@ -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) {
|
|
@@ -8,18 +31,31 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
31
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
32
|
});
|
|
10
33
|
};
|
|
34
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
|
+
};
|
|
11
37
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
38
|
exports.getStorage = exports.initialize = void 0;
|
|
39
|
+
const types_1 = require("../types");
|
|
13
40
|
const logger_1 = require("../util/logger");
|
|
14
41
|
const mysql_1 = require("./mysql");
|
|
15
42
|
const postgre_1 = require("./postgre");
|
|
16
43
|
const sqlite_1 = require("./sqlite");
|
|
44
|
+
const path_1 = __importStar(require("path"));
|
|
45
|
+
const fs_1 = __importDefault(require("fs"));
|
|
46
|
+
const child_process_1 = require("child_process");
|
|
47
|
+
const util = __importStar(require("node:util"));
|
|
17
48
|
let storage;
|
|
18
49
|
function initialize(config) {
|
|
19
50
|
return __awaiter(this, void 0, void 0, function* () {
|
|
20
51
|
if (config.postgreConfig) {
|
|
21
52
|
(0, logger_1.log)('Using PostgreSQL database');
|
|
22
|
-
|
|
53
|
+
let dumpDirectory = null;
|
|
54
|
+
if (config.migrateToPostgreFromSQLite) {
|
|
55
|
+
dumpDirectory = config.dbFolder;
|
|
56
|
+
createDumpForMigration(config);
|
|
57
|
+
}
|
|
58
|
+
storage = new postgre_1.PostgreStorage(config.postgreConfig, dumpDirectory);
|
|
23
59
|
}
|
|
24
60
|
else if (config.mysqlConfig) {
|
|
25
61
|
(0, logger_1.log)('Using MySQL database');
|
|
@@ -27,6 +63,10 @@ function initialize(config) {
|
|
|
27
63
|
}
|
|
28
64
|
else {
|
|
29
65
|
(0, logger_1.log)('Using SQLite database');
|
|
66
|
+
if (config.migrateToPostgreFromSQLite === false) {
|
|
67
|
+
(0, logger_1.log)('Try to get SQLite file from backup');
|
|
68
|
+
getSqLiteFileFromBackup(config);
|
|
69
|
+
}
|
|
30
70
|
storage = new sqlite_1.SQLiteStorage({ dbFolder: config.dbFolder });
|
|
31
71
|
}
|
|
32
72
|
yield storage.migrate();
|
|
@@ -40,3 +80,55 @@ function getStorage() {
|
|
|
40
80
|
return storage;
|
|
41
81
|
}
|
|
42
82
|
exports.getStorage = getStorage;
|
|
83
|
+
function createDumpForMigration(config) {
|
|
84
|
+
const sqliteFilePath = (0, path_1.join)(config.dbFolder, types_1.storageFiles.SQLITE);
|
|
85
|
+
const backupFilePath = (0, path_1.join)(config.dbFolder, types_1.storageFiles.SQLITE_BACKUP);
|
|
86
|
+
const dumpFilePath = (0, path_1.join)(config.dbFolder, 'dump_sqlite.sql');
|
|
87
|
+
if (!fs_1.default.existsSync(sqliteFilePath)) {
|
|
88
|
+
(0, logger_1.log)('SQLite database not found, skipping migration dump creation');
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
(0, logger_1.log)('Creating dump for migration from SQLite to PostgreSQL');
|
|
92
|
+
(0, child_process_1.execSync)(`sqlite3 ${sqliteFilePath} .dump > ${dumpFilePath}`);
|
|
93
|
+
fs_1.default.renameSync(sqliteFilePath, backupFilePath);
|
|
94
|
+
let modifiedContent = fs_1.default.readFileSync(dumpFilePath).toString();
|
|
95
|
+
// 1. Remove SQLite-specific PRAGMA statements
|
|
96
|
+
modifiedContent = modifiedContent.replace(/PRAGMA foreign_keys=OFF;\n/g, '');
|
|
97
|
+
// 2. Adjust transaction syntax for PostgreSQL
|
|
98
|
+
modifiedContent = modifiedContent.replace(/BEGIN TRANSACTION;\n/g, '');
|
|
99
|
+
modifiedContent = modifiedContent.replace(/COMMIT TRANSACTION;\n/g, '');
|
|
100
|
+
// 3. Ensure tables are only created if they don't already exist
|
|
101
|
+
modifiedContent = modifiedContent
|
|
102
|
+
.replace(/CREATE TABLE IF NOT EXISTS/g, 'CREATE TABLE') // Remove duplicate IF NOT EXISTS
|
|
103
|
+
.replace(/CREATE TABLE/g, 'CREATE TABLE IF NOT EXISTS'); // Add IF NOT EXISTS if missing
|
|
104
|
+
// 4. Add `ON CONFLICT DO NOTHING` to INSERT statements to handle conflicts gracefully
|
|
105
|
+
modifiedContent = modifiedContent.replace(/(INSERT INTO [^;]+)(;)/g, '$1 ON CONFLICT DO NOTHING;');
|
|
106
|
+
// 5. Convert SQLite-specific data types to PostgreSQL equivalents
|
|
107
|
+
modifiedContent = modifiedContent.replace(/integer not null primary key autoincrement/gi, 'serial primary key');
|
|
108
|
+
modifiedContent = modifiedContent.replace(/varchar not null primary key/gi, 'varchar primary key');
|
|
109
|
+
// 6. Remove SQLite-specific function replace()
|
|
110
|
+
modifiedContent = modifiedContent.replace(/replace\s*\('([^']+?)',\s*'?\\[rn]'?\s*,\s*char\s*\([0-9]+\)\s*\)/gi, "'$1'");
|
|
111
|
+
// 7. Remove SQLite-specific sequences
|
|
112
|
+
modifiedContent = modifiedContent.replace(/DELETE FROM sqlite_sequence;\n/g, '');
|
|
113
|
+
modifiedContent = modifiedContent.replace(/INSERT INTO sqlite_sequence .*;\n/g, '');
|
|
114
|
+
// 8. Split the dump into separate statements
|
|
115
|
+
const tables = modifiedContent.split(/(?=CREATE TABLE)/g);
|
|
116
|
+
tables.forEach((tableSql, index) => {
|
|
117
|
+
const match = tableSql.match(/CREATE TABLE IF NOT EXISTS (\w+)/);
|
|
118
|
+
if (match) {
|
|
119
|
+
const dumpFileName = util.format(types_1.storageFiles.DUMP_CHUNK, index);
|
|
120
|
+
(0, logger_1.log)(`Creating dump chunk ${dumpFileName} file for table ${match[1]}`);
|
|
121
|
+
const outputFilePath = path_1.default.join(config.dbFolder, dumpFileName);
|
|
122
|
+
fs_1.default.writeFileSync(outputFilePath, tableSql);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
fs_1.default.unlinkSync(dumpFilePath);
|
|
126
|
+
}
|
|
127
|
+
function getSqLiteFileFromBackup(config) {
|
|
128
|
+
const sqliteFilePath = (0, path_1.join)(config.dbFolder, types_1.storageFiles.SQLITE);
|
|
129
|
+
const backupFilePath = (0, path_1.join)(config.dbFolder, types_1.storageFiles.SQLITE_BACKUP);
|
|
130
|
+
if (fs_1.default.existsSync(backupFilePath) && !fs_1.default.existsSync(sqliteFilePath)) {
|
|
131
|
+
(0, logger_1.log)('Restoring SQLite database from backup');
|
|
132
|
+
fs_1.default.renameSync(backupFilePath, sqliteFilePath);
|
|
133
|
+
}
|
|
134
|
+
}
|
package/out/storage/postgre.d.ts
CHANGED
|
@@ -18,10 +18,11 @@ export interface PostgreStorageConfig {
|
|
|
18
18
|
}
|
|
19
19
|
export declare class PostgreStorage implements Storage {
|
|
20
20
|
private config;
|
|
21
|
+
private directoryPath;
|
|
21
22
|
private _res?;
|
|
22
23
|
private _rej?;
|
|
23
24
|
private dbPromise;
|
|
24
|
-
constructor(config: PostgreStorageConfig);
|
|
25
|
+
constructor(config: PostgreStorageConfig, directoryPath: string | null);
|
|
25
26
|
executeQuery<T>(command: (client: Client) => Promise<T>): Promise<T>;
|
|
26
27
|
migrate(): Promise<void>;
|
|
27
28
|
alterTables(client: Client): Promise<void>;
|
|
@@ -75,4 +76,5 @@ export declare class PostgreStorage implements Storage {
|
|
|
75
76
|
getFileTranslationCache({ integrationId, crowdinId, fileId, }: GetFileTranslationCache): Promise<TranslationCache[] | undefined>;
|
|
76
77
|
getFileTranslationCacheByLanguage({ integrationId, crowdinId, fileId, languageId, }: GetFileTranslationCacheByLanguageParams): Promise<TranslationCache | undefined>;
|
|
77
78
|
updateTranslationCache({ integrationId, crowdinId, fileId, languageId, etag, }: UpdateTranslationCacheParams): Promise<void>;
|
|
79
|
+
private migrateFromSqlite;
|
|
78
80
|
}
|
package/out/storage/postgre.js
CHANGED
|
@@ -9,19 +9,26 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
10
10
|
});
|
|
11
11
|
};
|
|
12
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
13
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
14
|
+
};
|
|
12
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
16
|
exports.PostgreStorage = void 0;
|
|
14
17
|
const pg_1 = require("pg");
|
|
15
18
|
const uuid_1 = require("uuid");
|
|
16
|
-
const types_1 = require("../
|
|
19
|
+
const types_1 = require("../types");
|
|
20
|
+
const types_2 = require("../modules/integration/util/types");
|
|
17
21
|
const util_1 = require("../util");
|
|
22
|
+
const fs_1 = __importDefault(require("fs"));
|
|
23
|
+
const path_1 = require("path");
|
|
18
24
|
class PostgreStorage {
|
|
19
|
-
constructor(config) {
|
|
25
|
+
constructor(config, directoryPath) {
|
|
20
26
|
this.dbPromise = new Promise((res, rej) => {
|
|
21
27
|
this._res = res;
|
|
22
28
|
this._rej = rej;
|
|
23
29
|
});
|
|
24
30
|
this.config = config;
|
|
31
|
+
this.directoryPath = directoryPath;
|
|
25
32
|
}
|
|
26
33
|
executeQuery(command) {
|
|
27
34
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -48,6 +55,9 @@ class PostgreStorage {
|
|
|
48
55
|
migrate() {
|
|
49
56
|
return __awaiter(this, void 0, void 0, function* () {
|
|
50
57
|
try {
|
|
58
|
+
if (this.directoryPath && fs_1.default.existsSync(this.directoryPath)) {
|
|
59
|
+
yield this.migrateFromSqlite(this.directoryPath);
|
|
60
|
+
}
|
|
51
61
|
yield this.executeQuery(this.addTables);
|
|
52
62
|
this._res && this._res();
|
|
53
63
|
// TODO: temporary code
|
|
@@ -64,6 +74,7 @@ class PostgreStorage {
|
|
|
64
74
|
yield this.addColumns(client, ['crowdin_id'], 'app_metadata');
|
|
65
75
|
yield this.addColumns(client, ['agent_id'], 'crowdin_credentials');
|
|
66
76
|
yield this.addColumn(client, 'attempt', 'job', 'int default 0');
|
|
77
|
+
yield this.addColumn(client, 'managers', 'integration_credentials', 'varchar NULL');
|
|
67
78
|
});
|
|
68
79
|
}
|
|
69
80
|
addColumns(client, newColumns, tableName) {
|
|
@@ -185,7 +196,7 @@ class PostgreStorage {
|
|
|
185
196
|
type varchar not null,
|
|
186
197
|
title varchar null,
|
|
187
198
|
progress int default 0,
|
|
188
|
-
status varchar default '${
|
|
199
|
+
status varchar default '${types_2.JobStatus.CREATED}',
|
|
189
200
|
payload varchar null,
|
|
190
201
|
info varchar null,
|
|
191
202
|
data varchar null,
|
|
@@ -588,7 +599,7 @@ class PostgreStorage {
|
|
|
588
599
|
if (status) {
|
|
589
600
|
updateFields.push('status = $' + updateParams.length.toString());
|
|
590
601
|
updateParams.push(status);
|
|
591
|
-
if ((!progress || progress <= 100) && [
|
|
602
|
+
if ((!progress || progress <= 100) && [types_2.JobStatus.FAILED, types_2.JobStatus.CANCELED].includes(status)) {
|
|
592
603
|
updateFields.push('finished_at = $' + updateParams.length.toString());
|
|
593
604
|
updateParams.push(Date.now().toString());
|
|
594
605
|
}
|
|
@@ -657,7 +668,7 @@ class PostgreStorage {
|
|
|
657
668
|
title, info, data, attempt, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
|
|
658
669
|
FROM job
|
|
659
670
|
WHERE status IN ($1, $2) AND finished_at is NULL
|
|
660
|
-
`, [
|
|
671
|
+
`, [types_2.JobStatus.IN_PROGRESS, types_2.JobStatus.CREATED]);
|
|
661
672
|
return (res === null || res === void 0 ? void 0 : res.rows) || [];
|
|
662
673
|
}));
|
|
663
674
|
});
|
|
@@ -708,5 +719,27 @@ class PostgreStorage {
|
|
|
708
719
|
`, [etag, integrationId, crowdinId, fileId, languageId]));
|
|
709
720
|
});
|
|
710
721
|
}
|
|
722
|
+
migrateFromSqlite(directoryPath) {
|
|
723
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
724
|
+
const [name, extension] = types_1.storageFiles.DUMP_CHUNK.split('%d');
|
|
725
|
+
const files = fs_1.default
|
|
726
|
+
.readdirSync(directoryPath)
|
|
727
|
+
.filter((file) => file.startsWith(name) && file.endsWith(extension))
|
|
728
|
+
.sort((a, b) => a.localeCompare(b, undefined, { numeric: true }));
|
|
729
|
+
for (const file of files) {
|
|
730
|
+
const filePath = (0, path_1.join)(directoryPath, file);
|
|
731
|
+
const sql = fs_1.default.readFileSync(filePath, 'utf8');
|
|
732
|
+
try {
|
|
733
|
+
yield this.executeQuery((client) => client.query(sql));
|
|
734
|
+
fs_1.default.unlinkSync(filePath);
|
|
735
|
+
}
|
|
736
|
+
catch (e) {
|
|
737
|
+
console.error('Error while executing', file);
|
|
738
|
+
console.error(e);
|
|
739
|
+
fs_1.default.renameSync(filePath, filePath.replace('dump_chunk_', 'error_dump_chunk_'));
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
});
|
|
743
|
+
}
|
|
711
744
|
}
|
|
712
745
|
exports.PostgreStorage = PostgreStorage;
|
package/out/storage/sqlite.js
CHANGED
|
@@ -16,7 +16,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
16
16
|
exports.SQLiteStorage = void 0;
|
|
17
17
|
const path_1 = require("path");
|
|
18
18
|
const uuid_1 = require("uuid");
|
|
19
|
-
const types_1 = require("../
|
|
19
|
+
const types_1 = require("../types");
|
|
20
|
+
const types_2 = require("../modules/integration/util/types");
|
|
20
21
|
class SQLiteStorage {
|
|
21
22
|
constructor(config) {
|
|
22
23
|
this.dbPromise = new Promise((res, rej) => {
|
|
@@ -132,6 +133,7 @@ class SQLiteStorage {
|
|
|
132
133
|
yield this.addColumns(['app_secret', 'domain', 'user_id', 'agent_id', 'organization_id', 'base_url'], 'crowdin_credentials');
|
|
133
134
|
yield this.addColumns(['crowdin_id'], 'app_metadata');
|
|
134
135
|
yield this.addColumn('job', 'attempt', 'DEFAULT 0');
|
|
136
|
+
yield this.addColumn('managers', 'integration_credentials', 'null');
|
|
135
137
|
});
|
|
136
138
|
}
|
|
137
139
|
moveIntegrationSettings() {
|
|
@@ -175,7 +177,7 @@ class SQLiteStorage {
|
|
|
175
177
|
});
|
|
176
178
|
const sqlite = require('sqlite3');
|
|
177
179
|
//@ts-ignore
|
|
178
|
-
this.db = new sqlite.Database((0, path_1.join)(this.config.dbFolder,
|
|
180
|
+
this.db = new sqlite.Database((0, path_1.join)(this.config.dbFolder, types_1.storageFiles.SQLITE), (error) => {
|
|
179
181
|
if (error) {
|
|
180
182
|
_connection_rej(error);
|
|
181
183
|
}
|
|
@@ -279,7 +281,7 @@ class SQLiteStorage {
|
|
|
279
281
|
type varchar not null,
|
|
280
282
|
title varchar null,
|
|
281
283
|
progress integer DEFAULT 0,
|
|
282
|
-
status varchar DEFAULT '${
|
|
284
|
+
status varchar DEFAULT '${types_2.JobStatus.CREATED}',
|
|
283
285
|
payload varchar null,
|
|
284
286
|
info varchar null,
|
|
285
287
|
data varchar null,
|
|
@@ -583,7 +585,7 @@ class SQLiteStorage {
|
|
|
583
585
|
if (status) {
|
|
584
586
|
updateFields.push('status = ?');
|
|
585
587
|
updateParams.push(status);
|
|
586
|
-
if (!updateFields.includes('finished_at = ?') && [
|
|
588
|
+
if (!updateFields.includes('finished_at = ?') && [types_2.JobStatus.FAILED, types_2.JobStatus.CANCELED].includes(status)) {
|
|
587
589
|
updateFields.push('finished_at = ?');
|
|
588
590
|
updateParams.push(Date.now().toString());
|
|
589
591
|
}
|
|
@@ -641,7 +643,7 @@ class SQLiteStorage {
|
|
|
641
643
|
SELECT id, integration_id as integrationId, crowdin_id as crowdinId, type, payload, progress, status, title, info, data, attempt, created_at as createdAt, updated_at as updatedAt, finished_at as finishedAt
|
|
642
644
|
FROM job
|
|
643
645
|
WHERE status IN (?,?) AND finished_at is NULL
|
|
644
|
-
`, [
|
|
646
|
+
`, [types_2.JobStatus.IN_PROGRESS, types_2.JobStatus.CREATED]);
|
|
645
647
|
});
|
|
646
648
|
}
|
|
647
649
|
saveTranslationCache({ integrationId, crowdinId, fileId, languageId, etag }) {
|
package/out/types.d.ts
CHANGED
|
@@ -82,6 +82,10 @@ export interface ClientConfig extends ImagePath {
|
|
|
82
82
|
* folder where module will create sqlite db file to persist credentials (e.g. {@example __dirname})
|
|
83
83
|
*/
|
|
84
84
|
dbFolder?: string;
|
|
85
|
+
/**
|
|
86
|
+
* migrate from SQLite to PostgreSQL
|
|
87
|
+
*/
|
|
88
|
+
migrateToPostgreFromSQLite?: boolean;
|
|
85
89
|
/**
|
|
86
90
|
* config to configure PostgreSQL as a storage
|
|
87
91
|
*/
|
|
@@ -449,4 +453,9 @@ export interface SignaturePatterns {
|
|
|
449
453
|
fileName?: string;
|
|
450
454
|
fileContent?: string;
|
|
451
455
|
}
|
|
456
|
+
export declare enum storageFiles {
|
|
457
|
+
SQLITE = "app.sqlite",
|
|
458
|
+
SQLITE_BACKUP = "backup_app.sqlite",
|
|
459
|
+
DUMP_CHUNK = "dump_chunk_%d.sql"
|
|
460
|
+
}
|
|
452
461
|
export {};
|
package/out/types.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ProjectPermissions = exports.UserPermissions = exports.EditorMode = exports.SubscriptionInfoType = exports.AccountType = exports.Scope = exports.AuthenticationType = void 0;
|
|
3
|
+
exports.storageFiles = exports.ProjectPermissions = exports.UserPermissions = exports.EditorMode = exports.SubscriptionInfoType = exports.AccountType = exports.Scope = exports.AuthenticationType = void 0;
|
|
4
4
|
var AuthenticationType;
|
|
5
5
|
(function (AuthenticationType) {
|
|
6
6
|
AuthenticationType["CODE"] = "authorization_code";
|
|
@@ -66,3 +66,9 @@ var ProjectPermissions;
|
|
|
66
66
|
ProjectPermissions["OWN"] = "own";
|
|
67
67
|
ProjectPermissions["RESTRICTED"] = "restricted";
|
|
68
68
|
})(ProjectPermissions = exports.ProjectPermissions || (exports.ProjectPermissions = {}));
|
|
69
|
+
var storageFiles;
|
|
70
|
+
(function (storageFiles) {
|
|
71
|
+
storageFiles["SQLITE"] = "app.sqlite";
|
|
72
|
+
storageFiles["SQLITE_BACKUP"] = "backup_app.sqlite";
|
|
73
|
+
storageFiles["DUMP_CHUNK"] = "dump_chunk_%d.sql";
|
|
74
|
+
})(storageFiles = exports.storageFiles || (exports.storageFiles = {}));
|
package/out/util/index.d.ts
CHANGED
|
@@ -14,3 +14,4 @@ export declare function isJson(string: string): boolean;
|
|
|
14
14
|
export declare function getPreviousDate(days: number): Date;
|
|
15
15
|
export declare function prepareFormDataMetadataId(req: CrowdinClientRequest, config: Config): Promise<string>;
|
|
16
16
|
export declare function validateEmail(email: string | number): boolean;
|
|
17
|
+
export declare function isApiRequest(req: Request, config: Config): boolean;
|
package/out/util/index.js
CHANGED
|
@@ -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.validateEmail = exports.prepareFormDataMetadataId = exports.getPreviousDate = exports.isJson = exports.isAuthorizedConfig = exports.getLogoUrl = exports.executeWithRetry = exports.decryptData = exports.encryptData = exports.runAsyncWrapper = exports.CodeError = void 0;
|
|
35
|
+
exports.isApiRequest = exports.validateEmail = exports.prepareFormDataMetadataId = exports.getPreviousDate = exports.isJson = exports.isAuthorizedConfig = exports.getLogoUrl = exports.executeWithRetry = exports.decryptData = exports.encryptData = exports.runAsyncWrapper = exports.CodeError = void 0;
|
|
36
36
|
const crypto = __importStar(require("crypto-js"));
|
|
37
37
|
const storage_1 = require("../storage");
|
|
38
38
|
const types_1 = require("../types");
|
|
@@ -162,3 +162,8 @@ function validateEmail(email) {
|
|
|
162
162
|
return emailRegExp.test(String(email).toLowerCase());
|
|
163
163
|
}
|
|
164
164
|
exports.validateEmail = validateEmail;
|
|
165
|
+
function isApiRequest(req, config) {
|
|
166
|
+
const origin = req.headers['origin'] || req.headers['referer'];
|
|
167
|
+
return !origin || !origin.includes(config.baseUrl);
|
|
168
|
+
}
|
|
169
|
+
exports.isApiRequest = isApiRequest;
|
|
@@ -573,16 +573,14 @@
|
|
|
573
573
|
} else if (tree.length) {
|
|
574
574
|
appComponent.pushIntegrationFilesData(tree).then(() => {
|
|
575
575
|
if (parentId) {
|
|
576
|
-
appIntegrationFiles.getSelected().then(selection => {
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
const
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
});
|
|
585
|
-
appIntegrationFiles.setSelected(selectedIds);
|
|
576
|
+
appIntegrationFiles.getSelected().then(async selection => {
|
|
577
|
+
const selectedIds = selection?.filter((node) => node).map(({id}) => id.toString());
|
|
578
|
+
const filteredNodes = tree.filter((node) => !selectedIds.includes(node.id.toString()) && selectedIds.includes(node.parent_id.toString()));
|
|
579
|
+
|
|
580
|
+
if (filteredNodes?.length) {
|
|
581
|
+
const filteredNodesId = filteredNodes.map(({id}) => id.toString());
|
|
582
|
+
await appIntegrationFiles.setSelected(filteredNodesId);
|
|
583
|
+
}
|
|
586
584
|
});
|
|
587
585
|
}
|
|
588
586
|
});
|
|
@@ -726,7 +724,7 @@
|
|
|
726
724
|
}
|
|
727
725
|
|
|
728
726
|
checkOrigin()
|
|
729
|
-
.then(restParams => fetch('api/jobs' + restParams + '&
|
|
727
|
+
.then(restParams => fetch('api/jobs' + restParams + '&jobId=' + jobId, {
|
|
730
728
|
method: 'DELETE',
|
|
731
729
|
headers: { 'Content-Type': 'application/json' },
|
|
732
730
|
}))
|
|
@@ -767,7 +765,7 @@
|
|
|
767
765
|
}
|
|
768
766
|
|
|
769
767
|
checkOrigin()
|
|
770
|
-
.then(restParams => fetch('api/jobs' + restParams + '&
|
|
768
|
+
.then(restParams => fetch('api/jobs' + restParams + '&jobId=' + jobId))
|
|
771
769
|
.then(checkResponse)
|
|
772
770
|
.then((job) => {
|
|
773
771
|
const isFailed = [JOB_STATUS.failed, JOB_STATUS.canceled].includes(job.status);
|
package/package.json
CHANGED