@crowdin/app-project-module 0.27.0 → 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.
@@ -14,12 +14,13 @@ const defaults_1 = require("../util/defaults");
14
14
  function handle(config, integration) {
15
15
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
16
16
  const projectId = req.crowdinContext.jwtPayload.context.project_id;
17
- (0, util_1.log)(`Upading crowdin project ${projectId}`, config.logger);
17
+ const uploadTranslations = req.query.uploadTranslations === 'true';
18
+ (0, util_1.log)(`Updating crowdin project ${projectId}`, config.logger);
18
19
  const rootFolder = yield (0, defaults_1.getRootFolder)(config, integration, req.crowdinApiClient, projectId);
19
20
  if (rootFolder) {
20
- (0, util_1.log)(`Upading crowdin files under folder ${rootFolder.id}`, config.logger);
21
+ (0, util_1.log)(`Updating crowdin files under folder ${rootFolder.id}`, config.logger);
21
22
  }
22
- const result = yield integration.updateCrowdin(projectId, req.crowdinApiClient, req.integrationCredentials, req.body, rootFolder, req.integrationSettings);
23
+ const result = yield integration.updateCrowdin(projectId, req.crowdinApiClient, req.integrationCredentials, req.body, rootFolder, req.integrationSettings, uploadTranslations);
23
24
  let message;
24
25
  if ((0, util_1.isExtendedResultType)(result)) {
25
26
  message = result.message;
@@ -0,0 +1,4 @@
1
+ /// <reference types="qs" />
2
+ import { Config, IntegrationLogic } from '../models';
3
+ import { Request, Response } from 'express';
4
+ export default function handle(config: Config, integration: IntegrationLogic): (req: Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: Function) => void;
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const util_1 = require("../util");
13
+ const webhooks_1 = require("../util/webhooks");
14
+ function handle(config, integration) {
15
+ return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
16
+ var _a, _b;
17
+ const urlParam = (_a = integration.webhooks) === null || _a === void 0 ? void 0 : _a.urlParam;
18
+ const webhookUrlParam = req.query[urlParam];
19
+ let filesToSync;
20
+ if (webhookUrlParam) {
21
+ const { projectId, crowdinClient, preparedIntegrationCredentials, rootFolder, appSettings, syncSettings } = yield (0, webhooks_1.prepareWebhookData)(config, integration, webhookUrlParam, 'crowdin');
22
+ if (!crowdinClient) {
23
+ return res.status(403).send({ error: 'Access denied' });
24
+ }
25
+ if (!syncSettings) {
26
+ return res.status(200).send({ message: 'Sync is not configured' });
27
+ }
28
+ if ((_b = integration.webhooks) === null || _b === void 0 ? void 0 : _b.crowdinWebhookInterceptor) {
29
+ filesToSync = yield integration.webhooks.crowdinWebhookInterceptor(projectId, crowdinClient.client, rootFolder, appSettings, syncSettings, req.body);
30
+ }
31
+ else {
32
+ filesToSync = (0, webhooks_1.filterSyncFiles)(req.body.events, JSON.parse(syncSettings.files));
33
+ }
34
+ const result = yield integration.updateIntegration(projectId, crowdinClient.client, preparedIntegrationCredentials, filesToSync, rootFolder, appSettings);
35
+ let message;
36
+ if ((0, util_1.isExtendedResultType)(result)) {
37
+ message = result.message;
38
+ }
39
+ res.send({ message });
40
+ }
41
+ }), config.onError);
42
+ }
43
+ exports.default = handle;
@@ -0,0 +1,3 @@
1
+ /// <reference types="qs" />
2
+ import { Response } from 'express';
3
+ export default function handle(): (req: 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;
@@ -0,0 +1,46 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ const util_1 = require("../util");
36
+ const storage = __importStar(require("../storage"));
37
+ function handle() {
38
+ return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
39
+ const id = req.query.id;
40
+ const data = (yield storage.getStorage().getMetadata(id)) || {};
41
+ return res.send({
42
+ formData: data,
43
+ });
44
+ }));
45
+ }
46
+ exports.default = handle;
@@ -0,0 +1,3 @@
1
+ /// <reference types="qs" />
2
+ import { Response } from 'express';
3
+ export default function handle(): (req: 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;
@@ -0,0 +1,56 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ const util_1 = require("../util");
36
+ const storage = __importStar(require("../storage"));
37
+ function handle() {
38
+ return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
39
+ const id = req.query.id;
40
+ const metadata = req.body.data;
41
+ const existing = yield storage.getStorage().getMetadata(id);
42
+ try {
43
+ if (!!existing) {
44
+ yield storage.getStorage().updateMetadata(id, metadata);
45
+ }
46
+ else {
47
+ yield storage.getStorage().saveMetadata(id, metadata);
48
+ }
49
+ }
50
+ catch (e) {
51
+ res.status(500).end();
52
+ }
53
+ res.status(204).end();
54
+ }));
55
+ }
56
+ exports.default = handle;
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const storage_1 = require("../storage");
13
13
  const util_1 = require("../util");
