@crowdin/app-project-module 0.13.2 → 0.14.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/README.md +22 -0
- package/out/handlers/crowdin-file-progress.js +2 -0
- package/out/handlers/crowdin-files.js +3 -0
- package/out/handlers/crowdin-project.js +4 -1
- package/out/handlers/crowdin-update.js +7 -2
- package/out/handlers/custom-file-format/download.js +1 -0
- package/out/handlers/custom-file-format/process.js +2 -0
- package/out/handlers/custom-mt/translate.js +3 -0
- package/out/handlers/install.js +3 -0
- package/out/handlers/integration-data.js +2 -0
- package/out/handlers/integration-login.js +3 -0
- package/out/handlers/integration-logout.js +1 -0
- package/out/handlers/integration-update.js +4 -0
- package/out/handlers/main.js +3 -0
- package/out/handlers/oauth-login.js +41 -27
- package/out/handlers/settings-save.js +1 -0
- package/out/handlers/sync-settings-save.js +2 -0
- package/out/handlers/sync-settings.js +2 -0
- package/out/handlers/uninstall.js +2 -0
- package/out/middlewares/crowdin-client.js +15 -0
- package/out/middlewares/integration-credentials.js +1 -0
- package/out/models/index.d.ts +8 -0
- package/out/util/index.d.ts +2 -1
- package/out/util/index.js +29 -1
- package/out/views/login.handlebars +5 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -38,6 +38,7 @@ In both options you will need to provide Crowdin App configuration file. Please
|
|
|
38
38
|
- [Background tasks](#background-tasks)
|
|
39
39
|
- [Error propagation](#error-propagation)
|
|
40
40
|
- [Error interceptor](#error-interceptor)
|
|
41
|
+
- [Debug mode](#debug-mode)
|
|
41
42
|
- [Custom File Format](#custom-file-format)
|
|
42
43
|
- [Custom MT](#custom-mt)
|
|
43
44
|
- [Resources](#resources)
|
|
@@ -412,6 +413,27 @@ configuration.onError = (error) => {
|
|
|
412
413
|
};
|
|
413
414
|
```
|
|
414
415
|
|
|
416
|
+
## Debug mode
|
|
417
|
+
|
|
418
|
+
Also you can turn on the debug mode and application will log everything (useful of debugging).
|
|
419
|
+
|
|
420
|
+
```javascript
|
|
421
|
+
configuration.logger = {
|
|
422
|
+
enabled: true
|
|
423
|
+
};
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
Or even you can pass you own function to log messages (e.g. send them to external monitoring system).
|
|
427
|
+
|
|
428
|
+
```javascript
|
|
429
|
+
configuration.logger = {
|
|
430
|
+
enabled: true,
|
|
431
|
+
log: (message) => {
|
|
432
|
+
console.log(message);
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
```
|
|
436
|
+
|
|
415
437
|
## Custom File Format
|
|
416
438
|
|
|
417
439
|
Example of [custom file format module](https://support.crowdin.com/crowdin-apps-modules/#custom-file-format-module).
|
|
@@ -13,7 +13,9 @@ const util_1 = require("../util");
|
|
|
13
13
|
function handle(config) {
|
|
14
14
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
15
15
|
const fileId = Number(req.params.fileId);
|
|
16
|
+
(0, util_1.log)(`Loading translation progress for file ${fileId}`, config.logger);
|
|
16
17
|
const progress = yield req.crowdinApiClient.translationStatusApi.getFileProgress(req.crowdinContext.jwtPayload.context.project_id, fileId);
|
|
18
|
+
(0, util_1.log)(`Translation progress for file ${fileId} ${JSON.stringify(progress.data, null, 2)}`, config.logger);
|
|
17
19
|
res.send({ [fileId]: progress.data.map(e => e.data) });
|
|
18
20
|
}), config.onError);
|
|
19
21
|
}
|
|
@@ -12,11 +12,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
const util_1 = require("../util");
|
|
13
13
|
function handle(config, integration) {
|
|
14
14
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
15
|
+
(0, util_1.log)('Loading crowdin files', config.logger);
|
|
15
16
|
if (integration.getCrowdinFiles) {
|
|
16
17
|
const rootFolder = yield (0, util_1.getRootFolder)(config, integration, req.crowdinApiClient, req.crowdinContext.jwtPayload.context.project_id);
|
|
18
|
+
(0, util_1.log)(`Loading files ${rootFolder ? `from folder ${rootFolder.id}` : 'from root'}`, config.logger);
|
|
17
19
|
const files = integration.getCrowdinFiles
|
|
18
20
|
? yield integration.getCrowdinFiles(req.crowdinContext.jwtPayload.context.project_id, req.crowdinApiClient, rootFolder, req.integrationSettings)
|
|
19
21
|
: [];
|
|
22
|
+
(0, util_1.log)(`Returning files ${JSON.stringify(files, null, 2)}`, config.logger);
|
|
20
23
|
res.send(files);
|
|
21
24
|
}
|
|
22
25
|
else {
|
|
@@ -12,7 +12,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
const util_1 = require("../util");
|
|
13
13
|
function handle(config) {
|
|
14
14
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
15
|
-
const
|
|
15
|
+
const projectId = req.crowdinContext.jwtPayload.context.project_id;
|
|
16
|
+
(0, util_1.log)(`Loading crowdin project ${projectId}`, config.logger);
|
|
17
|
+
const project = yield req.crowdinApiClient.projectsGroupsApi.getProject(projectId);
|
|
18
|
+
(0, util_1.log)(`Loaded crowdin project ${JSON.stringify(project, null, 2)}`, config.logger);
|
|
16
19
|
res.send(project.data);
|
|
17
20
|
}), config.onError);
|
|
18
21
|
}
|
|
@@ -12,8 +12,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
const util_1 = require("../util");
|
|
13
13
|
function handle(config, integration) {
|
|
14
14
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
15
|
-
const
|
|
16
|
-
|
|
15
|
+
const projectId = req.crowdinContext.jwtPayload.context.project_id;
|
|
16
|
+
(0, util_1.log)(`Upading crowdin project ${projectId}`, config.logger);
|
|
17
|
+
const rootFolder = yield (0, util_1.getRootFolder)(config, integration, req.crowdinApiClient, projectId);
|
|
18
|
+
if (rootFolder) {
|
|
19
|
+
(0, util_1.log)(`Upading crowdin files under folder ${rootFolder.id}`, config.logger);
|
|
20
|
+
}
|
|
21
|
+
yield integration.updateCrowdin(projectId, req.crowdinApiClient, req.integrationCredentials, req.body, rootFolder, req.integrationSettings);
|
|
17
22
|
res.status(204).end();
|
|
18
23
|
}), config.onError);
|
|
19
24
|
}
|
|
@@ -18,6 +18,7 @@ const util_1 = require("../../util");
|
|
|
18
18
|
function handle(config, folder) {
|
|
19
19
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
20
20
|
const filePath = path_1.default.join(folder, 'custom-file-format', req.query.file);
|
|
21
|
+
(0, util_1.log)(`Downloading file ${filePath}`, config.logger);
|
|
21
22
|
res.download(filePath, function (err) {
|
|
22
23
|
if (err) {
|
|
23
24
|
console.error(err);
|
|
@@ -98,6 +98,7 @@ function handle(baseConfig, baseUrl, folder, config) {
|
|
|
98
98
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
99
99
|
const baseFilesUrl = `${baseUrl}/file/download`;
|
|
100
100
|
const body = req.body;
|
|
101
|
+
(0, util_1.log)(`Recieved request to process file ${JSON.stringify(body, null, 2)}`, baseConfig.logger);
|
|
101
102
|
let file;
|
|
102
103
|
if (body.file.content) {
|
|
103
104
|
file = Buffer.from(body.file.content, 'base64').toString();
|
|
@@ -114,6 +115,7 @@ function handle(baseConfig, baseUrl, folder, config) {
|
|
|
114
115
|
response = yield handleParseFile(baseFilesUrl, folder, config, file, body, req.crowdinApiClient, req.crowdinContext, req.crowdinContext.jwtPayload.context.project_id);
|
|
115
116
|
break;
|
|
116
117
|
}
|
|
118
|
+
(0, util_1.log)(`Returning response from process file action ${JSON.stringify(response, null, 2)}`, baseConfig.logger);
|
|
117
119
|
res.send({ data: response });
|
|
118
120
|
}), baseConfig.onError);
|
|
119
121
|
}
|
|
@@ -15,6 +15,9 @@ function handle(baseConfig, config) {
|
|
|
15
15
|
const source = req.query.source;
|
|
16
16
|
const target = req.query.target;
|
|
17
17
|
const body = req.body;
|
|
18
|
+
(0, util_1.log)('Recieved request for custom mt', baseConfig.logger);
|
|
19
|
+
(0, util_1.log)(`Source language ${source}, target language ${target}`, baseConfig.logger);
|
|
20
|
+
(0, util_1.log)(`Payload ${JSON.stringify(body, null, 2)}`, baseConfig.logger);
|
|
18
21
|
const projectId = Number(req.query.project_id);
|
|
19
22
|
try {
|
|
20
23
|
if (source === 'en' && target === 'de' && body.strings && body.strings[0] === 'validation') {
|
package/out/handlers/install.js
CHANGED
|
@@ -16,6 +16,7 @@ const util_1 = require("../util");
|
|
|
16
16
|
function handle(config) {
|
|
17
17
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
18
18
|
const event = req.body;
|
|
19
|
+
(0, util_1.log)(`Recieved install request ${JSON.stringify(event, null, 2)}`, config.logger);
|
|
19
20
|
const token = yield (0, crowdin_apps_functions_1.generateOAuthToken)(config.clientId, config.clientSecret, event.code);
|
|
20
21
|
const credentials = {
|
|
21
22
|
id: (event.domain || event.organizationId).toString(),
|
|
@@ -27,9 +28,11 @@ function handle(config) {
|
|
|
27
28
|
const existingCredentials = yield (0, storage_1.getCrowdinCredentials)(credentials.id);
|
|
28
29
|
if (!!existingCredentials) {
|
|
29
30
|
yield (0, storage_1.updateCrowdinCredentials)(credentials);
|
|
31
|
+
(0, util_1.log)('An existing App has been reinstalled', config.logger);
|
|
30
32
|
}
|
|
31
33
|
else {
|
|
32
34
|
yield (0, storage_1.saveCrowdinCredentials)(credentials);
|
|
35
|
+
(0, util_1.log)('A new App has been installed', config.logger);
|
|
33
36
|
}
|
|
34
37
|
res.status(204).end();
|
|
35
38
|
}), config.onError);
|
|
@@ -12,7 +12,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
const util_1 = require("../util");
|
|
13
13
|
function handle(config, integration) {
|
|
14
14
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
15
|
+
(0, util_1.log)('Recieved request to get integration data', config.logger);
|
|
15
16
|
const files = yield integration.getIntegrationFiles(req.integrationCredentials, req.integrationSettings);
|
|
17
|
+
(0, util_1.log)(`Integration data response ${JSON.stringify(files, null, 2)}`, config.logger);
|
|
16
18
|
res.send(files);
|
|
17
19
|
}), config.onError);
|
|
18
20
|
}
|
|
@@ -13,11 +13,14 @@ const storage_1 = require("../storage");
|
|
|
13
13
|
const util_1 = require("../util");
|
|
14
14
|
function handle(config, integration) {
|
|
15
15
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
16
|
+
(0, util_1.log)('Recieved integration login request', config.logger);
|
|
16
17
|
if (integration.checkConnection) {
|
|
18
|
+
(0, util_1.log)('Checking the integration credentials', config.logger);
|
|
17
19
|
yield integration.checkConnection(req.body.credentials);
|
|
18
20
|
}
|
|
19
21
|
const existing = yield (0, storage_1.getIntegrationCredentials)(req.crowdinContext.clientId);
|
|
20
22
|
if (!!existing) {
|
|
23
|
+
(0, util_1.log)('Deleting old credentials', config.logger);
|
|
21
24
|
yield (0, storage_1.deleteIntegrationCredentials)(req.crowdinContext.clientId);
|
|
22
25
|
}
|
|
23
26
|
yield (0, storage_1.saveIntegrationCredentials)(req.crowdinContext.clientId, (0, util_1.encryptData)(config.clientSecret, JSON.stringify(req.body.credentials)), req.crowdinContext.crowdinId);
|
|
@@ -13,6 +13,7 @@ const storage_1 = require("../storage");
|
|
|
13
13
|
const util_1 = require("../util");
|
|
14
14
|
function handle(config) {
|
|
15
15
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
16
|
+
(0, util_1.log)('Recieved integration logout request', config.logger);
|
|
16
17
|
yield (0, storage_1.deleteIntegrationCredentials)(req.crowdinContext.clientId);
|
|
17
18
|
res.status(204).end();
|
|
18
19
|
}), config.onError);
|
|
@@ -12,7 +12,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
const util_1 = require("../util");
|
|
13
13
|
function handle(config, integration) {
|
|
14
14
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
15
|
+
(0, util_1.log)('Upading integratino data', config.logger);
|
|
15
16
|
const rootFolder = yield (0, util_1.getRootFolder)(config, integration, req.crowdinApiClient, req.crowdinContext.jwtPayload.context.project_id);
|
|
17
|
+
if (rootFolder) {
|
|
18
|
+
(0, util_1.log)(`Upading integration data for crowding root folder ${rootFolder.id}`, config.logger);
|
|
19
|
+
}
|
|
16
20
|
yield integration.updateIntegration(req.crowdinContext.jwtPayload.context.project_id, req.crowdinApiClient, req.integrationCredentials, req.body, rootFolder, req.integrationSettings);
|
|
17
21
|
res.status(204).end();
|
|
18
22
|
}), config.onError);
|
package/out/handlers/main.js
CHANGED
|
@@ -41,16 +41,19 @@ function handle(config, integration) {
|
|
|
41
41
|
options.loginFields = (_a = integration.loginForm) === null || _a === void 0 ? void 0 : _a.fields;
|
|
42
42
|
if (integration.oauthLogin) {
|
|
43
43
|
options.oauthUrl = constructOauthUrl(config, integration);
|
|
44
|
+
(0, util_1.log)(`Adding oauth url ${options.oauthUrl}`, config.logger);
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
else if (integration.getConfiguration) {
|
|
47
48
|
const configurationFields = yield integration.getConfiguration(req.crowdinContext.jwtPayload.context.project_id, req.crowdinApiClient, req.integrationCredentials);
|
|
48
49
|
options.configurationFields = configurationFields;
|
|
49
50
|
options.config = JSON.stringify(req.integrationSettings || {});
|
|
51
|
+
(0, util_1.log)(`Adding configuration fields ${JSON.stringify(configurationFields, null, 2)}`, config.logger);
|
|
50
52
|
}
|
|
51
53
|
options.infoModal = integration.infoModal;
|
|
52
54
|
options.withCronSync = integration.withCronSync;
|
|
53
55
|
options.withWebhookSync = integration.withWebhookSync;
|
|
56
|
+
(0, util_1.log)(`Routing user to ${view} view`, config.logger);
|
|
54
57
|
return res.render(view, options);
|
|
55
58
|
}), config.onError);
|
|
56
59
|
}
|
|
@@ -17,38 +17,52 @@ const util_1 = require("../util");
|
|
|
17
17
|
function handle(config, integration) {
|
|
18
18
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
19
19
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
20
|
+
const message = {
|
|
21
|
+
uid: 'oauth_popup',
|
|
22
|
+
};
|
|
20
23
|
const code = req.query[((_b = (_a = integration.oauthLogin) === null || _a === void 0 ? void 0 : _a.fieldsMapping) === null || _b === void 0 ? void 0 : _b.code) || 'code'];
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
if (oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.performGetTokenRequest) {
|
|
24
|
-
credentials = yield oauthLogin.performGetTokenRequest(code);
|
|
25
|
-
}
|
|
26
|
-
else {
|
|
27
|
-
const request = {};
|
|
24
|
+
(0, util_1.log)(`Recieved request from OAuth login callback. Code ${code}`, config.logger);
|
|
25
|
+
try {
|
|
28
26
|
const oauthLogin = integration.oauthLogin;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
27
|
+
let credentials;
|
|
28
|
+
if (oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.performGetTokenRequest) {
|
|
29
|
+
(0, util_1.log)('Performing custom get bearer token request', config.logger);
|
|
30
|
+
credentials = yield oauthLogin.performGetTokenRequest(code);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
const request = {};
|
|
34
|
+
const oauthLogin = integration.oauthLogin;
|
|
35
|
+
request[((_c = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _c === void 0 ? void 0 : _c.code) || 'code'] = code;
|
|
36
|
+
request[((_d = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _d === void 0 ? void 0 : _d.clientId) || 'client_id'] = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.clientId;
|
|
37
|
+
request[((_e = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _e === void 0 ? void 0 : _e.clientSecret) || 'client_secret'] = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.clientSecret;
|
|
38
|
+
request[((_f = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _f === void 0 ? void 0 : _f.redirectUri) || 'redirect_uri'] = `${config.baseUrl}${(0, util_1.getOauthRoute)(integration)}`;
|
|
39
|
+
if (oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.extraAccessTokenParameters) {
|
|
40
|
+
Object.entries(oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.extraAccessTokenParameters).forEach(([key, value]) => (request[key] = value));
|
|
41
|
+
}
|
|
42
|
+
credentials = (yield axios_1.default.post(((_g = integration.oauthLogin) === null || _g === void 0 ? void 0 : _g.accessTokenUrl) || '', request, {
|
|
43
|
+
headers: { Accept: 'application/json' },
|
|
44
|
+
})).data;
|
|
45
|
+
}
|
|
46
|
+
const oauthCredentials = {};
|
|
47
|
+
oauthCredentials.accessToken = credentials[((_h = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _h === void 0 ? void 0 : _h.accessToken) || 'access_token'];
|
|
48
|
+
if (oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.refresh) {
|
|
49
|
+
oauthCredentials.refreshToken = credentials[((_j = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _j === void 0 ? void 0 : _j.refreshToken) || 'refresh_token'];
|
|
50
|
+
oauthCredentials.expireIn =
|
|
51
|
+
Number(credentials[((_k = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _k === void 0 ? void 0 : _k.expiresIn) || 'expires_in']) + Date.now() / 1000;
|
|
35
52
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
})).data;
|
|
53
|
+
message.data = oauthCredentials;
|
|
54
|
+
return res.render('oauth', { message: JSON.stringify(message) });
|
|
39
55
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
56
|
+
catch (e) {
|
|
57
|
+
if (config.onError) {
|
|
58
|
+
config.onError(e);
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
console.error(e);
|
|
62
|
+
}
|
|
63
|
+
message.data = { error: (0, util_1.getMessage)(e) };
|
|
64
|
+
return res.render('oauth', { message: JSON.stringify(message) });
|
|
49
65
|
}
|
|
50
|
-
message.data = oauthCredentials;
|
|
51
|
-
return res.render('oauth', { message: JSON.stringify(message) });
|
|
52
66
|
}), config.onError);
|
|
53
67
|
}
|
|
54
68
|
exports.default = handle;
|
|
@@ -13,6 +13,7 @@ const storage_1 = require("../storage");
|
|
|
13
13
|
const util_1 = require("../util");
|
|
14
14
|
function handle(config) {
|
|
15
15
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
16
|
+
(0, util_1.log)(`Saving settings ${JSON.stringify(req.body.config, null, 2)}`, config.logger);
|
|
16
17
|
yield (0, storage_1.updateIntegrationConfig)(req.crowdinContext.clientId, JSON.stringify(req.body.config));
|
|
17
18
|
res.status(204).end();
|
|
18
19
|
}), config.onError);
|
|
@@ -16,9 +16,11 @@ function handle(config) {
|
|
|
16
16
|
const { files, type, provider } = req.body;
|
|
17
17
|
const existingSettings = yield (0, storage_1.getSyncSettings)(req.crowdinContext.clientId, req.crowdinContext.crowdinId, type, provider);
|
|
18
18
|
if (existingSettings) {
|
|
19
|
+
(0, util_1.log)(`Updating sync settings for type ${type} and provider ${provider} ${JSON.stringify(files, null, 2)}`, config.logger);
|
|
19
20
|
yield (0, storage_1.updateSyncSettings)(JSON.stringify(files), req.crowdinContext.clientId, req.crowdinContext.crowdinId, type, provider);
|
|
20
21
|
}
|
|
21
22
|
else {
|
|
23
|
+
(0, util_1.log)(`Saving sync settings for type ${type} and provider ${provider} ${JSON.stringify(files, null, 2)}`, config.logger);
|
|
22
24
|
yield (0, storage_1.saveSyncSettings)(JSON.stringify(files), req.crowdinContext.clientId, req.crowdinContext.crowdinId, type, provider);
|
|
23
25
|
}
|
|
24
26
|
res.status(204).end();
|
|
@@ -15,10 +15,12 @@ function handle(config) {
|
|
|
15
15
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
16
16
|
let files = {};
|
|
17
17
|
const provider = req.params.provider;
|
|
18
|
+
(0, util_1.log)(`Loading sync settings for provider ${provider}`, config.logger);
|
|
18
19
|
const syncSettings = yield (0, storage_1.getSyncSettingsByProvider)(req.crowdinContext.clientId, provider);
|
|
19
20
|
if (syncSettings) {
|
|
20
21
|
files = JSON.parse(syncSettings.files) || [];
|
|
21
22
|
}
|
|
23
|
+
(0, util_1.log)(`Returning sync settings ${JSON.stringify(files, null, 2)}`, config.logger);
|
|
22
24
|
res.send(files);
|
|
23
25
|
}), config.onError);
|
|
24
26
|
}
|
|
@@ -14,11 +14,13 @@ const util_1 = require("../util");
|
|
|
14
14
|
function handle(config) {
|
|
15
15
|
return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
16
16
|
const event = req.body;
|
|
17
|
+
(0, util_1.log)(`Recieved uninstall request ${JSON.stringify(event, null, 2)}`, config.logger);
|
|
17
18
|
const organization = (event.domain || event.organizationId).toString();
|
|
18
19
|
yield (0, storage_1.deleteCrowdinCredentials)(organization);
|
|
19
20
|
if (config.onUninstall) {
|
|
20
21
|
yield config.onUninstall(organization);
|
|
21
22
|
}
|
|
23
|
+
(0, util_1.log)('App has been uninstalled', config.logger);
|
|
22
24
|
res.status(204).end();
|
|
23
25
|
}), config.onError);
|
|
24
26
|
}
|
|
@@ -29,6 +29,7 @@ function prepareCrowdinRequest(jwtToken, config, optional = false) {
|
|
|
29
29
|
let context;
|
|
30
30
|
let client;
|
|
31
31
|
try {
|
|
32
|
+
(0, util_1.log)('Validating jwt token from incoming request', config.logger);
|
|
32
33
|
const jwtPayload = yield (0, crowdin_apps_functions_1.validateJwtToken)(jwtToken, config.clientSecret);
|
|
33
34
|
context = {
|
|
34
35
|
jwtPayload,
|
|
@@ -37,9 +38,16 @@ function prepareCrowdinRequest(jwtToken, config, optional = false) {
|
|
|
37
38
|
};
|
|
38
39
|
}
|
|
39
40
|
catch (e) {
|
|
41
|
+
if (config.onError) {
|
|
42
|
+
config.onError(e);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
console.error(e);
|
|
46
|
+
}
|
|
40
47
|
throw new Error("Can't verify");
|
|
41
48
|
}
|
|
42
49
|
try {
|
|
50
|
+
(0, util_1.log)('Loading crowdin credentials', config.logger);
|
|
43
51
|
const credentials = yield (0, storage_1.getCrowdinCredentials)(context.crowdinId);
|
|
44
52
|
if (!credentials) {
|
|
45
53
|
if (optional) {
|
|
@@ -47,9 +55,16 @@ function prepareCrowdinRequest(jwtToken, config, optional = false) {
|
|
|
47
55
|
}
|
|
48
56
|
throw new Error("Can't find organization by id");
|
|
49
57
|
}
|
|
58
|
+
(0, util_1.log)('Building crowdin client instance', config.logger);
|
|
50
59
|
client = yield (0, util_1.prepareCrowdinClient)(config, credentials);
|
|
51
60
|
}
|
|
52
61
|
catch (e) {
|
|
62
|
+
if (config.onError) {
|
|
63
|
+
config.onError(e);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
console.error(e);
|
|
67
|
+
}
|
|
53
68
|
throw new Error('Access denied');
|
|
54
69
|
}
|
|
55
70
|
return { context, client };
|
|
@@ -14,6 +14,7 @@ const util_1 = require("../util");
|
|
|
14
14
|
function handle(config, integration, optional = false) {
|
|
15
15
|
return (0, util_1.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
16
16
|
const clientId = req.crowdinContext.clientId;
|
|
17
|
+
(0, util_1.log)(`Loading integration credentials for client ${clientId}`, config.logger);
|
|
17
18
|
const integrationCredentials = yield (0, storage_1.getIntegrationCredentials)(clientId);
|
|
18
19
|
if (!integrationCredentials) {
|
|
19
20
|
if (optional) {
|
package/out/models/index.d.ts
CHANGED
|
@@ -102,6 +102,10 @@ export interface Config extends ImagePath {
|
|
|
102
102
|
* Error interceptor (can be used to log error in centralized place)
|
|
103
103
|
*/
|
|
104
104
|
onError?: (error: any) => void;
|
|
105
|
+
/**
|
|
106
|
+
* Configuration to log everything that are happening in the app
|
|
107
|
+
*/
|
|
108
|
+
logger?: Logger;
|
|
105
109
|
}
|
|
106
110
|
export declare enum Scope {
|
|
107
111
|
ALL_SCOPES = "all",
|
|
@@ -488,4 +492,8 @@ interface ImagePath {
|
|
|
488
492
|
*/
|
|
489
493
|
imagePath?: string;
|
|
490
494
|
}
|
|
495
|
+
export interface Logger {
|
|
496
|
+
enabled: boolean;
|
|
497
|
+
log?: (message: string) => void;
|
|
498
|
+
}
|
|
491
499
|
export {};
|
package/out/util/index.d.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import Crowdin, { SourceFilesModel } from '@crowdin/crowdin-api-client';
|
|
2
2
|
import { Request, Response } from 'express';
|
|
3
|
-
import { Config, CronJob, CrowdinCredentials, IntegrationCredentials, IntegrationLogic } from '../models';
|
|
3
|
+
import { Config, CronJob, CrowdinCredentials, IntegrationCredentials, IntegrationLogic, Logger } from '../models';
|
|
4
4
|
export declare class CodeError extends Error {
|
|
5
5
|
code: number | undefined;
|
|
6
6
|
constructor(message: string, code?: number);
|
|
7
7
|
}
|
|
8
|
+
export declare function log(message: string, logger?: Logger): void;
|
|
8
9
|
export declare function getMessage(err: any): any;
|
|
9
10
|
export declare function runAsyncWrapper(callback: Function, onError?: (e: any) => void): (req: Request, res: Response, next: Function) => void;
|
|
10
11
|
export declare function encryptData(secret: string, data: string): string;
|
package/out/util/index.js
CHANGED
|
@@ -31,7 +31,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
31
31
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
32
32
|
};
|
|
33
33
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
|
-
exports.filesCron = exports.runJob = exports.prepareIntegrationCredentials = exports.prepareCrowdinClient = exports.applyDefaults = exports.getRootFolder = exports.getOauthRoute = exports.decryptData = exports.encryptData = exports.runAsyncWrapper = exports.getMessage = exports.CodeError = void 0;
|
|
34
|
+
exports.filesCron = exports.runJob = exports.prepareIntegrationCredentials = exports.prepareCrowdinClient = exports.applyDefaults = exports.getRootFolder = exports.getOauthRoute = exports.decryptData = exports.encryptData = exports.runAsyncWrapper = exports.getMessage = exports.log = exports.CodeError = void 0;
|
|
35
35
|
const crowdin_api_client_1 = __importDefault(require("@crowdin/crowdin-api-client"));
|
|
36
36
|
const crowdinAppFunctions = __importStar(require("@crowdin/crowdin-apps-functions"));
|
|
37
37
|
const axios_1 = __importDefault(require("axios"));
|
|
@@ -45,6 +45,19 @@ class CodeError extends Error {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
exports.CodeError = CodeError;
|
|
48
|
+
function log(message, logger) {
|
|
49
|
+
if (logger === null || logger === void 0 ? void 0 : logger.enabled) {
|
|
50
|
+
if (logger.log) {
|
|
51
|
+
logger.log(message);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
const timestamp = new Date().toISOString();
|
|
55
|
+
// eslint-disable-next-line no-console
|
|
56
|
+
console.log(`[${timestamp}] ${message}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.log = log;
|
|
48
61
|
function isCrowdinClientRequest(req) {
|
|
49
62
|
return req.crowdinContext;
|
|
50
63
|
}
|
|
@@ -222,7 +235,9 @@ function prepareCrowdinClient(config, credentials) {
|
|
|
222
235
|
});
|
|
223
236
|
}
|
|
224
237
|
else {
|
|
238
|
+
log('Crowdin credentials have expired. Requesting a new credentials', config.logger);
|
|
225
239
|
const newCredentials = yield crowdinAppFunctions.refreshOAuthToken(config.clientId, config.clientSecret, decryptData(config.clientSecret, credentials.refreshToken));
|
|
240
|
+
log('Saving updated crowdin credentials in the database', config.logger);
|
|
226
241
|
yield (0, storage_1.updateCrowdinCredentials)({
|
|
227
242
|
id: credentials.id,
|
|
228
243
|
refreshToken: encryptData(config.clientSecret, newCredentials.refreshToken),
|
|
@@ -243,11 +258,13 @@ function prepareIntegrationCredentials(config, integration, integrationCredentia
|
|
|
243
258
|
return __awaiter(this, void 0, void 0, function* () {
|
|
244
259
|
const credentials = JSON.parse(decryptData(config.clientSecret, integrationCredentials.credentials));
|
|
245
260
|
if ((_a = integration.oauthLogin) === null || _a === void 0 ? void 0 : _a.refresh) {
|
|
261
|
+
log('Checking if integration credentials need to be refreshed', config.logger);
|
|
246
262
|
const oauthLogin = integration.oauthLogin;
|
|
247
263
|
const { expireIn } = credentials;
|
|
248
264
|
//2 min as an extra buffer
|
|
249
265
|
const isExpired = expireIn + 120 < Date.now() / 1000;
|
|
250
266
|
if (isExpired) {
|
|
267
|
+
log('Integration credentials have expired. Requesting a new credentials', config.logger);
|
|
251
268
|
let newCredentials;
|
|
252
269
|
if (oauthLogin.performRefreshTokenRequest) {
|
|
253
270
|
newCredentials = yield oauthLogin.performRefreshTokenRequest(credentials);
|
|
@@ -271,6 +288,7 @@ function prepareIntegrationCredentials(config, integration, integrationCredentia
|
|
|
271
288
|
if (newCredentials[((_g = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _g === void 0 ? void 0 : _g.refreshToken) || 'refresh_token']) {
|
|
272
289
|
credentials.refreshToken = newCredentials[((_h = oauthLogin === null || oauthLogin === void 0 ? void 0 : oauthLogin.fieldsMapping) === null || _h === void 0 ? void 0 : _h.refreshToken) || 'refresh_token'];
|
|
273
290
|
}
|
|
291
|
+
log('Saving updated integration credentials in the database', config.logger);
|
|
274
292
|
yield (0, storage_1.updateIntegrationCredentials)(integrationCredentials.id, encryptData(config.clientSecret, JSON.stringify(credentials)));
|
|
275
293
|
}
|
|
276
294
|
}
|
|
@@ -280,6 +298,7 @@ function prepareIntegrationCredentials(config, integration, integrationCredentia
|
|
|
280
298
|
exports.prepareIntegrationCredentials = prepareIntegrationCredentials;
|
|
281
299
|
function runJob(config, integration, job) {
|
|
282
300
|
return __awaiter(this, void 0, void 0, function* () {
|
|
301
|
+
log(`Starting cron job with expression [${job.expression}]`, config.logger);
|
|
283
302
|
const crowdinCredentialsList = yield (0, storage_1.getAllCrowdinCredentials)();
|
|
284
303
|
yield Promise.all(crowdinCredentialsList.map((crowdinCredentials) => __awaiter(this, void 0, void 0, function* () {
|
|
285
304
|
const crowdinClient = yield prepareCrowdinClient(config, crowdinCredentials);
|
|
@@ -291,14 +310,18 @@ function runJob(config, integration, job) {
|
|
|
291
310
|
const intConfig = integrationCredentials.config
|
|
292
311
|
? JSON.parse(integrationCredentials.config)
|
|
293
312
|
: undefined;
|
|
313
|
+
log(`Executing task for cron job with expression [${job.expression}] for project ${projectId}`, config.logger);
|
|
294
314
|
yield job.task(projectId, crowdinClient, apiCredentials, rootFolder, intConfig);
|
|
315
|
+
log(`Task for cron job with expression [${job.expression}] for project ${projectId} completed`, config.logger);
|
|
295
316
|
})));
|
|
296
317
|
})));
|
|
318
|
+
log(`Cron job with expression [${job.expression}] completed`, config.logger);
|
|
297
319
|
});
|
|
298
320
|
}
|
|
299
321
|
exports.runJob = runJob;
|
|
300
322
|
function filesCron(config, integration, period) {
|
|
301
323
|
return __awaiter(this, void 0, void 0, function* () {
|
|
324
|
+
log(`Starting files cron job with period [${period}]`, config.logger);
|
|
302
325
|
const syncSettingsList = yield (0, storage_1.getAllSyncSettingsByType)('schedule');
|
|
303
326
|
yield Promise.all(syncSettingsList.map((syncSettings) => __awaiter(this, void 0, void 0, function* () {
|
|
304
327
|
const files = JSON.parse(syncSettings.files);
|
|
@@ -314,14 +337,19 @@ function filesCron(config, integration, period) {
|
|
|
314
337
|
const apiCredentials = yield prepareIntegrationCredentials(config, integration, integrationCredentials);
|
|
315
338
|
const rootFolder = yield getRootFolder(config, integration, crowdinClient, projectId);
|
|
316
339
|
if (syncSettings.provider === 'crowdin') {
|
|
340
|
+
log(`Executing updateIntegration task for files cron job with period [${period}] for project ${projectId} and request ${JSON.stringify(files, null, 2)}`, config.logger);
|
|
317
341
|
yield integration.updateIntegration(projectId, crowdinClient, apiCredentials, files, rootFolder, intConfig);
|
|
342
|
+
log(`updateIntegration task for files cron job with period [${period}] for project ${projectId} completed`, config.logger);
|
|
318
343
|
}
|
|
319
344
|
else {
|
|
345
|
+
log(`Executing updateCrowdin task for files cron job with period [${period}] for project ${projectId} and request ${JSON.stringify(files, null, 2)}`, config.logger);
|
|
320
346
|
yield integration.updateCrowdin(projectId, crowdinClient, apiCredentials, files, rootFolder, intConfig);
|
|
347
|
+
log(`updateCrowdin task for files cron job with period [${period}] for project ${projectId} completed`, config.logger);
|
|
321
348
|
}
|
|
322
349
|
}
|
|
323
350
|
}
|
|
324
351
|
})));
|
|
352
|
+
log(`Files cron job with period [${period}] completed`, config.logger);
|
|
325
353
|
});
|
|
326
354
|
}
|
|
327
355
|
exports.filesCron = filesCron;
|
|
@@ -65,9 +65,13 @@
|
|
|
65
65
|
|
|
66
66
|
function oauthLogin() {
|
|
67
67
|
const url = '{{{ oauthUrl }}}';
|
|
68
|
-
const oauthWindow = window.open(url, '{{ name }}', 'location=0,status=0,width=800,height=400');
|
|
68
|
+
const oauthWindow = window.open(url, '{{ name }}', 'location=0,status=0,width=800,height=400');
|
|
69
69
|
postPromises['oauth_popup'] = {
|
|
70
70
|
resolve: (data) => {
|
|
71
|
+
if (data.error) {
|
|
72
|
+
showToast(data.error);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
71
75
|
integrationLogin({
|
|
72
76
|
refreshToken: data.refreshToken,
|
|
73
77
|
accessToken: data.accessToken,
|
package/package.json
CHANGED