@crowdin/app-project-module 0.26.6 → 0.28.0-10
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/CONTRIBUTING.md +19 -1
- package/README.md +1 -855
- package/out/handlers/crowdin-file-progress.d.ts +2 -2
- package/out/handlers/crowdin-file-progress.js +9 -4
- package/out/handlers/crowdin-update.js +4 -3
- package/out/handlers/crowdin-webhook.d.ts +4 -0
- package/out/handlers/crowdin-webhook.js +43 -0
- package/out/handlers/form-data-display.d.ts +3 -0
- package/out/handlers/form-data-display.js +46 -0
- package/out/handlers/form-data-save.d.ts +3 -0
- package/out/handlers/form-data-save.js +56 -0
- package/out/handlers/integration-logout.js +4 -0
- package/out/handlers/integration-webhook.d.ts +4 -0
- package/out/handlers/integration-webhook.js +39 -0
- package/out/handlers/main.js +7 -1
- package/out/handlers/settings-save.d.ts +2 -2
- package/out/handlers/settings-save.js +8 -3
- package/out/handlers/uninstall.js +4 -0
- package/out/index.js +50 -10
- package/out/middlewares/render-ui-module.d.ts +4 -0
- package/out/middlewares/render-ui-module.js +33 -0
- package/out/models/index.d.ts +79 -7
- package/out/models/index.js +13 -1
- package/out/static/css/styles.css +96 -0
- package/out/static/js/dependent.js +307 -0
- package/out/static/js/form.js +115 -0
- package/out/static/js/main.js +11 -1
- package/out/util/cron.js +9 -10
- package/out/util/defaults.js +55 -12
- package/out/util/index.js +5 -1
- package/out/util/webhooks.d.ts +29 -0
- package/out/util/webhooks.js +308 -0
- package/out/views/form.handlebars +29 -0
- package/out/views/login.handlebars +84 -16
- package/out/views/main.handlebars +171 -88
- package/out/views/partials/head.handlebars +5 -4
- package/package.json +37 -23
package/out/static/js/main.js
CHANGED
|
@@ -23,9 +23,19 @@ function parentWindowPostMessage(data) {
|
|
|
23
23
|
|
|
24
24
|
window.addEventListener('message', handleMessage);
|
|
25
25
|
|
|
26
|
+
function isJson(string) {
|
|
27
|
+
try {
|
|
28
|
+
JSON.parse(string);
|
|
29
|
+
} catch (e) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
|
|
26
36
|
function handleMessage(event) {
|
|
27
37
|
const eventData =
|
|
28
|
-
event.data && typeof event.data === 'string' ? JSON.parse(event.data) : {};
|
|
38
|
+
event.data && typeof event.data === 'string' && isJson(event.data) ? JSON.parse(event.data) : {};
|
|
29
39
|
if (postPromises[eventData.uid]) {
|
|
30
40
|
if (postPromises[eventData.uid].timer) {
|
|
31
41
|
clearTimeout(postPromises[eventData.uid].timer);
|
package/out/util/cron.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
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);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -31,15 +35,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
31
35
|
exports.filesCron = exports.runJob = void 0;
|
|
32
36
|
const crowdinAppFunctions = __importStar(require("@crowdin/crowdin-apps-functions"));
|
|
33
37
|
const _1 = require(".");
|
|
38
|
+
const models_1 = require("../models");
|
|
34
39
|
const storage_1 = require("../storage");
|
|
35
40
|
const connection_1 = require("./connection");
|
|
36
41
|
const defaults_1 = require("./defaults");
|
|
37
|
-
var SyncCondition;
|
|
38
|
-
(function (SyncCondition) {
|
|
39
|
-
SyncCondition["ALL"] = "0";
|
|
40
|
-
SyncCondition["TRANSLATED"] = "1";
|
|
41
|
-
SyncCondition["APPROVED"] = "2";
|
|
42
|
-
})(SyncCondition || (SyncCondition = {}));
|
|
43
42
|
function runJob(config, integration, job) {
|
|
44
43
|
return __awaiter(this, void 0, void 0, function* () {
|
|
45
44
|
(0, _1.log)(`Starting cron job with expression [${job.expression}]`, config.logger);
|
|
@@ -97,9 +96,9 @@ function filesCron(config, integration, period) {
|
|
|
97
96
|
const chunkSize = 10;
|
|
98
97
|
if (syncSettings.provider === 'crowdin') {
|
|
99
98
|
const crowdinFiles = files;
|
|
100
|
-
const onlyTranslated = intConfig.condition === SyncCondition.TRANSLATED;
|
|
101
|
-
const onlyApproved = intConfig.condition === SyncCondition.APPROVED;
|
|
102
|
-
const all = intConfig.condition === SyncCondition.ALL || intConfig.condition === undefined;
|
|
99
|
+
const onlyTranslated = +intConfig.condition === models_1.SyncCondition.TRANSLATED;
|
|
100
|
+
const onlyApproved = +intConfig.condition === models_1.SyncCondition.APPROVED;
|
|
101
|
+
const all = +intConfig.condition === models_1.SyncCondition.ALL || intConfig.condition === undefined;
|
|
103
102
|
const filesToProcess = all
|
|
104
103
|
? crowdinFiles
|
|
105
104
|
: yield getOnlyTranslatedOrApprovedFiles(config, projectId, crowdinFiles, crowdinClient, onlyApproved, onlyTranslated);
|
package/out/util/defaults.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
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);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -53,21 +57,20 @@ function getOauthRoute(integration) {
|
|
|
53
57
|
}
|
|
54
58
|
exports.getOauthRoute = getOauthRoute;
|
|
55
59
|
function applyDefaults(config, integration) {
|
|
60
|
+
var _a;
|
|
56
61
|
if (!integration.getCrowdinFiles) {
|
|
57
62
|
integration.getCrowdinFiles = (projectId, client, rootFolder) => __awaiter(this, void 0, void 0, function* () {
|
|
58
63
|
const allBranches = (yield client.sourceFilesApi.withFetchAll().listProjectBranches(projectId)).data.map((d) => d.data);
|
|
59
|
-
let
|
|
64
|
+
let options = {};
|
|
60
65
|
if (rootFolder) {
|
|
61
|
-
|
|
66
|
+
options = {
|
|
62
67
|
directoryId: rootFolder.id,
|
|
63
68
|
recursion: 'true',
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
allDirectories = (yield client.sourceFilesApi.withFetchAll().listProjectDirectories(projectId)).data.map((d) => d.data);
|
|
69
|
+
};
|
|
68
70
|
}
|
|
71
|
+
const allDirectories = (yield client.sourceFilesApi.withFetchAll().listProjectDirectories(projectId, options)).data.map((d) => d.data);
|
|
69
72
|
const directoryIds = allDirectories.map((d) => d.id);
|
|
70
|
-
let files = (yield client.sourceFilesApi.withFetchAll().listProjectFiles(projectId)).data.map((d) => d.data);
|
|
73
|
+
let files = (yield client.sourceFilesApi.withFetchAll().listProjectFiles(projectId, options)).data.map((d) => d.data);
|
|
71
74
|
files = files.filter((f) => (rootFolder && f.directoryId === rootFolder.id) ||
|
|
72
75
|
directoryIds.includes(f.directoryId) ||
|
|
73
76
|
(!rootFolder && !f.directoryId));
|
|
@@ -118,6 +121,12 @@ function applyDefaults(config, integration) {
|
|
|
118
121
|
return res;
|
|
119
122
|
});
|
|
120
123
|
}
|
|
124
|
+
if (!integration.getFileProgress) {
|
|
125
|
+
integration.getFileProgress = (projectId, client, fileId) => __awaiter(this, void 0, void 0, function* () {
|
|
126
|
+
const progress = yield client.translationStatusApi.getFileProgress(projectId, fileId);
|
|
127
|
+
return { [fileId]: progress.data.map((e) => e.data) };
|
|
128
|
+
});
|
|
129
|
+
}
|
|
121
130
|
if (!integration.loginForm) {
|
|
122
131
|
integration.loginForm = {
|
|
123
132
|
fields: [
|
|
@@ -129,22 +138,43 @@ function applyDefaults(config, integration) {
|
|
|
129
138
|
],
|
|
130
139
|
};
|
|
131
140
|
}
|
|
132
|
-
if (integration.withCronSync) {
|
|
141
|
+
if (integration.withCronSync || integration.webhooks) {
|
|
133
142
|
const getUserSettings = integration.getConfiguration;
|
|
134
143
|
integration.getConfiguration = (projectId, crowdinClient, integrationCredentials) => __awaiter(this, void 0, void 0, function* () {
|
|
135
144
|
let fields = [];
|
|
136
145
|
if (getUserSettings) {
|
|
137
146
|
fields = yield getUserSettings(projectId, crowdinClient, integrationCredentials);
|
|
138
147
|
}
|
|
139
|
-
|
|
148
|
+
const defaultSettings = [
|
|
140
149
|
{
|
|
141
150
|
label: 'Background synchronization',
|
|
142
151
|
},
|
|
143
|
-
|
|
152
|
+
];
|
|
153
|
+
const syncType = {
|
|
154
|
+
key: 'syncType',
|
|
155
|
+
label: 'Type of synchronization',
|
|
156
|
+
type: 'select',
|
|
157
|
+
defaultValue: '0',
|
|
158
|
+
options: [
|
|
159
|
+
{
|
|
160
|
+
value: '0',
|
|
161
|
+
label: 'None',
|
|
162
|
+
},
|
|
163
|
+
],
|
|
164
|
+
};
|
|
165
|
+
defaultSettings.push(syncType);
|
|
166
|
+
if (integration.withCronSync) {
|
|
167
|
+
syncType.options.push({
|
|
168
|
+
value: '1',
|
|
169
|
+
label: 'Schedule',
|
|
170
|
+
});
|
|
171
|
+
defaultSettings.push({
|
|
144
172
|
key: 'schedule',
|
|
145
173
|
label: 'Sync schedule',
|
|
146
174
|
helpText: 'Set the frequency for pushing sources and translations',
|
|
147
175
|
type: 'select',
|
|
176
|
+
defaultValue: '0',
|
|
177
|
+
dependencySettings: "[{'#syncType-settings':{'type':'equal','value':['1']} }]",
|
|
148
178
|
options: [
|
|
149
179
|
{
|
|
150
180
|
value: '0',
|
|
@@ -171,12 +201,22 @@ function applyDefaults(config, integration) {
|
|
|
171
201
|
label: '24 hours',
|
|
172
202
|
},
|
|
173
203
|
],
|
|
174
|
-
}
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
if (integration.webhooks) {
|
|
207
|
+
syncType.options.push({
|
|
208
|
+
value: '2',
|
|
209
|
+
label: 'Webhooks',
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
return [
|
|
213
|
+
...defaultSettings,
|
|
175
214
|
{
|
|
176
215
|
key: 'condition',
|
|
177
216
|
label: 'Files export settings',
|
|
178
217
|
type: 'select',
|
|
179
218
|
defaultValue: '0',
|
|
219
|
+
dependencySettings: "[{'#syncType-settings':{'type':'equal','value':['1','2']}}]",
|
|
180
220
|
options: [
|
|
181
221
|
{
|
|
182
222
|
value: '0',
|
|
@@ -201,6 +241,9 @@ function applyDefaults(config, integration) {
|
|
|
201
241
|
yield integration.getIntegrationFiles(apiCredentials);
|
|
202
242
|
});
|
|
203
243
|
}
|
|
244
|
+
if (integration.webhooks && !((_a = integration.webhooks) === null || _a === void 0 ? void 0 : _a.urlParam)) {
|
|
245
|
+
integration.webhooks.urlParam = 'crowdinData';
|
|
246
|
+
}
|
|
204
247
|
}
|
|
205
248
|
exports.applyDefaults = applyDefaults;
|
|
206
249
|
function constructOauthUrl(config, integration) {
|
package/out/util/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
3
|
if (k2 === undefined) k2 = k;
|
|
4
|
-
Object.
|
|
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);
|
|
5
9
|
}) : (function(o, m, k, k2) {
|
|
6
10
|
if (k2 === undefined) k2 = k;
|
|
7
11
|
o[k2] = m[k];
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import Crowdin from '@crowdin/crowdin-api-client';
|
|
2
|
+
import { Config, CrowdinContextInfo, IntegrationLogic, Payload, UpdateIntegrationRequest, WebhookUrlParams } from '../models';
|
|
3
|
+
import { WebhooksModel } from '@crowdin/crowdin-api-client/out/webhooks';
|
|
4
|
+
import { Request } from 'express';
|
|
5
|
+
export declare function encodedUrlParam(config: Config, integration: IntegrationLogic, crowdinContext: CrowdinContextInfo): string;
|
|
6
|
+
export declare function decodedUrlParam(config: Config, data: string): WebhookUrlParams;
|
|
7
|
+
export declare function makeCrowdinWebhookUrl(config: Config, integration: IntegrationLogic, crowdinContext: CrowdinContextInfo): string;
|
|
8
|
+
export declare function registerWebhooks(config: Config, integration: IntegrationLogic, client: Crowdin, crowdinContext: CrowdinContextInfo, apiCredentials: any, appSettings: any): Promise<void>;
|
|
9
|
+
export declare function unregisterWebhooks(config: Config, integration: IntegrationLogic, client: Crowdin, crowdinContext: CrowdinContextInfo, apiCredentials: any, appSettings: any): Promise<void>;
|
|
10
|
+
export declare function getCrowdinProjectWebhook(config: Config, client: Crowdin, projectId: number, name: string): Promise<WebhooksModel.Webhook | undefined>;
|
|
11
|
+
export declare function getAllCrowdinProjectWebhooks(config: Config, client: Crowdin, projectId: number): Promise<WebhooksModel.Webhook[]>;
|
|
12
|
+
export declare function registerCrowdinWebhook(config: Config, url: string, client: Crowdin, crowdinContext: CrowdinContextInfo, events: WebhooksModel.Event[]): Promise<void>;
|
|
13
|
+
export declare function updateCrowdinWebhooks(config: Config, client: Crowdin, projectId: number, webhook: WebhooksModel.Webhook, events: WebhooksModel.Event[], url: string): Promise<void>;
|
|
14
|
+
export declare function unregisterCrowdinWebhooks(config: Config, client: Crowdin, projectId: number, webhook: WebhooksModel.Webhook): Promise<void>;
|
|
15
|
+
export declare function unregisterAllCrowdinWebhooks(config: Config, integration: IntegrationLogic, crowdinId: string): Promise<void>;
|
|
16
|
+
export declare function filterSyncFiles(events: Payload[], syncFileSettings: UpdateIntegrationRequest): UpdateIntegrationRequest;
|
|
17
|
+
export declare function prepareWebhookData(config: Config, integration: IntegrationLogic, webhookUrlParam: string, provider: string): Promise<{
|
|
18
|
+
projectId: number;
|
|
19
|
+
crowdinClient: {
|
|
20
|
+
client: Crowdin;
|
|
21
|
+
token: string;
|
|
22
|
+
};
|
|
23
|
+
preparedIntegrationCredentials: any;
|
|
24
|
+
rootFolder: import("@crowdin/crowdin-api-client").SourceFilesModel.Directory | undefined;
|
|
25
|
+
appSettings: any;
|
|
26
|
+
syncSettings: import("../models").IntegrationSyncSettings | null | undefined;
|
|
27
|
+
}>;
|
|
28
|
+
export declare function updateCrowdinFromWebhookRequest(integration: IntegrationLogic, webhookData: any, req: Request): Promise<void | import("../models").ExtendedResult<void>>;
|
|
29
|
+
export declare function listenQueueMessage(config: Config, integration: IntegrationLogic, queueUrl: string, queueName: string): Promise<void>;
|
|
@@ -0,0 +1,308 @@
|
|
|
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
|
+
};
|
|
25
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
26
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
27
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
28
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
29
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
30
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
31
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
35
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
36
|
+
};
|
|
37
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
38
|
+
exports.listenQueueMessage = exports.updateCrowdinFromWebhookRequest = exports.prepareWebhookData = exports.filterSyncFiles = exports.unregisterAllCrowdinWebhooks = exports.unregisterCrowdinWebhooks = exports.updateCrowdinWebhooks = exports.registerCrowdinWebhook = exports.getAllCrowdinProjectWebhooks = exports.getCrowdinProjectWebhook = exports.unregisterWebhooks = exports.registerWebhooks = exports.makeCrowdinWebhookUrl = exports.decodedUrlParam = exports.encodedUrlParam = void 0;
|
|
39
|
+
const crowdinAppFunctions = __importStar(require("@crowdin/crowdin-apps-functions"));
|
|
40
|
+
const amqplib_1 = __importDefault(require("amqplib"));
|
|
41
|
+
const models_1 = require("../models");
|
|
42
|
+
const index_1 = require("./index");
|
|
43
|
+
const connection_1 = require("./connection");
|
|
44
|
+
const storage_1 = require("../storage");
|
|
45
|
+
const defaults_1 = require("./defaults");
|
|
46
|
+
const util_1 = require("../util");
|
|
47
|
+
const HookEvents = {
|
|
48
|
+
ALL: ['file.translated', 'file.approved'],
|
|
49
|
+
TRANSLATED: ['file.translated'],
|
|
50
|
+
APPROVED: ['file.approved'],
|
|
51
|
+
};
|
|
52
|
+
function encodedUrlParam(config, integration, crowdinContext) {
|
|
53
|
+
var _a;
|
|
54
|
+
const params = {
|
|
55
|
+
projectId: +crowdinContext.jwtPayload.context.project_id,
|
|
56
|
+
clientId: crowdinContext.clientId,
|
|
57
|
+
crowdinId: crowdinContext.crowdinId,
|
|
58
|
+
};
|
|
59
|
+
const encryptedParams = (0, index_1.encryptData)(config, JSON.stringify(params));
|
|
60
|
+
return `${(_a = integration.webhooks) === null || _a === void 0 ? void 0 : _a.urlParam}=${encodeURIComponent(encryptedParams)}`;
|
|
61
|
+
}
|
|
62
|
+
exports.encodedUrlParam = encodedUrlParam;
|
|
63
|
+
function decodedUrlParam(config, data) {
|
|
64
|
+
const params = (0, index_1.decryptData)(config, data);
|
|
65
|
+
return JSON.parse(params);
|
|
66
|
+
}
|
|
67
|
+
exports.decodedUrlParam = decodedUrlParam;
|
|
68
|
+
function makeCrowdinWebhookUrl(config, integration, crowdinContext) {
|
|
69
|
+
var _a;
|
|
70
|
+
const urlParam = encodedUrlParam(config, integration, crowdinContext);
|
|
71
|
+
return (`${config.baseUrl}${((_a = integration.webhooks) === null || _a === void 0 ? void 0 : _a.crowdinWebhookUrl) ? integration.webhooks.crowdinWebhookUrl : '/api/crowdin/webhook'}` + `?${urlParam}`);
|
|
72
|
+
}
|
|
73
|
+
exports.makeCrowdinWebhookUrl = makeCrowdinWebhookUrl;
|
|
74
|
+
function registerWebhooks(config, integration, client, crowdinContext, apiCredentials, appSettings) {
|
|
75
|
+
var _a, _b;
|
|
76
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
77
|
+
const isWebhookSync = +appSettings.syncType === models_1.SyncType.WEBHOOKS;
|
|
78
|
+
const projectId = crowdinContext.jwtPayload.context.project_id;
|
|
79
|
+
const urlParam = encodedUrlParam(config, integration, crowdinContext);
|
|
80
|
+
if ((_a = integration.webhooks) === null || _a === void 0 ? void 0 : _a.crowdinWebhooks) {
|
|
81
|
+
yield integration.webhooks.crowdinWebhooks(client, projectId, isWebhookSync, appSettings);
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
const webhookName = `${config.name} application hook ${crowdinContext.jwtPayload.sub}`;
|
|
85
|
+
const webhookUrl = makeCrowdinWebhookUrl(config, integration, crowdinContext);
|
|
86
|
+
const syncCondition = models_1.SyncCondition[+appSettings.condition];
|
|
87
|
+
const events = HookEvents[syncCondition];
|
|
88
|
+
const webhook = yield getCrowdinProjectWebhook(config, client, projectId, webhookName);
|
|
89
|
+
if (isWebhookSync && webhook) {
|
|
90
|
+
yield updateCrowdinWebhooks(config, client, projectId, webhook, events, webhookUrl);
|
|
91
|
+
}
|
|
92
|
+
else if (isWebhookSync && !webhook) {
|
|
93
|
+
yield registerCrowdinWebhook(config, webhookUrl, client, crowdinContext, events);
|
|
94
|
+
}
|
|
95
|
+
else if (!isWebhookSync && webhook) {
|
|
96
|
+
yield unregisterCrowdinWebhooks(config, client, projectId, webhook);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if ((_b = integration.webhooks) === null || _b === void 0 ? void 0 : _b.integrationWebhooks) {
|
|
100
|
+
yield integration.webhooks.integrationWebhooks(apiCredentials, urlParam, isWebhookSync, appSettings);
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
exports.registerWebhooks = registerWebhooks;
|
|
105
|
+
function unregisterWebhooks(config, integration, client, crowdinContext, apiCredentials, appSettings) {
|
|
106
|
+
var _a, _b;
|
|
107
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
108
|
+
if ((_a = integration.webhooks) === null || _a === void 0 ? void 0 : _a.crowdinWebhooks) {
|
|
109
|
+
yield integration.webhooks.crowdinWebhooks(client, crowdinContext.jwtPayload.context.project_id, false);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
const webhookName = `${config.name} application hook ${crowdinContext.jwtPayload.sub}`;
|
|
113
|
+
const webhook = yield getCrowdinProjectWebhook(config, client, crowdinContext.jwtPayload.context.project_id, webhookName);
|
|
114
|
+
if (webhook) {
|
|
115
|
+
yield unregisterCrowdinWebhooks(config, client, crowdinContext.jwtPayload.context.project_id, webhook);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if ((_b = integration.webhooks) === null || _b === void 0 ? void 0 : _b.integrationWebhooks) {
|
|
119
|
+
const urlParam = encodedUrlParam(config, integration, crowdinContext);
|
|
120
|
+
yield integration.webhooks.integrationWebhooks(apiCredentials, urlParam, false, appSettings);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
exports.unregisterWebhooks = unregisterWebhooks;
|
|
125
|
+
function getCrowdinProjectWebhook(config, client, projectId, name) {
|
|
126
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
127
|
+
const hooks = (yield client.webhooksApi.withFetchAll().listWebhooks(projectId)).data.map((e) => e.data);
|
|
128
|
+
return hooks.find((h) => h.name === name);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
exports.getCrowdinProjectWebhook = getCrowdinProjectWebhook;
|
|
132
|
+
function getAllCrowdinProjectWebhooks(config, client, projectId) {
|
|
133
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
134
|
+
const hooks = (yield client.webhooksApi.withFetchAll().listWebhooks(projectId)).data.map((e) => e.data);
|
|
135
|
+
return hooks.filter((h) => h.name.startsWith(`${config.name} application hook `));
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
exports.getAllCrowdinProjectWebhooks = getAllCrowdinProjectWebhooks;
|
|
139
|
+
function createPayload(events) {
|
|
140
|
+
const payload = {};
|
|
141
|
+
for (const event of events) {
|
|
142
|
+
payload[event] = {
|
|
143
|
+
event: '{{event}}',
|
|
144
|
+
projectId: '{{projectId}}',
|
|
145
|
+
language: '{{targetLanguageId}}',
|
|
146
|
+
fileId: '{{fileId}}',
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
return payload;
|
|
150
|
+
}
|
|
151
|
+
function registerCrowdinWebhook(config, url, client, crowdinContext, events) {
|
|
152
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
153
|
+
const name = `${config.name} application hook ${crowdinContext.jwtPayload.sub}`;
|
|
154
|
+
const payload = createPayload(events);
|
|
155
|
+
yield client.webhooksApi.addWebhook(crowdinContext.jwtPayload.context.project_id, {
|
|
156
|
+
name,
|
|
157
|
+
url,
|
|
158
|
+
events,
|
|
159
|
+
requestType: 'POST',
|
|
160
|
+
batchingEnabled: true,
|
|
161
|
+
payload,
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
exports.registerCrowdinWebhook = registerCrowdinWebhook;
|
|
166
|
+
function updateCrowdinWebhooks(config, client, projectId, webhook, events, url) {
|
|
167
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
168
|
+
const payload = createPayload(events);
|
|
169
|
+
yield client.webhooksApi.editWebhook(projectId, webhook.id, [
|
|
170
|
+
{
|
|
171
|
+
value: events,
|
|
172
|
+
op: 'replace',
|
|
173
|
+
path: '/events',
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
value: payload,
|
|
177
|
+
op: 'replace',
|
|
178
|
+
path: '/payload',
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
value: url,
|
|
182
|
+
op: 'replace',
|
|
183
|
+
path: '/url',
|
|
184
|
+
},
|
|
185
|
+
]);
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
exports.updateCrowdinWebhooks = updateCrowdinWebhooks;
|
|
189
|
+
function unregisterCrowdinWebhooks(config, client, projectId, webhook) {
|
|
190
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
191
|
+
yield client.webhooksApi.deleteWebhook(projectId, webhook.id);
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
exports.unregisterCrowdinWebhooks = unregisterCrowdinWebhooks;
|
|
195
|
+
function unregisterAllCrowdinWebhooks(config, integration, crowdinId) {
|
|
196
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
197
|
+
if (integration.webhooks) {
|
|
198
|
+
const crowdinCredentials = yield (0, storage_1.getStorage)().getCrowdinCredentials(crowdinId);
|
|
199
|
+
if (crowdinCredentials) {
|
|
200
|
+
const credentials = yield (0, storage_1.getStorage)().getAllIntegrationCredentials(crowdinId);
|
|
201
|
+
const projectIds = credentials.map((c) => crowdinAppFunctions.getProjectId(c.id));
|
|
202
|
+
const crowdinClient = yield (0, connection_1.prepareCrowdinClient)(config, crowdinCredentials);
|
|
203
|
+
yield Promise.all(projectIds.map((projectId) => __awaiter(this, void 0, void 0, function* () {
|
|
204
|
+
const webhooks = yield getAllCrowdinProjectWebhooks(config, crowdinClient.client, projectId);
|
|
205
|
+
yield Promise.all(webhooks.map((hook) => __awaiter(this, void 0, void 0, function* () { return yield unregisterCrowdinWebhooks(config, crowdinClient.client, projectId, hook); })));
|
|
206
|
+
})));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
exports.unregisterAllCrowdinWebhooks = unregisterAllCrowdinWebhooks;
|
|
212
|
+
function filterSyncFiles(events, syncFileSettings) {
|
|
213
|
+
const files = {};
|
|
214
|
+
events.forEach((event) => {
|
|
215
|
+
const fileId = event.fileId;
|
|
216
|
+
const language = event.language;
|
|
217
|
+
if (syncFileSettings[fileId] && syncFileSettings[fileId].includes(language)) {
|
|
218
|
+
if (files[fileId]) {
|
|
219
|
+
files[fileId] = [...files[fileId], event.language];
|
|
220
|
+
}
|
|
221
|
+
else {
|
|
222
|
+
files[fileId] = [event.language];
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
return files;
|
|
227
|
+
}
|
|
228
|
+
exports.filterSyncFiles = filterSyncFiles;
|
|
229
|
+
function prepareWebhookData(config, integration, webhookUrlParam, provider) {
|
|
230
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
231
|
+
let rootFolder = undefined;
|
|
232
|
+
let appSettings = null;
|
|
233
|
+
let syncSettings = null;
|
|
234
|
+
const { projectId, crowdinId, clientId } = decodedUrlParam(config, webhookUrlParam);
|
|
235
|
+
const crowdinCredentials = yield (0, storage_1.getStorage)().getCrowdinCredentials(crowdinId);
|
|
236
|
+
const crowdinClient = yield (0, connection_1.prepareCrowdinClient)(config, crowdinCredentials);
|
|
237
|
+
const integrationCredentials = yield (0, storage_1.getStorage)().getIntegrationCredentials(clientId);
|
|
238
|
+
const preparedIntegrationCredentials = yield (0, connection_1.prepareIntegrationCredentials)(config, integration, integrationCredentials);
|
|
239
|
+
if (integrationCredentials === null || integrationCredentials === void 0 ? void 0 : integrationCredentials.config) {
|
|
240
|
+
appSettings = JSON.parse(integrationCredentials.config);
|
|
241
|
+
const isWebhookSync = +appSettings.syncType === models_1.SyncType.WEBHOOKS;
|
|
242
|
+
if (isWebhookSync) {
|
|
243
|
+
syncSettings = yield (0, storage_1.getStorage)().getSyncSettings(clientId, crowdinId, 'schedule', provider);
|
|
244
|
+
rootFolder = yield (0, defaults_1.getRootFolder)(config, integration, crowdinClient.client, projectId);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return { projectId, crowdinClient, preparedIntegrationCredentials, rootFolder, appSettings, syncSettings };
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
exports.prepareWebhookData = prepareWebhookData;
|
|
251
|
+
function updateCrowdinFromWebhookRequest(integration, webhookData, req) {
|
|
252
|
+
var _a, _b;
|
|
253
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
254
|
+
let filesToSync = [];
|
|
255
|
+
const { projectId, crowdinClient, preparedIntegrationCredentials, rootFolder, appSettings, syncSettings } = webhookData;
|
|
256
|
+
if ((_a = integration.webhooks) === null || _a === void 0 ? void 0 : _a.integrationWebhookInterceptor) {
|
|
257
|
+
filesToSync = yield ((_b = integration.webhooks) === null || _b === void 0 ? void 0 : _b.integrationWebhookInterceptor(projectId, crowdinClient.client, preparedIntegrationCredentials, rootFolder, appSettings, syncSettings, req));
|
|
258
|
+
}
|
|
259
|
+
return yield integration.updateCrowdin(projectId, crowdinClient.client, preparedIntegrationCredentials, filesToSync, rootFolder, appSettings);
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
exports.updateCrowdinFromWebhookRequest = updateCrowdinFromWebhookRequest;
|
|
263
|
+
function listenQueueMessage(config, integration, queueUrl, queueName) {
|
|
264
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
265
|
+
try {
|
|
266
|
+
const connection = yield amqplib_1.default.connect(queueUrl);
|
|
267
|
+
connection.once('close', function () {
|
|
268
|
+
setTimeout(() => {
|
|
269
|
+
listenQueueMessage(config, integration, queueUrl, queueName);
|
|
270
|
+
}, 3000);
|
|
271
|
+
return;
|
|
272
|
+
});
|
|
273
|
+
const channel = yield connection.createChannel();
|
|
274
|
+
if (channel) {
|
|
275
|
+
yield channel.assertQueue(queueName, { durable: true });
|
|
276
|
+
yield channel.prefetch(1);
|
|
277
|
+
yield channel.consume(queueName, consumer(channel, config, integration), { noAck: false });
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
catch (e) {
|
|
281
|
+
setTimeout(() => {
|
|
282
|
+
listenQueueMessage(config, integration, queueUrl, queueName);
|
|
283
|
+
}, 3000);
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
exports.listenQueueMessage = listenQueueMessage;
|
|
288
|
+
function consumer(channel, config, integration) {
|
|
289
|
+
return function (msg) {
|
|
290
|
+
var _a;
|
|
291
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
292
|
+
if (!msg) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
try {
|
|
296
|
+
const data = JSON.parse(msg.content.toString());
|
|
297
|
+
const urlParam = (_a = integration.webhooks) === null || _a === void 0 ? void 0 : _a.urlParam;
|
|
298
|
+
const webhookUrlParam = data.query[urlParam];
|
|
299
|
+
const webhookData = yield prepareWebhookData(config, integration, webhookUrlParam, 'integration');
|
|
300
|
+
yield updateCrowdinFromWebhookRequest(integration, webhookData, data);
|
|
301
|
+
}
|
|
302
|
+
catch (e) {
|
|
303
|
+
(0, util_1.logError)(e, config.onError);
|
|
304
|
+
}
|
|
305
|
+
channel.ack(msg);
|
|
306
|
+
});
|
|
307
|
+
};
|
|
308
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
{{> head}}
|
|
4
|
+
<body>
|
|
5
|
+
<div
|
|
6
|
+
class="i_w"
|
|
7
|
+
style='max-width:680px; position: relative;'
|
|
8
|
+
>
|
|
9
|
+
<crowdin-card
|
|
10
|
+
is-shadowed
|
|
11
|
+
>
|
|
12
|
+
<div id="form"></div>
|
|
13
|
+
<div id="form-loading">
|
|
14
|
+
<crowdin-progress-indicator />
|
|
15
|
+
</div>
|
|
16
|
+
</crowdin-card>
|
|
17
|
+
</div>
|
|
18
|
+
<crowdin-toasts></crowdin-toasts>
|
|
19
|
+
<script>
|
|
20
|
+
/*<!--*/
|
|
21
|
+
var formGetDataUrl = '{{formGetDataUrl}}';
|
|
22
|
+
var formPostDataUrl = '{{formPostDataUrl}}';
|
|
23
|
+
var formSchema = {{{formSchema}}};
|
|
24
|
+
var formUiSchema = {{{formUiSchema}}};
|
|
25
|
+
/*-->*/
|
|
26
|
+
</script>
|
|
27
|
+
<script src="/assets/js/form.js"></script>
|
|
28
|
+
</body>
|
|
29
|
+
</html>
|