14
14
  const connection_1 = require("../util/connection");
15
+ const webhooks_1 = require("../util/webhooks");
15
16
  function handle(config, integration) {
16
17
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
17
18
  (0, util_1.log)('Received integration logout request', config.logger);
@@ -22,6 +23,9 @@ function handle(config, integration) {
22
23
  (0, util_1.log)(`Deleting integration credentials for ${req.crowdinContext.clientId} client`, config.logger);
23
24
  yield (0, storage_1.getStorage)().deleteIntegrationCredentials(req.crowdinContext.clientId);
24
25
  (0, connection_1.clearCache)(req.crowdinContext.crowdinId);
26
+ if (integration.webhooks) {
27
+ yield (0, webhooks_1.unregisterWebhooks)(config, integration, req.crowdinApiClient, req.crowdinContext, req.integrationCredentials, req.integrationSettings);
28
+ }
25
29
  res.status(204).end();
26
30
  }), config.onError);
27
31
  }
@@ -0,0 +1,4 @@
1
+ /// <reference types="qs" />
2
+ import { Config, IntegrationLogic } from '../models';
3
+ import { Request, Response } from 'express';
4
+ export default function handle(config: Config, integration: IntegrationLogic): (req: Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: Function) => void;
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const util_1 = require("../util");
13
+ const webhooks_1 = require("../util/webhooks");
14
+ function handle(config, integration) {
15
+ return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
16
+ var _a, _b;
17
+ const urlParam = (_a = integration.webhooks) === null || _a === void 0 ? void 0 : _a.urlParam;
18
+ const webhookUrlParam = req.query[urlParam];
19
+ if (((_b = integration.webhooks) === null || _b === void 0 ? void 0 : _b.integrationWebhookInterceptor) && webhookUrlParam) {
20
+ const webhookData = yield (0, webhooks_1.prepareWebhookData)(config, integration, webhookUrlParam, 'integration');
21
+ if (!webhookData.crowdinClient) {
22
+ return res.status(403).send({ error: 'Access denied' });
23
+ }
24
+ if (!webhookData.syncSettings) {
25
+ return res.status(200).send({ message: 'Sync is not configured' });
26
+ }
27
+ const result = yield (0, webhooks_1.updateCrowdinFromWebhookRequest)(integration, webhookData, req);
28
+ let message;
29
+ if ((0, util_1.isExtendedResultType)(result)) {
30
+ message = result.message;
31
+ }
32
+ res.send({ message });
33
+ }
34
+ else {
35
+ return res.status(403).send({ error: 'Access denied' });
36
+ }
37
+ }), config.onError);
38
+ }
39
+ exports.default = handle;
@@ -45,10 +45,16 @@ function handle(config, integration) {
45
45
  }
46
46
  options.infoModal = integration.infoModal;
47
47
  options.withCronSync = integration.withCronSync;
48
- options.withWebhookSync = integration.withWebhookSync;
48
+ options.webhooks = integration.webhooks
49
+ ? {
50
+ crowdin: true,
51
+ integration: !!integration.webhooks.integrationWebhookInterceptor,
52
+ }
53
+ : {};
49
54
  options.integrationOneLevelFetching = integration.integrationOneLevelFetching;
50
55
  options.integrationSearchListener = integration.integrationSearchListener;
51
56
  options.checkSubscription = !(0, connection_1.isAppFree)(config);
57
+ options.uploadTranslations = integration.uploadTranslations;
52
58
  (0, util_1.log)(`Routing user to ${view} view`, config.logger);
53
59
  return res.render(view, options);
54
60
  }), config.onError);
@@ -1,4 +1,4 @@
1
1
  /// <reference types="qs" />
2
2
  import { Response } from 'express';
3
- import { Config } from '../models';
4
- export default function handle(config: Config): (req: 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;
3
+ import { Config, IntegrationLogic } from '../models';
4
+ export default function handle(config: Config, integration: IntegrationLogic): (req: 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;
@@ -11,10 +11,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const storage_1 = require("../storage");
13
13
  const util_1 = require("../util");
14
- function handle(config) {
14
+ const webhooks_1 = require("../util/webhooks");
15
+ function handle(config, integration) {
15
16
  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);
17
- yield (0, storage_1.getStorage)().updateIntegrationConfig(req.crowdinContext.clientId, JSON.stringify(req.body.config));
17
+ const appSettings = req.body.config;
18
+ (0, util_1.log)(`Saving settings ${JSON.stringify(appSettings, null, 2)}`, config.logger);
19
+ yield (0, storage_1.getStorage)().updateIntegrationConfig(req.crowdinContext.clientId, JSON.stringify(appSettings));
20
+ if (integration.webhooks) {
21
+ yield (0, webhooks_1.registerWebhooks)(config, integration, req.crowdinApiClient, req.crowdinContext, req.integrationCredentials, appSettings);
22
+ }
18
23
  res.status(204).end();
19
24
  }), config.onError);
20
25
  }
@@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const storage_1 = require("../storage");
13
13
  const util_1 = require("../util");
14
14
  const connection_1 = require("../util/connection");
15
+ const webhooks_1 = require("../util/webhooks");
15
16
  function handle(config) {
16
17
  return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
17
18
  const event = req.body;
@@ -35,6 +36,9 @@ function handle(config) {
35
36
  yield config.onUninstall(organization, allCredentials);
36
37
  }
37
38
  if (projectIntegration) {
39
+ if (projectIntegration.webhooks) {
40
+ yield (0, webhooks_1.unregisterAllCrowdinWebhooks)(config, projectIntegration, organization);
41
+ }
38
42
  (0, util_1.log)(`Deleting all integration credentials for ${organization} organization`, config.logger);
39
43
  yield (0, storage_1.getStorage)().deleteAllIntegrationCredentials(organization);
40
44
  }
package/out/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.defineProperty(o, k2, { enumerable: true, get: function() { return m[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);
5
9
  }) : (function(o, m, k, k2) {
6
10
  if (k2 === undefined) k2 = k;
7
11
  o[k2] = m[k];
@@ -40,6 +44,8 @@ const crowdin_file_progress_1 = __importDefault(require("./handlers/crowdin-file
40
44
  const crowdin_files_1 = __importDefault(require("./handlers/crowdin-files"));
41
45
  const crowdin_project_1 = __importDefault(require("./handlers/crowdin-project"));
42
46
  const crowdin_update_1 = __importDefault(require("./handlers/crowdin-update"));
47
+ const crowdin_webhook_1 = __importDefault(require("./handlers/crowdin-webhook"));
48
+ const integration_webhook_1 = __importDefault(require("./handlers/integration-webhook"));
43
49
  const download_1 = __importDefault(require("./handlers/custom-file-format/download"));
44
50
  const process_1 = __importDefault(require("./handlers/custom-file-format/process"));
45
51
  const translate_1 = __importDefault(require("./handlers/custom-mt/translate"));
@@ -53,6 +59,8 @@ const manifest_1 = __importDefault(require("./handlers/manifest"));
53
59
  const oauth_login_1 = __importDefault(require("./handlers/oauth-login"));
54
60
  const oauth_url_1 = __importDefault(require("./handlers/oauth-url"));
55
61
  const settings_save_1 = __importDefault(require("./handlers/settings-save"));
62
+ const form_data_display_1 = __importDefault(require("./handlers/form-data-display"));
63
+ const form_data_save_1 = __importDefault(require("./handlers/form-data-save"));
56
64
  const subscription_info_1 = __importDefault(require("./handlers/subscription-info"));
57
65
  const subscription_paid_1 = __importDefault(require("./handlers/subscription-paid"));
58
66
  const sync_settings_1 = __importDefault(require("./handlers/sync-settings"));
@@ -62,14 +70,17 @@ const crowdin_client_1 = __importStar(require("./middlewares/crowdin-client"));
62
70
  const integration_credentials_1 = __importDefault(require("./middlewares/integration-credentials"));
63
71
  const json_response_1 = __importDefault(require("./middlewares/json-response"));
64
72
  const ui_module_1 = __importDefault(require("./middlewares/ui-module"));
73
+ const render_ui_module_1 = __importDefault(require("./middlewares/render-ui-module"));
65
74
  const storage = __importStar(require("./storage"));
66
75
  const util_1 = require("./util");
67
76
  const connection_1 = require("./util/connection");
68
77
  const cron_1 = require("./util/cron");
69
78
  const defaults_1 = require("./util/defaults");
79
+ const webhooks_1 = require("./util/webhooks");
70
80
  var models_1 = require("./models");
71
81
  Object.defineProperty(exports, "Scope", { enumerable: true, get: function () { return models_1.Scope; } });
72
82
  function addCrowdinEndpoints(app, plainConfig) {
83
+ var _a, _b, _c;
73
84
  if (!plainConfig.disableGlobalErrorHandling) {
74
85
  handleUncaughtErrors(plainConfig);
75
86
  }
@@ -94,6 +105,15 @@ function addCrowdinEndpoints(app, plainConfig) {
94
105
  }
95
106
  return options.inverse(this);
96
107
  },
108
+ in: function (a, b, options) {
109
+ if (a.includes(b)) {
110
+ return options.fn(this);
111
+ }
112
+ return options.inverse(this);
113
+ },
114
+ or: function (a, b, options) {
115
+ return a || b ? options.fn(this) : options.inverse(this);
116
+ },
97
117
  },
98
118
  }));
99
119
  app.set('view engine', 'handlebars');
@@ -110,7 +130,7 @@ function addCrowdinEndpoints(app, plainConfig) {
110
130
  app.get('/logo/integration/logo.png', (req, res) => res.sendFile(integrationLogic.imagePath || config.imagePath || (0, path_1.join)(__dirname, 'logo.png')));
111
131
  app.get('/', (0, crowdin_client_1.default)(config, true, false), (0, integration_credentials_1.default)(config, integrationLogic, true), (0, main_1.default)(config, integrationLogic));
112
132
  app.get('/api/subscription-info', json_response_1.default, (0, crowdin_client_1.default)(config), (0, subscription_info_1.default)(config));
113
- app.post('/api/settings', (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, integrationLogic), (0, settings_save_1.default)(config));
133
+ app.post('/api/settings', (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, integrationLogic), (0, settings_save_1.default)(config, integrationLogic));
114
134
  app.post('/api/login', (0, crowdin_client_1.default)(config, false, false), (0, integration_login_1.default)(config, integrationLogic));
115
135
  app.post('/api/logout', (0, crowdin_client_1.default)(config, false, false), (0, integration_credentials_1.default)(config, integrationLogic), (0, integration_logout_1.default)(config, integrationLogic));
116
136
  app.get('/api/crowdin/files', json_response_1.default, (0, crowdin_client_1.default)(config), (0, integration_credentials_1.default)(config, integrationLogic), (0, crowdin_files_1.default)(config, integrationLogic));
@@ -137,6 +157,19 @@ function addCrowdinEndpoints(app, plainConfig) {
137
157
  cron.schedule('0 */12 * * *', () => (0, cron_1.filesCron)(config, integrationLogic, '12').catch(console.error));
138
158
  cron.schedule('0 0 * * *', () => (0, cron_1.filesCron)(config, integrationLogic, '24').catch(console.error));
139
159
  }
160
+ if (integrationLogic.webhooks) {
161
+ app.post(`${integrationLogic.webhooks.crowdinWebhookUrl
162
+ ? integrationLogic.webhooks.crowdinWebhookUrl
163
+ : '/api/crowdin/webhook'}`, json_response_1.default, (0, crowdin_webhook_1.default)(config, integrationLogic));
164
+ if (((_a = integrationLogic.webhooks) === null || _a === void 0 ? void 0 : _a.integrationWebhookInterceptor) && !((_b = integrationLogic.webhooks) === null || _b === void 0 ? void 0 : _b.queueUrl)) {
165
+ app.post(`${integrationLogic.webhooks.integrationWebhookUrl
166
+ ? integrationLogic.webhooks.integrationWebhookUrl
167
+ : '/api/integration/webhook'}`, (0, integration_webhook_1.default)(config, integrationLogic));
168
+ }
169
+ if ((_c = integrationLogic.webhooks) === null || _c === void 0 ? void 0 : _c.queueUrl) {
170
+ (0, webhooks_1.listenQueueMessage)(config, integrationLogic, integrationLogic.webhooks.queueUrl, config.identifier);
171
+ }
172
+ }
140
173
  }
141
174
  if (config.customFileFormat) {
142
175
  app.post('/process', (0, crowdin_client_1.default)(config), (0, process_1.default)(config, config.baseUrl, config.customFileFormat.filesFolder || config.dbFolder || '/', config.customFileFormat));
@@ -148,28 +181,35 @@ function addCrowdinEndpoints(app, plainConfig) {
148
181
  }
149
182
  if (config.profileResourcesMenu) {
150
183
  app.get('/logo/resources/logo.png', (req, res) => { var _a; return res.sendFile(((_a = config.profileResourcesMenu) === null || _a === void 0 ? void 0 : _a.imagePath) || config.imagePath || (0, path_1.join)(__dirname, 'logo.png')); });
151
- app.use('/resources', (0, ui_module_1.default)(config, config.profileResourcesMenu.allowUnauthorized), express_1.default.static(config.profileResourcesMenu.uiPath));
184
+ app.use('/resources', (0, ui_module_1.default)(config, config.profileResourcesMenu.allowUnauthorized), (0, render_ui_module_1.default)(config, config.profileResourcesMenu));
152
185
  }
153
186
  if (config.organizationMenu) {
154
187
  app.get('/logo/resources/logo.png', (req, res) => { var _a; return res.sendFile(((_a = config.organizationMenu) === null || _a === void 0 ? void 0 : _a.imagePath) || config.imagePath || (0, path_1.join)(__dirname, 'logo.png')); });
155
- app.use('/resources', (0, ui_module_1.default)(config, config.organizationMenu.allowUnauthorized), express_1.default.static(config.organizationMenu.uiPath));
188
+ app.use('/resources', (0, ui_module_1.default)(config, config.organizationMenu.allowUnauthorized), (0, render_ui_module_1.default)(config, config.organizationMenu));
156
189
  }
157
190
  if (config.editorRightPanel) {
158
- app.use('/editor-panels', (0, ui_module_1.default)(config, config.editorRightPanel.allowUnauthorized), express_1.default.static(config.editorRightPanel.uiPath));
191
+ app.use('/editor-panels', (0, ui_module_1.default)(config, config.editorRightPanel.allowUnauthorized), (0, render_ui_module_1.default)(config, config.editorRightPanel));
159
192
  }
160
193
  if (config.projectMenu) {
161
- app.use('/project-menu', (0, ui_module_1.default)(config, config.projectMenu.allowUnauthorized), express_1.default.static(config.projectMenu.uiPath));
194
+ app.use('/project-menu', (0, ui_module_1.default)(config, config.projectMenu.allowUnauthorized), (0, render_ui_module_1.default)(config, config.projectMenu));
162
195
  }
163
196
  if (config.projectMenuCrowdsource) {
164
- app.use('/project-menu-crowdsource', (0, ui_module_1.default)(config, config.projectMenuCrowdsource.allowUnauthorized), express_1.default.static(config.projectMenuCrowdsource.uiPath));
197
+ app.use('/project-menu-crowdsource', (0, ui_module_1.default)(config, config.projectMenuCrowdsource.allowUnauthorized), (0, render_ui_module_1.default)(config, config.projectMenuCrowdsource));
165
198
  }
166
199
  if (config.projectTools) {
167
200
  app.get('/logo/tools/logo.png', (req, res) => { var _a; return res.sendFile(((_a = config.projectTools) === null || _a === void 0 ? void 0 : _a.imagePath) || config.imagePath || (0, path_1.join)(__dirname, 'logo.png')); });
168
- app.use('/tools', (0, ui_module_1.default)(config, config.projectTools.allowUnauthorized), express_1.default.static(config.projectTools.uiPath));
201
+ app.use('/tools', (0, ui_module_1.default)(config, config.projectTools.allowUnauthorized), (0, render_ui_module_1.default)(config, config.projectTools));
169
202
  }
170
203
  if (config.projectReports) {
171
204
  app.get('/logo/reports/logo.png', (req, res) => { var _a; return res.sendFile(((_a = config.projectReports) === null || _a === void 0 ? void 0 : _a.imagePath) || config.imagePath || (0, path_1.join)(__dirname, 'logo.png')); });
172
- app.use('/reports', (0, ui_module_1.default)(config, config.projectReports.allowUnauthorized), express_1.default.static(config.projectReports.uiPath));
205
+ app.use('/reports', (0, ui_module_1.default)(config, config.projectReports.allowUnauthorized), (0, render_ui_module_1.default)(config, config.projectReports));
206
+ }
207
+ if (Object.keys(config).some((moduleKey) => {
208
+ const moduleConfig = config[moduleKey];
209
+ return typeof moduleConfig === 'object' && moduleConfig.hasOwnProperty('formSchema');
210
+ })) {
211
+ app.get('/api/form-data', json_response_1.default, (0, crowdin_client_1.default)(config), (0, form_data_display_1.default)());
212
+ app.post('/api/form-data', (0, crowdin_client_1.default)(config), (0, form_data_save_1.default)());
173
213
  }
174
214
  return {
175
215
  getMetadata: storage.getStorage().getMetadata.bind(storage.getStorage()),
@@ -0,0 +1,4 @@
1
+ /// <reference types="qs" />
2
+ import express from 'express';
3
+ import { Config, UiModule } from '../models';
4
+ export default function handle(config: Config, moduleConfig: UiModule): (req: express.Request<import("express-serve-static-core").ParamsDictionary, any, any, import("qs").ParsedQs, Record<string, any>>, res: express.Response<any, Record<string, any>>, next: Function) => void;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const express_1 = __importDefault(require("express"));
16
+ const util_1 = require("../util");
17
+ function handle(config, moduleConfig) {
18
+ return (0, util_1.runAsyncWrapper)((req, res, next) => __awaiter(this, void 0, void 0, function* () {
19
+ if (moduleConfig.formSchema) {
20
+ return res.render('form', {
21
+ formGetDataUrl: moduleConfig.formGetDataUrl ? moduleConfig.formGetDataUrl : '/api/form-data',
22
+ formPostDataUrl: moduleConfig.formPostDataUrl ? moduleConfig.formPostDataUrl : '/api/form-data',
23
+ formSchema: JSON.stringify(moduleConfig.formSchema),
24
+ formUiSchema: moduleConfig.formUiSchema ? JSON.stringify(moduleConfig.formUiSchema) : '{}',
25
+ });
26
+ }
27
+ if (moduleConfig.uiPath) {
28
+ return express_1.default.static(moduleConfig.uiPath)(req, res, next);
29
+ }
30
+ throw new Error('uiPath or formSchema should be provided for module');
31
+ }), config.onError);
32
+ }
33
+ exports.default = handle;
@@ -187,7 +187,7 @@ export interface IntegrationLogic {
187
187
  /**
188
188
  * function to update crowdin files (e.g. pull integration data to crowdin source files)
189
189
  */
190
- updateCrowdin: (projectId: number, client: Crowdin, apiCredentials: any, request: IntegrationFile[], appRootFolder?: SourceFilesModel.Directory, config?: any) => Promise<void | ExtendedResult<void>>;
190
+ updateCrowdin: (projectId: number, client: Crowdin, apiCredentials: any, request: IntegrationFile[], appRootFolder?: SourceFilesModel.Directory, config?: any, uploadTranslations?: boolean) => Promise<void | ExtendedResult<void>>;
191
191
  /**
192
192
  * function to update integration content (e.g. load crowdin translations and push them to integration service)
193
193
  */
@@ -235,14 +235,22 @@ export interface IntegrationLogic {
235
235
  * Enable integration next page event
236
236
  */
237
237
  integrationPagination?: boolean;
238
+ /**
239
+ * Enable the option to upload translations to crowdin that are already present in the integration.
240
+ */
241
+ uploadTranslations?: boolean;
238
242
  /**
239
243
  * function to get crowdin file translation progress
240
244
  */
241
245
  getFileProgress?: (projectId: number, client: Crowdin, fileId: number) => Promise<{
242
246
  [key: number]: TranslationStatusModel.LanguageProgress[];
243
247
  }>;
248
+ /**
249
+ * Register Crowdin webhook to get notified when translations are ready
250
+ */
251
+ webhooks?: Webhooks;
244
252
  }
245
- export declare type FormEntity = FormField | FormDelimeter;
253
+ export type FormEntity = FormField | FormDelimeter;
246
254
  export interface FormDelimeter {
247
255
  label: string;
248
256
  }
@@ -364,7 +372,7 @@ export interface FormField {
364
372
  helpText?: string;
365
373
  helpTextHtml?: string;
366
374
  label: string;
367
- type?: 'text' | 'password' | 'checkbox' | 'select';
375
+ type?: 'text' | 'password' | 'checkbox' | 'select' | 'textarea' | 'file';
368
376
  defaultValue?: any;
369
377
  /**
370
378
  * only for select
@@ -381,19 +389,27 @@ export interface FormField {
381
389
  label: string;
382
390
  value: string;
383
391
  }[];
392
+ /**
393
+ * only for type file
394
+ */
395
+ accept?: string;
396
+ /**
397
+ * field dependency settings
398
+ */
399
+ dependencySettings?: string;
384
400
  }
385
401
  export interface ExtendedResult<T> {
386
402
  data?: T;
387
403
  message?: string;
388
404
  stopPagination?: boolean;
389
405
  }
390
- export declare type TreeItem = File | Folder;
406
+ export type TreeItem = File | Folder;
391
407
  /**
392
408
  * 0 - folder
393
409
  * 1 - file
394
410
  * 2 - branch
395
411
  */
396
- declare type IntegrationTreeElementType = '0' | '1' | '2';
412
+ type IntegrationTreeElementType = '0' | '1' | '2';
397
413
  export interface File {
398
414
  id: string;
399
415
  name: string;
@@ -580,10 +596,29 @@ export interface CustomMTRequest {
580
596
  strings: string[];
581
597
  }
582
598
  export interface UiModule {
599
+ /**
600
+ * Form schema for react-jsonschema-doc to be used as front-end
601
+ * https://rjsf-team.github.io/react-jsonschema-form/docs
602
+ */
603
+ formSchema?: object;
604
+ /**
605
+ * URL to custom endpoint that can be used instead of default one to save form data.
606
+ * Endpoint should accept POST requests.
607
+ */
608
+ formPostDataUrl?: string;
609
+ /**
610
+ * URL to custom endpoint that can be used instead of default one to retrieve form data.
611
+ * Endpoint should accept GET requests.
612
+ */
613
+ formGetDataUrl?: string;
614
+ /**
615
+ * Additional attributes for react-jsonschema-doc
616
+ */
617
+ formUiSchema?: object;
583
618
  /**
584
619
  * path to ui folder (e.g. {@example join(__dirname, 'public')})
585
620
  */
586
- uiPath: string;
621
+ uiPath?: string;
587
622
  /**
588
623
  * page name (default index.html)
589
624
  */
@@ -643,4 +678,35 @@ export interface Pricing {
643
678
  cachingSeconds?: number;
644
679
  infoDisplayDaysThreshold?: number;
645
680
  }
681
+ export interface Webhooks {
682
+ crowdinWebhookUrl?: string;
683
+ integrationWebhookUrl?: string;
684
+ urlParam?: string;
685
+ crowdinWebhooks?: (client: Crowdin, projectId: number, available: boolean, config?: any) => Promise<void>;
686
+ integrationWebhooks?: (apiCredentials: any, urlParam: string, available: boolean, config?: any, syncSettings?: any) => Promise<void>;
687
+ crowdinWebhookInterceptor?: (projectId: number, client: Crowdin, appRootFolder?: SourceFilesModel.Directory, config?: any, syncSettings?: any, webhookRequest?: any) => Promise<UpdateIntegrationRequest>;
688
+ integrationWebhookInterceptor?: (projectId: number, client: Crowdin, apiCredentials: any, appRootFolder?: SourceFilesModel.Directory, config?: any, syncSettings?: any, webhookRequest?: any) => Promise<IntegrationFile[]>;
689
+ queueUrl: string;
690
+ }
691
+ export declare enum SyncCondition {
692
+ ALL = 0,
693
+ TRANSLATED = 1,
694
+ APPROVED = 2
695
+ }
696
+ export declare enum SyncType {
697
+ NONE = 0,
698
+ SCHEDULE = 1,
699
+ WEBHOOKS = 2
700
+ }
701
+ export type Payload = {
702
+ event: string;
703
+ projectId: string;
704
+ language: string;
705
+ fileId: string;
706
+ };
707
+ export type WebhookUrlParams = {
708
+ projectId: number;
709
+ crowdinId: string;
710
+ clientId: string;
711
+ };
646
712
  export {};